SlideShare una empresa de Scribd logo
1 de 70
Customizing and Extending  Perl Critic YAPC::NA 2007 Houston, TX Josh McAdams
Extending Perl Critic Perl Critic is a very powerful and customizable system in its off-the-CPAN state; however, there are times when you need to create your own policies to enforce your own coding standards.  We will see how to do that by creating a variant of one of the core modules:  BuiltinFunctions::RequireBlockGrep .  We'll call our policy  BuiltinFunctions::RequireBlockGrepAndMap  and make it force block  map s in addition to  grep s.
Extending Perl Critic use strict; use warnings; use Test::More tests => 1; use_ok( 'Perl::Critic::Policy::' . 'BuiltinFunctions::RequireBlockGrepAndMap' ); t/initial-setup.t
Extending Perl Critic --(0)> prove -Ilib t/initial-setup.t t/initial-setup.... #  Failed test 'use Perl::Critic::Policy::BuiltinFunctions::RequireBlockGrepAndMap;' #  at t/initial-setup.t line 5. #  Tried to use 'Perl::Critic::Policy::BuiltinFunctions::RequireBlockGrepAndMap'. #  Error:  Can't locate Perl/Critic/Policy/BuiltinFunctions/RequireBlockGrepAndMap.pm in @INC (...) line 2. # BEGIN failed--compilation aborted at t/initial-setup.t line 5. # Looks like you failed 1 test of 1. t/initial-setup....dubious  Test returned status 1 (wstat 256, 0x100) DIED. FAILED test 1 Failed 1/1 tests, 0.00% okay Failed Test  Stat Wstat Total Fail  List of Failed ------------------------------------------------------------------------------- t/initial-setup.t  1  256  1  1  1 Failed 1/1 test scripts. 1/1 subtests failed. Files=1, Tests=1,  0 wallclock secs ( 0.04 cusr +  0.02 csys =  0.06 CPU) Failed 1/1 test programs. 1/1 subtests failed.
Extending Perl Critic package  Perl::Critic::Policy::BuiltinFunctions::RequireBlockGrepAndMap ; use warnings; use strict; 1; lib/Perl/Critic/Policy/BuiltinFunctions/RequireBlockGrepAndMap.pm
Extending Perl Critic --(0)> prove -Ilib t/* t/initial-setup....ok  All tests successful.
Extending Perl Critic use strict; use warnings; use Test::More tests => 2; use_ok( 'Perl::Critic::Policy::' . 'BuiltinFunctions::RequireBlockGrepAndMap' ); my $policy =  Perl::Critic::Policy::BuiltinFunctions::RequireBlockGrepAndMap ->new(); is($policy->get_severity(), 4, 'high severity set'); t/initial-setup.t
Extending Perl Critic --(0)> prove -Ilib t/* t/initial-setup....Can't locate object method "new" via package "Perl::Critic::Policy::BuiltinFunctions::RequireBlockGrepAndMap" at t/initial-setup.t line 10. # Looks like you planned 2 tests but only ran 1. # Looks like your test died just after 1. t/initial-setup....dubious  Test returned status 255 (wstat 65280, 0xff00) DIED. FAILED test 2 Failed 1/2 tests, 50.00% okay Failed Test  Stat Wstat Total Fail  List of Failed ------------------------------------------------------------------------------- t/initial-setup.t  255 65280  2  2  2 Failed 1/1 test scripts. 1/2 subtests failed. Files=1, Tests=2,  0 wallclock secs ( 0.04 cusr +  0.02 csys =  0.06 CPU) Failed 1/1 test programs. 1/2 subtests failed.
Extending Perl Critic package  Perl::Critic::Policy::BuiltinFunctions::RequireBlockGrepAndMap;  use warnings; use strict; use base qw(Perl::Critic::Policy); use Perl::Critic::Utils; sub new { my ($class, %args) = @_; return $class->SUPER::new(%args); } sub default_severity { return $SEVERITY_HIGH; } 1; lib/Perl/Critic/Policy/BuiltinFunctions/RequireBlockGrepAndMap.pm
Extending Perl Critic --(0)> prove -Ilib t/* t/initial-setup....ok  All tests successful. Files=1, Tests=2,  0 wallclock secs ( 0.12 cusr +  0.03 csys =  0.15 CPU)
Extending Perl Critic Severity Level Variables Exported By Perl::Critic::Utils $SEVERITY_HIGHEST  == 5 $SEVERITY_HIGH  == 4 $SEVERITY_MEDIUM  == 3 $SEVERITY_LOW  == 2 $SEVERITY_LOWEST  == 1
Extending Perl Critic ... is_deeply( [$policy->get_themes()],  [qw(almost_core pbp)],  'proper themes set' ); t/initial-setup.t
Extending Perl Critic --(0)> prove -Ilib t/* t/initial-setup....NOK 3  #  Failed test 'proper themes set' #  at t/initial-setup.t line 16. #  Structures begin differing at: #  $got->[0] = Does not exist #  $expected->[0] = 'almost_core' # Looks like you failed 1 test of 3. t/initial-setup....dubious  Test returned status 1 (wstat 256, 0x100) DIED. FAILED test 3 Failed 1/3 tests, 66.67% okay Failed Test  Stat Wstat Total Fail  List of Failed ------------------------------------------------------------------------------- t/initial-setup.t  1  256  3  1  3 Failed 1/1 test scripts. 1/3 subtests failed. Files=1, Tests=3,  0 wallclock secs ( 0.12 cusr +  0.03 csys =  0.15 CPU) Failed 1/1 test programs. 1/3 subtests failed.
Extending Perl Critic sub default_themes {  return qw( almost_core pbp );  } lib/Perl/Critic/Policy/BuiltinFunctions/RequireBlockGrepAndMap.pm
Extending Perl Critic --(0)> prove -Ilib t/* t/initial-setup....ok  All tests successful. Files=1, Tests=3,  0 wallclock secs ( 0.12 cusr +  0.03 csys =  0.15 CPU)
Extending Perl Critic ... is_deeply( [$policy->applies_to()],  [qw(PPI::Token::Word)],  'applies only to words' ); t/initial-setup.t
Extending Perl Critic --(0)> prove -Ilib t/* t/initial-setup....NOK 4  #  Failed test 'applies only to words' #  at t/initial-setup.t line 18. #  Structures begin differing at: #  $got->[0] = 'PPI::Element' #  $expected->[0] = 'PPI::Token::Word' # Looks like you failed 1 test of 4. t/initial-setup....dubious  Test returned status 1 (wstat 256, 0x100) DIED. FAILED test 4 Failed 1/4 tests, 75.00% okay Failed Test  Stat Wstat Total Fail  List of Failed ------------------------------------------------------------------------------- t/initial-setup.t  1  256  4  1  4 Failed 1/1 test scripts. 1/4 subtests failed. Files=1, Tests=4,  0 wallclock secs ( 0.12 cusr +  0.03 csys =  0.15 CPU) Failed 1/1 test programs. 1/4 subtests failed.
Extending Perl Critic sub applies_to {  return 'PPI::Token::Word'; } lib/Perl/Critic/Policy/BuiltinFunctions/RequireBlockGrepAndMap.pm
Extending Perl Critic --(0)> prove -Ilib t/* t/initial-setup....ok  All tests successful. Files=1, Tests=4,  0 wallclock secs ( 0.12 cusr +  0.03 csys =  0.15 CPU)
Extending Perl Critic PPI::Document PPI::Document::File PPI::Document::Fragment PPI::Document::Normalized PPI::Element PPI::Statement PPI::Statement::Break PPI::Statement::Compound PPI::Statement::Data PPI::Statement::End PPI::Statement::Expression PPI::Statement::Include PPI::Statement::Null PPI::Statement::Package PPI::Statement::Scheduled PPI::Statement::Sub PPI::Statement::Unknown PPI::Statement::UnmatchedBrace PPI::Statement::Variable PPI::Structure PPI::Structure::Block PPI::Structure::Condition PPI::Structure::Constructor PPI::Token::Quote::Single PPI::Token::QuoteLike PPI::Token::QuoteLike::Backtick PPI::Token::QuoteLike::Command PPI::Token::QuoteLike::Readline PPI::Token::QuoteLike::Regexp PPI::Token::QuoteLike::Words PPI::Token::Regexp PPI::Token::Regexp::Match PPI::Token::Regexp::Substitute PPI::Token::Regexp::Transliterate PPI::Token::Separator PPI::Token::Structure PPI::Token::Symbol PPI::Token::Unknown PPI::Token::Whitespace PPI::Token::Word PPI::Structure::ForLoop PPI::Structure::List PPI::Structure::Subscript PPI::Structure::Unknown PPI::Token PPI::Token::ArrayIndex PPI::Token::Attribute PPI::Token::Cast PPI::Token::Comment PPI::Token::DashedWord PPI::Token::Data PPI::Token::End PPI::Token::HereDoc PPI::Token::Label PPI::Token::Magic PPI::Token::Number PPI::Token::Operator PPI::Token::Pod PPI::Token::Prototype PPI::Token::Quote PPI::Token::Quote::Double PPI::Token::Quote::Interpolate PPI::Token::Quote::Literal PPI Modules
Extending Perl Critic use warnings; use strict; use Test::More tests => 1; use Perl::Critic::TestUtils qw(pcritique); my $custom_policy = 'BuiltinFunctions::RequireBlockGrepAndMap'; my $code = 'grep { $_ }'; my $violation_count =  pcritique( $custom_policy, code ); ok(!$violation_count, 'allowed block grep'); t/exercise-policy.t
Extending Perl Critic Some Perl::Critic::TestUtils Help Methods - block_perlcriticrc - critique - pcritique - fcritique
Extending Perl Critic --(0)> prove -Ilib t/* t/exercise-policy....Can't call abstract method at /opt/local/lib/perl5/site_perl/5.8.7/Perl/Critic/Policy.pm line 98 Perl::Critic::Policy::violates('Perl::Critic::Policy::BuiltinFunctions::RequireBlockGrepAndMa...', 'PPI::Token::Word=HASH(0x1a01b40)', 'Perl::Critic::Document=HASH(0x183d338)') called at /opt/local/lib/perl5/site_perl/5.8.7/Perl/Critic.pm line 165 Perl::Critic::_critique('Perl::Critic::Policy::BuiltinFunctions::RequireBlockGrepAndMa...', 'Perl::Critic::Document=HASH(0x183d338)', 'HASH(0x19fc194)') called at /opt/local/lib/perl5/site_perl/5.8.7/Perl/Critic.pm line 121 Perl::Critic::critique('Perl::Critic=HASH(0x1800f88)', 'SCALAR(0x1810eac)') called at /opt/local/lib/perl5/site_perl/5.8.7/Perl/Critic/TestUtils.pm line 53 Perl::Critic::TestUtils::pcritique('BuiltinFunctions::RequireBlockGrepAndMap', 'SCALAR(0x1810eac)') called at t/exercise-policy.t line 9 # Looks like your test died before it could output anything. t/exercise-policy....dubious  Test returned status 255 (wstat 65280, 0xff00) DIED. FAILED test 1 Failed 1/1 tests, 0.00% okay t/initial-setup......ok  Failed Test  Stat Wstat Total Fail  List of Failed ------------------------------------------------------------------------------- t/exercise-policy.t  255 65280  1  2  1 Failed 1/2 test scripts. 1/5 subtests failed. Files=2, Tests=5,  1 wallclock secs ( 0.99 cusr +  0.24 csys =  1.23 CPU) Failed 1/2 test programs. 1/5 subtests failed.
Extending Perl Critic sub violates {} lib/Perl/Critic/Policy/BuiltinFunctions/RequireBlockGrepAndMap.pm
Extending Perl Critic --(0)> prove -Ilib t/* t/exercise-policy....ok t/initial-setup......ok All tests successful. Files=2, Tests=5,  2 wallclock secs ( 0.98 cusr +  0.22 csys =  1.20 CPU)
Extending Perl Critic my $custom_policy =  'BuiltinFunctions::RequireBlockGrepAndMap'; { my $code = 'grep { $_ }'; my $violation_count =  pcritique( $custom_policy, code ); is($violation_count, 0, 'allowed block grep'); } { my $code = 'grep "$_"'; my $violation_count =  pcritique( $custom_policy, code ); is($violation_count, 1, 'disallowed string grep'); } t/exercise-policy.t
Extending Perl Critic --(0)> prove -Ilib t/* t/exercise-policy....NOK 2  #  Failed test 'disallowed string grep' #  at t/exercise-policy.t line 17. #  got: '0' #  expected: '1' # Looks like you failed 1 test of 2. t/exercise-policy....dubious  Test returned status 1 (wstat 256, 0x100) DIED. FAILED test 2 Failed 1/2 tests, 50.00% okay t/initial-setup......ok  Failed Test  Stat Wstat Total Fail  List of Failed ------------------------------------------------------------------------------- t/exercise-policy.t  1  256  2  1  2 Failed 1/2 test scripts. 1/6 subtests failed. Files=2, Tests=6,  2 wallclock secs ( 1.00 cusr +  0.22 csys =  1.22 CPU) Failed 1/2 test programs. 1/6 subtests failed.
Extending Perl Critic my $description = q{Expression form of "grep" and "map"}; my $explanation = [169]; sub violates { my ( $self, $element, $document ) = @_; return unless $element eq 'grep'; my $sibling = $element->snext_sibling(); return if $sibling->isa('PPI::Structure::Block'); return $self->violation(  $description,  $explanation,  $element,  ); } lib/Perl/Critic/Policy/BuiltinFunctions/RequireBlockGrepAndMap.pm
Extending Perl Critic t/exercise-policy....ok t/initial-setup......ok All tests successful. Files=2, Tests=6,  1 wallclock secs ( 1.00 cusr +  0.22 csys =  1.22 CPU)
Extending Perl Critic Some PPI Utility Methods (from PPI::Element) - parent - next_sibling - snext_sibling - previous_sibling - sprevious_sibling - first_token - last_token - next_token - previous_token
Extending Perl Critic use warnings; use strict; use Test::More; use Perl::Critic::TestUtils qw(subtests_in_tree fcritique pcritique); my $custom_policy = 'BuiltinFunctions::RequireBlockGrepAndMap'; my $subtests  = subtests_in_tree('t/BuiltinFunctions'); my $test_count = 0; $test_count += @{$subtests->{$_}} for ( keys %{$subtests} ); plan tests => $test_count; ... t/exercise-policy.t
Extending Perl Critic for my $policy ( sort keys %$subtests ) { for my $subtest ( @{ $subtests->{$policy} } ) { local $TODO = $subtest->{TODO}; my $desc = join( ' - ', $policy, "line $subtest->{lineno}", $subtest->{name} ); my $violations = $subtest->{filename} ? eval { fcritique( $policy,  subtest->{code}, $subtest->{filename}, $subtest->{parms} ); } : eval { pcritique( $policy, subtest->{code}, $subtest->{parms} ) }; my $err = $@; if ( $subtest->{error} ) { if ( 'Regexp' eq ref $subtest->{error} ) { like( $err, $subtest->{error}, $desc ); } else { ok( $err, $desc ); } } else { die $err if $err; is( $violations, $subtest->{failures}, $desc ); } } } t/exercise-policy.t
Extending Perl Critic ## name allowed block grep ## failures 0 ## cut grep { $_ } ## name disallowed string grep ## failures 1 ## cut grep "$_" t/BuiltinFunctions/RequireBlockGrepAndMap.run
Extending Perl Critic --(0)> prove -Ilib t/* t/exercise-policy....ok t/initial-setup......ok All tests successful. Files=2, Tests=6,  2 wallclock secs ( 1.01 cusr +  0.22 csys =  1.23 CPU)
Extending Perl Critic ## name  A Test Name ## parms { allow_y => 0 } ## TODO Should pass later ## error 1 ## error /Can't load Foo::Bar/ ## filename lib/Foo/Bar.pm ## cut Options For .run Files
Extending Perl Critic ... ## name grep as a method call ## failures 0 ## cut $object->grep('this'); t/BuiltinFunctions/RequireBlockGrepAndMap.run
Extending Perl Critic --(0)> prove -Ilib t/* t/exercise-policy....NOK 3  #  Failed test 'BuiltinFunctions::RequireBlockGrepAndMap - line 13 - grep as a method call' #  at t/exercise-policy.t line 41. #  got: '1' #  expected: '0' # Looks like you failed 1 test of 3. t/exercise-policy....dubious  Test returned status 1 (wstat 256, 0x100) DIED. FAILED test 3 Failed 1/3 tests, 66.67% okay t/initial-setup......ok  Failed Test  Stat Wstat Total Fail  List of Failed ------------------------------------------------------------------------------- t/exercise-policy.t  1  256  3  1  3 Failed 1/2 test scripts. 1/7 subtests failed. Files=2, Tests=7,  2 wallclock secs ( 1.00 cusr +  0.24 csys =  1.24 CPU) Failed 1/2 test programs. 1/7 subtests failed.
Extending Perl Critic use Perl::Critic::Utils; ... sub violates { my ( $self, $element, $document ) = @_; return unless $element eq 'grep'; return if is_method_call($element); my $sibling = $element->snext_sibling(); return if $sibling ->isa('PPI::Structure::Block'); return $self->violation(  $description, $explanation, $element ); } lib/Perl/Critic/Policy/BuiltinFunctions/RequireBlockGrepAndMap.pm
Extending Perl Critic --(0)> prove -Ilib t/* t/exercise-policy....ok t/initial-setup......ok All tests successful. Files=2, Tests=7,  2 wallclock secs ( 1.01 cusr +  0.24 csys =  1.25 CPU)
Extending Perl Critic Some Useful Methods From Perl::Critic::Utils - is_perl_global - is_perl_builtin - is_hash_key - is_method_call - is_subroutine_name - is_function_call - first_arg - parse_arg_list
Extending Perl Critic ... ## name grep as a hash key ## failures 0 ## cut $my_hash{ grep } = 1; t/BuiltinFunctions/RequireBlockGrepAndMap.run
Extending Perl Critic --(0)> prove -Ilib t/* t/exercise-policy....ok 1/4Can't call method "isa" without a package or object reference at lib/Perl/Critic/Policy/BuiltinFunctions/RequireBlockGrepAndMap.pm line 36. # Looks like you planned 4 tests but only ran 3. # Looks like your test died just after 3. t/exercise-policy....dubious Test returned status 255 (wstat 65280, 0xff00) DIED. FAILED test 4 Failed 1/4 tests, 75.00% okay t/initial-setup......ok Failed Test  Stat Wstat Total Fail  List of Failed ------------------------------------------------------------------------------- t/exercise-policy.t  255 65280  4  2  4 Failed 1/2 test scripts. 1/8 subtests failed. Files=2, Tests=8,  1 wallclock secs ( 1.00 cusr +  0.22 csys =  1.22 CPU) Failed 1/2 test programs. 1/8 subtests failed.
Extending Perl Critic sub violates { my ( $self, $element, $document ) = @_; return unless $element eq 'grep'; return if is_method_call($element); return if is_hash_key($element); my $sibling = $element->snext_sibling(); return if $sibling->isa('PPI::Structure::Block'); return $self->violation(  $description,  $explanation,  $element ); } lib/Perl/Critic/Policy/BuiltinFunctions/RequireBlockGrepAndMap.pm
Extending Perl Critic --(0)> prove -Ilib t/* t/exercise-policy....ok t/initial-setup......ok All tests successful. Files=2, Tests=8,  2 wallclock secs ( 1.02 cusr +  0.25 csys =  1.27 CPU)
Extending Perl Critic ... ## name grep is a sub name ## failures 0 ## cut sub grep { return } t/BuiltinFunctions/RequireBlockGrepAndMap.run
Extending Perl Critic --(0)> prove -Ilib t/* t/exercise-policy....ok t/initial-setup......ok All tests successful. Files=2, Tests=9,  2 wallclock secs ( 1.02 cusr +  0.22 csys =  1.24 CPU)
Extending Perl Critic ... ## name grep is a sub prototype name ## failures 0 ## cut sub grep; t/BuiltinFunctions/RequireBlockGrepAndMap.run
Extending Perl Critic --(0)> prove -Ilib t/* t/exercise-policy....NOK 6  #  Failed test 'BuiltinFunctions::RequireBlockGrepAndMap - line 31 - grep is a sub prototype name' #  at t/exercise-policy.t line 41. #  got: '1' #  expected: '0' # Looks like you failed 1 test of 6. t/exercise-policy....dubious  Test returned status 1 (wstat 256, 0x100) DIED. FAILED test 6 Failed 1/6 tests, 83.33% okay t/initial-setup......ok  Failed Test  Stat Wstat Total Fail  List of Failed ------------------------------------------------------------------------------- t/exercise-policy.t  1  256  6  1  6 Failed 1/2 test scripts. 1/10 subtests failed. Files=2, Tests=10,  1 wallclock secs ( 1.04 cusr +  0.22 csys =  1.26 CPU) Failed 1/2 test programs. 1/10 subtests failed.
Extending Perl Critic sub violates { my ( $self, $element, $document ) = @_; return unless $element eq 'grep'; return if is_method_call($element); return if is_hash_key($element); return if is_subroutine_name($element); my $sibling = $element->snext_sibling(); return if $sibling->isa('PPI::Structure::Block'); return $self->violation(  $description,  $explanation,  $element, ); } lib/Perl/Critic/Policy/BuiltinFunctions/RequireBlockGrepAndMap.pm
Extending Perl Critic --(0)> prove -Ilib t/* t/exercise-policy....ok t/initial-setup......ok All tests successful. Files=2, Tests=10,  2 wallclock secs ( 1.02 cusr +  0.22 csys =  1.24 CPU)
Extending Perl Critic ... ## name grep has parens ## failures 0 ## cut grep ( { $_ } @list ); t/BuiltinFunctions/RequireBlockGrepAndMap.run
Extending Perl Critic --(0)> prove -Ilib t/* t/exercise-policy....NOK 7 #  Failed test 'BuiltinFunctions::RequireBlockGrepAndMap - line 37 - grep has parens' #  at t/exercise-policy.t line 41. #  got: '1' #  expected: '0' # Looks like you failed 1 test of 7. t/exercise-policy....dubious  Test returned status 1 (wstat 256, 0x100) DIED. FAILED test 7 Failed 1/7 tests, 85.71% okay t/initial-setup......ok  Failed Test  Stat Wstat Total Fail  List of Failed ------------------------------------------------------------------------------- t/exercise-policy.t  1  256  7  1  7 Failed 1/2 test scripts. 1/11 subtests failed. Files=2, Tests=11,  2 wallclock secs ( 1.03 cusr +  0.22 csys =  1.25 CPU) Failed 1/2 test programs. 1/11 subtests failed.
Extending Perl Critic sub violates { my ( $self, $element, $document ) = @_; return unless $element eq 'grep'; return if is_method_call($element); return if is_hash_key($element); return if is_subroutine_name($element); my $sibling = $element->snext_sibling(); $sibling = $sibling->schild(0)    if $sibling->isa('PPI::Structure::List'); return if $sibling->isa('PPI::Structure::Block'); return $self->violation(  $description,  $explanation,  $element, ); } lib/Perl/Critic/Policy/BuiltinFunctions/RequireBlockGrepAndMap.pm
Extending Perl Critic --(0)> prove -Ilib t/* t/exercise-policy....ok t/initial-setup......ok All tests successful. Files=2, Tests=11,  2 wallclock secs ( 1.04 cusr +  0.24 csys =  1.28 CPU)
Extending Perl Critic ... ## name block map ## failures 0 ## cut map { $_ } t/BuiltinFunctions/RequireBlockGrepAndMap.run
Extending Perl Critic --(0)> prove -Ilib t/* t/exercise-policy....ok t/initial-setup......ok All tests successful. Files=2, Tests=12,  2 wallclock secs ( 1.04 cusr +  0.22 csys =  1.26 CPU)
Extending Perl Critic ... ## name string map ## failures 1 ## cut map "$_" t/BuiltinFunctions/RequireBlockGrepAndMap.run
Extending Perl Critic --(0)> prove -Ilib t/* t/exercise-policy....NOK 9 #  Failed test 'BuiltinFunctions::RequireBlockGrepAndMap - line 49 - string map' #  at t/exercise-policy.t line 41. #  got: '0' #  expected: '1' # Looks like you failed 1 test of 9. t/exercise-policy....dubious  Test returned status 1 (wstat 256, 0x100) DIED. FAILED test 9 Failed 1/9 tests, 88.89% okay t/initial-setup......ok Failed Test  Stat Wstat Total Fail  List of Failed ------------------------------------------------------------------------------- t/exercise-policy.t  1  256  9  1  9 Failed 1/2 test scripts. 1/13 subtests failed. Files=2, Tests=13,  1 wallclock secs ( 1.05 cusr +  0.22 csys =  1.27 CPU) Failed 1/2 test programs. 1/13 subtests failed.
Extending Perl Critic sub violates { my ( $self, $element, $document ) = @_; return unless grep { $element eq $_ } qw[grep map]; return if is_method_call($element); return if is_hash_key($element); return if is_subroutine_name($element); my $sibling = $element->snext_sibling(); $sibling = $sibling->schild(0)  if $sibling->isa('PPI::Structure::List'); return if $sibling->isa('PPI::Structure::Block'); return $self->violation(  $description,  $explanation,  $element, ); } lib/Perl/Critic/Policy/BuiltinFunctions/RequireBlockGrepAndMap.pm
Extending Perl Critic --(0)> prove -Ilib t/* t/exercise-policy....ok t/initial-setup......ok All tests successful. Files=2, Tests=13,  1 wallclock secs ( 1.05 cusr +  0.23 csys =  1.28 CPU)
Extending Perl Critic ... ## name string map allowed ## failures 0 ## parms { allow => ['map'] } ## cut map "$_" t/BuiltinFunctions/RequireBlockGrepAndMap.run
Extending Perl Critic --(0)> prove -Ilib t/* t/exercise-policy....NOK 10 #  Failed test 'BuiltinFunctions::RequireBlockGrepAndMap - line 55 - string map allowed' #  at t/exercise-policy.t line 41. #  got: '1' #  expected: '0' # Looks like you failed 1 test of 10. t/exercise-policy....dubious Test returned status 1 (wstat 256, 0x100) DIED. FAILED test 10 Failed 1/10 tests, 90.00% okay t/initial-setup......ok Failed Test  Stat Wstat Total Fail  List of Failed ------------------------------------------------------------------------------- t/exercise-policy.t  1  256  10  1  10 Failed 1/2 test scripts. 1/14 subtests failed. Files=2, Tests=14,  2 wallclock secs ( 1.05 cusr +  0.22 csys =  1.27 CPU) Failed 1/2 test programs. 1/14 subtests failed.
Extending Perl Critic sub new { my ($class, %args) = @_; my $self = $class->SUPER::new(%args); $args{allow} = [] unless exists $args{allow}; for my $function (qw(grep map)) { push @{$self->{filter}}, $function unless grep { $_ eq $function } @{$args{allow}}; } return $self; } lib/Perl/Critic/Policy/BuiltinFunctions/RequireBlockGrepAndMap.pm
Extending Perl Critic sub violates { my ( $self, $element, $document ) = @_; return  unless grep { $element eq $_ } @{$self->{filter} || []}; return if is_method_call($element); return if is_hash_key($element); return if is_subroutine_name($element); my $sibling = $element->snext_sibling(); $sibling = $sibling->schild(0)  if $sibling->isa('PPI::Structure::List'); return if $sibling->isa('PPI::Structure::Block'); return $self->violation(  $description,  $explanation,  $element, ); } lib/Perl/Critic/Policy/BuiltinFunctions/RequireBlockGrepAndMap.pm
Extending Perl Critic --(0)> prove -Ilib t/* t/exercise-policy....ok t/initial-setup......ok All tests successful. Files=2, Tests=14,  2 wallclock secs ( 1.06 cusr +  0.24 csys =  1.30 CPU)
Extending Perl Critic ... ## name string grep allowed ## failures 0 ## parms { allow => ['grep'] } ## cut grep "$_" ## name string grep and map allowed ## failures 0 ## parms { allow => ['grep', 'map'] } ## cut grep "$_"; map "$_"; ## name string grep and map not allowed ## failures 2 ## cut grep "$_"; map "$_"; t/BuiltinFunctions/RequireBlockGrepAndMap.run
Extending Perl Critic --(0)> prove -Ilib t/* t/exercise-policy....ok t/initial-setup......ok All tests successful. Files=2, Tests=17,  2 wallclock secs ( 1.08 cusr +  0.22 csys =  1.30 CPU)
Extending Perl Critic That's it for coding our module.  We could of course add some POD. =pod =head1 NAME Perl::Critic::Policy::BuiltinFunctions::RequireBlockGrepAndMap =head1 DESCRIPTION The expression form of C<grep> and C<map> is awkward and hard to read.  Use the block forms instead. @matches = grep  /pattern/,  @list;  #not ok @matches = grep { /pattern/ }  @list;  #ok @mapped = map  transform($_),  @list;  #not ok @mapped = map { transform($_) }  @list;  #ok =cut
Extending Perl Critic ... and more tests!
Extending Perl Critic - Use Perl::Critic::TestUtils to test your policies - Have your policies subclass Perl::Critic::Policy - Set a default severity for your policies - Set a default tag set for your policies - Configure your policy to apply to specific PPI elements - Create a violates subroutine that does your validation and  throws a Perl::Critic::Violation when the policy finds a  problem - Use Perl::Critic::Utils to help create your policy - User PPI::Element methods to traverse the PPI DOM In Review

Más contenido relacionado

La actualidad más candente

Test your code like a pro - PHPUnit in practice
Test your code like a pro - PHPUnit in practiceTest your code like a pro - PHPUnit in practice
Test your code like a pro - PHPUnit in practiceSebastian Marek
 
Mocking Dependencies in PHPUnit
Mocking Dependencies in PHPUnitMocking Dependencies in PHPUnit
Mocking Dependencies in PHPUnitmfrost503
 
Introduction to Unit Testing with PHPUnit
Introduction to Unit Testing with PHPUnitIntroduction to Unit Testing with PHPUnit
Introduction to Unit Testing with PHPUnitMichelangelo van Dam
 
Unit Testing using PHPUnit
Unit Testing using  PHPUnitUnit Testing using  PHPUnit
Unit Testing using PHPUnitvaruntaliyan
 
Advanced PHPUnit Testing
Advanced PHPUnit TestingAdvanced PHPUnit Testing
Advanced PHPUnit TestingMike Lively
 
What is wrong on Test::More? / Test::Moreが抱える問題点とその解決策
What is wrong on Test::More? / Test::Moreが抱える問題点とその解決策What is wrong on Test::More? / Test::Moreが抱える問題点とその解決策
What is wrong on Test::More? / Test::Moreが抱える問題点とその解決策kwatch
 
New Features PHPUnit 3.3 - Sebastian Bergmann
New Features PHPUnit 3.3 - Sebastian BergmannNew Features PHPUnit 3.3 - Sebastian Bergmann
New Features PHPUnit 3.3 - Sebastian Bergmanndpc
 
PHPUnit: from zero to hero
PHPUnit: from zero to heroPHPUnit: from zero to hero
PHPUnit: from zero to heroJeremy Cook
 
2010 07-28-testing-zf-apps
2010 07-28-testing-zf-apps2010 07-28-testing-zf-apps
2010 07-28-testing-zf-appsVenkata Ramana
 
Unlock The Mystery Of PHPUnit (Wave PHP 2018)
Unlock The Mystery Of PHPUnit (Wave PHP 2018)Unlock The Mystery Of PHPUnit (Wave PHP 2018)
Unlock The Mystery Of PHPUnit (Wave PHP 2018)ENDelt260
 
Unit testing with PHPUnit - there's life outside of TDD
Unit testing with PHPUnit - there's life outside of TDDUnit testing with PHPUnit - there's life outside of TDD
Unit testing with PHPUnit - there's life outside of TDDPaweł Michalik
 
Testing Code and Assuring Quality
Testing Code and Assuring QualityTesting Code and Assuring Quality
Testing Code and Assuring QualityKent Cowgill
 
Test Driven Development With Python
Test Driven Development With PythonTest Driven Development With Python
Test Driven Development With PythonSiddhi
 
Test driven node.js
Test driven node.jsTest driven node.js
Test driven node.jsJay Harris
 
Testes pythonicos com pytest
Testes pythonicos com pytestTestes pythonicos com pytest
Testes pythonicos com pytestviniciusban
 
Unit Testng with PHP Unit - A Step by Step Training
Unit Testng with PHP Unit - A Step by Step TrainingUnit Testng with PHP Unit - A Step by Step Training
Unit Testng with PHP Unit - A Step by Step TrainingRam Awadh Prasad, PMP
 

La actualidad más candente (20)

Test your code like a pro - PHPUnit in practice
Test your code like a pro - PHPUnit in practiceTest your code like a pro - PHPUnit in practice
Test your code like a pro - PHPUnit in practice
 
Phpunit testing
Phpunit testingPhpunit testing
Phpunit testing
 
PHPUnit
PHPUnitPHPUnit
PHPUnit
 
Mocking Dependencies in PHPUnit
Mocking Dependencies in PHPUnitMocking Dependencies in PHPUnit
Mocking Dependencies in PHPUnit
 
Introduction to Unit Testing with PHPUnit
Introduction to Unit Testing with PHPUnitIntroduction to Unit Testing with PHPUnit
Introduction to Unit Testing with PHPUnit
 
Unit Testing using PHPUnit
Unit Testing using  PHPUnitUnit Testing using  PHPUnit
Unit Testing using PHPUnit
 
Advanced PHPUnit Testing
Advanced PHPUnit TestingAdvanced PHPUnit Testing
Advanced PHPUnit Testing
 
What is wrong on Test::More? / Test::Moreが抱える問題点とその解決策
What is wrong on Test::More? / Test::Moreが抱える問題点とその解決策What is wrong on Test::More? / Test::Moreが抱える問題点とその解決策
What is wrong on Test::More? / Test::Moreが抱える問題点とその解決策
 
New Features PHPUnit 3.3 - Sebastian Bergmann
New Features PHPUnit 3.3 - Sebastian BergmannNew Features PHPUnit 3.3 - Sebastian Bergmann
New Features PHPUnit 3.3 - Sebastian Bergmann
 
PHPUnit: from zero to hero
PHPUnit: from zero to heroPHPUnit: from zero to hero
PHPUnit: from zero to hero
 
2010 07-28-testing-zf-apps
2010 07-28-testing-zf-apps2010 07-28-testing-zf-apps
2010 07-28-testing-zf-apps
 
Unlock The Mystery Of PHPUnit (Wave PHP 2018)
Unlock The Mystery Of PHPUnit (Wave PHP 2018)Unlock The Mystery Of PHPUnit (Wave PHP 2018)
Unlock The Mystery Of PHPUnit (Wave PHP 2018)
 
Unit testing with PHPUnit - there's life outside of TDD
Unit testing with PHPUnit - there's life outside of TDDUnit testing with PHPUnit - there's life outside of TDD
Unit testing with PHPUnit - there's life outside of TDD
 
Testing Code and Assuring Quality
Testing Code and Assuring QualityTesting Code and Assuring Quality
Testing Code and Assuring Quality
 
Test Driven Development With Python
Test Driven Development With PythonTest Driven Development With Python
Test Driven Development With Python
 
PHPUnit testing to Zend_Test
PHPUnit testing to Zend_TestPHPUnit testing to Zend_Test
PHPUnit testing to Zend_Test
 
Test driven node.js
Test driven node.jsTest driven node.js
Test driven node.js
 
groovy & grails - lecture 7
groovy & grails - lecture 7groovy & grails - lecture 7
groovy & grails - lecture 7
 
Testes pythonicos com pytest
Testes pythonicos com pytestTestes pythonicos com pytest
Testes pythonicos com pytest
 
Unit Testng with PHP Unit - A Step by Step Training
Unit Testng with PHP Unit - A Step by Step TrainingUnit Testng with PHP Unit - A Step by Step Training
Unit Testng with PHP Unit - A Step by Step Training
 

Destacado

Destacado (7)

Reclamos
ReclamosReclamos
Reclamos
 
Increible1
Increible1Increible1
Increible1
 
Hist Inter2
Hist Inter2Hist Inter2
Hist Inter2
 
Tu mayor tesoro
Tu mayor tesoroTu mayor tesoro
Tu mayor tesoro
 
Semillas
SemillasSemillas
Semillas
 
Perspectives des de Catalunya en formació
Perspectives des de Catalunya en formacióPerspectives des de Catalunya en formació
Perspectives des de Catalunya en formació
 
DIAPOSITIVAS
DIAPOSITIVASDIAPOSITIVAS
DIAPOSITIVAS
 

Similar a YAPC::NA 2007 - Customizing And Extending Perl Critic

YAPC::NA 2007 - An Introduction To Perl Critic
YAPC::NA 2007 - An Introduction To Perl CriticYAPC::NA 2007 - An Introduction To Perl Critic
YAPC::NA 2007 - An Introduction To Perl Criticjoshua.mcadams
 
New Features Of Test Unit 2.x
New Features Of Test Unit 2.xNew Features Of Test Unit 2.x
New Features Of Test Unit 2.xdjberg96
 
Automated Unit Testing
Automated Unit TestingAutomated Unit Testing
Automated Unit TestingMike Lively
 
MT_01_unittest_python.pdf
MT_01_unittest_python.pdfMT_01_unittest_python.pdf
MT_01_unittest_python.pdfHans Jones
 
JUDCon London 2011 - Bin packing with drools planner by example
JUDCon London 2011 - Bin packing with drools planner by exampleJUDCon London 2011 - Bin packing with drools planner by example
JUDCon London 2011 - Bin packing with drools planner by exampleGeoffrey De Smet
 
An Introduction To Perl Critic
An Introduction To Perl CriticAn Introduction To Perl Critic
An Introduction To Perl Criticjoshua.mcadams
 
Exploiting the newer perl to improve your plugins
Exploiting the newer perl to improve your pluginsExploiting the newer perl to improve your plugins
Exploiting the newer perl to improve your pluginsMarian Marinov
 
O CPAN tem as ferramentas que você precisa para fazer TDD em Perl, o Coding D...
O CPAN tem as ferramentas que você precisa para fazer TDD em Perl, o Coding D...O CPAN tem as ferramentas que você precisa para fazer TDD em Perl, o Coding D...
O CPAN tem as ferramentas que você precisa para fazer TDD em Perl, o Coding D...Rodolfo Carvalho
 
Leveling Up With Unit Testing - php[tek] 2023
Leveling Up With Unit Testing - php[tek] 2023Leveling Up With Unit Testing - php[tek] 2023
Leveling Up With Unit Testing - php[tek] 2023Mark Niebergall
 
Perl web app 테스트전략
Perl web app 테스트전략Perl web app 테스트전략
Perl web app 테스트전략Jeen Lee
 
Continuous integration with Git & CI Joe
Continuous integration with Git & CI JoeContinuous integration with Git & CI Joe
Continuous integration with Git & CI JoeShawn Price
 
Ch ch-changes cake php2
Ch ch-changes cake php2Ch ch-changes cake php2
Ch ch-changes cake php2markstory
 
Automated Frontend Testing
Automated Frontend TestingAutomated Frontend Testing
Automated Frontend TestingNeil Crosby
 
Владимир Перепелица "Модули"
Владимир Перепелица "Модули"Владимир Перепелица "Модули"
Владимир Перепелица "Модули"Media Gorod
 
Best Practices in Plugin Development (WordCamp Seattle)
Best Practices in Plugin Development (WordCamp Seattle)Best Practices in Plugin Development (WordCamp Seattle)
Best Practices in Plugin Development (WordCamp Seattle)andrewnacin
 
Perl Tidy Perl Critic
Perl Tidy Perl CriticPerl Tidy Perl Critic
Perl Tidy Perl Criticolegmmiller
 
Perl Teach-In (part 1)
Perl Teach-In (part 1)Perl Teach-In (part 1)
Perl Teach-In (part 1)Dave Cross
 
How to Design a Great API (using flask) [ploneconf2017]
How to Design a Great API (using flask) [ploneconf2017]How to Design a Great API (using flask) [ploneconf2017]
How to Design a Great API (using flask) [ploneconf2017]Devon Bernard
 

Similar a YAPC::NA 2007 - Customizing And Extending Perl Critic (20)

YAPC::NA 2007 - An Introduction To Perl Critic
YAPC::NA 2007 - An Introduction To Perl CriticYAPC::NA 2007 - An Introduction To Perl Critic
YAPC::NA 2007 - An Introduction To Perl Critic
 
New Features Of Test Unit 2.x
New Features Of Test Unit 2.xNew Features Of Test Unit 2.x
New Features Of Test Unit 2.x
 
Automated Unit Testing
Automated Unit TestingAutomated Unit Testing
Automated Unit Testing
 
MT_01_unittest_python.pdf
MT_01_unittest_python.pdfMT_01_unittest_python.pdf
MT_01_unittest_python.pdf
 
JUDCon London 2011 - Bin packing with drools planner by example
JUDCon London 2011 - Bin packing with drools planner by exampleJUDCon London 2011 - Bin packing with drools planner by example
JUDCon London 2011 - Bin packing with drools planner by example
 
An Introduction To Perl Critic
An Introduction To Perl CriticAn Introduction To Perl Critic
An Introduction To Perl Critic
 
Exploiting the newer perl to improve your plugins
Exploiting the newer perl to improve your pluginsExploiting the newer perl to improve your plugins
Exploiting the newer perl to improve your plugins
 
Test driven development_for_php
Test driven development_for_phpTest driven development_for_php
Test driven development_for_php
 
Extending Perl Critic
Extending Perl CriticExtending Perl Critic
Extending Perl Critic
 
O CPAN tem as ferramentas que você precisa para fazer TDD em Perl, o Coding D...
O CPAN tem as ferramentas que você precisa para fazer TDD em Perl, o Coding D...O CPAN tem as ferramentas que você precisa para fazer TDD em Perl, o Coding D...
O CPAN tem as ferramentas que você precisa para fazer TDD em Perl, o Coding D...
 
Leveling Up With Unit Testing - php[tek] 2023
Leveling Up With Unit Testing - php[tek] 2023Leveling Up With Unit Testing - php[tek] 2023
Leveling Up With Unit Testing - php[tek] 2023
 
Perl web app 테스트전략
Perl web app 테스트전략Perl web app 테스트전략
Perl web app 테스트전략
 
Continuous integration with Git & CI Joe
Continuous integration with Git & CI JoeContinuous integration with Git & CI Joe
Continuous integration with Git & CI Joe
 
Ch ch-changes cake php2
Ch ch-changes cake php2Ch ch-changes cake php2
Ch ch-changes cake php2
 
Automated Frontend Testing
Automated Frontend TestingAutomated Frontend Testing
Automated Frontend Testing
 
Владимир Перепелица "Модули"
Владимир Перепелица "Модули"Владимир Перепелица "Модули"
Владимир Перепелица "Модули"
 
Best Practices in Plugin Development (WordCamp Seattle)
Best Practices in Plugin Development (WordCamp Seattle)Best Practices in Plugin Development (WordCamp Seattle)
Best Practices in Plugin Development (WordCamp Seattle)
 
Perl Tidy Perl Critic
Perl Tidy Perl CriticPerl Tidy Perl Critic
Perl Tidy Perl Critic
 
Perl Teach-In (part 1)
Perl Teach-In (part 1)Perl Teach-In (part 1)
Perl Teach-In (part 1)
 
How to Design a Great API (using flask) [ploneconf2017]
How to Design a Great API (using flask) [ploneconf2017]How to Design a Great API (using flask) [ploneconf2017]
How to Design a Great API (using flask) [ploneconf2017]
 

Más de joshua.mcadams

Open Flash Chart And Perl
Open Flash Chart And PerlOpen Flash Chart And Perl
Open Flash Chart And Perljoshua.mcadams
 
Introduction To Testing With Perl
Introduction To Testing With PerlIntroduction To Testing With Perl
Introduction To Testing With Perljoshua.mcadams
 
Thank A Cpan Contributor Today
Thank A Cpan Contributor TodayThank A Cpan Contributor Today
Thank A Cpan Contributor Todayjoshua.mcadams
 
Utility Modules That You Should Know About
Utility Modules That You Should Know AboutUtility Modules That You Should Know About
Utility Modules That You Should Know Aboutjoshua.mcadams
 
YAPC::NA 2007 - Epic Perl Coding
YAPC::NA 2007 - Epic Perl CodingYAPC::NA 2007 - Epic Perl Coding
YAPC::NA 2007 - Epic Perl Codingjoshua.mcadams
 
Lightning Talk: An Introduction To Scrum
Lightning Talk: An Introduction To ScrumLightning Talk: An Introduction To Scrum
Lightning Talk: An Introduction To Scrumjoshua.mcadams
 

Más de joshua.mcadams (6)

Open Flash Chart And Perl
Open Flash Chart And PerlOpen Flash Chart And Perl
Open Flash Chart And Perl
 
Introduction To Testing With Perl
Introduction To Testing With PerlIntroduction To Testing With Perl
Introduction To Testing With Perl
 
Thank A Cpan Contributor Today
Thank A Cpan Contributor TodayThank A Cpan Contributor Today
Thank A Cpan Contributor Today
 
Utility Modules That You Should Know About
Utility Modules That You Should Know AboutUtility Modules That You Should Know About
Utility Modules That You Should Know About
 
YAPC::NA 2007 - Epic Perl Coding
YAPC::NA 2007 - Epic Perl CodingYAPC::NA 2007 - Epic Perl Coding
YAPC::NA 2007 - Epic Perl Coding
 
Lightning Talk: An Introduction To Scrum
Lightning Talk: An Introduction To ScrumLightning Talk: An Introduction To Scrum
Lightning Talk: An Introduction To Scrum
 

Último

Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityPrincipled Technologies
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slidevu2urc
 
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...gurkirankumar98700
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Paola De la Torre
 
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitecturePixlogix Infotech
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024Scott Keck-Warren
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...shyamraj55
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking MenDelhi Call girls
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
Maximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxMaximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxOnBoard
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 3652toLead Limited
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024The Digital Insurer
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 

Último (20)

Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101
 
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC Architecture
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
Maximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxMaximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptx
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 

YAPC::NA 2007 - Customizing And Extending Perl Critic

  • 1. Customizing and Extending Perl Critic YAPC::NA 2007 Houston, TX Josh McAdams
  • 2. Extending Perl Critic Perl Critic is a very powerful and customizable system in its off-the-CPAN state; however, there are times when you need to create your own policies to enforce your own coding standards. We will see how to do that by creating a variant of one of the core modules: BuiltinFunctions::RequireBlockGrep . We'll call our policy BuiltinFunctions::RequireBlockGrepAndMap and make it force block map s in addition to grep s.
  • 3. Extending Perl Critic use strict; use warnings; use Test::More tests => 1; use_ok( 'Perl::Critic::Policy::' . 'BuiltinFunctions::RequireBlockGrepAndMap' ); t/initial-setup.t
  • 4. Extending Perl Critic --(0)> prove -Ilib t/initial-setup.t t/initial-setup.... # Failed test 'use Perl::Critic::Policy::BuiltinFunctions::RequireBlockGrepAndMap;' # at t/initial-setup.t line 5. # Tried to use 'Perl::Critic::Policy::BuiltinFunctions::RequireBlockGrepAndMap'. # Error: Can't locate Perl/Critic/Policy/BuiltinFunctions/RequireBlockGrepAndMap.pm in @INC (...) line 2. # BEGIN failed--compilation aborted at t/initial-setup.t line 5. # Looks like you failed 1 test of 1. t/initial-setup....dubious Test returned status 1 (wstat 256, 0x100) DIED. FAILED test 1 Failed 1/1 tests, 0.00% okay Failed Test Stat Wstat Total Fail List of Failed ------------------------------------------------------------------------------- t/initial-setup.t 1 256 1 1 1 Failed 1/1 test scripts. 1/1 subtests failed. Files=1, Tests=1, 0 wallclock secs ( 0.04 cusr + 0.02 csys = 0.06 CPU) Failed 1/1 test programs. 1/1 subtests failed.
  • 5. Extending Perl Critic package Perl::Critic::Policy::BuiltinFunctions::RequireBlockGrepAndMap ; use warnings; use strict; 1; lib/Perl/Critic/Policy/BuiltinFunctions/RequireBlockGrepAndMap.pm
  • 6. Extending Perl Critic --(0)> prove -Ilib t/* t/initial-setup....ok All tests successful.
  • 7. Extending Perl Critic use strict; use warnings; use Test::More tests => 2; use_ok( 'Perl::Critic::Policy::' . 'BuiltinFunctions::RequireBlockGrepAndMap' ); my $policy = Perl::Critic::Policy::BuiltinFunctions::RequireBlockGrepAndMap ->new(); is($policy->get_severity(), 4, 'high severity set'); t/initial-setup.t
  • 8. Extending Perl Critic --(0)> prove -Ilib t/* t/initial-setup....Can't locate object method &quot;new&quot; via package &quot;Perl::Critic::Policy::BuiltinFunctions::RequireBlockGrepAndMap&quot; at t/initial-setup.t line 10. # Looks like you planned 2 tests but only ran 1. # Looks like your test died just after 1. t/initial-setup....dubious Test returned status 255 (wstat 65280, 0xff00) DIED. FAILED test 2 Failed 1/2 tests, 50.00% okay Failed Test Stat Wstat Total Fail List of Failed ------------------------------------------------------------------------------- t/initial-setup.t 255 65280 2 2 2 Failed 1/1 test scripts. 1/2 subtests failed. Files=1, Tests=2, 0 wallclock secs ( 0.04 cusr + 0.02 csys = 0.06 CPU) Failed 1/1 test programs. 1/2 subtests failed.
  • 9. Extending Perl Critic package Perl::Critic::Policy::BuiltinFunctions::RequireBlockGrepAndMap; use warnings; use strict; use base qw(Perl::Critic::Policy); use Perl::Critic::Utils; sub new { my ($class, %args) = @_; return $class->SUPER::new(%args); } sub default_severity { return $SEVERITY_HIGH; } 1; lib/Perl/Critic/Policy/BuiltinFunctions/RequireBlockGrepAndMap.pm
  • 10. Extending Perl Critic --(0)> prove -Ilib t/* t/initial-setup....ok All tests successful. Files=1, Tests=2, 0 wallclock secs ( 0.12 cusr + 0.03 csys = 0.15 CPU)
  • 11. Extending Perl Critic Severity Level Variables Exported By Perl::Critic::Utils $SEVERITY_HIGHEST == 5 $SEVERITY_HIGH == 4 $SEVERITY_MEDIUM == 3 $SEVERITY_LOW == 2 $SEVERITY_LOWEST == 1
  • 12. Extending Perl Critic ... is_deeply( [$policy->get_themes()], [qw(almost_core pbp)], 'proper themes set' ); t/initial-setup.t
  • 13. Extending Perl Critic --(0)> prove -Ilib t/* t/initial-setup....NOK 3 # Failed test 'proper themes set' # at t/initial-setup.t line 16. # Structures begin differing at: # $got->[0] = Does not exist # $expected->[0] = 'almost_core' # Looks like you failed 1 test of 3. t/initial-setup....dubious Test returned status 1 (wstat 256, 0x100) DIED. FAILED test 3 Failed 1/3 tests, 66.67% okay Failed Test Stat Wstat Total Fail List of Failed ------------------------------------------------------------------------------- t/initial-setup.t 1 256 3 1 3 Failed 1/1 test scripts. 1/3 subtests failed. Files=1, Tests=3, 0 wallclock secs ( 0.12 cusr + 0.03 csys = 0.15 CPU) Failed 1/1 test programs. 1/3 subtests failed.
  • 14. Extending Perl Critic sub default_themes { return qw( almost_core pbp ); } lib/Perl/Critic/Policy/BuiltinFunctions/RequireBlockGrepAndMap.pm
  • 15. Extending Perl Critic --(0)> prove -Ilib t/* t/initial-setup....ok All tests successful. Files=1, Tests=3, 0 wallclock secs ( 0.12 cusr + 0.03 csys = 0.15 CPU)
  • 16. Extending Perl Critic ... is_deeply( [$policy->applies_to()], [qw(PPI::Token::Word)], 'applies only to words' ); t/initial-setup.t
  • 17. Extending Perl Critic --(0)> prove -Ilib t/* t/initial-setup....NOK 4 # Failed test 'applies only to words' # at t/initial-setup.t line 18. # Structures begin differing at: # $got->[0] = 'PPI::Element' # $expected->[0] = 'PPI::Token::Word' # Looks like you failed 1 test of 4. t/initial-setup....dubious Test returned status 1 (wstat 256, 0x100) DIED. FAILED test 4 Failed 1/4 tests, 75.00% okay Failed Test Stat Wstat Total Fail List of Failed ------------------------------------------------------------------------------- t/initial-setup.t 1 256 4 1 4 Failed 1/1 test scripts. 1/4 subtests failed. Files=1, Tests=4, 0 wallclock secs ( 0.12 cusr + 0.03 csys = 0.15 CPU) Failed 1/1 test programs. 1/4 subtests failed.
  • 18. Extending Perl Critic sub applies_to { return 'PPI::Token::Word'; } lib/Perl/Critic/Policy/BuiltinFunctions/RequireBlockGrepAndMap.pm
  • 19. Extending Perl Critic --(0)> prove -Ilib t/* t/initial-setup....ok All tests successful. Files=1, Tests=4, 0 wallclock secs ( 0.12 cusr + 0.03 csys = 0.15 CPU)
  • 20. Extending Perl Critic PPI::Document PPI::Document::File PPI::Document::Fragment PPI::Document::Normalized PPI::Element PPI::Statement PPI::Statement::Break PPI::Statement::Compound PPI::Statement::Data PPI::Statement::End PPI::Statement::Expression PPI::Statement::Include PPI::Statement::Null PPI::Statement::Package PPI::Statement::Scheduled PPI::Statement::Sub PPI::Statement::Unknown PPI::Statement::UnmatchedBrace PPI::Statement::Variable PPI::Structure PPI::Structure::Block PPI::Structure::Condition PPI::Structure::Constructor PPI::Token::Quote::Single PPI::Token::QuoteLike PPI::Token::QuoteLike::Backtick PPI::Token::QuoteLike::Command PPI::Token::QuoteLike::Readline PPI::Token::QuoteLike::Regexp PPI::Token::QuoteLike::Words PPI::Token::Regexp PPI::Token::Regexp::Match PPI::Token::Regexp::Substitute PPI::Token::Regexp::Transliterate PPI::Token::Separator PPI::Token::Structure PPI::Token::Symbol PPI::Token::Unknown PPI::Token::Whitespace PPI::Token::Word PPI::Structure::ForLoop PPI::Structure::List PPI::Structure::Subscript PPI::Structure::Unknown PPI::Token PPI::Token::ArrayIndex PPI::Token::Attribute PPI::Token::Cast PPI::Token::Comment PPI::Token::DashedWord PPI::Token::Data PPI::Token::End PPI::Token::HereDoc PPI::Token::Label PPI::Token::Magic PPI::Token::Number PPI::Token::Operator PPI::Token::Pod PPI::Token::Prototype PPI::Token::Quote PPI::Token::Quote::Double PPI::Token::Quote::Interpolate PPI::Token::Quote::Literal PPI Modules
  • 21. Extending Perl Critic use warnings; use strict; use Test::More tests => 1; use Perl::Critic::TestUtils qw(pcritique); my $custom_policy = 'BuiltinFunctions::RequireBlockGrepAndMap'; my $code = 'grep { $_ }'; my $violation_count = pcritique( $custom_policy, code ); ok(!$violation_count, 'allowed block grep'); t/exercise-policy.t
  • 22. Extending Perl Critic Some Perl::Critic::TestUtils Help Methods - block_perlcriticrc - critique - pcritique - fcritique
  • 23. Extending Perl Critic --(0)> prove -Ilib t/* t/exercise-policy....Can't call abstract method at /opt/local/lib/perl5/site_perl/5.8.7/Perl/Critic/Policy.pm line 98 Perl::Critic::Policy::violates('Perl::Critic::Policy::BuiltinFunctions::RequireBlockGrepAndMa...', 'PPI::Token::Word=HASH(0x1a01b40)', 'Perl::Critic::Document=HASH(0x183d338)') called at /opt/local/lib/perl5/site_perl/5.8.7/Perl/Critic.pm line 165 Perl::Critic::_critique('Perl::Critic::Policy::BuiltinFunctions::RequireBlockGrepAndMa...', 'Perl::Critic::Document=HASH(0x183d338)', 'HASH(0x19fc194)') called at /opt/local/lib/perl5/site_perl/5.8.7/Perl/Critic.pm line 121 Perl::Critic::critique('Perl::Critic=HASH(0x1800f88)', 'SCALAR(0x1810eac)') called at /opt/local/lib/perl5/site_perl/5.8.7/Perl/Critic/TestUtils.pm line 53 Perl::Critic::TestUtils::pcritique('BuiltinFunctions::RequireBlockGrepAndMap', 'SCALAR(0x1810eac)') called at t/exercise-policy.t line 9 # Looks like your test died before it could output anything. t/exercise-policy....dubious Test returned status 255 (wstat 65280, 0xff00) DIED. FAILED test 1 Failed 1/1 tests, 0.00% okay t/initial-setup......ok Failed Test Stat Wstat Total Fail List of Failed ------------------------------------------------------------------------------- t/exercise-policy.t 255 65280 1 2 1 Failed 1/2 test scripts. 1/5 subtests failed. Files=2, Tests=5, 1 wallclock secs ( 0.99 cusr + 0.24 csys = 1.23 CPU) Failed 1/2 test programs. 1/5 subtests failed.
  • 24. Extending Perl Critic sub violates {} lib/Perl/Critic/Policy/BuiltinFunctions/RequireBlockGrepAndMap.pm
  • 25. Extending Perl Critic --(0)> prove -Ilib t/* t/exercise-policy....ok t/initial-setup......ok All tests successful. Files=2, Tests=5, 2 wallclock secs ( 0.98 cusr + 0.22 csys = 1.20 CPU)
  • 26. Extending Perl Critic my $custom_policy = 'BuiltinFunctions::RequireBlockGrepAndMap'; { my $code = 'grep { $_ }'; my $violation_count = pcritique( $custom_policy, code ); is($violation_count, 0, 'allowed block grep'); } { my $code = 'grep &quot;$_&quot;'; my $violation_count = pcritique( $custom_policy, code ); is($violation_count, 1, 'disallowed string grep'); } t/exercise-policy.t
  • 27. Extending Perl Critic --(0)> prove -Ilib t/* t/exercise-policy....NOK 2 # Failed test 'disallowed string grep' # at t/exercise-policy.t line 17. # got: '0' # expected: '1' # Looks like you failed 1 test of 2. t/exercise-policy....dubious Test returned status 1 (wstat 256, 0x100) DIED. FAILED test 2 Failed 1/2 tests, 50.00% okay t/initial-setup......ok Failed Test Stat Wstat Total Fail List of Failed ------------------------------------------------------------------------------- t/exercise-policy.t 1 256 2 1 2 Failed 1/2 test scripts. 1/6 subtests failed. Files=2, Tests=6, 2 wallclock secs ( 1.00 cusr + 0.22 csys = 1.22 CPU) Failed 1/2 test programs. 1/6 subtests failed.
  • 28. Extending Perl Critic my $description = q{Expression form of &quot;grep&quot; and &quot;map&quot;}; my $explanation = [169]; sub violates { my ( $self, $element, $document ) = @_; return unless $element eq 'grep'; my $sibling = $element->snext_sibling(); return if $sibling->isa('PPI::Structure::Block'); return $self->violation( $description, $explanation, $element, ); } lib/Perl/Critic/Policy/BuiltinFunctions/RequireBlockGrepAndMap.pm
  • 29. Extending Perl Critic t/exercise-policy....ok t/initial-setup......ok All tests successful. Files=2, Tests=6, 1 wallclock secs ( 1.00 cusr + 0.22 csys = 1.22 CPU)
  • 30. Extending Perl Critic Some PPI Utility Methods (from PPI::Element) - parent - next_sibling - snext_sibling - previous_sibling - sprevious_sibling - first_token - last_token - next_token - previous_token
  • 31. Extending Perl Critic use warnings; use strict; use Test::More; use Perl::Critic::TestUtils qw(subtests_in_tree fcritique pcritique); my $custom_policy = 'BuiltinFunctions::RequireBlockGrepAndMap'; my $subtests = subtests_in_tree('t/BuiltinFunctions'); my $test_count = 0; $test_count += @{$subtests->{$_}} for ( keys %{$subtests} ); plan tests => $test_count; ... t/exercise-policy.t
  • 32. Extending Perl Critic for my $policy ( sort keys %$subtests ) { for my $subtest ( @{ $subtests->{$policy} } ) { local $TODO = $subtest->{TODO}; my $desc = join( ' - ', $policy, &quot;line $subtest->{lineno}&quot;, $subtest->{name} ); my $violations = $subtest->{filename} ? eval { fcritique( $policy, subtest->{code}, $subtest->{filename}, $subtest->{parms} ); } : eval { pcritique( $policy, subtest->{code}, $subtest->{parms} ) }; my $err = $@; if ( $subtest->{error} ) { if ( 'Regexp' eq ref $subtest->{error} ) { like( $err, $subtest->{error}, $desc ); } else { ok( $err, $desc ); } } else { die $err if $err; is( $violations, $subtest->{failures}, $desc ); } } } t/exercise-policy.t
  • 33. Extending Perl Critic ## name allowed block grep ## failures 0 ## cut grep { $_ } ## name disallowed string grep ## failures 1 ## cut grep &quot;$_&quot; t/BuiltinFunctions/RequireBlockGrepAndMap.run
  • 34. Extending Perl Critic --(0)> prove -Ilib t/* t/exercise-policy....ok t/initial-setup......ok All tests successful. Files=2, Tests=6, 2 wallclock secs ( 1.01 cusr + 0.22 csys = 1.23 CPU)
  • 35. Extending Perl Critic ## name A Test Name ## parms { allow_y => 0 } ## TODO Should pass later ## error 1 ## error /Can't load Foo::Bar/ ## filename lib/Foo/Bar.pm ## cut Options For .run Files
  • 36. Extending Perl Critic ... ## name grep as a method call ## failures 0 ## cut $object->grep('this'); t/BuiltinFunctions/RequireBlockGrepAndMap.run
  • 37. Extending Perl Critic --(0)> prove -Ilib t/* t/exercise-policy....NOK 3 # Failed test 'BuiltinFunctions::RequireBlockGrepAndMap - line 13 - grep as a method call' # at t/exercise-policy.t line 41. # got: '1' # expected: '0' # Looks like you failed 1 test of 3. t/exercise-policy....dubious Test returned status 1 (wstat 256, 0x100) DIED. FAILED test 3 Failed 1/3 tests, 66.67% okay t/initial-setup......ok Failed Test Stat Wstat Total Fail List of Failed ------------------------------------------------------------------------------- t/exercise-policy.t 1 256 3 1 3 Failed 1/2 test scripts. 1/7 subtests failed. Files=2, Tests=7, 2 wallclock secs ( 1.00 cusr + 0.24 csys = 1.24 CPU) Failed 1/2 test programs. 1/7 subtests failed.
  • 38. Extending Perl Critic use Perl::Critic::Utils; ... sub violates { my ( $self, $element, $document ) = @_; return unless $element eq 'grep'; return if is_method_call($element); my $sibling = $element->snext_sibling(); return if $sibling ->isa('PPI::Structure::Block'); return $self->violation( $description, $explanation, $element ); } lib/Perl/Critic/Policy/BuiltinFunctions/RequireBlockGrepAndMap.pm
  • 39. Extending Perl Critic --(0)> prove -Ilib t/* t/exercise-policy....ok t/initial-setup......ok All tests successful. Files=2, Tests=7, 2 wallclock secs ( 1.01 cusr + 0.24 csys = 1.25 CPU)
  • 40. Extending Perl Critic Some Useful Methods From Perl::Critic::Utils - is_perl_global - is_perl_builtin - is_hash_key - is_method_call - is_subroutine_name - is_function_call - first_arg - parse_arg_list
  • 41. Extending Perl Critic ... ## name grep as a hash key ## failures 0 ## cut $my_hash{ grep } = 1; t/BuiltinFunctions/RequireBlockGrepAndMap.run
  • 42. Extending Perl Critic --(0)> prove -Ilib t/* t/exercise-policy....ok 1/4Can't call method &quot;isa&quot; without a package or object reference at lib/Perl/Critic/Policy/BuiltinFunctions/RequireBlockGrepAndMap.pm line 36. # Looks like you planned 4 tests but only ran 3. # Looks like your test died just after 3. t/exercise-policy....dubious Test returned status 255 (wstat 65280, 0xff00) DIED. FAILED test 4 Failed 1/4 tests, 75.00% okay t/initial-setup......ok Failed Test Stat Wstat Total Fail List of Failed ------------------------------------------------------------------------------- t/exercise-policy.t 255 65280 4 2 4 Failed 1/2 test scripts. 1/8 subtests failed. Files=2, Tests=8, 1 wallclock secs ( 1.00 cusr + 0.22 csys = 1.22 CPU) Failed 1/2 test programs. 1/8 subtests failed.
  • 43. Extending Perl Critic sub violates { my ( $self, $element, $document ) = @_; return unless $element eq 'grep'; return if is_method_call($element); return if is_hash_key($element); my $sibling = $element->snext_sibling(); return if $sibling->isa('PPI::Structure::Block'); return $self->violation( $description, $explanation, $element ); } lib/Perl/Critic/Policy/BuiltinFunctions/RequireBlockGrepAndMap.pm
  • 44. Extending Perl Critic --(0)> prove -Ilib t/* t/exercise-policy....ok t/initial-setup......ok All tests successful. Files=2, Tests=8, 2 wallclock secs ( 1.02 cusr + 0.25 csys = 1.27 CPU)
  • 45. Extending Perl Critic ... ## name grep is a sub name ## failures 0 ## cut sub grep { return } t/BuiltinFunctions/RequireBlockGrepAndMap.run
  • 46. Extending Perl Critic --(0)> prove -Ilib t/* t/exercise-policy....ok t/initial-setup......ok All tests successful. Files=2, Tests=9, 2 wallclock secs ( 1.02 cusr + 0.22 csys = 1.24 CPU)
  • 47. Extending Perl Critic ... ## name grep is a sub prototype name ## failures 0 ## cut sub grep; t/BuiltinFunctions/RequireBlockGrepAndMap.run
  • 48. Extending Perl Critic --(0)> prove -Ilib t/* t/exercise-policy....NOK 6 # Failed test 'BuiltinFunctions::RequireBlockGrepAndMap - line 31 - grep is a sub prototype name' # at t/exercise-policy.t line 41. # got: '1' # expected: '0' # Looks like you failed 1 test of 6. t/exercise-policy....dubious Test returned status 1 (wstat 256, 0x100) DIED. FAILED test 6 Failed 1/6 tests, 83.33% okay t/initial-setup......ok Failed Test Stat Wstat Total Fail List of Failed ------------------------------------------------------------------------------- t/exercise-policy.t 1 256 6 1 6 Failed 1/2 test scripts. 1/10 subtests failed. Files=2, Tests=10, 1 wallclock secs ( 1.04 cusr + 0.22 csys = 1.26 CPU) Failed 1/2 test programs. 1/10 subtests failed.
  • 49. Extending Perl Critic sub violates { my ( $self, $element, $document ) = @_; return unless $element eq 'grep'; return if is_method_call($element); return if is_hash_key($element); return if is_subroutine_name($element); my $sibling = $element->snext_sibling(); return if $sibling->isa('PPI::Structure::Block'); return $self->violation( $description, $explanation, $element, ); } lib/Perl/Critic/Policy/BuiltinFunctions/RequireBlockGrepAndMap.pm
  • 50. Extending Perl Critic --(0)> prove -Ilib t/* t/exercise-policy....ok t/initial-setup......ok All tests successful. Files=2, Tests=10, 2 wallclock secs ( 1.02 cusr + 0.22 csys = 1.24 CPU)
  • 51. Extending Perl Critic ... ## name grep has parens ## failures 0 ## cut grep ( { $_ } @list ); t/BuiltinFunctions/RequireBlockGrepAndMap.run
  • 52. Extending Perl Critic --(0)> prove -Ilib t/* t/exercise-policy....NOK 7 # Failed test 'BuiltinFunctions::RequireBlockGrepAndMap - line 37 - grep has parens' # at t/exercise-policy.t line 41. # got: '1' # expected: '0' # Looks like you failed 1 test of 7. t/exercise-policy....dubious Test returned status 1 (wstat 256, 0x100) DIED. FAILED test 7 Failed 1/7 tests, 85.71% okay t/initial-setup......ok Failed Test Stat Wstat Total Fail List of Failed ------------------------------------------------------------------------------- t/exercise-policy.t 1 256 7 1 7 Failed 1/2 test scripts. 1/11 subtests failed. Files=2, Tests=11, 2 wallclock secs ( 1.03 cusr + 0.22 csys = 1.25 CPU) Failed 1/2 test programs. 1/11 subtests failed.
  • 53. Extending Perl Critic sub violates { my ( $self, $element, $document ) = @_; return unless $element eq 'grep'; return if is_method_call($element); return if is_hash_key($element); return if is_subroutine_name($element); my $sibling = $element->snext_sibling(); $sibling = $sibling->schild(0) if $sibling->isa('PPI::Structure::List'); return if $sibling->isa('PPI::Structure::Block'); return $self->violation( $description, $explanation, $element, ); } lib/Perl/Critic/Policy/BuiltinFunctions/RequireBlockGrepAndMap.pm
  • 54. Extending Perl Critic --(0)> prove -Ilib t/* t/exercise-policy....ok t/initial-setup......ok All tests successful. Files=2, Tests=11, 2 wallclock secs ( 1.04 cusr + 0.24 csys = 1.28 CPU)
  • 55. Extending Perl Critic ... ## name block map ## failures 0 ## cut map { $_ } t/BuiltinFunctions/RequireBlockGrepAndMap.run
  • 56. Extending Perl Critic --(0)> prove -Ilib t/* t/exercise-policy....ok t/initial-setup......ok All tests successful. Files=2, Tests=12, 2 wallclock secs ( 1.04 cusr + 0.22 csys = 1.26 CPU)
  • 57. Extending Perl Critic ... ## name string map ## failures 1 ## cut map &quot;$_&quot; t/BuiltinFunctions/RequireBlockGrepAndMap.run
  • 58. Extending Perl Critic --(0)> prove -Ilib t/* t/exercise-policy....NOK 9 # Failed test 'BuiltinFunctions::RequireBlockGrepAndMap - line 49 - string map' # at t/exercise-policy.t line 41. # got: '0' # expected: '1' # Looks like you failed 1 test of 9. t/exercise-policy....dubious Test returned status 1 (wstat 256, 0x100) DIED. FAILED test 9 Failed 1/9 tests, 88.89% okay t/initial-setup......ok Failed Test Stat Wstat Total Fail List of Failed ------------------------------------------------------------------------------- t/exercise-policy.t 1 256 9 1 9 Failed 1/2 test scripts. 1/13 subtests failed. Files=2, Tests=13, 1 wallclock secs ( 1.05 cusr + 0.22 csys = 1.27 CPU) Failed 1/2 test programs. 1/13 subtests failed.
  • 59. Extending Perl Critic sub violates { my ( $self, $element, $document ) = @_; return unless grep { $element eq $_ } qw[grep map]; return if is_method_call($element); return if is_hash_key($element); return if is_subroutine_name($element); my $sibling = $element->snext_sibling(); $sibling = $sibling->schild(0) if $sibling->isa('PPI::Structure::List'); return if $sibling->isa('PPI::Structure::Block'); return $self->violation( $description, $explanation, $element, ); } lib/Perl/Critic/Policy/BuiltinFunctions/RequireBlockGrepAndMap.pm
  • 60. Extending Perl Critic --(0)> prove -Ilib t/* t/exercise-policy....ok t/initial-setup......ok All tests successful. Files=2, Tests=13, 1 wallclock secs ( 1.05 cusr + 0.23 csys = 1.28 CPU)
  • 61. Extending Perl Critic ... ## name string map allowed ## failures 0 ## parms { allow => ['map'] } ## cut map &quot;$_&quot; t/BuiltinFunctions/RequireBlockGrepAndMap.run
  • 62. Extending Perl Critic --(0)> prove -Ilib t/* t/exercise-policy....NOK 10 # Failed test 'BuiltinFunctions::RequireBlockGrepAndMap - line 55 - string map allowed' # at t/exercise-policy.t line 41. # got: '1' # expected: '0' # Looks like you failed 1 test of 10. t/exercise-policy....dubious Test returned status 1 (wstat 256, 0x100) DIED. FAILED test 10 Failed 1/10 tests, 90.00% okay t/initial-setup......ok Failed Test Stat Wstat Total Fail List of Failed ------------------------------------------------------------------------------- t/exercise-policy.t 1 256 10 1 10 Failed 1/2 test scripts. 1/14 subtests failed. Files=2, Tests=14, 2 wallclock secs ( 1.05 cusr + 0.22 csys = 1.27 CPU) Failed 1/2 test programs. 1/14 subtests failed.
  • 63. Extending Perl Critic sub new { my ($class, %args) = @_; my $self = $class->SUPER::new(%args); $args{allow} = [] unless exists $args{allow}; for my $function (qw(grep map)) { push @{$self->{filter}}, $function unless grep { $_ eq $function } @{$args{allow}}; } return $self; } lib/Perl/Critic/Policy/BuiltinFunctions/RequireBlockGrepAndMap.pm
  • 64. Extending Perl Critic sub violates { my ( $self, $element, $document ) = @_; return unless grep { $element eq $_ } @{$self->{filter} || []}; return if is_method_call($element); return if is_hash_key($element); return if is_subroutine_name($element); my $sibling = $element->snext_sibling(); $sibling = $sibling->schild(0) if $sibling->isa('PPI::Structure::List'); return if $sibling->isa('PPI::Structure::Block'); return $self->violation( $description, $explanation, $element, ); } lib/Perl/Critic/Policy/BuiltinFunctions/RequireBlockGrepAndMap.pm
  • 65. Extending Perl Critic --(0)> prove -Ilib t/* t/exercise-policy....ok t/initial-setup......ok All tests successful. Files=2, Tests=14, 2 wallclock secs ( 1.06 cusr + 0.24 csys = 1.30 CPU)
  • 66. Extending Perl Critic ... ## name string grep allowed ## failures 0 ## parms { allow => ['grep'] } ## cut grep &quot;$_&quot; ## name string grep and map allowed ## failures 0 ## parms { allow => ['grep', 'map'] } ## cut grep &quot;$_&quot;; map &quot;$_&quot;; ## name string grep and map not allowed ## failures 2 ## cut grep &quot;$_&quot;; map &quot;$_&quot;; t/BuiltinFunctions/RequireBlockGrepAndMap.run
  • 67. Extending Perl Critic --(0)> prove -Ilib t/* t/exercise-policy....ok t/initial-setup......ok All tests successful. Files=2, Tests=17, 2 wallclock secs ( 1.08 cusr + 0.22 csys = 1.30 CPU)
  • 68. Extending Perl Critic That's it for coding our module. We could of course add some POD. =pod =head1 NAME Perl::Critic::Policy::BuiltinFunctions::RequireBlockGrepAndMap =head1 DESCRIPTION The expression form of C<grep> and C<map> is awkward and hard to read. Use the block forms instead. @matches = grep /pattern/, @list; #not ok @matches = grep { /pattern/ } @list; #ok @mapped = map transform($_), @list; #not ok @mapped = map { transform($_) } @list; #ok =cut
  • 69. Extending Perl Critic ... and more tests!
  • 70. Extending Perl Critic - Use Perl::Critic::TestUtils to test your policies - Have your policies subclass Perl::Critic::Policy - Set a default severity for your policies - Set a default tag set for your policies - Configure your policy to apply to specific PPI elements - Create a violates subroutine that does your validation and throws a Perl::Critic::Violation when the policy finds a problem - Use Perl::Critic::Utils to help create your policy - User PPI::Element methods to traverse the PPI DOM In Review