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   1858 use strict;
  3         5  
  3         90  
2              
3             package Yaadgom;
4 3     3   49 use 5.008_005;
  3         9  
5             our $VERSION = '0.09';
6 3     3   921 use Moo;
  3         25857  
  3         16  
7 3     3   3522 use Devel::GlobalDestruction;
  3         7  
  3         16  
8              
9 3     3   1187 use Encode qw/decode/;
  3         27929  
  3         262  
10 3     3   32 use JSON::MaybeXS;
  3         8  
  3         193  
11 3     3   24 use URI;
  3         8  
  3         78  
12 3     3   15 use Carp;
  3         7  
  3         171  
13 3     3   1073 use Class::Trigger;
  3         4073  
  3         35  
14              
15             has '_json_ed' => (
16             is => 'rw',
17             lazy => 1,
18             builder => '_build_json'
19             );
20              
21             sub _build_json {
22 3     3   65 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 20403 my ( $self, %opt ) = @_;
32              
33 3         14 my $req = $opt{req};
34 3         8 my $res = $opt{res};
35              
36 3         8 for my $obj (qw/res req/) {
37 6 100       23 for my $func ( qw/as_string/, ( $obj eq 'req' ? qw/uri/ : () ) ) {
38 9         17 eval { $opt{$obj}->$func };
  9         42  
39 9 50       806 croak "Param{$obj}->$func() died, perhaps you forgot to pass an HTTP object: \n$@" if $@;
40             }
41             }
42              
43 3         28 my $rep = $self->slash_filename_replacement;
44              
45 3 50       12 my $file = exists $opt{file} ? $opt{file} : undef;
46              
47 3 50       10 if ($file) {
48 0         0 $file =~ s/^\///;
49 0         0 $file =~ s/\/$//;
50             }
51             else {
52 3         8 $file = URI->new( $req->uri->path )->path;
53              
54 3         402 $file =~ s/^\///;
55 3         8 $file =~ s/\/$//;
56 3         8 $file =~ s/\//$rep/gio;
57 3         9 $file =~ s/[0-9]+/*/go;
58 3         60 $file =~ s/[^a-z$rep*]//gio;
59              
60 3         26 $self->call_trigger( 'filename_generated', { req => $req, file => $file } );
61 3         278 my @results = @{ $self->last_trigger_results };
  3         12  
62 3 50       25 ($file) = @{ $results[-1] } if $results[-1];
  0         0  
63             }
64              
65 3 50 33     15 my $weight = defined $opt{weight} && $opt{weight} =~ /^[0-9]+$/ ? $opt{weight} : 1;
66              
67 3         41 push @{ $self->_results->{$file}{$weight} },
68             {
69             extra => $opt{extra},
70             file => $file,
71 3   100     6 folder => $opt{folder} || 'default',
72             markdown => $self->get_markdown(%opt)
73             };
74              
75             }
76              
77             sub _write_title {
78 3     3   8 my ( $self, $title ) = @_;
79 3         27 "\n## $title\n\n";
80             }
81              
82             sub _write_subtitle {
83 6     6   17 my ( $self, $title ) = @_;
84 6         28 "\n### $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   42 my ( $self, $str ) = @_;
94 6         31 "
$str\n
\n";
95             }
96              
97             sub format_body {
98 6     6 0 419 my ( $self, $str ) = @_;
99 6         24 my ( $header, $body ) = split /\n\n/, $str, 2;
100 6 100 66     74 if ( $header =~ /application\/json/ && $body ) {
101 3         69 $body = $self->_json_ed->encode( $self->_json_ed->decode($body) );
102 3         231 $body = decode( 'utf8', $body );
103             }
104              
105 6         222 $self->call_trigger( 'format_body', { response_str => $body } );
106 6         295 my @results = @{ $self->last_trigger_results };
  6         16  
107 6 50       40 ($body) = @{ $results[-1] } if $results[-1];
  0         0  
108              
109 6         33 return "$header\n\n$body";
110             }
111              
112             sub get_markdown {
113 3     3 0 12 my ( $self, %opt ) = @_;
114              
115 3         12 my $file_name = $self->file_name;
116              
117 3         7 my $req = $opt{req};
118 3         5 my $res = $opt{res};
119              
120 3 50       10 my $desc = join ' ', $req->method, $req->uri->path, $opt{extra}{is_fail} ? ' + expected failure' : '';
121              
122 3         81 do {
123 3         20 $self->call_trigger( 'format_title', { title => $desc } );
124 3         201 my @results = @{ $self->last_trigger_results };
  3         9  
125 3 50       21 ($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       12 ( 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         8 do {
138 3         17 $self->call_trigger( 'format_before_extras', { str => $str } );
139 3         231 my @results = @{ $self->last_trigger_results };
  3         18  
140 3 50       39 ($str) = @{ $results[-1] } if $results[-1];
  0         0  
141             };
142              
143 3         7 do {
144 3         18 $self->call_trigger( 'process_extras', %opt );
145 3         196 my @results = @{ $self->last_trigger_results };
  3         24  
146 3         25 $str .= join '', $_ for @results;
147             };
148              
149 3 50       12 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         7 do {
166 3         15 $self->call_trigger( 'format_after_extras', { str => $str } );
167 3         172 my @results = @{ $self->last_trigger_results };
  3         8  
168 3 50       20 ($str) = @{ $results[-1] } if $results[-1];
  0         0  
169             };
170              
171 3         20 return $str;
172             }
173              
174             sub export_to_dir {
175 1     1 1 245 my ( $self, %conf ) = @_;
176              
177 1         3 my $dir = $conf{dir};
178 1 50       10 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         3 my $str = $info{str};
185 1         2 my $folder = $info{folder};
186 1         7 my $file = $dir . '/' . $folder . '/' . $info{file} . '.md';
187              
188 1         36 mkdir $dir . '/' . $folder;
189              
190 1 50       46 open my $fh, '>>:utf8', $file or croak "cant open file $file $!";
191 1         12 print $fh $str;
192 1         29 close $fh;
193             }
194 1         13 );
195              
196 1         8 return 1;
197             }
198              
199             sub map_results {
200 3     3 1 44 my ( $self, $callback ) = @_;
201              
202 3         10 my $tests = $self->_results;
203              
204 3         10 foreach my $endpoint ( keys %$tests ) {
205              
206 3         5 my @in_order;
207 3         5 foreach my $num ( sort { $a <=> $b } keys %{ $tests->{$endpoint} } ) {
  0         0  
  3         11  
208 3         9 push @in_order, @{ $tests->{$endpoint}{$num} };
  3         11  
209             }
210              
211 3         10 my $folders = {};
212              
213 3         8 foreach (@in_order) {
214 3         8 push @{ $folders->{ $_->{folder} }{ $_->{file} } }, $_;
  3         18  
215             }
216              
217 3         9 for my $folder ( keys %$folders ) {
218 3         6 for my $file ( keys %{ $folders->{$folder} } ) {
  3         7  
219              
220 3         6 my $str = join "\n
\n", map { $_->{markdown} } @{ $folders->{$folder}{$file} };
  3         13  
  3         7  
221              
222 3         53 my $format_time = "\ngenerated at " . gmtime(time) . " GMT\n";
223 3         6 do {
224 3         13 $self->call_trigger( 'format_generated_str', { str => $format_time } );
225 3         189 my @results = @{ $self->last_trigger_results };
  3         8  
226 3 50       20 ($format_time) = @{ $results[-1] } if $results[-1];
  0         0  
227             };
228              
229 3         8 $str .= $format_time;
230              
231 3   100     14 $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   5009 my $self = shift;
248              
249 3 50       161 if ( ref $self->on_destroy eq 'CODE' ) {
250 0           $self->on_destroy->($self);
251             }
252              
253             }
254              
255             1;
256              
257             __END__