File Coverage

blib/lib/Mojolicious/Command/snoodoc.pm
Criterion Covered Total %
statement 12 66 18.1
branch 0 12 0.0
condition n/a
subroutine 4 13 30.7
pod 1 1 100.0
total 17 92 18.4


line stmt bran cond sub pod time code
1             package Mojolicious::Command::snoodoc;
2              
3 1     1   739 use Mojo::Base 'Mojolicious::Command';
  1         2  
  1         8  
4              
5 1     1   16699696 use Mojo::UserAgent;
  1         2412982  
  1         11  
6 1     1   36 use Mojo::URL;
  1         2  
  1         6  
7              
8 1     1   1269 use Getopt::Long qw(GetOptionsFromArray);
  1         11454  
  1         7  
9              
10             our $VERSION = '0.05';
11              
12             has description => 'Quick reference tool for the reddit API';
13              
14             has usage => <
15             Usage:
16              
17             mojo snoodoc
18             mojo snoodoc --all
19              
20             Options:
21              
22             --all, -a Print a list of endpoints available
23              
24             Example:
25              
26             mojo snoodoc /api/hide
27              
28             EOF
29              
30             has ua => sub { Mojo::UserAgent->new() };
31              
32             has url => 'https://www.reddit.com/dev/api';
33              
34             sub _print_all_endpoints {
35 0     0     my $self = shift;
36              
37             $self->ua->get($self->url)->res->dom->at('div.toc')->find('a.section')->each(
38             sub {
39              
40             # print section title
41 0     0     say $_->text;
42              
43             $_->following->first->find('li a')->each(
44             sub {
45              
46             # convert paceholder tags, e.g. /by_id/{names}
47 0           $_->find('em')->each(sub { $_->replace('{' . $_->text . '}') });
  0            
48              
49             # indent results
50 0           say ' ' . $_->text;
51             }
52 0           );
53             }
54 0           );
55             }
56              
57             sub _pretty_print {
58 0     0     my ($self, $title, $scopes, $desc, $params) = @_;
59              
60 0           my $divider = join '', "=" x length $title;
61              
62 0           say "$divider\n$title\n$divider\n";
63              
64 0           say "OAuth Scopes:\n\n$scopes\n";
65              
66 0           print "Description:";
67 0 0         say length $desc ? "\n\n$desc\n" : " n/a\n";
68              
69 0           say "Parameters:\n\n$params";
70             }
71              
72             sub _get_info {
73 0     0     my ($self, $container) = @_;
74              
75             my $scopes = $container->find('.api-badge\ oauth-scope')->map( #
76             sub {
77             # indentaion
78 0     0     my $t = ' * ' . $_->text;
79             # Remove scope element so not to appear in $title text.
80 0           $_->remove();
81 0           $t;
82             }
83 0           )->join("\n\n");
84              
85 0           my $title = $container->at('h3')->all_text;
86              
87             my $desc = $container->find('.md p')->map(
88             sub {
89 0 0   0     unless ($_->text =~ /\bSee also\b/) {
90 0           $_->find('*')->map('strip'); # get all text available
91 0           return ' ' . $_->text;
92             }
93              
94             # use strip() instead?
95             return 'See also: ', $_->find('a')->map(
96             sub {
97 0           my $attr = $_->attr('href');
98              
99             # remove leading #POST/GET
100 0           $attr =~ s/^#[A-Z]{3,4}_//;
101              
102             # look like URL
103 0           $attr =~ s@_@/@g;
104 0           $attr =~ s/%7B/{/g;
105 0           $attr =~ s/%7D/}/g;
106 0           " $attr"; # indentation
107             }
108 0           )->join("\n\n");
109             }
110 0           )->join("\n\n");
111              
112             my $params = $container->find('table.parameters tr')->map(
113             sub {
114 0     0     my $param = $_->at('th')->text;
115              
116             # some parameters don't have a description
117 0 0         if (my $param_desc = $_->at('td p')) {
118             ## strip code elements
119 0           $param_desc->children->map('strip');
120 0           $param .= ': ' . $param_desc->text;
121             }
122              
123             # indentation
124 0           " $param";
125             }
126 0           )->join("\n\n");
127              
128 0           $self->_pretty_print($title, $scopes, $desc, $params);
129             }
130              
131             sub run {
132 0     0 1   my ($self, @args) = @_;
133              
134 0           GetOptionsFromArray(
135             \@args, #
136             'all|a' => \my $all,
137             );
138              
139 0 0         if ($all) {
140 0           $self->_print_all_endpoints();
141 0           return;
142             }
143              
144             # assuming only one endpoint was given
145 0           my $endpoint = shift @args;
146              
147             # do not continue without endpoint
148 0 0         unless ($endpoint) {
149 0           print $self->usage;
150 0           return;
151             }
152              
153 0           $endpoint =~ s@^/@@; # remove leading /
154 0           $endpoint =~ s@/@_@g; # look like URL fragment
155              
156             my @containers = $self->ua->get($self->url)->res->dom->find('div[id*=' . $endpoint . ']')->each(
157             sub {
158 0     0     $self->_get_info($_);
159             }
160 0           );
161              
162 0 0         unless (@containers) {
163 0           print "No endpoint matching that text was found.\n";
164 0           return;
165             }
166             }
167              
168             1;
169             __END__