Navigation Menu

Skip to content

Commit

Permalink
add delete_p, get_p, head_p, options_p, patch_p, post_p, put_p and st…
Browse files Browse the repository at this point in the history
…art_p methods to Mojo::UserAgent
  • Loading branch information
kraih committed Nov 2, 2017
1 parent ef07d1e commit 494614e
Show file tree
Hide file tree
Showing 4 changed files with 213 additions and 29 deletions.
4 changes: 3 additions & 1 deletion Changes
@@ -1,5 +1,7 @@

7.52 2017-11-01
7.52 2017-11-02
- Added delete_p, get_p, head_p, options_p, patch_p, post_p, put_p and start_p
methods to Mojo::UserAgent.

7.51 2017-10-31
- Added -signatures flag to Mojo::Base and Mojolicious::Lite.
Expand Down
170 changes: 157 additions & 13 deletions lib/Mojo/UserAgent.pm
Expand Up @@ -34,6 +34,10 @@ for my $name (qw(DELETE GET HEAD OPTIONS PATCH POST PUT)) {
my ($self, $cb) = (shift, ref $_[-1] eq 'CODE' ? pop : undef);
return $self->start($self->build_tx($name, @_), $cb);
};
monkey_patch __PACKAGE__, lc($name) . '_p', sub {
my $self = shift;
return $self->start_p($self->build_tx($name, @_));
};
}

sub DESTROY { Mojo::Util::_global_destruction() or shift->_cleanup }
Expand Down Expand Up @@ -61,6 +65,22 @@ sub start {
return $tx;
}

sub start_p {
my ($self, $tx) = @_;

my $promise = Mojo::IOLoop->delay;
$self->start(
$tx => sub {
my ($self, $tx) = @_;
my $err = $tx->error;
$promise->resolve($tx) if !$err || $err->{code};
$promise->reject($err->{message});
}
);

return $promise;
}

sub websocket {
my ($self, $cb) = (shift, pop);
$self->start($self->build_websocket_tx(@_), $cb);
Expand Down Expand Up @@ -403,19 +423,14 @@ Mojo::UserAgent - Non-blocking I/O HTTP and WebSocket user agent
});
Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
# Concurrent non-blocking requests (synchronized with a delay)
Mojo::IOLoop->delay(
sub {
my $delay = shift;
$ua->get('mojolicious.org' => $delay->begin);
$ua->get('cpan.org' => $delay->begin);
},
sub {
my ($delay, $mojo, $cpan) = @_;
say $mojo->result->dom->at('title')->text;
say $cpan->result->dom->at('title')->text;
}
)->wait;
# Concurrent non-blocking requests (synchronized with promises)
my $mojo = $ua->get_p('mojolicious.org');
my $cpan = $ua->get_p('cpan.org');
$mojo->all($cpan)->then(sub {
my ($mojo, $cpan) = @_;
say $mojo->[0]->result->dom->at('title')->text;
say $cpan->[0]->result->dom->at('title')->text;
})->wait;
# WebSocket connection sending and receiving JSON via UNIX domain socket
$ua->websocket('ws+unix://%2Ftmp%2Fmyapp.sock/echo.json' => sub {
Expand Down Expand Up @@ -746,6 +761,22 @@ implied). You can also append a callback to perform requests non-blocking.
});
Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
=head2 delete_p
my $promise = $ua->delete_p('http://example.com');
Same as L</"delete">, but performs all requests non-blocking and returns a
L<Mojo::IOLoop::Delay> object to be used as a promise instead of accepting a
callback.
$ua->delete_p('http://example.com' => json => {a => 'b'})->then(sub {
my $tx = shift;
say $tx->result->body;
})->catch(sub {
my $err = shift;
warn "Connection error: $err";
})->wait;
=head2 get
my $tx = $ua->get('example.com');
Expand All @@ -766,6 +797,22 @@ perform requests non-blocking.
});
Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
=head2 get_p
my $promise = $ua->get_p('http://example.com');
Same as L</"get">, but performs all requests non-blocking and returns a
L<Mojo::IOLoop::Delay> object to be used as a promise instead of accepting a
callback.
$ua->get_p('http://example.com' => json => {a => 'b'})->then(sub {
my $tx = shift;
say $tx->result->body;
})->catch(sub {
my $err = shift;
warn "Connection error: $err";
})->wait;
=head2 head
my $tx = $ua->head('example.com');
Expand All @@ -786,6 +833,22 @@ implied). You can also append a callback to perform requests non-blocking.
});
Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
=head2 head_p
my $promise = $ua->head_p('http://example.com');
Same as L</"head">, but performs all requests non-blocking and returns a
L<Mojo::IOLoop::Delay> object to be used as a promise instead of accepting a
callback.
$ua->head_p('http://example.com' => json => {a => 'b'})->then(sub {
my $tx = shift;
say $tx->result->body;
})->catch(sub {
my $err = shift;
warn "Connection error: $err";
})->wait;
=head2 options
my $tx = $ua->options('example.com');
Expand All @@ -806,6 +869,22 @@ implied). You can also append a callback to perform requests non-blocking.
});
Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
=head2 options_p
my $promise = $ua->options_p('http://example.com');
Same as L</"options">, but performs all requests non-blocking and returns a
L<Mojo::IOLoop::Delay> object to be used as a promise instead of accepting a
callback.
$ua->options_p('http://example.com' => json => {a => 'b'})->then(sub {
my $tx = shift;
say $tx->result->body;
})->catch(sub {
my $err = shift;
warn "Connection error: $err";
})->wait;
=head2 patch
my $tx = $ua->patch('example.com');
Expand All @@ -826,6 +905,22 @@ implied). You can also append a callback to perform requests non-blocking.
});
Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
=head2 patch_p
my $promise = $ua->patch_p('http://example.com');
Same as L</"patch">, but performs all requests non-blocking and returns a
L<Mojo::IOLoop::Delay> object to be used as a promise instead of accepting a
callback.
$ua->patch_p('http://example.com' => json => {a => 'b'})->then(sub {
my $tx = shift;
say $tx->result->body;
})->catch(sub {
my $err = shift;
warn "Connection error: $err";
})->wait;
=head2 post
my $tx = $ua->post('example.com');
Expand All @@ -846,6 +941,22 @@ implied). You can also append a callback to perform requests non-blocking.
});
Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
=head2 post_p
my $promise = $ua->post_p('http://example.com');
Same as L</"post">, but performs all requests non-blocking and returns a
L<Mojo::IOLoop::Delay> object to be used as a promise instead of accepting a
callback.
$ua->post_p('http://example.com' => json => {a => 'b'})->then(sub {
my $tx = shift;
say $tx->result->body;
})->catch(sub {
my $err = shift;
warn "Connection error: $err";
})->wait;
=head2 put
my $tx = $ua->put('example.com');
Expand All @@ -866,6 +977,22 @@ perform requests non-blocking.
});
Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
=head2 put_p
my $promise = $ua->put_p('http://example.com');
Same as L</"put">, but performs all requests non-blocking and returns a
L<Mojo::IOLoop::Delay> object to be used as a promise instead of accepting a
callback.
$ua->put_p('http://example.com' => json => {a => 'b'})->then(sub {
my $tx = shift;
say $tx->result->body;
})->catch(sub {
my $err = shift;
warn "Connection error: $err";
})->wait;
=head2 start
my $tx = $ua->start(Mojo::Transaction::HTTP->new);
Expand All @@ -881,6 +1008,23 @@ to perform requests non-blocking.
});
Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
=head2 start_p
my $promise = $ua->start_p(Mojo::Transaction::HTTP->new);
Same as L</"start">, but performs all requests non-blocking and returns a
L<Mojo::IOLoop::Delay> object to be used as a promise instead of accepting a
callback.
my $tx = $ua->build_tx(GET => 'http://example.com');
$ua->start_p($tx)->then(sub {
my $tx = shift;
say $tx->result->body;
})->catch(sub {
my $err = shift;
warn "Connection error: $err";
})->wait;
=head2 websocket
$ua->websocket('ws://example.com' => sub {...});
Expand Down
23 changes: 9 additions & 14 deletions lib/Mojolicious/Guides/Tutorial.pod
Expand Up @@ -868,20 +868,15 @@ L<Mojo::JSON> and L<Mojo::DOM> this can be a very powerful tool.
# Concurrent non-blocking
get '/titles' => sub {
my $c = shift;
$c->delay(
sub {
my $delay = shift;
$c->ua->get('http://mojolicious.org' => $delay->begin);
$c->ua->get('https://metacpan.org' => $delay->begin);
},
sub {
my ($delay, $mojo, $cpan) = @_;
$c->render(json => {
mojo => $mojo->result->dom->at('title')->text,
cpan => $cpan->result->dom->at('title')->text
});
}
);
my $mojo = $ua->get_p('http://mojolicious.org');
my $cpan = $ua->get_p('https://metacpan.org');
$mojo->all($cpan)->then(sub {
my ($mojo, $cpan) = @_;
$c->render(json => {
mojo => $mojo->[0]->result->dom->at('title')->text,
cpan => $cpan->[0]->result->dom->at('title')->text
});
})->wait;
};

app->start;
Expand Down
45 changes: 44 additions & 1 deletion t/mojo/user_agent.t
Expand Up @@ -132,6 +132,43 @@ ok $success, 'successful';
is $code, 200, 'right status';
is $body, 'works!', 'right content';

# Promises
my @results;
my $p1 = $ua->get_p('/');
my $p2 = $ua->get_p('/');
$p1->all($p2)->then(
sub {
my ($first, $second) = @_;
push @results, $first, $second;
}
)->wait;
ok $results[0][0]->success, 'successful';
is $results[0][0]->res->code, 200, 'right status';
is $results[0][0]->res->body, 'works!', 'right content';
ok $results[1][0]->success, 'successful';
is $results[1][0]->res->code, 200, 'right status';
is $results[1][0]->res->body, 'works!', 'right content';

# Promises (shortcut methods)
my $result;
$ua->delete_p('/method')->then(sub { $result = shift->res->body })->wait;
is $result, 'DELETE', 'right result';
$ua->get_p('/method')->then(sub { $result = shift->res->body })->wait;
is $result, 'GET', 'right result';
$ua->head_p('/method')->then(sub { $result = shift->res->body })->wait;
is $result, '', 'no result';
$ua->options_p('/method')->then(sub { $result = shift->res->body })->wait;
is $result, 'OPTIONS', 'right result';
$ua->patch_p('/method')->then(sub { $result = shift->res->body })->wait;
is $result, 'PATCH', 'right result';
$ua->post_p('/method')->then(sub { $result = shift->res->body })->wait;
is $result, 'POST', 'right result';
$ua->put_p('/method')->then(sub { $result = shift->res->body })->wait;
is $result, 'PUT', 'right result';
$ua->start_p($ua->build_tx(TEST => '/method'))
->then(sub { $result = shift->res->body })->wait;
is $result, 'TEST', 'right result';

# SOCKS proxy request without SOCKS support
$ua = Mojo::UserAgent->new;
my $tx = $ua->build_tx(GET => '/');
Expand All @@ -146,6 +183,12 @@ $tx = $ua->get($ua->server->url->scheme('https'));
like $tx->error->{message}, qr/IO::Socket::SSL/, 'right error';
ok !Mojo::IOLoop::TLS->can_tls, 'no TLS support';

# Promises (rejected)
my $error;
$ua->get_p($ua->server->url->scheme('https'))->catch(sub { $error = shift })
->wait;
like $error, qr/IO::Socket::SSL/, 'right error';

# No non-blocking name resolution
ok !Mojo::IOLoop::Client->can_nnr, 'no non-blocking name resolution support';

Expand Down Expand Up @@ -611,7 +654,7 @@ is $tx->res->body, 'Hi!', 'right content';

# Connection limit
$ua = Mojo::UserAgent->new(max_connections => 2);
my $result;
$result = undef;
Mojo::IOLoop->delay(
sub {
my $delay = shift;
Expand Down

0 comments on commit 494614e

Please sign in to comment.