File Coverage

blib/lib/Mojolicious/Command/replget.pm
Criterion Covered Total %
statement 24 76 31.5
branch 0 36 0.0
condition 0 29 0.0
subroutine 8 17 47.0
pod 1 1 100.0
total 33 159 20.7


line stmt bran cond sub pod time code
1             package Mojolicious::Command::replget;
2 1     1   13547 use Mojo::Base 'Mojolicious::Command';
  1         6752  
  1         4  
3              
4             our $VERSION = '0.01';
5             $VERSION = eval $VERSION;
6              
7 1     1   104623 use Mojo::DOM;
  1         8031  
  1         26  
8 1     1   427 use Mojo::IOLoop;
  1         71773  
  1         5  
9 1     1   405 use Mojo::JSON qw(encode_json j);
  1         11582  
  1         61  
10 1     1   541 use Mojo::JSON::Pointer;
  1         480  
  1         7  
11 1     1   490 use Mojo::UserAgent;
  1         49923  
  1         7  
12 1     1   37 use Mojo::Util qw(decode encode getopt);
  1         1  
  1         45  
13 1     1   3 use Scalar::Util 'weaken';
  1         2  
  1         892  
14              
15             has description => 'Perform HTTP requests in a REPL';
16             has usage => sub { shift->extract_usage };
17              
18             sub run {
19 0     0 1   my ($self) = @_;
20              
21 0           my $ua = Mojo::UserAgent->new(ioloop => Mojo::IOLoop->singleton);
22 0           while ( 1 ) {
23 0           print "\nreplget> ";
24 0           chomp(my $stdin = );
25 0           my @args = split / +/, $stdin;
26             getopt \@args,
27             'C|charset=s' => \my $charset,
28             'c|content=s' => \(my $content = ''),
29             'H|header=s' => \my @headers,
30 0     0     'i|inactivity-timeout=i' => sub { $ua->inactivity_timeout($_[1]) },
31             'M|method=s' => \(my $method = 'GET'),
32 0     0     'o|connect-timeout=i' => sub { $ua->connect_timeout($_[1]) },
33             'r|redirect' => \my $redirect,
34 0     0     'S|response-size=i' => sub { $ua->max_response_size($_[1]) },
35 0           'v|verbose' => \my $verbose;
36              
37 0           @args = map { decode 'UTF-8', $_ } @args;
  0            
38 0 0 0       $self->usage and next unless my $url = shift @args;
39 0           my $selector = shift @args;
40              
41             # Parse header pairs
42 0 0         my %headers = map { /^\s*([^:]+)\s*:\s*(.*+)$/ ? ($1, $2) : () } @headers;
  0            
43              
44             # Detect proxy for absolute URLs
45 0 0         $url !~ m!^/! ? $ua->proxy->detect : $ua->server->app($self->app);
46 0 0         $ua->max_redirects(10) if $redirect;
47              
48 0           my $buffer = '';
49             $ua->on(
50             start => sub {
51 0     0     my ($ua, $tx) = @_;
52              
53             # Verbose
54 0           weaken $tx;
55             $tx->res->content->on(
56 0           body => sub { warn _header($tx->req), _header($tx->res) })
57 0 0         if $verbose;
58              
59             # Stream content (ignore redirects)
60             $tx->res->content->unsubscribe('read')->on(
61             read => sub {
62 0 0 0       return if $redirect && $tx->res->is_redirect;
63 0 0         defined $selector ? ($buffer .= pop) : print pop;
64             }
65 0           );
66             }
67 0           );
68              
69             # Switch to verbose for HEAD requests
70 0 0         $verbose = 1 if $method eq 'HEAD';
71 0           STDOUT->autoflush(1);
72 0           my $tx = $ua->start($ua->build_tx($method, $url, \%headers, $content));
73 0           my $res = $tx->result;
74              
75             # JSON Pointer
76 0 0         next unless defined $selector;
77 0 0 0       _json($buffer, $selector) and next if !length $selector || $selector =~ m!^/!;
      0        
78              
79             # Selector
80 0   0       $charset //= $res->content->charset || $res->default_charset;
      0        
81 0           _select($buffer, $selector, $charset, @args);
82             }
83             }
84              
85 0     0     sub _header { $_[0]->build_start_line, $_[0]->headers->to_string, "\n\n" }
86              
87             sub _json {
88 0 0   0     return unless my $data = j(shift);
89 0 0         return unless defined($data = Mojo::JSON::Pointer->new($data)->get(shift));
90 0 0 0       return _say($data) unless ref $data eq 'HASH' || ref $data eq 'ARRAY';
91 0           say encode_json($data);
92             }
93              
94 0   0 0     sub _say { length && say encode('UTF-8', $_) for @_ }
95              
96             sub _select {
97 0     0     my ($buffer, $selector, $charset, @args) = @_;
98              
99             # Keep a strong reference to the root
100 0 0 0       $buffer = decode($charset, $buffer) // $buffer if $charset;
101 0           my $dom = Mojo::DOM->new($buffer);
102 0           my $results = $dom->find($selector);
103              
104 0           while (defined(my $command = shift @args)) {
105              
106             # Number
107 0 0 0       ($results = $results->slice($command)) and next if $command =~ /^\d+$/;
108              
109             # Text
110 0 0         return _say($results->map('text')->each) if $command eq 'text';
111              
112             # All text
113 0 0         return _say($results->map('all_text')->each) if $command eq 'all';
114              
115             # Attribute
116 0 0 0       return _say($results->map(attr => $args[0] // '')->each)
117             if $command eq 'attr';
118              
119             # Unknown
120 0           die qq{Unknown command "$command".\n};
121             }
122              
123 0           _say($results->each);
124             }
125              
126             1;
127              
128             =encoding utf8
129              
130             =head1 NAME
131              
132             Mojolicious::Command::replget - Get command in a REPL
133              
134             =head1 SYNOPSIS
135              
136             Usage: APPLICATION replget
137            
138             replget> [OPTIONS] URL [SELECTOR|JSON-POINTER] [COMMANDS]
139              
140             ./myapp.pl replget
141            
142             replget> /
143             replget -H 'Accept: text/html' /hello.html 'head > title' text
144             replget //sri:secr3t@/secrets.json /1/content
145             replget mojolicious.org
146             replget -v -r -o 25 -i 50 google.com
147             replget -v -H 'Host: mojolicious.org' -H 'Accept: */*' mojolicious.org
148             replget -M POST -H 'Content-Type: text/trololo' -c 'trololo' perl.org
149             replget mojolicious.org 'head > title' text
150             replget mojolicious.org .footer all
151             replget mojolicious.org a attr href
152             replget mojolicious.org '*' attr id
153             replget mojolicious.org 'h1, h2, h3' 3 text
154             replget https://api.metacpan.org/v0/author/SRI /name
155             replget -H 'Host: example.com' http+unix://%2Ftmp%2Fmyapp.sock/index.html
156              
157             Options:
158             -C, --charset Charset of HTML/XML content, defaults
159             to auto-detection
160             -c, --content Content to send with request
161             -H, --header Additional HTTP header
162             -h, --help Show this summary of available options
163             --home Path to home directory of your
164             application, defaults to the value of
165             MOJO_HOME or auto-detection
166             -i, --inactivity-timeout Inactivity timeout, defaults to the
167             value of MOJO_INACTIVITY_TIMEOUT or 20
168             -M, --method HTTP method to use, defaults to "GET"
169             -m, --mode Operating mode for your application,
170             defaults to the value of
171             MOJO_MODE/PLACK_ENV or "development"
172             -o, --connect-timeout Connect timeout, defaults to the value
173             of MOJO_CONNECT_TIMEOUT or 10
174             -r, --redirect Follow up to 10 redirects
175             -S, --response-size Maximum response size in bytes,
176             defaults to 2147483648 (2GB)
177             -v, --verbose Print request and response headers to
178             STDERR
179              
180             =head1 DESCRIPTION
181              
182             L is a command line interface for
183             L in a REPL.
184              
185             =head1 ATTRIBUTES
186              
187             L performs requests to remote hosts or local
188             applications.
189              
190             =head2 description
191              
192             my $description = $replget->description;
193             $replget = $replget->description('Foo');
194              
195             Short description of this command, used for the command list.
196              
197             =head2 usage
198              
199             my $usage = $replget->usage;
200             $replget = $replget->usage('Foo');
201              
202             Usage information for this command, used for the help screen.
203              
204             =head1 METHODS
205              
206             L inherits all methods from L
207             and implements the following new ones.
208              
209             =head2 run
210              
211             $get->run(@ARGV);
212              
213             Run this command.
214              
215             =head1 SEE ALSO
216              
217             L, L, L.
218              
219             =cut