AnyEvent-Twitter

 view release on metacpan or  search on metacpan

lib/AnyEvent/Twitter.pm  view on Meta::CPAN

package AnyEvent::Twitter;
use strict;
use warnings;
use utf8;
use 5.008;
our $VERSION = '0.64';

use Carp;
use JSON;
use URI;
use URI::Escape;
use Digest::SHA;
use Time::Piece;
use AnyEvent::HTTP;
use HTTP::Request::Common 'POST';
use Data::Recursive::Encode;

use Net::OAuth;
use Net::OAuth::ProtectedResourceRequest;
use Net::OAuth::RequestTokenRequest;
use Net::OAuth::AccessTokenRequest;

$Net::OAuth::PROTOCOL_VERSION = Net::OAuth::PROTOCOL_VERSION_1_0A;

our %PATH = (
    site          => 'https://twitter.com/',
    request_token => 'https://api.twitter.com/oauth/request_token',
    authorize     => 'https://api.twitter.com/oauth/authorize',
    access_token  => 'https://api.twitter.com/oauth/access_token',
    authenticate  => 'https://api.twitter.com/oauth/authenticate',
);

our %RESOURCE_URL_BASE = (
    '1.0' => 'http://api.twitter.com/1/%s.json',
    '1.1' => 'https://api.twitter.com/1.1/%s.json',
);

sub new {
    my ($class, %args) = @_;

    $args{api_version}         ||= '1.1';
    $args{access_token}        ||= $args{token};
    $args{access_token_secret} ||= $args{token_secret};

    my @required = qw(access_token access_token_secret consumer_key consumer_secret);
    for my $item (@required) {
         defined $args{$item} or Carp::croak "$item is required";
    }

    return bless { %args }, $class;
}

sub get {
    my $cb = pop;
    my ($self, $endpoint, $params) = @_;

    my $type = $endpoint =~ /^http.+\.json$/ ? 'url' : 'api';
    $self->request($type => $endpoint, method => 'GET', params => $params, $cb);

    return $self;
}

sub post {
    my ($self, $endpoint, $params, $cb) = @_;

    my $type = $endpoint =~ /^http.+\.json$/ ? 'url' : 'api';
    $self->request($type => $endpoint, method => 'POST', params => $params, $cb);

    return $self;
}

sub request {
    my $cb = pop;
    my ($self, %opt) = @_;

    ($opt{api} || $opt{url})
        or Carp::croak "'api' or 'url' option is required";

    my $url_base = $RESOURCE_URL_BASE{ $self->{api_version} };
    my $url = $opt{url} || sprintf $url_base, $opt{api};

    ref $cb eq 'CODE'
        or Carp::croak "callback coderef is required";

    my $params = $opt{params} || {};
    my $is_multipart = ref $params eq 'ARRAY';

    my $method = uc $opt{method};
    $method =~ /^(?:GET|POST)$/
        or Carp::croak "'method' option should be GET or POST";

    my $req = $self->_make_oauth_request(
        class => 'Net::OAuth::ProtectedResourceRequest',
        request_url     => $url,
        request_method  => $method,
        extra_params    => ($is_multipart ? {} : $params),
        consumer_key    => $self->{consumer_key},
        consumer_secret => $self->{consumer_secret},
        token           => $self->{access_token},
        token_secret    => $self->{access_token_secret},
    );

    my $req_params = {};

    if ($method eq 'POST') {
        $url = $req->normalized_request_url;

        if ($is_multipart) {
            my $encoded_params = Data::Recursive::Encode::_apply(
                sub { utf8::is_utf8($_[0]) ? Encode::encode_utf8($_[0]) : $_[0] },
                {},
                $params
            );

            my $ireq = POST(
                $url,
                Content_Type => 'multipart/form-data',
                Content => [ @$encoded_params ]
            );

            $req_params->{body} = $ireq->content;
            $req_params->{headers} = {
                Authorization  => $req->to_authorization_header,
                'Content-Type' => join "; ", $ireq->content_type,
            };

        } else {

lib/AnyEvent/Twitter.pm  view on Meta::CPAN

You can find available C<api>s at L<API Documentation|https://dev.twitter.com/docs/api>

=item C<method> and C<params>

Investigate the HTTP method and required parameters of Twitter API that you want to use.
Then specify it. GET and POST methods are allowed. You can omit C<params> if Twitter API doesn't require it.

=item callback

This module is L<AnyEvent::HTTP> style, so you have to pass the callback (coderef).

Passed callback will be called with C<$header>, C<$response>, C<$reason> and C<$error_response>.
If something is wrong with the response from Twitter API, C<$response> will be C<undef>.
On non-2xx HTTP status code, you can get the decoded response via C<$error_response>.
So you can check the value like below.

    my $callback = sub {
        my ($header, $response, $reason, $error_response) = @_;

        if ($response) {
            say $response->{screen_name};
        } else {
            say $reason;
            for my $error (@{$error_response->{errors}}) {
                say "$error->{code}: $error->{message}";
            }
        }
    };

=back

=head2 parse_timestamp

C<parse_timestamp> parses C<created_at> timestamp like "Thu Mar 01 17:38:56 +0000 2012".
It returns L<Time::Piece> object. Its timezone is localtime.

=over 4

=item C<< AnyEvent::Twitter->parse_timestamp($created_at) >>

=back

=head1 TESTS

Most of all tests are written as author tests since this module depends on remote API server.
So if you want read code that works well, take a look at C<xt/> directory.

=head1 EXPERIMENTAL METHODS

Methods listed below are experimental feature. So interfaces or returned values may vary in the future.

=head2 C<< AnyEvent::Twitter->get_request_token >>

    AnyEvent::Twitter->get_request_token(
        consumer_key    => $consumer_key,
        consumer_secret => $consumer_secret,
        callback_url    => 'http://example.com/callback',
        # auth => 'authenticate',
        cb => sub {
            my ($location, $response, $body, $header) = @_;
            # $location is the endpoint where users are asked the permission
            # $response is a hashref of parsed body
            # $body is raw response itself
            # $header is response headers
        },
    );

=head2 C<< AnyEvent::Twitter->get_access_token >>

    AnyEvent::Twitter->get_access_token(
        consumer_key       => $consumer_key,
        consumer_secret    => $consumer_secret,
        oauth_token        => $oauth_token,
        oauth_token_secret => $oauth_token_secret,
        oauth_verifier     => $oauth_verifier,
        cb => sub {
            my ($token, $body, $header) = @_;
            # $token is the parsed body
            # $body is raw response
            # $header is response headers
        },
    );

=head1 CONTRIBUTORS

=over 4

=item ramusara

He gave me plenty of test code.

=item Hideki Yamamura

He cleaned my code up.

=back

=head1 AUTHOR

punytan E<lt>punytan@gmail.comE<gt>

=head1 SEE ALSO

L<AnyEvent::HTTP>, L<Net::OAuth>

=head1 LICENSE

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.

=cut



( run in 0.669 second using v1.01-cache-2.11-cpan-2398b32b56e )