File Coverage

blib/lib/Venus/Data.pm
Criterion Covered Total %
statement 84 95 88.4
branch 28 42 66.6
condition 13 16 81.2
subroutine 13 14 92.8
pod 8 10 80.0
total 146 177 82.4


line stmt bran cond sub pod time code
1             package Venus::Data;
2              
3 86     86   1920 use 5.018;
  86         291  
4              
5 86     86   461 use strict;
  86         155  
  86         1733  
6 86     86   383 use warnings;
  86         162  
  86         2568  
7              
8 86     86   426 use Venus::Class 'attr', 'base';
  86         147  
  86         633  
9              
10             base 'Venus::Path';
11              
12             # ATTRIBUTES
13              
14             attr 'from';
15             attr 'stag';
16             attr 'etag';
17              
18             # BUILDERS
19              
20             sub build_self {
21 293     293 0 929 my ($self, $data) = @_;
22              
23 293         1120 return $self->docs;
24             };
25              
26             # METHODS
27              
28             sub assertion {
29 0     0 1 0 my ($self) = @_;
30              
31 0         0 my $assert = $self->SUPER::assertion;
32              
33 0         0 $assert->clear->expression('string');
34              
35 0         0 return $assert;
36             }
37              
38             sub count {
39 2     2 1 6 my ($self, $data) = @_;
40              
41 2         6 my @result = ($self->search($data));
42              
43 2         26 return scalar @result;
44             }
45              
46             sub data {
47 8     8 1 33 my ($self) = @_;
48              
49 8         21 my $data = $self->read;
50              
51 8   50     101 $data = (split(/^__END__/m, (split(/^__DATA__/m, $data))[1] || ''))[0] || '';
52              
53 8         171 $data =~ s/^\s+|\s+$//g;
54              
55 8         27 return $data;
56             }
57              
58             sub docs {
59 302     302 1 741 my ($self) = @_;
60              
61 302         1086 $self->stag('=');
62 302         1212 $self->etag('=cut');
63 302         1273 $self->from('read');
64              
65 302         928 return $self;
66             }
67              
68             sub explode {
69 7189     7189 0 13856 my ($self) = @_;
70              
71 7189         20026 my $from = $self->from;
72 7189         27142 my $data = $self->$from;
73 7189         35063 my $stag = $self->stag;
74 7189         21875 my $etag = $self->etag;
75              
76 7189         6991906 my @chunks = split /^(?:\@$stag|$stag)\s*(.+?)\s*\r?\n/m, ($data . "\n");
77              
78 7189         23992 shift @chunks;
79              
80 7189         19169 my $items = [];
81              
82 7189         31892 while (my ($meta, $data) = splice @chunks, 0, 2) {
83 2225262 100 66     5892149 next unless $meta && $data;
84 2157025 50       3298342 next unless $meta ne $etag;
85              
86 2157025         4684462 my @info = split /\s/, $meta, 2;
87 2157025 100       4436842 my ($list, $name) = @info == 2 ? @info : (undef, @info);
88              
89 2157025         5125034 $data =~ s/(\r?\n)\+$stag/$1$stag/g; # auto-escape nested syntax
90 2157025         11385208 $data = [split /\r?\n\r?\n/, $data];
91              
92 2157025         6356049 my $item = {name => $name, data => $data, index => @$items + 1, list => $list};
93              
94 2157025         6786759 push @$items, $item;
95             }
96              
97 7189         22568 return $items;
98             }
99              
100             sub find {
101 3400     3400 1 8359 my ($self, $list, $name) = @_;
102              
103 3400         14319 return $self->search({list => $list, name => $name});
104             }
105              
106             sub search {
107 7189     7189 1 14509 my ($self, $data) = @_;
108              
109 7189   100     16847 $data //= {};
110              
111 7189         17659 my $exploded = $self->explode;
112              
113 7189 50       25413 return wantarray ? (@$exploded) : $exploded if !keys %$data;
    100          
114              
115 7187         11450 my @result;
116              
117 7187         42429 my $sought = {map +($_, 1), keys %$data};
118              
119 7187         64200 for my $item (sort {$a->{index} <=> $b->{index}} @$exploded) {
  2150696         2650811  
120 2157015         3195655 my $found = {};
121              
122 2157015         2498260 my $text;
123 2157015 50       3549832 if ($text = $data->{data}) {
124 0 0       0 $text = ref($text) eq 'Regexp' ? $text : qr/^@{[quotemeta($text)]}$/;
  0         0  
125 0 0       0 $found->{data} = 1 if "@{$item->{data}}" =~ $text;
  0         0  
126             }
127              
128 2157015         2373098 my $index;
129 2157015 50       3291895 if ($index = $data->{index}) {
130 0 0       0 $index = ref($index) eq 'Regexp' ? $index : qr/^@{[quotemeta($index)]}$/;
  0         0  
131 0 0       0 $found->{index} = 1 if $item->{index} =~ $index;
132             }
133              
134 2157015         2385948 my $list;
135 2157015 100       3295232 if ($list = $data->{list}) {
136 996308 50       1479306 $list = (ref($list) eq 'Regexp' ? $list : qr/^@{[quotemeta($list)]}$/);
  996308         3393841  
137 996308 100 100     3658703 $found->{list} = 1 if defined $item->{list} && $item->{list} =~ $list;
138             }
139             else {
140             $found->{list} = 1 if (exists $data->{list} && !defined $data->{list})
141 1160707 100 66     4398599 && !defined $item->{list};
      100        
142             }
143              
144 2157015         2599078 my $name;
145 2157015 100       3587893 if ($name = $data->{name}) {
146 2156705 50       3252255 $name = ref($name) eq 'Regexp' ? $name : qr/^@{[quotemeta($name)]}$/;
  2156705         7218605  
147 2156705 100       6302459 $found->{name} = 1 if $item->{name} =~ $name;
148             }
149              
150 2157015 100       7835765 if (not(grep(not(defined($found->{$_})), keys(%$sought)))) {
151 7201         25253 push @result, $item;
152             }
153             }
154              
155 7187 100       1189472 return wantarray ? (@result) : \@result;
156             }
157              
158             sub string {
159 5     5 1 18 my ($self, $list, $name) = @_;
160              
161 5         10 my @result;
162              
163 5         13 for my $item ($self->find($list, $name)) {
164 8         15 push @result, join "\n\n", @{$item->{data}};
  8         37  
165             }
166              
167 5 100       76 return wantarray ? (@result) : join "\n", @result;
168             }
169              
170             sub text {
171 8     8 1 28 my ($self) = @_;
172              
173 8         24 $self->stag('@@ ');
174 8         26 $self->etag('@@ end');
175 8         32 $self->from('data');
176              
177 8         38 return $self;
178             }
179              
180             1;
181              
182              
183              
184             =head1 NAME
185              
186             Venus::Data - Data Class
187              
188             =cut
189              
190             =head1 ABSTRACT
191              
192             Data Class for Perl 5
193              
194             =cut
195              
196             =head1 SYNOPSIS
197              
198             package main;
199              
200             use Venus::Data;
201              
202             my $data = Venus::Data->new('t/data/sections');
203              
204             # $data->find(undef, 'name');
205              
206             =cut
207              
208             =head1 DESCRIPTION
209              
210             This package provides methods for extracting C sections and POD blocks
211             from any file or package. The package can be configured to parse either POD or
212             DATA blocks, and it defaults to being configured for POD blocks.
213              
214             =head2 DATA syntax
215              
216             __DATA__
217              
218             # data syntax
219              
220             @@ name
221              
222             Example Name
223              
224             @@ end
225              
226             @@ titles #1
227              
228             Example Title #1
229              
230             @@ end
231              
232             @@ titles #2
233              
234             Example Title #2
235              
236             @@ end
237              
238             =head2 DATA syntax (nested)
239              
240             __DATA__
241              
242             # data syntax (nested)
243              
244             @@ nested
245              
246             Example Nested
247              
248             +@@ demo
249              
250             blah blah blah
251              
252             +@@ end
253              
254             @@ end
255              
256             =head2 POD syntax
257              
258             # pod syntax
259              
260             =head1 NAME
261              
262             Example #1
263              
264             =cut
265              
266             =head1 NAME
267              
268             Example #2
269              
270             =cut
271              
272             # pod-ish syntax
273              
274             =name
275              
276             Example #1
277              
278             =cut
279              
280             =name
281              
282             Example #2
283              
284             =cut
285              
286             =head2 POD syntax (nested)
287              
288             # pod syntax (nested)
289              
290             =nested
291              
292             Example #1
293              
294             +=head1 WHY?
295              
296             blah blah blah
297              
298             +=cut
299              
300             More information on the same topic as was previously mentioned in the
301             previous section demonstrating the topic, obviously from said section.
302              
303             =cut
304              
305             =cut
306              
307             =head1 INHERITS
308              
309             This package inherits behaviors from:
310              
311             L
312              
313             =cut
314              
315             =head1 METHODS
316              
317             This package provides the following methods:
318              
319             =cut
320              
321             =head2 count
322              
323             count(HashRef $criteria) (Int)
324              
325             The count method uses the criteria provided to L for and return the
326             number of blocks found.
327              
328             I>
329              
330             =over 4
331              
332             =item count example 1
333              
334             # given: synopsis;
335              
336             my $count = $data->docs->count;
337              
338             # 6
339              
340             =back
341              
342             =over 4
343              
344             =item count example 2
345              
346             # given: synopsis;
347              
348             my $count = $data->text->count;
349              
350             # 3
351              
352             =back
353              
354             =cut
355              
356             =head2 data
357              
358             data() (Str)
359              
360             The data method returns the text between the C and C sections of a
361             Perl package or file.
362              
363             I>
364              
365             =over 4
366              
367             =item data example 1
368              
369             # given: synopsis;
370              
371             $data = $data->data;
372              
373             # ...
374              
375             =back
376              
377             =cut
378              
379             =head2 docs
380              
381             docs() (Data)
382              
383             The docs method configures the instance for parsing POD blocks.
384              
385             I>
386              
387             =over 4
388              
389             =item docs example 1
390              
391             # given: synopsis;
392              
393             my $docs = $data->docs;
394              
395             # bless({ etag => "=cut", from => "read", stag => "=", ... }, "Venus::Data")
396              
397             =back
398              
399             =cut
400              
401             =head2 find
402              
403             find(Maybe[Str] $list, Maybe[Str] $name) (ArrayRef)
404              
405             The find method is a wrapper around L as shorthand for searching by
406             C and C.
407              
408             I>
409              
410             =over 4
411              
412             =item find example 1
413              
414             # given: synopsis;
415              
416             my $find = $data->docs->find(undef, 'name');
417              
418             # [
419             # { data => ["Example #1"], index => 4, list => undef, name => "name" },
420             # { data => ["Example #2"], index => 5, list => undef, name => "name" },
421             # ]
422              
423             =back
424              
425             =over 4
426              
427             =item find example 2
428              
429             # given: synopsis;
430              
431             my $find = $data->docs->find('head1', 'NAME');
432              
433             # [
434             # { data => ["Example #1"], index => 1, list => "head1", name => "NAME" },
435             # { data => ["Example #2"], index => 2, list => "head1", name => "NAME" },
436             # ]
437              
438             =back
439              
440             =over 4
441              
442             =item find example 3
443              
444             # given: synopsis;
445              
446             my $find = $data->text->find(undef, 'name');
447              
448             # [
449             # { data => ["Example Name"], index => 1, list => undef, name => "name" },
450             # ]
451              
452             =back
453              
454             =over 4
455              
456             =item find example 4
457              
458             # given: synopsis;
459              
460             my $find = $data->text->find('titles', '#1');
461              
462             # [
463             # { data => ["Example Title #1"], index => 2, list => "titles", name => "#1" },
464             # ]
465              
466             =back
467              
468             =cut
469              
470             =head2 search
471              
472             The search method returns the set of blocks matching the criteria provided.
473             This method can return a list of values in list-context.
474              
475             =over 4
476              
477             =item search example 1
478              
479             # given: synopsis;
480              
481             my $search = $data->docs->search({list => undef, name => 'name'});
482              
483             # [
484             # { data => ["Example #1"], index => 4, list => undef, name => "name" },
485             # { data => ["Example #2"], index => 5, list => undef, name => "name" },
486             # ]
487              
488             =back
489              
490             =over 4
491              
492             =item search example 2
493              
494             # given: synopsis;
495              
496             my $search = $data->docs->search({list => 'head1', name => 'NAME'});
497              
498             # [
499             # { data => ["Example #1"], index => 1, list => "head1", name => "NAME" },
500             # { data => ["Example #2"], index => 2, list => "head1", name => "NAME" },
501             # ]
502              
503             =back
504              
505             =over 4
506              
507             =item search example 3
508              
509             # given: synopsis;
510              
511             my $find = $data->text->search({list => undef, name => 'name'});
512              
513             # [
514             # { data => ["Example Name"], index => 1, list => undef, name => "name" },
515             # ]
516              
517             =back
518              
519             =over 4
520              
521             =item search example 4
522              
523             # given: synopsis;
524              
525             my $search = $data->text->search({list => 'titles', name => '#1'});
526              
527             # [
528             # { data => ["Example Title #1"], index => 2, list => "titles", name => "#1" },
529             # ]
530              
531             =back
532              
533             =cut
534              
535             =head2 string
536              
537             string(Maybe[Str] $list, Maybe[Str] $name) (Str)
538              
539             The string method is a wrapper around L as shorthand for searching by
540             C and C, returning only the strings found.
541              
542             I>
543              
544             =over 4
545              
546             =item string example 1
547              
548             # given: synopsis;
549              
550             my $string = $data->docs->string(undef, 'name');
551              
552             # "Example #1\nExample #2"
553              
554             =back
555              
556             =over 4
557              
558             =item string example 2
559              
560             # given: synopsis;
561              
562             my $string = $data->docs->string('head1', 'NAME');
563              
564             # "Example #1\nExample #2"
565              
566             =back
567              
568             =over 4
569              
570             =item string example 3
571              
572             # given: synopsis;
573              
574             my $string = $data->text->string(undef, 'name');
575              
576             # "Example Name"
577              
578             =back
579              
580             =over 4
581              
582             =item string example 4
583              
584             # given: synopsis;
585              
586             my $string = $data->text->string('titles', '#1');
587              
588             # "Example Title #1"
589              
590             =back
591              
592             =over 4
593              
594             =item string example 5
595              
596             # given: synopsis;
597              
598             my @string = $data->docs->string('head1', 'NAME');
599              
600             # ("Example #1", "Example #2")
601              
602             =back
603              
604             =cut
605              
606             =head2 text
607              
608             text() (Data)
609              
610             The text method configures the instance for parsing DATA blocks.
611              
612             I>
613              
614             =over 4
615              
616             =item text example 1
617              
618             # given: synopsis;
619              
620             my $text = $data->text;
621              
622             # bless({ etag => '@@ end', from => 'data', stag => '@@ ', ... }, "Venus::Data")
623              
624             =back
625              
626             =cut
627              
628             =head1 AUTHORS
629              
630             Awncorp, C
631              
632             =cut
633              
634             =head1 LICENSE
635              
636             Copyright (C) 2000, Al Newkirk.
637              
638             This program is free software, you can redistribute it and/or modify it under
639             the terms of the Apache license version 2.0.
640              
641             =cut