File Coverage

blib/lib/LaTeX/TikZ/Mod/Layer.pm
Criterion Covered Total %
statement 72 77 93.5
branch 14 22 63.6
condition 2 6 33.3
subroutine 17 18 94.4
pod 9 10 90.0
total 114 133 85.7


line stmt bran cond sub pod time code
1             package LaTeX::TikZ::Mod::Layer;
2              
3 10     10   41 use strict;
  10         12  
  10         325  
4 10     10   67 use warnings;
  10         14  
  10         326  
5              
6             =head1 NAME
7              
8             LaTeX::TikZ::Mod::Layer - A modifier that specifies a drawing layer.
9              
10             =head1 VERSION
11              
12             Version 0.03
13              
14             =cut
15              
16             our $VERSION = '0.03';
17              
18 10     10   34 use Scalar::Util ();
  10         11  
  10         110  
19 10     10   30 use List::Util ();
  10         11  
  10         163  
20              
21 10     10   2883 use LaTeX::TikZ::Mod::Formatted;
  10         14  
  10         217  
22              
23 10     10   42 use LaTeX::TikZ::Interface;
  10         10  
  10         124  
24              
25 10     10   27 use Mouse;
  10         9  
  10         24  
26 10     10   1960 use Mouse::Util::TypeConstraints;
  10         13  
  10         27  
27              
28             =head1 RELATIONSHIPS
29              
30             This class consumes the L role, and as such implements the L, L, L and L methods.
31              
32             =cut
33              
34             with 'LaTeX::TikZ::Mod';
35              
36             =head1 ATTRIBUTES
37              
38             =head2 C
39              
40             =cut
41              
42             has 'name' => (
43             is => 'ro',
44             isa => 'Str',
45             required => 1,
46             );
47              
48             =head2 C
49              
50             =cut
51              
52             subtype 'LaTeX::TikZ::Mod::LevelList'
53             => as 'ArrayRef[LaTeX::TikZ::Mod::Layer]';
54              
55             coerce 'LaTeX::TikZ::Mod::LevelList'
56             => from 'Str'
57             => via { [ __PACKAGE__->new(name => $_) ] };
58              
59             coerce 'LaTeX::TikZ::Mod::LevelList'
60             => from 'ArrayRef[Str]'
61             => via { [ map __PACKAGE__->new(name => $_), @$_ ] };
62              
63             has '_above' => (
64             is => 'ro',
65             isa => 'LaTeX::TikZ::Mod::LevelList',
66             init_arg => 'above',
67             default => sub { [ ] },
68             coerce => 1,
69             );
70              
71 22     22 1 14 sub above { @{$_[0]->_above} }
  22         63  
72              
73             =head2 C
74              
75             =cut
76              
77             has '_below' => (
78             is => 'ro',
79             isa => 'LaTeX::TikZ::Mod::LevelList',
80             init_arg => 'below',
81             default => sub { [ ] },
82             coerce => 1,
83             );
84              
85 22     22 1 19 sub below { @{$_[0]->_below} }
  22         51  
86              
87             has '_score' => (
88             is => 'ro',
89             isa => 'Int',
90             init_arg => undef,
91             lazy => 1,
92             builder => '_build_score',
93             );
94              
95             =head1 METHODS
96              
97             =cut
98              
99             my %layers;
100              
101             around 'new' => sub {
102             my ($orig, $self, %args) = @_;
103              
104             my $name = $args{name};
105             if (defined $name) {
106             $self->meta->find_attribute_by_name('name')
107             ->type_constraint->assert_valid($name);
108             my $layer = $layers{$name};
109             if (defined $layer) {
110             confess("Can't redefine layer '$name'") if keys(%args) > 1;
111             return $layer;
112             }
113             }
114              
115             return $self->$orig(%args);
116             };
117              
118             sub BUILD {
119 6     6 1 25 my ($self) = @_;
120              
121 6         12 my $name = $self->name;
122 6         7 $layers{$name} = $self;
123 6         42 Scalar::Util::weaken($layers{$name});
124             }
125              
126             sub DEMOLISH {
127 6     6 1 2266 my ($self) = @_;
128              
129 6         94 delete $layers{$self->name};
130             }
131              
132             =head2 C
133              
134             =cut
135              
136             sub tag {
137 48     48 1 42 my ($self) = @_;
138              
139 48         137 ref($self) . '/' . $self->name;
140             }
141              
142             =head2 C
143              
144             =cut
145              
146 0     0 1 0 sub covers { $_[0]->name eq $_[1]->name }
147              
148             =head2 C
149              
150             =cut
151              
152             {
153             our %score;
154              
155             sub score {
156 35     35 1 27 my $layer = $_[0];
157              
158 35         43 my $name = $layer->name;
159              
160 35 100       71 return $score{$name} if exists $score{$name};
161              
162 22         18 my (@lower, $min);
163 22         31 for ($layer->above) {
164 10         18 my $cur = $_->score;
165 10 50       14 if (defined $cur) {
166 10 50 33     36 $min = $cur if not defined $min or $min < $cur;
167             } else {
168 0         0 push @lower, $_;
169             }
170             }
171              
172 22         23 my (@higher, $max);
173 22         31 for ($layer->below) {
174 3         6 my $cur = $_->score;
175 3 50       7 if (defined $cur) {
176 3 50 33     11 $max = $cur if not defined $max or $max < $cur;
177             } else {
178 0         0 push @higher, $_;
179             }
180             }
181              
182 22 100       49 if (defined $min) {
    50          
183 10 100       22 if (defined $max) {
184 3 50       7 confess("Order mismatch for $name") unless $min < $max;
185 3         8 $score{$name} = ($min + $max) / 2;
186             } else {
187 7         24 my $i = List::Util::max(values %score);
188 7         16 $score{$_} = ++$i for $name, @higher;
189             }
190             } elsif (defined $max) {
191 0         0 my $i = List::Util::min(values %score);
192 0         0 $score{$_} = --$i for @lower, $name;
193             } else {
194 12         37 my $i = 0;
195 12         33 $score{$_} = ++$i for @lower, $name, @higher;
196             }
197              
198 22         45 $score{$name}
199             }
200              
201             =head2 C
202              
203             =cut
204              
205             sub declare {
206 11     11 1 11 shift;
207              
208 11 50       20 return unless @_;
209              
210 11         23 local %score = (main => 0);
211              
212 11         28 $_->score for @_;
213              
214 31 50       56 my @layers = sort { $score{$a} <=> $score{$b} }
  33         73  
215 11         27 map { ref() ? $_->name : $_ }
216             keys %score;
217              
218 11         48 my @intro = map "\\pgfdeclarelayer{$_}",
219             grep $_ ne 'main',
220             @layers;
221              
222             return (
223 11         54 @intro,
224             "\\pgfsetlayers{" . join(',', @layers) . "}",
225             );
226             }
227             }
228              
229             =head2 C
230              
231             =cut
232              
233             sub apply {
234 24     24 1 20 my ($self) = @_;
235              
236 24         135 LaTeX::TikZ::Mod::Formatted->new(
237             type => 'layer',
238             content => $self->name,
239             )
240             }
241              
242             LaTeX::TikZ::Interface->register(
243             layer => sub {
244 3     3 0 1177 shift;
245              
246 3         4 my $name = shift;
247 3         13 __PACKAGE__->new(name => $name, @_);
248             },
249             );
250              
251             __PACKAGE__->meta->make_immutable(
252             inline_constructor => 0,
253             );
254              
255             =head1 SEE ALSO
256              
257             L, L.
258              
259             =head1 AUTHOR
260              
261             Vincent Pit, C<< >>, L.
262              
263             You can contact me by mail or on C (vincent).
264              
265             =head1 BUGS
266              
267             Please report any bugs or feature requests to C, or through the web interface at L.
268             I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
269              
270             =head1 SUPPORT
271              
272             You can find documentation for this module with the perldoc command.
273              
274             perldoc LaTeX::TikZ
275              
276             =head1 COPYRIGHT & LICENSE
277              
278             Copyright 2010,2011,2012,2013,2014,2015 Vincent Pit, all rights reserved.
279              
280             This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
281              
282             =cut
283              
284             1; # End of LaTeX::TikZ::Mod::Layer