File Coverage

blib/lib/Yaadgom.pm
Criterion Covered Total %
statement 136 157 86.6
branch 21 40 52.5
condition 7 10 70.0
subroutine 20 21 95.2
pod 3 5 60.0
total 187 233 80.2


line stmt bran cond sub pod time code
1 3     3   1574 use strict;
  3         4  
  3         88  
2              
3             package Yaadgom;
4 3     3   64 use 5.008_005;
  3         6  
5             our $VERSION = '0.07';
6 3     3   1399 use Moo;
  3         30293  
  3         14  
7 3     3   2952 use Devel::GlobalDestruction;
  3         3  
  3         20  
8              
9 3     3   1479 use Encode qw/decode/;
  3         18745  
  3         163  
10 3     3   1108 use JSON::MaybeXS;
  3         10824  
  3         136  
11 3     3   13 use URI;
  3         4  
  3         51  
12 3     3   9 use Carp;
  3         3  
  3         123  
13 3     3   1192 use Class::Trigger;
  3         2580  
  3         14  
14              
15             has '_json_ed' => (
16             is => 'rw',
17             lazy => 1,
18             builder => '_build_json'
19             );
20              
21             sub _build_json {
22 3     3   1060 JSON::MaybeXS->new( utf8 => 1, pretty => 1, canonical => 1 );
23             }
24              
25             has 'slash_filename_replacement' => ( is => 'rw', default => sub { '-' } );
26              
27             has '_results' => ( is => 'rw', default => sub { +{} } );
28             has 'file_name' => ( is => 'rw', default => sub { $0 } );
29              
30             sub process_response {
31 3     3 1 17550 my ( $self, %opt ) = @_;
32              
33 3         7 my $req = $opt{req};
34 3         4 my $res = $opt{res};
35              
36 3         8 for my $obj (qw/res req/) {
37 6 100       16 for my $func ( qw/as_string/, ( $obj eq 'req' ? qw/uri/ : () ) ) {
38 9         11 eval { $opt{$obj}->$func };
  9         31  
39 9 50       542 croak "Param{$obj}->$func() died, perhaps you forgot to pass an HTTP object: \n$@" if $@;
40             }
41             }
42              
43 3         57 my $rep = $self->slash_filename_replacement;
44              
45 3 50       10 my $file = exists $opt{file} ? $opt{file} : undef;
46              
47 3 50       7 if ($file) {
48 0         0 $file =~ s/^\///;
49 0         0 $file =~ s/\/$//;
50             }
51             else {
52 3         10 $file = URI->new( $req->uri->path )->path;
53              
54 3         250 $file =~ s/^\///;
55 3         4 $file =~ s/\/$//;
56 3         8 $file =~ s/\//$rep/gio;
57 3         5 $file =~ s/[0-9]+/*/go;
58 3         52 $file =~ s/[^a-z$rep*]//gio;
59              
60 3         18 $self->call_trigger( 'filename_generated', { req => $req, file => $file } );
61 3         192 my @results = @{ $self->last_trigger_results };
  3         8  
62 3 50       22 ($file) = @{ $results[-1] } if $results[-1];
  0         0  
63             }
64              
65 3 50 33     55 my $weight = defined $opt{weight} && $opt{weight} =~ /^[0-9]+$/ ? $opt{weight} : 1;
66              
67 3         39 push @{ $self->_results->{$file}{$weight} },
68             {
69             extra => $opt{extra},
70             file => $file,
71 3   100     5 folder => $opt{folder} || 'default',
72             markdown => $self->get_markdown(%opt)
73             };
74              
75             }
76              
77             sub _write_title {
78 3     3   4 my ( $self, $title ) = @_;
79 3         29 "## $title\n\n";
80             }
81              
82             sub _write_subtitle {
83 6     6   7 my ( $self, $title ) = @_;
84 6         19 "### $title\n\n";
85             }
86              
87             sub _write_line {
88 0     0   0 my ( $self, $title ) = @_;
89 0         0 my $str = "$title\n";
90             }
91              
92             sub _write_preformated {
93 6     6   7 my ( $self, $str ) = @_;
94 6         20 "
$str\n
\n";
95             }
96              
97             sub format_body {
98 6     6 0 245 my ( $self, $str ) = @_;
99 6         20 my ( $header, $body ) = split /\n\n/, $str;
100 6 100 66     43 if ( $header =~ /application\/json/ && $body ) {
101 3         10 $body = $self->_json_ed->encode( $self->_json_ed->decode($body) );
102 3         235 $body = decode( 'utf8', $body );
103             }
104              
105 6         196 $self->call_trigger( 'format_body', { response_str => $body } );
106 6         190 my @results = @{ $self->last_trigger_results };
  6         13  
107 6 50       30 ($body) = @{ $results[-1] } if $results[-1];
  0         0  
108              
109 6         22 return "$header\n$body";
110             }
111              
112             sub get_markdown {
113 3     3 0 6 my ( $self, %opt ) = @_;
114              
115 3         9 my $file_name = $self->file_name;
116              
117 3         5 my $req = $opt{req};
118 3         4 my $res = $opt{res};
119              
120 3 50       8 my $desc = join ' ', $req->method, $req->uri->path, $opt{extra}{is_fail} ? ' + expected failure' : '';
121              
122 3         58 do {
123 3         12 $self->call_trigger( 'format_title', { title => $desc } );
124 3         129 my @results = @{ $self->last_trigger_results };
  3         9  
125 3 50       20 ($desc) = @{ $results[-1] } if $results[-1];
  0         0  
126             };
127              
128             my $str = join '',
129             $self->_write_title($desc),
130             ( defined $file_name ? "$file_name\n" : '' ),
131 3 50       9 ( exists $opt{extra}{name} ? ( $self->_write_line( '> ' . $opt{extra}{name} . "\n" ) ) : () ),
    50          
132             $self->_write_subtitle('Request'),
133             $self->_write_preformated( $self->format_body( $req->as_string ) ),
134             $self->_write_subtitle('Response'),
135             $self->_write_preformated( $self->format_body( $res->as_string ) );
136              
137 3         6 do {
138 3         11 $self->call_trigger( 'format_before_extras', { str => $str } );
139 3         110 my @results = @{ $self->last_trigger_results };
  3         7  
140 3 50       16 ($str) = @{ $results[-1] } if $results[-1];
  0         0  
141             };
142              
143 3         4 do {
144 3         10 $self->call_trigger( 'process_extras', %opt );
145 3         95 my @results = @{ $self->last_trigger_results };
  3         7  
146 3         14 $str .= join '', $_ for @results;
147             };
148              
149 3 50       8 if ( exists $opt{extra}{fields} ) {
150 0         0 $str .= $self->_write_subtitle('Fields details');
151 0         0 while ( my ( $key, $maybealist ) = each %{ $opt{extra}{fields} } ) {
  0         0  
152              
153 0         0 $str .= $self->_write_line( '#### ' . $key );
154 0 0       0 if ( ref $maybealist eq 'ARRAY' ) {
155 0         0 $str .= $self->_write_line( '* ' . $_ ) for @$maybealist;
156 0         0 $str .= "\n";
157             }
158             else {
159 0         0 $str .= $self->_write_line( '- ' . $maybealist );
160 0         0 $str .= "\n";
161             }
162             }
163             }
164              
165 3         4 do {
166 3         10 $self->call_trigger( 'format_after_extras', { str => $str } );
167 3         90 my @results = @{ $self->last_trigger_results };
  3         6  
168 3 50       14 ($str) = @{ $results[-1] } if $results[-1];
  0         0  
169             };
170              
171 3         18 return $str;
172             }
173              
174             sub export_to_dir {
175 1     1 1 405103 my ( $self, %conf ) = @_;
176              
177 1         4 my $dir = $conf{dir};
178 1 50       40 croak "dir ($dir) is not an directory" unless -d $dir;
179              
180             $self->map_results(
181             sub {
182 1     1   3 my (%info) = @_;
183              
184 1         2 my $str = $info{str};
185 1         2 my $folder = $info{folder};
186 1         3 my $file = $dir . '/' . $folder . '/' . $info{file} . '.md';
187              
188 1         70 mkdir $dir . '/' . $folder;
189              
190 1 50       72 open my $fh, '>>:utf8', $file or croak "cant open file $file $!";
191 1         14 print $fh $str;
192 1         40 close $fh;
193             }
194 1         30 );
195              
196 1         8 return 1;
197             }
198              
199             sub map_results {
200 3     3 1 45 my ( $self, $callback ) = @_;
201              
202 3         12 my $tests = $self->_results;
203              
204 3         14 foreach my $endpoint ( keys %$tests ) {
205              
206 3         4 my @in_order;
207 3         5 foreach my $num ( sort { $a <=> $b } keys %{ $tests->{$endpoint} } ) {
  0         0  
  3         13  
208 3         5 push @in_order, @{ $tests->{$endpoint}{$num} };
  3         9  
209             }
210              
211 3         8 my $folders = {};
212              
213 3         7 foreach (@in_order) {
214 3         4 push @{ $folders->{ $_->{folder} }{ $_->{file} } }, $_;
  3         18  
215             }
216              
217 3         9 for my $folder ( keys %$folders ) {
218 3         4 for my $file ( keys %{ $folders->{$folder} } ) {
  3         8  
219              
220 3         6 my $str = join "\n
\n", map { $_->{markdown} } @{ $folders->{$folder}{$file} };
  3         16  
  3         7  
221              
222 3         70 my $format_time = "\ngenerated at " . gmtime(time) . " GMT\n";
223 3         4 do {
224 3         17 $self->call_trigger( 'format_generated_str', { str => $format_time } );
225 3         147 my @results = @{ $self->last_trigger_results };
  3         10  
226 3 50       17 ($format_time) = @{ $results[-1] } if $results[-1];
  0         0  
227             };
228              
229 3         6 $str .= $format_time;
230              
231 3   100     16 $callback->(
232             folder => $folder,
233             file => $file || '_index',
234             str => $str
235             );
236              
237             }
238             }
239              
240             }
241              
242             }
243              
244             has 'on_destroy' => ( is => 'rw' );
245              
246             sub DESTROY {
247 3     3   3572 my $self = shift;
248              
249 3 50       122 if ( ref $self->on_destroy eq 'CODE' ) {
250 0           $self->on_destroy->($self);
251             }
252              
253             }
254              
255             1;
256              
257             __END__