File Coverage

lib/APISchema/Generator/Markdown/Formatter.pm
Criterion Covered Total %
statement 98 102 96.0
branch 45 54 83.3
condition 6 6 100.0
subroutine 21 21 100.0
pod 0 12 0.0
total 170 195 87.1


line stmt bran cond sub pod time code
1             package APISchema::Generator::Markdown::Formatter;
2 4     4   1057 use 5.014;
  4         20  
3 4     4   23 use strict;
  4         6  
  4         76  
4 4     4   17 use warnings;
  4         5  
  4         135  
5              
6             # core
7 4     4   21 use Exporter qw(import);
  4         6  
  4         245  
8             our @EXPORT = qw(type json pretty_json code restriction desc anchor method methods content_type http_status http_status_code);
9              
10             # cpan
11 4     4   1810 use HTTP::Status qw(status_message);
  4         16550  
  4         429  
12 4     4   1327 use URI::Escape qw(uri_escape_utf8);
  4         4005  
  4         187  
13 4     4   30 use JSON::XS ();
  4         8  
  4         198  
14             my $JSON = JSON::XS->new->canonical(1);
15              
16             use constant +{
17 4         4636 RESTRICTIONS => [qw(required max_items min_items max_length min_length maximum minimum pattern)],
18             SHORT_DESCRIPTION_LENGTH => 100,
19 4     4   24 };
  4         10  
20              
21             sub type ($); # type has recursive call
22              
23             sub type ($) {
24 87     87 0 10218 my $def = shift;
25 87         127 my $bar = '|';
26              
27 87 100       175 if (ref $def) {
28 69         150 for my $type (qw(oneOf anyOf allOf)) {
29 205 100       381 if (my $union = $def->{$type}) {
30 1         3 return join($bar, map { type($_) } @$union);
  2         8  
31             }
32             }
33             }
34              
35 86 100       181 my $ref = ref $def ? $def->{'$ref'} : $def;
36 86 100       140 if ($ref) {
37 22         42 $ref = $ref =~ s!^#/resource/!!r;
38 22         46 my $ref_text = "`$ref`";
39 22         40 my $name = $ref =~ s!/.*$!!r;
40 22 50       58 $ref_text = sprintf('[%s](#%s)', $ref_text, anchor(resource => $name)) if $name;
41 22         855 return $ref_text;
42             }
43              
44 64 100       124 return join $bar, map { code($_) } @{$def->{enum}} if $def->{enum};
  14         30  
  5         14  
45              
46 59         84 my $type = $def->{type};
47 59 100       122 if ($type) {
48 58 100       1141 return sprintf '`%s`', $type unless ref $type;
49 1 50       6 return join $bar, map { code($_) } @{$type} if ref $type eq 'ARRAY';
  2         8  
  1         4  
50             }
51              
52 1         5 return 'undefined';
53             }
54              
55             sub json ($) {
56 68     68 0 106 my $x = shift;
57 68 100       169 if (ref $x eq 'SCALAR') {
    100          
58 1 50       5 if ($$x eq 1) {
    0          
59 1         2 $x = 'true';
60             } elsif ($$x eq 0) {
61 0         0 $x = 'false';
62             }
63             } elsif (ref $x) {
64 30         295 $x = $JSON->encode($x);
65             } else {
66 37         173 $x = $JSON->encode([$x]);
67 37         246 $x =~ s/^\[(.*)\]$/$1/;
68             }
69 68         251 return $x;
70             }
71              
72             my $PRETTY_JSON = JSON::XS->new->canonical(1)->indent(1)->pretty(1);
73             sub pretty_json ($) {
74 19     19 0 34 my $x = shift;
75 19 100       48 if (ref $x) {
76 17         182 $x = $PRETTY_JSON->encode($x);
77             } else {
78 2         10 $x = $PRETTY_JSON->encode([$x]);
79 2         19 $x =~ s/^\[\s*(.*)\s*\]\n$/$1/;
80             }
81 19         413 return $x;
82             }
83              
84             sub _code ($) {
85 80     80   130 my $text = shift;
86 80 100       307 return '' unless defined $text;
87 72 50       196 if ($text =~ /[`|]/) {
88 0         0 $text =~ s/[|]/|/g;
89 0         0 return sprintf '%s', $text;
90             }
91 72         1113 return sprintf '`%s`', $text;
92             }
93              
94             sub code ($;$) {
95 98     98 0 855 my ($text, $exists) = @_;
96 98 100       1118 return $exists ? '`null`' : '' unless defined $text;
    100          
97 40         82 return _code json $text;
98             }
99              
100             sub anchor ($$) {
101 78     78 0 3403 my ($label, $obj) = @_;
102 78 100       203 my $name = ref $obj ? $obj->title : $obj;
103 78         268 return sprintf '%s-%s', $label, uri_escape_utf8($name);
104             }
105              
106             sub restriction ($) {
107 41     41 0 347 my $def = shift;
108 41 50       94 return '' unless (ref $def) eq 'HASH';
109              
110 41         74 my @result = ();
111 41         52 for my $r (sort @{+RESTRICTIONS}) {
  41         218  
112 328 100       556 next unless defined $def->{$r};
113              
114 10 50       25 if (ref $def->{$r}) {
115 10         33 push @result, _code sprintf "$r%s", json $def->{$r};
116             } else {
117 0         0 push @result, _code sprintf "$r(%s)", json $def->{$r};
118             }
119             }
120 41         744 return join ' ', @result;
121             }
122              
123             sub desc ($) {
124 41   100 41 0 401 my $text = shift || '';
125 41         119 $text = $text =~ s/[\r\n].*\z//sr;
126 41 50       104 $text = substr($text, 0, SHORT_DESCRIPTION_LENGTH) . '...'
127             if length($text) > SHORT_DESCRIPTION_LENGTH;
128 41         731 return $text;
129             }
130              
131             sub method ($) {
132 9     9 0 477 my $method = shift;
133 9 100 100     65 return $method->[0] if (ref $method || '') eq 'ARRAY';
134 8         171 return $method;
135             }
136              
137             sub methods ($) {
138 18     18 0 1122 my $method = shift;
139 18 100 100     85 return join ', ', map { _code($_) } @$method
  4         11  
140             if (ref $method || '') eq 'ARRAY';
141 16         38 return _code($method);
142             }
143              
144             sub content_type ($) {
145 30     30 0 243 my $type = shift;
146 30 100       300 return '-' unless length($type);
147 15         258 return "`$type`";
148             }
149              
150             sub http_status ($) {
151 19     19 0 610 my $code = shift;
152 19 100       64 return undef unless $code;
153 11         37 return join(' ', $code, status_message($code));
154             }
155              
156             sub http_status_code {
157 10     10 0 287 return _code http_status shift;
158             }
159              
160             1;