File Coverage

blib/lib/Venus/Data.pm
Criterion Covered Total %
statement 84 96 87.5
branch 28 42 66.6
condition 13 19 68.4
subroutine 13 15 86.6
pod 8 10 80.0
total 146 182 80.2


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