File Coverage

blib/lib/Data/Object/Data.pm
Criterion Covered Total %
statement 101 107 94.3
branch 29 40 72.5
condition 18 27 66.6
subroutine 15 16 93.7
pod 7 11 63.6
total 170 201 84.5


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