App-Adenosine
view release on metacpan or search on metacpan
This fetches the data and lets you edit it, and then does a PUT on the
resource. If you don't like vi you can specify your preferred editor by
setting the EDITOR environment variable.
Errors and Output
For successful 2xx responses, the response body is printed on stdout.
You can pipe the output to stuff, process it, and then pipe it back to
adenosine, if you want.
For responses other than 2xx the response body is dumped to stderr.
Passing Command Line Options To Curl
Anything after the (optional) path and data arguments is passed on to
curl.
For example:
$ GET /blogs.json -H "Range: items=1-10"
$ POST -v -u user:test
In this example the path and data arguments were left off, but -v and
-u user:test will be passed through to curl, as you would expect.
Here are some useful options to try:
-v
verbose output, shows HTTP headers and status on stderr
-j
junk session cookies (refresh cookie-based session)
<-u $username:$password>
HTTP basic authentication
<-H $header>
bin/adenosine view on Meta::CPAN
This fetches the data and lets you edit it, and then does a PUT on the
resource. If you don't like vi you can specify your preferred editor by
setting the C<EDITOR> environment variable.
=head1 Errors and Output
For successful 2xx responses, the response body is printed on stdout. You
can pipe the output to stuff, process it, and then pipe it back to adenosine,
if you want.
For responses other than 2xx the response body is dumped to stderr.
=head1 Passing Command Line Options To Curl
Anything after the (optional) C<path> and C<data> arguments is passed on to
C<curl>.
For example:
$ GET /blogs.json -H "Range: items=1-10"
bin/adenosine view on Meta::CPAN
In this example the C<path> and C<data> arguments were left off, but C<-v> and
C<-u user:test> will be passed through to C<curl>, as you would expect.
Here are some useful options to try:
=over 2
=item C<-v>
verbose output, shows HTTP headers and status on stderr
=item C<-j>
junk session cookies (refresh cookie-based session)
=item <-u $username:$password>
HTTP basic authentication
=item <-H $header>
lib/App/Adenosine.pm view on Meta::CPAN
$query = "?$query" if $query;
my @curl = @{$self->curl_command({
method => $action,
data => $data,
cookie_jar => $self->cookie_jar($uri_base),
rest => \@extra,
location => "$_path$query",
})};
$self->stderr(join(" ", map "'$_'", @curl) . "\n") if $self->verbose;
my ($out, $err, $ret) = $self->capture_curl(@curl);
return $self->handle_curl_output($out, $err, $ret);
} elsif ($action eq 'exports') {
print <<'SHELL';
function HEAD() { adenosine HEAD "$@"; };
function OPTIONS() { adenosine OPTIONS "$@"; };
function GET() { adenosine GET "$@"; };
function POST() { adenosine POST "$@"; };
function PUT() { adenosine PUT "$@"; };
lib/App/Adenosine.pm view on Meta::CPAN
$loc = "$ENV{HOME}/.resty"
}
my $ret = dir($loc);
$ret->mkpath unless -d $ret->stringify;
$ret
}
sub stdout { print STDOUT $_[1] }
sub stderr { print STDERR $_[1] }
sub capture_curl {
my ($self, @rest) = @_;
my @wrappers = grep { $_->does('App::Adenosine::Role::WrapsCurlCommand') }
$self->plugins;
my $wrapped = sub {
my @rest = @_;
require Capture::Tiny;
Capture::Tiny::capture(sub { system(@rest) });
lib/App/Adenosine.pm view on Meta::CPAN
$wrapped->(@rest);
}
sub handle_curl_output {
my ($self, $out, $err, $ret) = @_;
my ( $http_code ) = ($err =~ m{.*HTTP/1\.[01] (\d)\d\d });
if ($self->verbose) {
my @filters = grep { $_->does('App::Adenosine::Role::FiltersStdErr') }
$self->plugins;
$err = $_->filter_stderr($err) for @filters;
$self->stderr($err)
}
$out .= "\n" unless $out =~ m/\n\Z/m;
$self->stdout($out);
return if $http_code == 2;
return $http_code;
}
sub argv { $_[0]->{argv} }
sub uri_base {
lib/App/Adenosine.pm view on Meta::CPAN
scratch-the-itch situation. If you have a use case for a new plugin hook
let me know and I'll set it up.
Plugins are just objects that the C<Adenosine> object has. There are a number
of interface style roles that the plugin consumes to signal that the plugin
uses a certain hook. Note that plugins can consume multiple roles to use more
than one hook. The next sections document the roles and their respective hooks.
=head2 C<App::Adenosine::Role::FiltersStdErr>
Only a C<filter_stderr> method needs to be implemented. It takes a string
(stderr output from curl) and should return a string. An existing example of
a plugin that consumes this role is L<App::Adenosine::Plugin::Rainbow>.
=head2 C<App::Adenosine::Role::WrapsCurlCommand>
Only a C<wrap> method needs to be implemented. It takes a coderef and should
return a coderef. The returned coderef should pass the args it gets to the
coderef the method got and return out values returned by the coderef. To be
more clear, this is the pattern:
sub wrap {
lib/App/Adenosine/Plugin/Rainbow.pm view on Meta::CPAN
method => $self->request_method_color,
uri => $self->request_uri_color,
protocol => $self->request_protocol_color,
protocol_version => $self->request_protocol_version_color,
})
}
return $pre .
$self->colorize($self->request_bracket_color, '> ') .
$post
}
sub filter_stderr {
my ($self, $err) = @_;
my @out;
for my $line (map { s/\r$//; $_ } split /\n/, $err) {
if ($line =~ /^(.*)\* (.*)$/) {
$line = $self->filter_info($1, $2)
} elsif ($line =~ /^(.*)< (.*)$/) {
$line = $self->filter_response($1, $2)
} elsif ($line =~ /^(.*)> (.*)$/) {
$line = $self->filter_request($1, $2)
lib/App/Adenosine/Plugin/Rainbow.pm view on Meta::CPAN
1;
Then use it the same way you use C<Rainbow>:
...
App::Adenosine->new({ argv => \@ARGV, plugins => ['::Rainbow::Valentine'] })
=head1 COLORABLE SECTIONS
C<Rainbow> splits apart the stderr string from curl and hilights the various
sections respectively. The values of the sections are what is passed as
the first argument to L</colorize>. The names of the sections are:
=over 2
=item * C<response_header_colon_color>
=item * C<response_header_name_color>
=item * C<response_header_value_color>
lib/App/Adenosine/Plugin/Stopwatch.pm view on Meta::CPAN
=head1 NAME
App::Adenosine::Plugin::Stopwatch
=head1 VERSION
version 2.002000
=head1 DESCRIPTION
Appends handy timer information to curl's stderr, giving the user a simple way
to understand the duration of a requestion.
=head1 METHODS
=head2 render_duration
Takes a scalar of seconds and renders them as a string. If you are subclassing
this plugin to add color coding, for example, you just need to override this
method.
lib/App/Adenosine/Role/FiltersStdErr.pm view on Meta::CPAN
package App::Adenosine::Role::FiltersStdErr;
$App::Adenosine::Role::FiltersStdErr::VERSION = '2.002000';
use Moo::Role;
requires 'filter_stderr';
1;
__END__
=pod
=encoding UTF-8
=head1 NAME
TestAdenosine->new({
argv => ['https://google.com/user/*/1'],
plugins => [qw(Plugin1)],
@noxdg,
});
is($TestAdenosine::stdout, "https://google.com/user/*/1\n", 'https + *');
is($TestAdenosine::uri_base, "https://google.com/user/*/1", 'uri_base set');
cmp_deeply(\@TestAdenosine::extra_options, [], 'extra options cleared');
$TestAdenosine::curl_stderr = <<'BLUUU';
* About to connect() to google.com port 80 (#0)
* Trying 167.10.21.20... connected
> HEAD / HTTP/1.1
> User-Agent: curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3
> Host: google.com
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Thu, 08 Nov 2012 23:22:28 GMT
< Server: HTTP::Server::PSGI
my $exit_code = TestAdenosine->new({ argv => ['GET'], @noxdg });
cmp_deeply(\@TestAdenosine::curl_options, [
qw(curl -sLv -X GET -b), $c, '-c', $c, '-H', 'Accept: text/html',
'https://google.com/user//1',
], 'GET');
is($TestAdenosine::stdout, $TestAdenosine::curl_stdout, 'output the right stuff!');
ok(!$exit_code, '200 means exit with 0');
$TestAdenosine::curl_stderr =~ s[(< HTTP/1\.1 )2][${1}5];
$exit_code = TestAdenosine->new({
argv => [qw(GET 1 -v)],
plugins => [{ '::Plugin2' => {} }],
@noxdg,
});
cmp_deeply(\@TestAdenosine::curl_options, [
qw(curl -sLv -X GET -b), $c, '-c', $c, '-H', 'Accept: text/html',
'https://google.com/user/1/1',
], 'GET 1');
is($exit_code, 5, '500 exits correctly');
is($TestAdenosine::stderr, "'curl' '-sLv' '-X' 'GET' '-b' '$c' '-c' '$c' '-H' 'Accept: text/html' 'https://google.com/user/1/1'
$TestAdenosine::curl_stderr", '-v works');
TestAdenosine->new({ argv => [qw(POST 2), '{"foo":"bar"}'], @noxdg });
cmp_deeply(\@TestAdenosine::curl_options, [
qw(curl -sLv {"foo":"bar"} -X POST -b ), $c, '-c', $c, qw(
--data-binary -u foo:bar https://google.com/user/2/1),
], 'POST 2 $data');
if ($^O ne 'MSWin32') {
TestAdenosine->new({ argv => [qw(POST 2), '-V'], @noxdg });
cmp_deeply(\@TestAdenosine::curl_options, [
require mro;
} else {
require MRO::Compat;
}
use lib 'lib';
use base 'App::Adenosine';
our @curl_options;
our $stdout = '';
our $stderr = '';
our $curl_stderr;
our $curl_stdout;
our $uri_base;
our %host_config;
our @extra_options;
sub _set_uri_base { $uri_base = $_[1] }
sub _get_uri_base { $uri_base }
sub _load_host_method_config { split /\n/, $host_config{$_[1]} }
sub new {
my $self = shift;
$stdout = '';
$stderr = '';
$self->next::method(@_)
}
sub capture_curl {
my $self = shift;
@curl_options = @_;
return ($curl_stdout, $curl_stderr, 0);
}
sub stdout { $stdout .= $_[1] }
sub stderr { $stderr .= $_[1] }
sub _set_extra_options { my $self = shift; @extra_options = @_ }
sub _get_extra_options { @extra_options }
package Plugin1;
$INC{'Plugin1.pm'} = __FILE__;
use Moo;
with 'App::Adenosine::Role::FiltersStdErr';
sub filter_stderr { $_[1] }
package App::Adenosine::Plugin::Plugin2;
$INC{'App/Adenosine/Plugin/Plugin2.pm'} = __FILE__;
use Moo;
with 'App::Adenosine::Role::FiltersStdErr';
sub filter_stderr { $_[1] }
}
( run in 0.488 second using v1.01-cache-2.11-cpan-26ccb49234f )