File Coverage

blib/lib/Module/Format/Module.pm
Criterion Covered Total %
statement 78 85 91.7
branch 12 18 66.6
condition 2 2 100.0
subroutine 21 21 100.0
pod 7 7 100.0
total 120 133 90.2


line stmt bran cond sub pod time code
1             package Module::Format::Module;
2             $Module::Format::Module::VERSION = '0.4.0';
3 4     4   70246 use warnings;
  4         16  
  4         135  
4 4     4   21 use strict;
  4         14  
  4         7755  
5              
6              
7             sub _new
8             {
9 22     22   42 my $class = shift;
10 22         44 my $self = bless {}, $class;
11 22         76 $self->_init(@_);
12 22         89 return $self;
13             }
14              
15             sub _components
16             {
17 84     84   136 my $self = shift;
18              
19 84 100       190 if (@_)
20             {
21 22         45 $self->{_components} = shift;
22             }
23 84         444 return $self->{_components};
24             }
25              
26             sub _init
27             {
28 22     22   38 my ( $self, $args ) = @_;
29              
30 22         36 $self->_components( [ @{ $args->{_components} } ] );
  22         70  
31              
32 22         34 return;
33             }
34              
35              
36             sub from_components
37             {
38 4     4 1 1384 my ( $class, $args ) = @_;
39              
40 4         7 return $class->_new( { _components => [ @{ $args->{components} } ] } );
  4         14  
41             }
42              
43              
44             my $dash_re = qr{(?:\w+-)*\w+};
45             my $colon_re = qr{(?:\w+::)*\w+};
46             my $METACPAN_REL = 'https://metacpan.org/release/';
47              
48             sub _gen_dash_format
49             {
50 12     12   34 my ($args) = @_;
51              
52 12         26 my $prefix = $args->{prefix};
53 12         22 my $name = $args->{name};
54              
55             return +{
56             name => $name,
57             regex => qr{\A\Q$prefix\E$dash_re\z},
58             input => sub {
59 3     3   7 my ( $class, $value ) = @_;
60              
61 3 50       44 if ( $value !~ s{\A\Q$prefix\E}{} )
62             {
63 0         0 die "$name value does not start with the '$prefix' prefix.";
64             }
65              
66 3         12 return $class->_calc_components_from_string(
67             { format => 'dash', value => $value } );
68             },
69             format => sub {
70 9     9   21 my ($self) = @_;
71              
72 9         24 return $prefix . $self->format_as('dash');
73             },
74 12         269 };
75             }
76              
77             sub _gen_colon_format
78             {
79 8     8   21 my ($args) = @_;
80              
81 8         17 my $prefix = $args->{prefix};
82 8         11 my $suffix = $args->{suffix};
83 8         13 my $name = $args->{name};
84              
85             return +{
86             name => $name,
87             regex => qr{\A\Q$prefix\E$colon_re\Q$suffix\E\z},
88             input => sub {
89 4     4   11 my ( $class, $value ) = @_;
90              
91 4 50       90 if ( $value !~ m{\A\Q$prefix\E((?:\w+::)*\w+)\Q$suffix\E\z} )
92             {
93 0         0 die "Improper value for $name";
94             }
95              
96 4         30 return $class->_calc_components_from_string(
97             { format => 'colon', value => $1 } );
98             },
99             format => sub {
100 5     5   8 my ($self) = @_;
101              
102 5         12 return $prefix . $self->format_as('colon') . $suffix;
103             },
104 8         569 };
105             }
106              
107             my @formats_by_priority = (
108             _gen_dash_format(
109             {
110             name => 'rpm_dash',
111             prefix => 'perl-',
112             }
113             ),
114             _gen_colon_format(
115             {
116             name => 'rpm_colon',
117             prefix => 'perl(',
118             suffix => ')',
119             }
120             ),
121             {
122             name => 'colon',
123             regex => qr{\A$colon_re\z},
124             input => sub {
125             my ( $class, $value ) = @_;
126             return [ split( /::/, $value, -1 ) ];
127             },
128             format => sub {
129             my ($self) = @_;
130              
131             return join( '::', @{ $self->_components() } );
132             },
133             },
134             {
135             name => 'dash',
136             regex => qr{\A$dash_re\z},
137             input => sub {
138             my ( $class, $value ) = @_;
139             return [ split( /-/, $value, -1 ) ];
140             },
141             format => sub {
142             my ($self) = @_;
143              
144             return join( '-', @{ $self->_components() } );
145             },
146             },
147             {
148             name => 'unix',
149             regex => qr{\A(?:\w+/)*\w+\.pm\z},
150             input => sub {
151             my ( $class, $value ) = @_;
152              
153             if ( $value !~ s{\.pm\z}{} )
154             {
155             die "Cannot find a .pm suffix in the 'unix' format.";
156             }
157              
158             return [ split( m{/}, $value, -1 ) ];
159             },
160             format => sub {
161             my ($self) = @_;
162              
163             return join( '/', @{ $self->_components() } ) . '.pm';
164             },
165             },
166             _gen_dash_format(
167             {
168             name => 'metacpan_rel',
169             prefix => $METACPAN_REL,
170             }
171             ),
172             _gen_colon_format(
173             {
174             name => 'metacpan_pod',
175             prefix => 'https://metacpan.org/pod/',
176             suffix => '',
177             }
178             ),
179             {
180             name => 'debian',
181             format => sub {
182             my ($self) = @_;
183              
184             return 'lib' . lc( $self->format_as('dash') ) . '-perl';
185             },
186             },
187             _gen_dash_format(
188             {
189             name => 'freebsd_dash',
190             prefix => 'p5-',
191             }
192             ),
193             );
194              
195             my %formats = ( map { $_->{name} => $_ } @formats_by_priority );
196              
197             sub _calc_components_from_string
198             {
199 25     25   49 my ( $class, $args ) = @_;
200              
201 25         36 my $format = $args->{format};
202 25         37 my $value = $args->{value};
203              
204 25 50       57 if ( exists( $formats{$format} ) )
205             {
206 25 50       57 if ( my $handler = $formats{$format}->{'input'} )
207             {
208 25         54 return $class->$handler($value);
209             }
210             else
211             {
212 0         0 die "Format $format is output-only!";
213             }
214             }
215             else
216             {
217 0         0 die "Unknown format '$format'!";
218             }
219             }
220              
221             sub from
222             {
223 18     18 1 2678 my ( $class, $args ) = @_;
224              
225 18         30 my $format = $args->{format};
226 18         33 my $value = $args->{value};
227              
228 18         44 return $class->_new(
229             {
230             _components => $class->_calc_components_from_string($args)
231             }
232             );
233             }
234              
235              
236             sub get_components_list
237             {
238 20     20 1 5881 my $self = shift;
239              
240 20         30 return [ @{ $self->_components() } ];
  20         43  
241             }
242              
243              
244             sub format_as
245             {
246 53     53 1 114 my ( $self, $format ) = @_;
247              
248 53 50       121 if ( exists( $formats{$format} ) )
249             {
250 53         92 my $handler = $formats{$format}->{'format'};
251 53         113 return $self->$handler();
252             }
253             else
254             {
255 0         0 die "Unknown format '$format';";
256             }
257              
258 0         0 return;
259             }
260              
261              
262             sub clone
263             {
264 1     1 1 281 my $self = shift;
265              
266             return
267 1         5 ref($self)
268             ->from_components( { components => $self->get_components_list() } );
269             }
270              
271              
272             sub _all
273             {
274 4     4   9 my ( $cb, $l ) = @_;
275              
276 4         9 foreach (@$l)
277             {
278 9 100       18 if ( not $cb->($_) )
279             {
280 1         5 return;
281             }
282             }
283              
284 3         11 return 1;
285             }
286              
287             sub is_sane
288             {
289 4     4 1 15 my $self = shift;
290              
291 4     9   19 return _all( sub { m{\A\w+\z}; }, $self->_components() );
  9         46  
292             }
293              
294              
295             sub from_guess
296             {
297 12     12 1 4035 my ( $class, $args ) = @_;
298              
299 12         21 my $dummy_format_string;
300              
301 12         21 my $string = $args->{value};
302 12   100     61 my $out_format_ref = ( $args->{format_ref} || ( \$dummy_format_string ) );
303              
304             # TODO : After the previous line the indentation in vim is reset to the
305             # first column.
306              
307 12         25 foreach my $format_record (@formats_by_priority)
308             {
309 44 50       97 if ( my $regex = $format_record->{regex} )
310             {
311 44 100       214 if ( $string =~ $regex )
312             {
313 12         24 my $format_id = $format_record->{name};
314              
315 12         19 ${$out_format_ref} = $format_id;
  12         21  
316              
317 12         45 return $class->from(
318             { value => $string, format => $format_id, } );
319             }
320             }
321             }
322              
323 0           die "Could not guess the format of the value '$string'!";
324             }
325              
326              
327             1; # End of Module::Format::Module
328              
329             __END__