File Coverage

blib/lib/Stardoc/Module/Perl.pm
Criterion Covered Total %
statement 67 76 88.1
branch 16 28 57.1
condition n/a
subroutine 11 11 100.0
pod 1 8 12.5
total 95 123 77.2


line stmt bran cond sub pod time code
1             ##
2             # name: Stardoc::Module::Perl
3             # abstract: Stardoc Perl Module
4             # author: Ingy döt Net
5             # copyright: 2011
6             # license: perl
7              
8             package Stardoc::Module::Perl;
9 1     1   6 use Mouse;
  1         1  
  1         6  
10             extends 'Stardoc::Module';
11              
12 1     1   1282 use IO::All;
  1         56126  
  1         14  
13 1     1   2274 use YAML::XS;
  1         5736  
  1         2240  
14              
15             has meta => (
16             is => 'ro',
17             default => sub {
18             {
19             markup => 'pod',
20             encoding => 'utf8',
21             }
22             },
23             );
24             has other => (
25             is => 'ro',
26             default => sub {[]},
27             );
28             has name => (
29             is => 'rw',
30             );
31             has synopsis => (
32             is => 'rw',
33             );
34             has description => (
35             is => 'rw',
36             );
37             has usage => (
38             is => 'rw',
39             );
40             has see => (
41             is => 'rw',
42             );
43             has author => (
44             is => 'rw',
45             );
46             has copyright => (
47             is => 'rw',
48             );
49              
50             sub BUILD {
51 2     2 1 5 my ($self) = @_;
52 2         8 $self->parse();
53             }
54              
55             my $pod_re = qr/^=\w+.*?(?:^=cut\s*\n|(?=^=\w)|\z)/ms;
56             # XXX - Need to account for perlcritic ## at some point.
57             my $star_re = qr/^##\s.*\n(?:#.*\n)*/m;
58             my $end_re = qr/^__(?:END|DATA)__.*/ms;
59              
60             sub parse {
61 2     2 0 5 my ($self) = @_;
62 2         20 my $text = io($self->file)->all;
63 2         18000 my $sections = $self->sections;
64 2         266 for ($text =~ /($star_re|$pod_re|$end_re)/g) {
65 8         21 push @$sections, $self->make_sections($_)
66             }
67             }
68              
69             sub merge_meta {
70 2     2 0 4 my ($self, $data) = @_;
71 2         10 my $meta = $self->meta;
72 2         8 for my $key (keys %$data) {
73 11         20 my $val = $data->{$key};
74 11 100       26 if ($key eq 'author') {
    100          
75 2         7 $meta->{author} = $self->parse_author($val);
76             }
77             elsif ($key eq 'see') {
78 1 50       7 $meta->{see} = ref($val) ? $val : [$val];
79             }
80             else {
81 8         23 $meta->{$key} = $data->{$key};
82             }
83             }
84             }
85              
86             sub parse_author {
87 2     2 0 3 my ($self, $val) = @_;
88 2 50       5 return [$val] if ref $val eq 'HASH';
89 2 50       7 my $list = [ (ref $val eq 'ARRAY') ? @$val : $val ];
90 2         15 for (my $i = 0; $i < @$list; $i++) {
91 2 50       6 if (not ref $list->[$i]) {
92 2         3 my $string = $list->[$i];
93 2         5 my $hash = $list->[$i] = {};
94 2 50       22 if ($string =~ /^\s*(.*?)\s*<(.*)>$/) {
95 2         7 $hash->{name} = $1;
96 2         10 $hash->{email} = $2;
97             }
98             else {
99 0         0 $hash->{name} = $val;
100             }
101             }
102             }
103 2         7 return $list;
104             }
105              
106              
107             sub make_sections {
108 8     8 0 13 my ($self, $text) = @_;
109 8         161 $text =~ s/\s\z/\n/;
110 8 100       25 if ($text =~ /^##\s/) {
111 2         8 return $self->make_comment_sections($text);
112             }
113 6 50       21 if ($text =~ /^=\w/) {
114 6         10 $text =~ s/^\s*\n=cut\s*\n/\n/m;
115 6         16 return $self->make_pod_sections($text);
116             }
117 0 0       0 if ($text =~ s/^__(END|DATA)__\s\n//) {
118 0         0 $self->merge_meta;
119 0         0 return map {
120 0         0 $self->make_sections($_)
121             } ($text =~ /($star_re|$pod_re)/g);
122             }
123 0         0 die $text;
124             }
125              
126             sub make_comment_sections {
127 2     2 0 6 my ($self, $text) = @_;
128 2         9 $text =~ s/^##.*\n//;
129 2         18 $text =~ s/^# ?//gm;
130 2         5 my @sections;
131 2         5 while ($text) {
132 2         8 $text =~ s/^\s*//;
133 2 50       16 if ($text =~ s/(^\w+:\s.*?\n)(\.\.\.\s*\n|\n\s*|\z)//s) {
    0          
134 2         9 push @sections, $self->make_meta_data($1);
135             }
136             elsif ($text =~ s/^(=\w.*)//s) {
137 0         0 push @sections, $self->make_pod_sections($1);
138             }
139             else {
140 0         0 die;
141             }
142             }
143 2         5 return @sections;
144             }
145              
146             my $name_re = qr/\S+\s+(NAME|DESCRIPTION|SYNOPSIS)/;
147             sub make_pod_sections {
148 6     6 0 12 my ($self, $text) = @_;
149 6         15 my $other = $self->other;
150 6         44 for my $section ($text =~ /(=\w.*?\n)\s*(?=^=\w|\z)/gms) {
151 6         22 my $hash = {
152             type => 'pod',
153             text => $section,
154             };
155 6 100       65 if ($section =~ $name_re) {
156 4         10 my $name = lc($1);
157 4         22 $self->$name($hash);
158             }
159             else {
160 2         6 push @$other, $hash;
161             }
162             }
163 6         22 return ();
164             }
165              
166             sub make_meta_data {
167 2     2 0 6 my ($self, $text) = @_;
168 2         4 my $data;
169 2         3 eval { $data = Load($text) };
  2         254  
170 2 50       10 if ($@) {
171 0         0 warn "Invalid YAML in Stardoc. Skipping section.\n$@";
172             }
173 2         8 $self->merge_meta($data);
174 2         12 return;
175             }
176              
177             1;