File Coverage

blib/lib/OpenAPI/Generator/From/Pod.pm
Criterion Covered Total %
statement 79 81 97.5
branch 26 30 86.6
condition 3 6 50.0
subroutine 18 18 100.0
pod 2 2 100.0
total 128 137 93.4


line stmt bran cond sub pod time code
1             package OpenAPI::Generator::From::Pod;
2              
3 2     2   1120 use 5.012;
  2         7  
4 2     2   12 use strict;
  2         4  
  2         39  
5 2     2   10 use warnings;
  2         4  
  2         50  
6              
7 2     2   29 use Carp;
  2         6  
  2         124  
8 2     2   12 use File::Find;
  2         4  
  2         222  
9 2     2   909 use OpenAPI::Generator::Util qw(merge_definitions);
  2         4  
  2         112  
10 2     2   1012 use Pod::Simple::SimpleTree;
  2         126600  
  2         77  
11 2     2   583 use YAML qw(Load);
  2         7145  
  2         146  
12              
13 2     2   15 use constant OPENAPI_HEAD_NAME => 'OPENAPI';
  2         5  
  2         1931  
14              
15             sub new {
16              
17 3     3 1 20 bless {}, shift
18             }
19              
20             sub generate {
21              
22 3     3 1 9 my($self, $conf) = @_;
23              
24 3         10 my $src = $conf->{src};
25 3         13 $self->_check_src($src);
26 3         14 my @files = $self->_src_as_files($src);
27              
28 3         9 my @defs;
29 3         19 push @defs, $self->_parse_file($_) for @files;
30              
31 3 100       15 return unless @defs;
32              
33 2         13 merge_definitions(@defs);
34             }
35              
36             sub _parse_file {
37 5     5   14 my($self, $file) = @_;
38 5         49 my $parser = Pod::Simple::SimpleTree->new;
39              
40 5         215 my $struct = $parser->parse_file($file)->root;
41 5         16440 my $openapi_node = $self->_extract_openapi_node($struct);
42              
43 5 100       13 unless ($openapi_node) {
44 2         22 return;
45             }
46              
47 3         21 my %common_definition = (
48             paths => {},
49             components => {
50             schemas => {},
51             parameters => {},
52             securitySchemes => {},
53             },
54             );
55              
56 3         7 while (my($index, $node) = each @{$openapi_node}) {
  39         121  
57 36 100       87 next unless ref $node eq uc'array';
58 30 100       82 next unless $node->[0] eq 'item-text';
59              
60 15         29 my $item_name = $node->[2];
61              
62 15         29 my $definition_node = $openapi_node->[$index + 1];
63 15 50 33     80 if (!$definition_node || $definition_node->[0] ne 'Verbatim') {
64 0         0 croak("can not find definition for $node->[2]")
65             }
66 15         51 my $definition = Load $definition_node->[2];
67              
68 15 100       86036 if ($item_name =~ /^\s*SCHEMA/) {
    100          
    100          
69 3         12 my $schema_name = $self->_extract_component_name($item_name);
70 3         13 $common_definition{components}{schemas}{$schema_name} = $definition;
71             }
72             elsif ($item_name =~ /^\s*PARAM/) {
73 3         14 my $param_name = $self->_extract_component_name($item_name);
74 3         12 $common_definition{components}{parameters}{$param_name} = $definition;
75             }
76             elsif ($item_name =~ /^\s*SECURITY/) {
77 3         12 my $security_schema_name = $self->_extract_component_name($item_name);
78 3         13 $common_definition{components}{securitySchemes}{$security_schema_name} = $definition;
79             }
80             else {
81 6         22 my($method, $route) = $self->_extract_method_and_route($item_name);
82 6         31 $common_definition{paths}{$route}{$method} = $definition;
83             }
84             }
85              
86 3         109 return \%common_definition;
87             }
88              
89             sub _extract_component_name {
90              
91 9     9   44 my($type, $name) = split /\s/, $_[1];
92 9         25 return $name;
93             }
94              
95             sub _extract_method_and_route {
96              
97 6     6   36 my ($method, $route) = split /\s/, $_[1];
98 6         25 return lc($method), $route
99             }
100              
101             sub _extract_openapi_node {
102              
103 5     5   16 my($self, $struct) = @_;
104 5         10 while (my($index, $node) = each @{$struct}) {
  21         86  
105 19 100       55 next unless ref $node eq uc'array';
106 9 100       25 if ($node->[2] eq OPENAPI_HEAD_NAME) {
107 3         6 my $openapi_node = $struct->[$index + 1];
108 3 50       10 if (!$openapi_node) {
109 0         0 croak 'can not find openapi node: no nodes found below openapi annotation'
110             }
111              
112 3         8 return $openapi_node;
113             }
114             }
115             }
116              
117             sub _check_src {
118              
119 3 50 66 3   165 croak "$_[1] is not file or directory" unless(-f $_[1] or -d $_[1]);
120 3 50       58 croak "$_[1] is not readable" unless(-r $_[1]);
121             }
122              
123             sub _src_as_files {
124              
125 3 100   3   47 return $_[1] if -f $_[1];
126              
127 1         4 my @files;
128 1 100   4   131 find sub { push @files, $File::Find::name if /\.(pm|pl|t|pod)$/ }, $_[1];
  4         193  
129             @files
130 1         9 }
131              
132             1
133              
134             __END__