line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Net::Douban; |
2
|
|
|
|
|
|
|
{ |
3
|
|
|
|
|
|
|
$Net::Douban::VERSION = '1.14'; |
4
|
|
|
|
|
|
|
} |
5
|
13
|
|
|
13
|
|
351681
|
use URI; |
|
13
|
|
|
|
|
483719
|
|
|
13
|
|
|
|
|
398
|
|
6
|
13
|
|
|
13
|
|
10409
|
use Moose; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
use Moose::Util::TypeConstraints; |
8
|
|
|
|
|
|
|
use MooseX::StrictConstructor; |
9
|
|
|
|
|
|
|
use Carp qw/carp croak/; |
10
|
|
|
|
|
|
|
with 'Net::Douban::OAuth'; |
11
|
|
|
|
|
|
|
with 'MooseX::Traits'; |
12
|
|
|
|
|
|
|
with "Net::Douban::Roles"; |
13
|
|
|
|
|
|
|
use namespace::autoclean; |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
subtype 'Net::Douban::URI', as class_type('URI'), |
16
|
|
|
|
|
|
|
## this regex is taken from FormValidator::Lite::Constraint::URL |
17
|
|
|
|
|
|
|
where { |
18
|
|
|
|
|
|
|
$_->canonical =~ /^s?https?:\/\/[-_.!~*'()a-zA-Z0-9;\/?:\@&=+\$,%#]+$/; |
19
|
|
|
|
|
|
|
}, message { |
20
|
|
|
|
|
|
|
'Invalid URL' |
21
|
|
|
|
|
|
|
}; |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
coerce 'Net::Douban::URI' => from 'Str' => via { URI->new($_) }; |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
has 'realm' => (is => 'ro', default => 'www.douban.com'); |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
has 'api_base' => ( |
28
|
|
|
|
|
|
|
is => 'rw', |
29
|
|
|
|
|
|
|
isa => 'Net::Douban::URI', |
30
|
|
|
|
|
|
|
default => sub { URI->new('http://api.douban.com') }, |
31
|
|
|
|
|
|
|
); |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
has '+request_url' => ( |
34
|
|
|
|
|
|
|
is => 'rw', |
35
|
|
|
|
|
|
|
isa => 'Net::Douban::URI', |
36
|
|
|
|
|
|
|
default => |
37
|
|
|
|
|
|
|
sub { URI->new('http://www.douban.com/service/auth/request_token') }, |
38
|
|
|
|
|
|
|
); |
39
|
|
|
|
|
|
|
has '+access_url' => ( |
40
|
|
|
|
|
|
|
is => 'rw', |
41
|
|
|
|
|
|
|
isa => 'Net::Douban::URI', |
42
|
|
|
|
|
|
|
default => |
43
|
|
|
|
|
|
|
sub { URI->new('http://www.douban.com/service/auth/access_token') }, |
44
|
|
|
|
|
|
|
); |
45
|
|
|
|
|
|
|
has '+authorize_url' => ( |
46
|
|
|
|
|
|
|
is => 'rw', |
47
|
|
|
|
|
|
|
isa => 'Net::Douban::URI', |
48
|
|
|
|
|
|
|
default => |
49
|
|
|
|
|
|
|
sub { URI->new('http://www.douban.com/service/auth/authorize') }, |
50
|
|
|
|
|
|
|
); |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
sub init { |
53
|
|
|
|
|
|
|
my $class = shift; |
54
|
|
|
|
|
|
|
my %args = @_; |
55
|
|
|
|
|
|
|
if ($args{Traits} && $args{Roles}) { |
56
|
|
|
|
|
|
|
warn "Roles will be ignored when we have Traits"; |
57
|
|
|
|
|
|
|
} |
58
|
|
|
|
|
|
|
if ($args{Traits}) { |
59
|
|
|
|
|
|
|
my @traits = ref $args{Traits} ? @{$args{Traits}} : ($args{Traits}); |
60
|
|
|
|
|
|
|
for my $t (@traits) { |
61
|
|
|
|
|
|
|
if ($t =~ s/^\+//g) { |
62
|
|
|
|
|
|
|
$class = $class->with_traits($t); |
63
|
|
|
|
|
|
|
} else { |
64
|
|
|
|
|
|
|
$class = $class->with_traits("Net::Douban::Traits::$t"); |
65
|
|
|
|
|
|
|
} |
66
|
|
|
|
|
|
|
} |
67
|
|
|
|
|
|
|
} elsif ($args{Roles}) { |
68
|
|
|
|
|
|
|
my @roles = ref $args{Roles} ? @{$args{Roles}} : ($args{Roles}); |
69
|
|
|
|
|
|
|
$class = $class->with_traits("Net::Douban::$_") foreach @roles; |
70
|
|
|
|
|
|
|
} else { |
71
|
|
|
|
|
|
|
croak "Without Traits or Roles, I can not do anything"; |
72
|
|
|
|
|
|
|
} |
73
|
|
|
|
|
|
|
delete $args{Roles}; |
74
|
|
|
|
|
|
|
delete $args{Traits}; |
75
|
|
|
|
|
|
|
return $class->new(%args); |
76
|
|
|
|
|
|
|
} |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
__PACKAGE__->meta->make_immutable; |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
1; |
81
|
|
|
|
|
|
|
__END__ |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
=pod |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
=head1 NAME |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
Net::Douban - Perl client for douban.com |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
=head1 VERSION |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
version 1.14 |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
=head1 SYNOPSIS |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
use Net::Douban; |
96
|
|
|
|
|
|
|
my $client = Net::Douban->init(Traits => 'Gift'); |
97
|
|
|
|
|
|
|
my $client = Net::Douban->init(Roles => [qw/User Review .../]); |
98
|
|
|
|
|
|
|
$client->res_callback(sub{shift}); |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
print $client->get_user_contact(userID => 'Net-Douban')->decoded_content; |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
=head1 DESCRIPTION |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
Net::Douban is a perl client wrapper on the Chinese website 'douban.com' API. |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
=head1 METHODS |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
=over |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
=item B<init> |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
B<init> is the B<new> for C<Net::Douban>. it is here because of |
113
|
|
|
|
|
|
|
C<MooseX::Traits> limits |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
$client = Net::Douban->init(Traits => 'Gift'); |
116
|
|
|
|
|
|
|
$client = Net::Douban->init(Roles => 'User'); |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
=back |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
=head1 OAuth |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
Here is how to get the tokens before you can access the website |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
my $c = Net::Douban->init(consumer_key =>'...', consumer_secret =>'...'); |
125
|
|
|
|
|
|
|
$c->get_request_token; |
126
|
|
|
|
|
|
|
## ask your customer go to this url to allow the access to his account |
127
|
|
|
|
|
|
|
print $c->paste_url(); |
128
|
|
|
|
|
|
|
<>; |
129
|
|
|
|
|
|
|
$c->get_access_token; |
130
|
|
|
|
|
|
|
## now you can save those tokens |
131
|
|
|
|
|
|
|
say $c->request_token, $c->request_token_secret, $c->access_token, |
132
|
|
|
|
|
|
|
$c->access_token_secret; |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
## next time you can load tokens,all tokens are needed, the key for |
135
|
|
|
|
|
|
|
the hash is the name of the method. |
136
|
|
|
|
|
|
|
$c->load_token(%token_hash); |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
=head1 API |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
=head2 Roles |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
$client = Net::Douban->init(Roles => [qw/User Review/]); |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
B<Roles> are just individual douban API sections. You can pass B<Roles> |
145
|
|
|
|
|
|
|
to the constructure, then those sections are loaded to the object. |
146
|
|
|
|
|
|
|
Avalable roles are qw/User Subject Review Collection Miniblog Note Event |
147
|
|
|
|
|
|
|
Recommendation Review Doumail Tag/ |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
=head2 Traits |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
Traits are special Roles, Right now just there is just a |
153
|
|
|
|
|
|
|
L<Net::Douban::Traits::Gift>, you can write your own trait, refer to |
154
|
|
|
|
|
|
|
L<Net::Douban::Traits::Gift> to see how to do it. |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
When you want to use Traits under your own namespace(that is not under |
157
|
|
|
|
|
|
|
Net::Douban), you should pass it with a '+' in front of the name; |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
$c = Net::Douban->init("Traits" => '+My::Trait'); |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
=head2 res_callback |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
You can use your own res_callback to handle the returned |
164
|
|
|
|
|
|
|
L<HTTP::Response> object by: |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
$client->res_callback(sub{....}); |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
The only argument for this callback is B<$res> return from |
169
|
|
|
|
|
|
|
L<LWP::UserAgent>. By default, res_callback will return the decoded JSON |
170
|
|
|
|
|
|
|
hash. |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
=head2 Paging |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
Paging is support by passing argments 'start-index' and 'max-results' to |
175
|
|
|
|
|
|
|
search and get functions. |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
=head1 SEE ALSO |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
L<Net::Douban::OAuth> L<Net::Douban::Traits::Gift> L<Net::Douban::User> |
180
|
|
|
|
|
|
|
L<Net::Douban::Utils> |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
=head1 AUTHOR |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
woosley.xu <woosley.xu@gmail.com> |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
=head1 COPYRIGHT & LICENSE |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
This software is copyright (c) 2010 - 2011 by woosley.xu. |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
This is free software; you can redistribute it and/or modify it under |
191
|
|
|
|
|
|
|
the same terms as the Perl 5 programming language system itself. |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
=cut |