File Coverage

blib/lib/LaTeX/TikZ/Functor/Rule.pm
Criterion Covered Total %
statement 46 49 93.8
branch 9 14 64.2
condition n/a
subroutine 8 8 100.0
pod 2 2 100.0
total 65 73 89.0


line stmt bran cond sub pod time code
1             package LaTeX::TikZ::Functor::Rule;
2              
3 10     10   50 use strict;
  10         29  
  10         317  
4 10     10   53 use warnings;
  10         17  
  10         402  
5              
6             =head1 NAME
7              
8             LaTeX::TikZ::Functor::Rule - An object that specifies how functors should handle a certain kind of set or mod.
9              
10             =head1 VERSION
11              
12             Version 0.02
13              
14             =cut
15              
16             our $VERSION = '0.02';
17              
18             =head1 DESCRIPTION
19              
20             A rule specifies how functors (L<LaTeX::TikZ::Functor> objects) should handle a certain kind of set or mod.
21             A functor is basically an ordered collection of rules.
22              
23             =cut
24              
25 10     10   54 use Carp ();
  10         16  
  10         175  
26              
27 10     10   53 use Any::Moose;
  10         18  
  10         66  
28 10     10   5689 use Any::Moose 'Util' => [ qw[find_meta does_role] ];
  10         19  
  10         53  
29 10     10   2295 use Any::Moose 'Util::TypeConstraints';
  10         21  
  10         41  
30              
31             =head1 ATTRIBUTES
32              
33             =head2 C<target>
34              
35             A class or role name against which set or mod candidates will be matched.
36             It must consume either L<LaTeX::TikZ::Set> or L<LaTeX::TikZ::Mod>, directly or through inheritance.
37              
38             =cut
39              
40             has 'target' => (
41             is => 'ro',
42             isa => 'ClassName|RoleName',
43             required => 1,
44             );
45              
46             =head2 C<handler>
47              
48             The code reference executed when the rule handles a given set or mod object.
49             It is called with the L<LaTeX::TikZ::Functor> object as its first argument, the set/mod object as its second, and then the arguments passed to the functor itself.
50              
51             =cut
52              
53             has 'handler' => (
54             is => 'ro',
55             isa => 'CodeRef',
56             required => 1,
57             );
58              
59             =head2 C<is_role>
60              
61             True if and only if the target is a role.
62              
63             =cut
64              
65             has 'is_role' => (
66             is => 'ro',
67             isa => 'Bool',
68             required => 1,
69             );
70              
71             =head2 C<is_set>
72              
73             True when the target does the L<LaTeX::TikZ::Set> role, and false when it does L<LaTeX::TikZ::Mod>.
74              
75             =cut
76              
77             has 'is_set' => (
78             is => 'ro',
79             isa => 'Bool',
80             required => 1,
81             );
82              
83             my $ltfrl_tc = subtype 'LaTeX::TikZ::Functor::RuleList'
84             => as 'ArrayRef[LaTeX::TikZ::Functor::Rule]';
85              
86             =head1 METHODS
87              
88             =head2 C<< new target => $target, handler => $handler >>
89              
90             Constructs a new rule object with target C<$target> and handler C<$handler>.
91              
92             =cut
93              
94             around 'BUILDARGS' => sub {
95             my ($orig, $class, %args) = @_;
96              
97             my $target = $args{target};
98             __PACKAGE__->meta->find_attribute_by_name('target')
99             ->type_constraint->assert_valid($target);
100              
101             (my $pm = $target) =~ s{::}{/}g;
102             $pm .= '.pm';
103             require $pm;
104              
105             my $meta = find_meta($target);
106             Carp::confess("No meta object associated with target $target")
107             unless defined $meta;
108             $args{is_role} = $meta->isa(any_moose('Meta::Role'));
109              
110             my $is_set;
111             if (does_role($target, 'LaTeX::TikZ::Set')) {
112             $is_set = 1;
113             } elsif (does_role($target, 'LaTeX::TikZ::Mod')) {
114             $is_set = 0;
115             } else {
116             Carp::confess("Target $target is neither a set nor a mod");
117             }
118             $args{is_set} = $is_set;
119              
120             $class->$orig(%args);
121             };
122              
123             =head2 C<< insert into => \@list, overwrite => $overwrite, replace => $replace >>
124              
125             Inserts the current rule into the list of rules C<@list>.
126              
127             If C<$replace> is false, then the rule will be appended to the C<@list> ; except if there already is an existent entry for the same target, in which case it will be overwritten if C<$overwrite> is true, or an exception will be thrown if it is false.
128              
129             If C<$replace> is true, then the rule will replace the first rule in the list that is a subclass or that consumes the role denoted by the target.
130             All the subsequent rules in the list that inherit or consume the target will be removed.
131              
132             =cut
133              
134             sub insert {
135 100     100 1 416 my ($rule, %args) = @_;
136              
137 100         187 my $list = $args{into};
138 100         332 $ltfrl_tc->assert_valid($list);
139              
140 100         1037 my $overwrite = $args{overwrite};
141 100         175 my $replace = $args{replace};
142              
143 100         276 my $target = $rule->target;
144 100         250 my $is_role = $rule->is_role;
145              
146 100 100       216 if ($replace) {
147 1         3 my @remove;
148              
149 1         6 for my $i (0 .. $#$list) {
150 1         8 my $old_target = $list->[$i]->target;
151 1 50       6 if ($rule->handles($old_target)) {
152 1 50       71 if (defined $rule) {
153 1         4 splice @$list, $i, 1, $rule;
154 1         6 $rule = undef;
155             } else {
156 0         0 push @remove, $i;
157             }
158             }
159             }
160              
161 1         3 my $shift;
162 1         3 for (@remove) {
163 0         0 splice @$list, $_ - $shift, 1;
164 0         0 ++$shift;
165             }
166 1 50       11 return 1 unless defined $rule;
167              
168             } else { # Replace only an existent rule
169              
170 99         353 for my $i (0 .. $#$list) {
171 316         736 my $old_target = $list->[$i]->target;
172 316 100       904 if ($old_target eq $target) {
173 9 50       40 Carp::confess("Default rule already defined for target $target")
174             unless $overwrite;
175 9         29 splice @$list, $i, 1, $rule;
176 9         73 return 1;
177             }
178             }
179             }
180              
181 90         219 push @$list, $rule;
182 90         529 return 0;
183             }
184              
185             =head2 C<handles $obj>
186              
187             Returns true if and only if the current rule can handle the object or class/role name C<$obj>.
188              
189             =cut
190              
191             sub handles {
192 7     7 1 13 my ($rule, $obj) = @_;
193              
194 7 50       44 $rule->is_role ? does_role($obj, $rule->target) : $obj->isa($rule->target);
195             }
196              
197             __PACKAGE__->meta->make_immutable;
198              
199             =head1 SEE ALSO
200              
201             L<LaTeX::TikZ>, L<LaTeX::TikZ::Functor>.
202              
203             =head1 AUTHOR
204              
205             Vincent Pit, C<< <perl at profvince.com> >>, L<http://www.profvince.com>.
206              
207             You can contact me by mail or on C<irc.perl.org> (vincent).
208              
209             =head1 BUGS
210              
211             Please report any bugs or feature requests to C<bug-latex-tikz at rt.cpan.org>, or through the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=LaTeX-TikZ>.
212             I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
213              
214             =head1 SUPPORT
215              
216             You can find documentation for this module with the perldoc command.
217              
218             perldoc LaTeX::TikZ
219              
220             =head1 COPYRIGHT & LICENSE
221              
222             Copyright 2010 Vincent Pit, all rights reserved.
223              
224             This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
225              
226             =cut
227              
228             1; # End of LaTeX::TikZ::Functor::Rule