NAME

Module::Checkstyle::Check - Base class for checks

WRITING CHECK MODULES

Module::Checkstyle is extensible via a plug-in mechanism. This guide takes you through the basic steps in writing your own check.

To write a check you create a module that lives in the namespace Module::Checkstyle::Check:: and that extends Module::Checkstyle::Check. As an example we'll write a check that counts the length of a named subroutine.

To begin with we create a module named Module::Checkstyle::Check::SubLength either via h2xs or Module::Starter.

In the file Module/Checkstyle/Check/SubLength.pm we enter the following code:

package Module::Checkstyle::Check::SubLength;

use strict;
use warnings;
use Readonly;

use Module::Checkstyle::Util qw(:args :problem);
use base qw(Module::Checkstyle::Check);

Next we need to tell Module::Checkstyle what we want to recive events for. We do this by overriding the subroutine register which is called if the check is enabled in the configuration file.

sub register {
    return ('enter PPI::Statement::Sub' => \&enter_subroutine);
}

The method register must return a hash with event => handler pairs (actually it's a list that is returned). The event is defined by an optional operation, enter or leave, followed by the type of PPI::Element we want to respond to, which in this case is PPI::Statement::Sub.

The plug-in is then instansiated by calling its new method. This method should read the configuration directives into the object itself because there can exist mulitple instances of the check with different configurations. The new method is supplied an instance of Module::Checkstyle::Config. Lets define the configuration-directive max-length as a readonly-variable and add a constructor that reads it into the instance.

Readonly my $MAX_LENGTH => 'max-length';

sub new {
    my ($class, $config) = @_;
    $class = ref $class || $class;

    my $self = bless { config => $config }, $class;

    $self->{$MAX_LENGTH} = as_numeric($config->get_directive($MAX_LENGTH));
    
    return $self;
}

The function as_numeric is provided by Module::Checkstyle::Util via the tag args.

Next we need to write our event handling code that is called when a named subroutine is found. Event-handlers retrieves three arguments: the instance of the plug-in, the PPI::Element and the path of the current file that is being processed.

my enter_subroutine {
    my ($self, $subroutine, $file) = @_;

    my @problems;

    if ($self->{$MAX_LENGTH}) { # No need to run code if it's turned off
        my $block = $subroutine->block();
        if ($block) { # It's not a forward declaration
            my $line = $subroutine->location->[0]; # The line the declartion is on
            my $last_line = $block->last_element->location->[0]; # The line where } is at
            my $length = $last_line - $line;
            if ($length > $self->{$MAX_LENGTH}) {
                my $name = $subroutine->name();
                push @problems, make_problem($self->{config}->get_severity($MAX_LENGTH),
                                             "Subroutine '$name' is too long ($length)",
                                             $subroutine->location,
                                             $file);
            }
        }
    }

    return @problems;
}

The function make_problem is exported by Module::Checkstyle::Util in the tag problem.

To finish up our module we write the documentation, see Module::Checkstyle::Check::Package for an example, write the tests and make sure the module returns a true value.

METHODS

new ($config)

Default constructor that returns a hash-reference blessed to the subclass. The returned object will have the passed configuration object available under the key config.

register

Abstract method that subclasses should override that provides the events it responds to.

BUGS AND LIMITATIONS

Please report any bugs or feature requests to bug-module-checkstyle@rt.cpan.org, or through the web interface at http://rt.cpan.org.

AUTHOR

Claes Jacobsson <claesjac@cpan.org>

LICENCE AND COPYRIGHT

Copyright (c) 2005, Claes Jacobsson <claesjac@cpan.org>. All rights reserved.

This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See perlartistic.

DISCLAIMER OF WARRANTY

BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR, OR CORRECTION.

IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.