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   2057 use 5.018;
  86         291  
4              
5 86     86   457 use strict;
  86         158  
  86         1724  
6 86     86   405 use warnings;
  86         156  
  86         2450  
7              
8 86     86   462 use Venus::Class 'attr', 'base';
  86         142  
  86         612  
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 1021 my ($self, $data) = @_;
22              
23 293         1113 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         5 my @result = ($self->search($data));
42              
43 2         26 return scalar @result;
44             }
45              
46             sub data {
47 8     8 1 13 my ($self) = @_;
48              
49 8         21 my $data = $self->read;
50              
51 8   50     92 $data = (split(/^__END__/m, (split(/^__DATA__/m, $data))[1] || ''))[0] || '';
52              
53 8         172 $data =~ s/^\s+|\s+$//g;
54              
55 8         26 return $data;
56             }
57              
58             sub docs {
59 302     302 1 747 my ($self) = @_;
60              
61 302         1063 $self->stag('=');
62 302         1215 $self->etag('=cut');
63 302         1352 $self->from('read');
64              
65 302         1035 return $self;
66             }
67              
68             sub explode {
69 7202     7202 0 12845 my ($self) = @_;
70              
71 7202         18780 my $from = $self->from;
72 7202         25324 my $data = $self->$from;
73 7202         33145 my $stag = $self->stag;
74 7202         20435 my $etag = $self->etag;
75              
76 7202         7044044 my @chunks = split /^(?:\@$stag|$stag)\s*(.+?)\s*\r?\n/m, ($data . "\n");
77              
78 7202         22863 shift @chunks;
79              
80 7202         18526 my $items = [];
81              
82 7202         32169 while (my ($meta, $data) = splice @chunks, 0, 2) {
83 2238738 100 66     5938186 next unless $meta && $data;
84 2168383 50       3302502 next unless $meta ne $etag;
85              
86 2168383         4720399 my @info = split /\s/, $meta, 2;
87 2168383 100       4456081 my ($list, $name) = @info == 2 ? @info : (undef, @info);
88              
89 2168383         5151962 $data =~ s/(\r?\n)\+$stag/$1$stag/g; # auto-escape nested syntax
90 2168383         11433217 $data = [split /\r?\n\r?\n/, $data];
91              
92 2168383         6393803 my $item = {name => $name, data => $data, index => @$items + 1, list => $list};
93              
94 2168383         6835237 push @$items, $item;
95             }
96              
97 7202         21952 return $items;
98             }
99              
100             sub find {
101 3404     3404 1 8427 my ($self, $list, $name) = @_;
102              
103 3404         13992 return $self->search({list => $list, name => $name});
104             }
105              
106             sub search {
107 7202     7202 1 14162 my ($self, $data) = @_;
108              
109 7202   100     16869 $data //= {};
110              
111 7202         16705 my $exploded = $self->explode;
112              
113 7202 50       24903 return wantarray ? (@$exploded) : $exploded if !keys %$data;
    100          
114              
115 7200         10949 my @result;
116              
117 7200         40680 my $sought = {map +($_, 1), keys %$data};
118              
119 7200         60156 for my $item (sort {$a->{index} <=> $b->{index}} @$exploded) {
  2162041         2661501  
120 2168373         3213090 my $found = {};
121              
122 2168373         2526899 my $text;
123 2168373 50       3550683 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 2168373         2382786 my $index;
129 2168373 50       3319684 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 2168373         2396592 my $list;
135 2168373 100       3323413 if ($list = $data->{list}) {
136 996860 50       1502299 $list = (ref($list) eq 'Regexp' ? $list : qr/^@{[quotemeta($list)]}$/);
  996860         3471188  
137 996860 100 100     3761977 $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 1171513 100 66     4419776 && !defined $item->{list};
      100        
142             }
143              
144 2168373         2629968 my $name;
145 2168373 100       3616568 if ($name = $data->{name}) {
146 2168063 50       3265098 $name = ref($name) eq 'Regexp' ? $name : qr/^@{[quotemeta($name)]}$/;
  2168063         7324434  
147 2168063 100       6406429 $found->{name} = 1 if $item->{name} =~ $name;
148             }
149              
150 2168373 100       7838626 if (not(grep(not(defined($found->{$_})), keys(%$sought)))) {
151 7214         24970 push @result, $item;
152             }
153             }
154              
155 7200 100       1161581 return wantarray ? (@result) : \@result;
156             }
157              
158             sub string {
159 5     5 1 10 my ($self, $list, $name) = @_;
160              
161 5         10 my @result;
162              
163 5         12 for my $item ($self->find($list, $name)) {
164 8         18 push @result, join "\n\n", @{$item->{data}};
  8         23  
165             }
166              
167 5 100       70 return wantarray ? (@result) : join "\n", @result;
168             }
169              
170             sub text {
171 8     8 1 20 my ($self) = @_;
172              
173 8         22 $self->stag('@@ ');
174 8         26 $self->etag('@@ end');
175 8         22 $self->from('data');
176              
177 8         35 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