File Coverage

blib/lib/Perl/Critic/Policy/Freenode/OverloadOptions.pm
Criterion Covered Total %
statement 41 42 97.6
branch 17 18 94.4
condition 18 22 81.8
subroutine 10 11 90.9
pod 4 5 80.0
total 90 98 91.8


line stmt bran cond sub pod time code
1             package Perl::Critic::Policy::Freenode::OverloadOptions;
2              
3 1     1   658 use strict;
  1         3  
  1         29  
4 1     1   5 use warnings;
  1         2  
  1         29  
5              
6 1     1   6 use Perl::Critic::Utils qw(:severities :classification :ppi);
  1         2  
  1         62  
7 1     1   348 use parent 'Perl::Critic::Policy';
  1         2  
  1         6  
8              
9             our $VERSION = '0.030';
10              
11 1     1   83 use constant DESC => 'Using overload.pm without a boolean overload or fallback';
  1         2  
  1         66  
12 1     1   8 use constant EXPL => 'When using overload.pm to define overloads for an object class, always define an overload on "bool" explicitly and set the fallback option. This prevents objects from autogenerating a potentially surprising boolean overload, and causes operators for which overloads can\'t be autogenerated to act on the object as they normally would.';
  1         1  
  1         450  
13              
14 6     6 0 21329 sub supported_parameters { () }
15 8     8 1 84 sub default_severity { $SEVERITY_HIGH }
16 0     0 1 0 sub default_themes { 'freenode' }
17 6     6 1 69664 sub applies_to { 'PPI::Statement::Include' }
18              
19             sub violates {
20 13     13 1 1293 my ($self, $elem) = @_;
21 13 50 50     40 return () unless ($elem->type // '') eq 'use' and ($elem->module // '') eq 'overload';
      50        
      33        
22 13         583 my @args = $elem->arguments;
23 13         488 my ($has_bool, $has_fallback);
24 13         0 my @options;
25 13         31 while (@args) {
26 90         437 my $arg = shift @args;
27             # use overload qw(...);
28 90 100 100     567 if ($arg->isa('PPI::Token::QuoteLike::Words')) {
    100 100        
    100          
    100          
29 3         15 push @options, $arg->literal;
30             # use overload 'foo', 1;
31             } elsif ($arg->isa('PPI::Token::Quote')) {
32 11         46 push @options, $arg->string;
33             # use overload foo => 1;
34             } elsif ($arg->isa('PPI::Token::Word') or $arg->isa('PPI::Token::Number')) {
35 24         61 push @options, $arg->literal;
36             # unpack lists and expressions
37             } elsif ($arg->isa('PPI::Structure::List') or $arg->isa('PPI::Statement::Expression')) {
38 11         173 unshift @args, $arg->schildren;
39             }
40             }
41             # use overload; or use overload ();
42 13 100       249 return () unless @options;
43 10         26 foreach my $i (0..$#options) {
44 39         54 my $item = $options[$i];
45 39 100 100     127 if ($item eq 'fallback' and defined $options[$i+1] and $options[$i+1] ne 'undef') {
    100 100        
46 4         8 $has_fallback = 1;
47             } elsif ($item eq 'bool') {
48 6         10 $has_bool = 1;
49             }
50             }
51 10 100 100     58 return $self->violation(DESC, EXPL, $elem) unless $has_bool and $has_fallback;
52 2         6 return ();
53             }
54              
55             1;
56              
57             =head1 NAME
58              
59             Perl::Critic::Policy::Freenode::OverloadOptions - Don't use overload without
60             specifying a bool overload and enabling fallback
61              
62             =head1 DESCRIPTION
63              
64             The L<overload> module allows an object class to specify behavior for an object
65             used in various operations. However, when activated it enables additional
66             behavior by default: it L<autogenerates|overload/"Magic Autogeneration">
67             overload behavior for operators that are not specified, and if it cannot
68             autogenerate an overload for an operator, using that operator on the object
69             will throw an exception.
70              
71             An autogenerated boolean overload can lead to surprising behavior where an
72             object is considered "false" because of another overloaded value. For example,
73             if a class overloads stringification to return the object's name, but the
74             object's name is C<0>, then the object will be considered false due to an
75             autogenerated overload using the boolean value of the string. This is rarely
76             desired behavior, and if needed, it can be set as an explicit boolean overload.
77              
78             Without setting the C<fallback> option, any operators that cannot be
79             autogenerated from defined overloads will result in an exception when used.
80             By setting C<fallback> to C<1>, the operator will instead fall back to standard
81             behavior as if no overload was defined, which is generally the expected
82             behavior when only overloading a few operations.
83              
84             use overload '""' => sub { $_[0]->name }; # not ok
85             use overload '""' => sub { $_[0]->name }, bool => sub { 1 }; # not ok
86             use overload '""' => sub { $_[0]->name }, fallback => 1; # not ok
87             use overload '""' => sub { $_[0]->name }, bool => sub { 1 }, fallback => 1; # ok
88              
89             =head1 AFFILIATION
90              
91             This policy is part of L<Perl::Critic::Freenode>.
92              
93             =head1 CONFIGURATION
94              
95             This policy is not configurable except for the standard options.
96              
97             =head1 AUTHOR
98              
99             Dan Book, C<dbook@cpan.org>
100              
101             =head1 COPYRIGHT AND LICENSE
102              
103             Copyright 2015, Dan Book.
104              
105             This library is free software; you may redistribute it and/or modify it under
106             the terms of the Artistic License version 2.0.
107              
108             =head1 SEE ALSO
109              
110             L<Perl::Critic>