File Coverage

blib/lib/Data/Object/Data.pm
Criterion Covered Total %
statement 99 107 92.5
branch 25 40 62.5
condition 14 27 51.8
subroutine 15 16 93.7
pod 7 11 63.6
total 160 201 79.6


line stmt bran cond sub pod time code
1             package Data::Object::Data;
2              
3 1     1   37164 use 5.014;
  1         3  
4              
5 1     1   5 use strict;
  1         2  
  1         31  
6 1     1   5 use warnings;
  1         1  
  1         24  
7 1     1   5 use routines;
  1         1  
  1         9  
8              
9 1     1   1886 use Moo;
  1         2  
  1         5  
10              
11             require Carp;
12              
13             our $VERSION = '2.02'; # VERSION
14              
15             # BUILD
16              
17             has data => (
18             is => 'ro',
19             builder => 'new_data',
20             lazy => 1
21             );
22              
23 10     10 0 81 fun new_data($self) {
  10         11  
24 10         150 my $file = $self->file;
25 10         72 my $data = $self->parser($self->lines);
26              
27 10         29 return $data;
28             }
29              
30             has file => (
31             is => 'ro',
32             builder => 'new_file',
33             lazy => 1
34             );
35              
36 0     0 0 0 fun new_file($self) {
  0         0  
37 0 0       0 my $from = $self->from or return;
38 0         0 my $path = $from =~ s/::/\//gr;
39              
40 0         0 return $INC{"$path.pm"};
41             }
42              
43             has from => (
44             is => 'ro',
45             lazy => 1
46             );
47              
48 10     10 0 135661 fun BUILD($self, $args) {
  10         16  
49 10         184 $self->file;
50 10         242 $self->data;
51              
52 10         242 return $self;
53             }
54              
55             # METHODS
56              
57 1     1 1 6 method content($name) {
  1         3  
  1         2  
58 1 50       6 my $item = $self->item($name) or return;
59 1         4 my $data = $item->{data};
60              
61 1         13 return $data;
62             }
63              
64 1     1 1 19 method contents($name, $seek) {
  1         3  
  1         2  
65 1 50       5 my $items = $self->list($name) or return;
66 1 50       3 @$items = grep { $_->{name} eq $seek } @$items if $seek;
  0         0  
67 1         4 my $data = [map { $_->{data} } @$items];
  2         5  
68              
69 1         13 return $data;
70             }
71              
72 2     2 1 7 method item($name) {
  2         5  
  2         2  
73 2         8 for my $item (@{$self->{data}}) {
  2         5  
74 2 50 33     27 return $item if !$item->{list} && $item->{name} eq $name;
75             }
76              
77 0         0 return;
78             }
79              
80 10     10 0 21 method lines() {
  10         13  
81 10 50       150 my $file = $self->file or return '';
82              
83 10 50       518 open my $fh, '<', $file or Carp::confess "$!: $file";
84 10         906 my $lines = join "\n", <$fh>;
85 10         166 close $fh;
86              
87 10         123 return $lines;
88             }
89              
90 3     3 1 12 method list($name) {
  3         4  
  3         5  
91 3 50       8 return if !$name;
92              
93 3         4 my @list;
94              
95 3         5 for my $item (@{$self->{data}}) {
  3         9  
96 6 50 33     26 push @list, $item if $item->{list} && $item->{list} eq $name;
97             }
98              
99 3         12 return [sort { $a->{index} <=> $b->{index} } @list];
  3         31  
100             }
101              
102 1     1 1 11 method list_item($list, $name) {
  1         4  
  1         2  
103 1 50       2 my $items = $self->list($list) or return;
104 1         3 my $data = [grep { $_->{name} eq $name } @$items];
  2         6  
105              
106 1         12 return $data;
107             }
108              
109 11     11 1 27 method parser($data) {
  11         27  
  11         15  
110 11         1639 $data =~ s/\n*$/\n/;
111              
112 11         402 my @chunks = split /^=\s*(.+?)\s*\r?\n/m, $data;
113              
114 11         21 shift @chunks;
115              
116 11         29 my $items = [];
117              
118 11         43 while (my ($meta, $data) = splice @chunks, 0, 2) {
119 118 100 66     419 next unless $meta && $data;
120 77 100       147 next unless $meta ne 'cut';
121              
122 75         188 my @info = split /\s/, $meta, 2;
123 75 100       175 my ($list, $name) = @info == 2 ? @info : (undef, @info);
124              
125 75         314 $data = [split /\n\n/, $data];
126              
127 75         245 my $item = { name => $name, data => $data, index => @$items + 1, list => $list };
128              
129 75         250 push @$items, $item;
130             }
131              
132 11         53 return $items;
133             }
134              
135 5     5 1 26 method pluck($type, $name) {
  5         12  
  5         7  
136 5 50       13 return if !$name;
137 5 50 66     26 return if !$type || ($type ne 'item' && $type ne 'list');
      33        
138              
139 5         9 my (@list, @copy);
140              
141 5         8 for my $item (@{$self->{data}}) {
  5         14  
142 7         9 my $matched = 0;
143              
144 7 50 66     28 $matched = 1 if $type eq 'list' && $item->{list} && $item->{list} eq $name;
      33        
145 7 100 66     28 $matched = 1 if $type eq 'item' && $item->{name} && $item->{name} eq $name;
      66        
146              
147 7 100       15 push @list, $item if $matched;
148 7 100       21 push @copy, $item if !$matched;
149             }
150              
151 5         15 $self->{data} = [sort { $a->{index} <=> $b->{index} } @copy];
  0         0  
152              
153 5 50       79 return $type eq 'name' ? $list[0] : [@list];
154             }
155              
156             1;
157              
158             =encoding utf8
159              
160             =head1 NAME
161              
162             Data::Object::Data
163              
164             =cut
165              
166             =head1 ABSTRACT
167              
168             Podish Parser for Perl 5
169              
170             =cut
171              
172             =head1 SYNOPSIS
173              
174             package main;
175              
176             use Data::Object::Data;
177              
178             my $data = Data::Object::Data->new(
179             file => 't/Data_Object_Data.t'
180             );
181              
182             =cut
183              
184             =head1 DESCRIPTION
185              
186             This package provides methods for parsing and extracting pod-like sections from
187             any file or package. The pod-like syntax allows for using these sections
188             anywhere in the source code and having Perl properly ignoring them.
189              
190             =cut
191              
192             =head1 ATTRIBUTES
193              
194             This package has the following attributes:
195              
196             =cut
197              
198             =head2 data
199              
200             data(Str)
201              
202             This attribute is read-only, accepts C<(Str)> values, and is optional.
203              
204             =cut
205              
206             =head2 file
207              
208             file(Str)
209              
210             This attribute is read-only, accepts C<(Str)> values, and is optional.
211              
212             =cut
213              
214             =head2 from
215              
216             from(Str)
217              
218             This attribute is read-only, accepts C<(Str)> values, and is optional.
219              
220             =cut
221              
222             =head1 METHODS
223              
224             This package implements the following methods:
225              
226             =cut
227              
228             =head2 content
229              
230             content(Str $name) : ArrayRef[Str]
231              
232             The content method the pod-like section where the name matches the given
233             string.
234              
235             =over 4
236              
237             =item content example #1
238              
239             # =name
240             #
241             # Example #1
242             #
243             # =cut
244             #
245             # =name
246             #
247             # Example #2
248             #
249             # =cut
250              
251             my $data = Data::Object::Data->new(
252             file => 't/examples/content.pod'
253             );
254              
255             $data->content('name');
256              
257             # ['Example #1']
258              
259             =back
260              
261             =cut
262              
263             =head2 contents
264              
265             contents(Str $list, Str $name) : ArrayRef[ArrayRef]
266              
267             The contents method returns all pod-like sections that start with the given
268             string, e.g. C<pod> matches C<=pod foo>. This method returns an arrayref of
269             data for the matched sections. Optionally, you can filter the results by name
270             by providing an additional argument.
271              
272             =over 4
273              
274             =item contents example #1
275              
276             # =name example-1
277             #
278             # Example #1
279             #
280             # =cut
281             #
282             # =name example-2
283             #
284             # Example #2
285             #
286             # =cut
287              
288             my $data = Data::Object::Data->new(
289             file => 't/examples/contents.pod'
290             );
291              
292             $data->contents('name');
293              
294             # [['Example #1'], ['Example #2']]
295              
296             =back
297              
298             =cut
299              
300             =head2 item
301              
302             item(Str $name) : HashRef
303              
304             The item method returns metadata for the pod-like section that matches the
305             given string.
306              
307             =over 4
308              
309             =item item example #1
310              
311             # =name
312             #
313             # Example #1
314             #
315             # =cut
316             #
317             # =name
318             #
319             # Example #2
320             #
321             # =cut
322              
323             my $data = Data::Object::Data->new(
324             file => 't/examples/content.pod'
325             );
326              
327             $data->item('name');
328              
329             # {
330             # index => 1,
331             # data => ['Example #1'],
332             # list => undef,
333             # name => 'name'
334             # }
335              
336             =back
337              
338             =cut
339              
340             =head2 list
341              
342             list(Str $name) : ArrayRef
343              
344             The list method returns metadata for each pod-like section that matches the
345             given string.
346              
347             =over 4
348              
349             =item list example #1
350              
351             # =name example-1
352             #
353             # Example #1
354             #
355             # =cut
356             #
357             # =name example-2
358             #
359             # Example #2
360             #
361             # =cut
362              
363             my $data = Data::Object::Data->new(
364             file => 't/examples/contents.pod'
365             );
366              
367             $data->list('name');
368              
369             # [{
370             # index => 1,
371             # data => ['Example #1'],
372             # list => 'name',
373             # name => 'example-1'
374             # },
375             # {
376             # index => 2,
377             # data => ['Example #2'],
378             # list => 'name',
379             # name => 'example-2'
380             # }]
381              
382             =back
383              
384             =cut
385              
386             =head2 list_item
387              
388             list_item(Str $list, Str $item) : ArrayRef[HashRef]
389              
390             The list_item method returns metadata for the pod-like sections that matches
391             the given list name and argument.
392              
393             =over 4
394              
395             =item list_item example #1
396              
397             # =name example-1
398             #
399             # Example #1
400             #
401             # =cut
402             #
403             # =name example-2
404             #
405             # Example #2
406             #
407             # =cut
408              
409             my $data = Data::Object::Data->new(
410             file => 't/examples/contents.pod'
411             );
412              
413             $data->list_item('name', 'example-2');
414              
415             # [{
416             # index => 2,
417             # data => ['Example #2'],
418             # list => 'name',
419             # name => 'example-2'
420             # }]
421              
422             =back
423              
424             =cut
425              
426             =head2 parser
427              
428             parser(Str $string) : ArrayRef
429              
430             The parser method extracts pod-like sections from a given string and returns an
431             arrayref of metadata.
432              
433             =over 4
434              
435             =item parser example #1
436              
437             # given: synopsis
438              
439             $data->parser("=pod\n\nContent\n\n=cut");
440              
441             # [{
442             # index => 1,
443             # data => ['Content'],
444             # list => undef,
445             # name => 'pod'
446             # }]
447              
448             =back
449              
450             =cut
451              
452             =head2 pluck
453              
454             pluck(Str $type, Str $item) : ArrayRef[HashRef]
455              
456             The pluck method splices and returns metadata for the pod-like section that
457             matches the given list or item by name. Splicing means that the parsed dataset
458             will be reduced each time this method returns data, making this useful with
459             iterators and reducers.
460              
461             =over 4
462              
463             =item pluck example #1
464              
465             # =name example-1
466             #
467             # Example #1
468             #
469             # =cut
470             #
471             # =name example-2
472             #
473             # Example #2
474             #
475             # =cut
476              
477             my $data = Data::Object::Data->new(
478             file => 't/examples/contents.pod'
479             );
480              
481             $data->pluck('list', 'name');
482              
483             # [{
484             # index => 1,
485             # data => ['Example #1'],
486             # list => 'name',
487             # name => 'example-1'
488             # },{
489             # index => 2,
490             # data => ['Example #2'],
491             # list => 'name',
492             # name => 'example-2'
493             # }]
494              
495             =back
496              
497             =over 4
498              
499             =item pluck example #2
500              
501             # =name example-1
502             #
503             # Example #1
504             #
505             # =cut
506             #
507             # =name example-2
508             #
509             # Example #2
510             #
511             # =cut
512              
513             my $data = Data::Object::Data->new(
514             file => 't/examples/contents.pod'
515             );
516              
517             $data->pluck('item', 'example-1');
518              
519             # [{
520             # index => 1,
521             # data => ['Example #1'],
522             # list => 'name',
523             # name => 'example-1'
524             # }]
525              
526             $data->pluck('item', 'example-2');
527              
528             # [{
529             # index => 2,
530             # data => ['Example #2'],
531             # list => 'name',
532             # name => 'example-2'
533             # }]
534              
535             =back
536              
537             =over 4
538              
539             =item pluck example #3
540              
541             # =name example-1
542             #
543             # Example #1
544             #
545             # =cut
546             #
547             # =name example-2
548             #
549             # Example #2
550             #
551             # =cut
552              
553             my $data = Data::Object::Data->new(
554             file => 't/examples/contents.pod'
555             );
556              
557             $data->pluck('list', 'name');
558              
559             # [{
560             # index => 1,
561             # data => ['Example #1'],
562             # list => 'name',
563             # name => 'example-1'
564             # },{
565             # index => 2,
566             # data => ['Example #2'],
567             # list => 'name',
568             # name => 'example-2'
569             # }]
570              
571             $data->pluck('list', 'name');
572              
573             # []
574              
575             =back
576              
577             =cut
578              
579             =head1 AUTHOR
580              
581             Al Newkirk, C<awncorp@cpan.org>
582              
583             =head1 LICENSE
584              
585             Copyright (C) 2011-2019, Al Newkirk, et al.
586              
587             This is free software; you can redistribute it and/or modify it under the terms
588             of the The Apache License, Version 2.0, as elucidated in the L<"license
589             file"|https://github.com/iamalnewkirk/data-object-data/blob/master/LICENSE>.
590              
591             =head1 PROJECT
592              
593             L<Wiki|https://github.com/iamalnewkirk/data-object-data/wiki>
594              
595             L<Project|https://github.com/iamalnewkirk/data-object-data>
596              
597             L<Initiatives|https://github.com/iamalnewkirk/data-object-data/projects>
598              
599             L<Milestones|https://github.com/iamalnewkirk/data-object-data/milestones>
600              
601             L<Contributing|https://github.com/iamalnewkirk/data-object-data/blob/master/CONTRIBUTE.md>
602              
603             L<Issues|https://github.com/iamalnewkirk/data-object-data/issues>
604              
605             =cut