Extending Perl Critic
Upcoming SlideShare
Loading in...5
×
 

Extending Perl Critic

on

  • 7,784 views

Josh McAdams presents "Extending Perl Critic" at the Nordic Perl Workshop 2007.

Josh McAdams presents "Extending Perl Critic" at the Nordic Perl Workshop 2007.

Statistics

Views

Total Views
7,784
Views on SlideShare
7,776
Embed Views
8

Actions

Likes
2
Downloads
141
Comments
0

4 Embeds 8

http://thomas-fahle.blogspot.com 5
http://209.85.135.104 1
http://www.slideshare.net 1
http://www.slideee.com 1

Accessibility

Categories

Upload Details

Uploaded via as OpenOffice

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Extending Perl Critic Extending Perl Critic Presentation Transcript

  • Customizing and Extending Perl Critic Nordic Perl Workshop 2007 Customizing and Extending Perl Critic Josh McAdams
  • Customizing and Extending Perl Critic Nordic Perl Workshop 2007 A Quick Review - What is Perl Critic ... a static source code analyzer for Perl code ... a system of policies that are enforced on your code ... written by Jeffrey Ryan Thalhammer #!/usr/bin/perl print “Hallo, Denmark ”;
  • Customizing and Extending Perl Critic Nordic Perl Workshop 2007 A Quick Review --(0)> perlcritic hello_denmark.pl Code before strictures are enabled at line 3, column 1. See page 429 of PBP. (Severity: 5) ... is the jarring your memory? Running perlcritic...
  • Customizing and Extending Perl Critic Nordic Perl Workshop 2007 Customizing Perl Critic - How do you customize Perl Critic ... we saw much of this in the “Introduction” talk ... you can ... ignore policies ... assign new severities to policies ... group policies into themes ... pass constructor arguments to policies
  • Customizing and Extending Perl Critic Nordic Perl Workshop 2007 Customizing Perl Critic --(0)> cat ~/.perlcriticrc severity = 2 top = 5 exclude = Editor::RequireEmacsFileVariables Miscellanea::RequireRcsKeywords [ControlStructures::ProhibitPostfixControls] severity = 4 allow = if unless theme = iffy Looking into a .perlcriticrc file... ... but what about extending Perl Critic? The default severity to report How many violations to report Policies to ignore Change the default severity for a policy Pass arguments to the policy constructor, in this case telling it to allow trailing ifs and unlesses Apply a new theme
  • Customizing and Extending Perl Critic Nordic Perl Workshop 2007 Extending Perl Critic - Customizing is out-of-the-box easy, how do I extend Perl Critic? ... extending Perl Critic is as easy as adding new policy modules ... you can write your own, or grab some pre-written extensions from CPAN
  • Customizing and Extending Perl Critic Nordic Perl Workshop 2007 Surveying The Land - First, let's see what all policies Perl Critic provides for us ... there are 98 policies that you get in the core distribution ... the policies are all in the Perl::Critic::Policy namespace ... the policies are divided into 16 categories
  • Customizing and Extending Perl Critic Nordic Perl Workshop 2007 Core Policy Categories (1-4) - BuiltinFunctions ... fun with builtins like ProhibitStringyEval - ClassHierarchies ... oo rules like ProhibitExplicitISA - CodeLayout ... picky stuff like RequireTidyCode - ControlStructures ... control structure rules like ProhibitUnlessBlocks
  • Customizing and Extending Perl Critic Nordic Perl Workshop 2007 Core Policy Categories (5-8) - Documentation ... POD rules like RequirePodAtEnd - ErrorHandling ... the singular RequireCarping - InputOutput ... I/O related like ProhibitTwoArgOpen - Miscellanea ... random pickiness like RequireRcsKeywords
  • Customizing and Extending Perl Critic Nordic Perl Workshop 2007 Core Policy Categories (9-12) - Modules ... module rules like RequireEndWithOne - NamingConventions ... includes MyFavorite ProhibitMixedCaseSubs - References ... the one and only ProhibitDoubleSigils - RegularExpressions ... regex goodness like RequireExtendedFormatting
  • Customizing and Extending Perl Critic Nordic Perl Workshop 2007 Core Policy Categories (13-16) - Subroutines ... subroutine related like RequireFinalReturn - TestingAndDebugging ... tends to be prama-related things like RequireUseStrict - ValuesAndExpressions ... rhs rules such as ProhibitEmptyQuotes - Variables ... variable rules such as ProhibitLocalVars
  • Customizing and Extending Perl Critic Nordic Perl Workshop 2007 Core Policy Categories (the end) - hey, stop complaining, I could have done all 98 :) - so what if these polices aren't enough or just don't fit your organization? ... use someone else's extensions!
  • Customizing and Extending Perl Critic Nordic Perl Workshop 2007 Perl::Critic::Bangs - a collection of Perl Critic policies written by Andy Lester - readily available on CPAN - adds the following policies: ... ProhibitCommentedOutCode ... because your not really using it and it's in svn anyway ... ProhibitFlagComments ... don't TODO, JFDI ... ProhibitNoPlan ... plan your tests, test your plan
  • Customizing and Extending Perl Critic Nordic Perl Workshop 2007 Perl::Critic::Bangs (cont'd) - and a few more: ... ProhibitNumberedNames ... because $my_variable2 isn't very creative ... ProhibitRefProtoOrProto ... ref($proto) || $proto for determining class name is typically wrong ... ProhibitVagueNames ... $data, $info, $wtf? ... is that still not enough for you? The fully qualified name is Perl::Critic::Policy::Bangs::ProhibitNumberedNames
  • Customizing and Extending Perl Critic Nordic Perl Workshop 2007 Perl::Critic::More - then how about more, Chris Dolan's Perl::Critic::More that is: ... CodeLayout::RequireASCII ... no high-bit code characters for you! ... Editor::RequireEmacsFileVariables ... special emacs variables... I'll have to take your word on this one ... Modules::PerlMinimumVersion ... how backwards-compatible are you? ... Modules::RequirePerlVersion ... use 5.8.0 ... how about one more set?
  • Customizing and Extending Perl Critic Nordic Perl Workshop 2007 Perl::Critic::Lax - is Perl Critic too strict, the try Ricardo Signes's Perl::Critic::Lax: ... ProhibitEmptyQuotes::ExceptAsFallback ... $got || ''; looks too good not to use ... ProhibitStringyEval::ExceptForRequire ... stringy evals are bad and all, but sometimes you just gotta use them ... RequireEndWithTrueConst ... because sometimes humor is more important ... RequireExplicitPackage::ExceptForPragmata ... because your not always in need of a package, but you can always use warnings and strict
  • Customizing and Extending Perl Critic Nordic Perl Workshop 2007 CPAN'd Extensions - we've seen a pretty good mix of Perl Critic extensions that are available on CPAN: ... Perl::Critic::Bangs ... Perl::Critic::More ... Perl::Critic::Lax ... but these won't always do the trick
  • Customizing and Extending Perl Critic Nordic Perl Workshop 2007 Creating Your Own Policies - Sometimes you just have to warm up the editor and code your own ... how difficult is it? - It is actually surprisingly easy to create your own policies, you just need to create a module in the Perl::Critic::Policy namespace that has some required subroutines. ... let's see what it takes
  • Customizing and Extending Perl Critic Nordic Perl Workshop 2007 BuiltinFunctions::RequireBlockGrep - We'll start by looking at a core Policy that requires that you use the block form of grep - Here's what it is looking for: @matches = grep /pattern/, @list; #not ok @matches = grep { /pattern/ } @list; #ok ... real code please!
  • Customizing and Extending Perl Critic Nordic Perl Workshop 2007 BuiltinFunctions::RequireBlockGrep - There's a little administrative overhead: package Perl::Critic::Policy::BuiltinFunctions::RequireBlockGrep; use strict; use warnings; use Perl::Critic::Utils qw{ :severities :classification :ppi }; use base 'Perl::Critic::Policy'; our $VERSION = 1.051; Declare your package Import some handy utilities Inherit from the core Policy class
  • Customizing and Extending Perl Critic Nordic Perl Workshop 2007 BuiltinFunctions::RequireBlockGrep - Some information required by Perl Critic: my $desc = q{Expression form of "grep"}; my $expl = [ 169 ]; A description of what you policy does Either a page reference for “Perl Best Practices” or an explaination of what the offending code is doing and instructions on how to fix it.
  • Customizing and Extending Perl Critic Nordic Perl Workshop 2007 BuiltinFunctions::RequireBlockGrep - Some information required by Perl Critic: sub supported_parameters { return() } sub default_severity { return $SEVERITY_HIGH } * See ControlStructures::ProhibitPostfixControls for an example Returns a list of constructor parameters that the module supports, in this case none* Returns a numeric value that indicates the default severity for the module. There are five constants exported from a Perl Critic utility module: $SEVERITY_HIGHEST = 5 $SEVERITY_HIGH = 4 $SEVERITY_MEDIUM = 3 $SEVERITY_LOW = 2 $SEVERITY_LOWEST = 1 Why these aren't 'brutal' through 'gental' I don't know
  • Customizing and Extending Perl Critic Nordic Perl Workshop 2007 BuiltinFunctions::RequireBlockGrep - Some information required by Perl Critic: sub default_themes { return qw( core bugs pbp ) } sub applies_to { return 'PPI::Token::Word' } Returns a list of default themes that identify this policy; you probably won't be using core Returns a list of PPI package names that the policy is applied to. Since all of the PPI DOM objects could be potentially analyzed by every Perl Critic policy, this provides a filter that gets passes your policy only the elements that you care about.
  • Customizing and Extending Perl Critic Nordic Perl Workshop 2007 BuiltinFunctions::RequireBlockGrep - And now the method that does all of the work: sub violates { my ( $self, $elem, undef ) = @_; return if $elem ne 'grep'; return if ! is_function_call($elem); my $arg = first_arg($elem); return if !$arg; return if $arg->isa('PPI::Structure::Block'); return $self->violation( $desc, $expl, $elem ); } The method is passed the policy object, a PPI document object representing the current element in the code, and the entire PPI document. If a problem is found, the violation method is called with the the policy description, explanation of the issue, and offending PPI object as arguments... I guess you can tweak the description and explanation if you want.
  • Customizing and Extending Perl Critic Nordic Perl Workshop 2007 BuiltinFunctions::RequireBlockGrep - Let's take a closer look at the meat of the subroutine: return if $elem ne 'grep'; return if ! is_function_call($elem); We know we are getting PPI::Token::Words, which are subclasses of PPI::Element, which in turn overrides 'ne' to return the actual content of the element... in this case the actual word. We only want to consider 'grep' is_function_call is one of those handy subroutines exported by Perl::Critic::Utils. In this case, it does the dirty work involved in determining if a given word is a function call based on the PPI::Token::Word's context in the document. We only want to consider grep if it is actually the function call to grep.
  • Customizing and Extending Perl Critic Nordic Perl Workshop 2007 BuiltinFunctions::RequireBlockGrep - Only a little more to go my $arg = first_arg($elem); return if !$arg; return if $arg->isa('PPI::Structure::Block'); first_arg is another one of those Perl Critic utility methods. In this case, it is plucking the first argument passed to the grep function. If there is no argument, we can't tell if it is null, so assume it's not wrong. Finally we see if the first argument to grep is a block. If it is, then everything is okay.
  • Customizing and Extending Perl Critic Nordic Perl Workshop 2007 BuiltinFunctions::RequireBlockGrep - Let's look at the code one more time sub violates { my ( $self, $elem, undef ) = @_; return if $elem ne 'grep'; return if ! is_function_call($elem); my $arg = first_arg($elem); return if !$arg; return if $arg->isa('PPI::Structure::Block'); return $self->violation( $desc, $expl, $elem ); }
  • Customizing and Extending Perl Critic Nordic Perl Workshop 2007 BuiltinFunctions::RequireBlockGrep - Do you see the basic idea behind the code? ... We try to find every excuse for why the code is not in violation ... are you a grep? ... are you a grep function? ... do you have any arguments? ... is your first argument a block? ... and finally, we return a violation ... innocent until proven guilty ... your code doesn't have to flow this way, but it tends to be a good way to approach the problem
  • Customizing and Extending Perl Critic Nordic Perl Workshop 2007 What Did We Learn - Building custom policies is pretty easy; it requires: ... a little bit of setup code ... a package name (Perl::Critic::Policy::) ... a description of the policy ... an explanation of the issue ... a default set of themes ... a default severity ... a list of PPI elements to consider ... an optional list of accepted constructor arguments ... a violates method to do all of the work ... but this is typically a small amount of work ... most policies can be implemented in tens of lines of code
  • Customizing and Extending Perl Critic Nordic Perl Workshop 2007 Perl::Critic::Utils and PPI - So what makes policy building tricky? ... working with Perl::Critic::Utils and PPI ... both are easy to use, but it takes some time to remember all of the functionality that they provide
  • Customizing and Extending Perl Critic Nordic Perl Workshop 2007 Perl::Critic::Utils - Provides 33 importable subroutines for analyzing and working with PPI elements ... some examples: ... is_hash_key ... is_label_pointer ... is_perl_bareword ... is_perl_builtin_with_optional_argument - Provides 21 importable constants ... some examples: ... $COMMA ... $FATCOMMA ... you really just have to RTFM
  • Customizing and Extending Perl Critic Nordic Perl Workshop 2007 PPI - Provides 62 types of PDOM objects representing pieces of ... some examples: ... PPI::Document::Fragment ... PPI::Statement::Package ... PPI::Structure::ForLoop ... PPI::Token::Whitespace ... PPI::Token::QuoteLike::Backtick - Any of the PDOM types could be included in your applies_to() list of elements that you want to consider in your policy ... there are so many of these that you really have to RTFM
  • Customizing and Extending Perl Critic Nordic Perl Workshop 2007 PPI::Element - Most of the PPI PDOM objects you'll be interested in inherit from PPI::Element, which provides it's own set of utility methods to help you poke around the PDOM passed to your violates() method. ... some examples: ... significant – is the element really significant to the code ... next_sibling – next element in the PDOM ... snext_sibling – same as above, only skips insignificant elements ... previous_token – previous PPI::Token element - There are a lot of these that let you walk around the code
  • Customizing and Extending Perl Critic Nordic Perl Workshop 2007 Testing Your Policies - Testing policies is actually quite easy also... if you peek into the Perl Critic source and borrow code from them that is :) - All that you have to do is create a Perl::Critic object and your policy object and then just run the policy on a suite of code samples
  • Customizing and Extending Perl Critic Nordic Perl Workshop 2007 Testing Your Policies - First set use some modules and then set up some tests use warnings; use strict; use Test::More; use Perl::Critic; my @to_validate = ( 'grep {}', 'grep { 1 }', 'grip ""', ); my @to_violate = ( 'grep ""', 'grep "1"', ); plan tests => @to_validate + @to_violate; I like setting up pieces of code that I expect to be valid and pieces that I expect to violate my policy And dynamically creating my test plan based on the number of code samples I'm using
  • Customizing and Extending Perl Critic Nordic Perl Workshop 2007 Testing Your Policies - Then create a Perl::Critic object and an object of your policy my $c = Perl::Critic->new( -profile => 'NONE' ); my $policy = Perl::Critic::Policy::BuiltinFunctions::RequireBlockGrep ->new(); $c->add_policy( -policy => $policy ); Just create the two objects and add your policy as the one-and-only policy
  • Customizing and Extending Perl Critic Nordic Perl Workshop 2007 Testing Your Policies - And finally apply your policy to the code samples ok( ( scalar $c->critique( $_ ) == 0 ), 'policy on valid code' ) for (@to_validate); ok( ( scalar $c->critique( $_ ) > 0 ), 'policy on invalid code' ) for (@to_violate);
  • Customizing and Extending Perl Critic Nordic Perl Workshop 2007 Testing Your Policies - We have tests! --(0)> prove test.pl test....ok All tests successful. Files=1, Tests=6, 1 wallclock secs ( 0.86 cusr + 0.18 csys = 1.04 CPU )
  • Customizing and Extending Perl Critic Nordic Perl Workshop 2007 Questions? Comments? Criticisms?