Add the warning elsewhere too why not
[gitmo/Perl-Critic-Dynamic-Moose.git] / lib / Perl / Critic / Policy / DynamicMoose.pm
CommitLineData
84a1bb62 1package Perl::Critic::Policy::DynamicMoose;
a3c86d00 2use Moose;
8f31d0d0 3use MooseX::NonMoose;
a3c86d00 4extends 'Perl::Critic::DynamicPolicy';
5
8f31d0d0 6has document => (
1e6decf8 7 is => 'rw',
8 isa => 'PPI::Document',
9 handles => [qw/ppi_document/],
8f31d0d0 10);
11
cc784ef4 12sub applies_to { 'PPI::Document' }
914f300c 13sub applies_to_metaclass { 'Class::MOP::Class', inner() }
528d0b4b 14sub default_themes { qw(moose dynamic dynamicmoose), inner() }
8f31d0d0 15
16around violation => sub {
1e6decf8 17 my $orig = shift;
18 my $self = shift;
19 my $desc = shift;
20 my $expl = shift;
21 my $element = shift;
22
23 if (!$element) {
24 my $doc = $self->ppi_document;
0004d229 25
26 # Without this hack, Storable complains of being unable to reconstruct
27 # overloading for an unknown package (perhaps PPI::Document?). For some
28 # reason it works for PPI::Element. Anyway, this should hopefully be
29 # replaced with a more useful location, something like
30 # ( class:MyClass / attr:foo / builder:build_foo )
1e6decf8 31 $element = $doc->find('PPI::Element')->[0];
32 }
8f31d0d0 33
1e6decf8 34 return $self->$orig($desc, $expl, $element, @_);
8f31d0d0 35};
36
a3c86d00 37sub violates_dynamic {
38 my $self = shift;
39 my $doc = shift;
40
8f31d0d0 41 $self->document($doc);
8f31d0d0 42
34502164 43 my $old_packages = $self->find_packages;
44 $self->compile_document;
45 my @new_packages = $self->new_packages($old_packages);
8f31d0d0 46
47 my @violations;
34502164 48 for my $package (@new_packages) {
c140dc59 49 my $meta = Class::MOP::class_of($package)
50 or next;
51
52 grep { $meta->isa($_) } $self->applies_to_metaclass
53 or next;
8f31d0d0 54
55 push @violations, $self->violates_metaclass($meta, $doc);
56 }
57
58 return @violations;
59}
60
61sub compile_document {
62 my $self = shift;
63 my $doc = $self->document;
64
1ad52929 65 my $source_code = $doc->content;
66
67 eval $source_code;
68
69 die "Unable to execute " . $doc->filename . ": $@" if $@;
8f31d0d0 70}
71
72sub find_packages {
73 my $self = shift;
34502164 74 return [ Class::MOP::get_all_metaclass_names ];
75}
76
77sub new_packages {
78 my $self = shift;
79 my $old = shift;
80 my @new;
81 my %seen;
82
83 $seen{$_} = 1 for @$old;
84
85 for (@{ $self->find_packages }) {
86 push @new, $_ if !$seen{$_}++;
87 }
a3c86d00 88
34502164 89 return @new;
a3c86d00 90}
91
a3c86d00 92no Moose;
93
941;
95
e556eafb 96__END__
97
98=head1 NAME
99
100Perl::Critic::Policy::DynamicMoose
101
102=head1 DESCRIPTION
103
104The included policies are:
105
106=over 4
107
108=item L<Perl::Critic::Policy::DynamicMoose::ProhibitPublicBuilders>
109
110Prohibit public builder methods for attributes. [Severity: 3]
111
112=back
113
ea5503e8 114=head1 WARNING
115
116B<VERY IMPORTANT:> Most L<Perl::Critic> Policies (including all the ones that
117ship with Perl::Critic> use pure static analysis -- they never compile nor
118execute any of the code that they analyze. However, this policy is very
119different. It actually attempts to compile your code and then compares the
120subroutines mentioned in your code to those found in the symbol table.
121Therefore you should B<not> use this Policy on any code that you do not trust,
122or may have undesirable side-effects at compile-time (such as connecting to the
123network or mutating files).
124
125For this Policy to work, all the modules included in your code must be
126installed locally, and must compile without error.
127
e556eafb 128=head1 AUTHOR
129
130Shawn M Moore, C<sartak@bestpractical.com>
131
132=cut
133