File Coverage

blib/lib/WWW/HatenaDiary.pm
Criterion Covered Total %
statement 16 18 88.8
branch n/a
condition n/a
subroutine 6 6 100.0
pod n/a
total 22 24 91.6


line stmt bran cond sub pod time code
1             package WWW::HatenaDiary;
2 3     3   1555 use strict;
  3         8  
  3         641  
3 3     3   20 use warnings;
  3         4  
  3         100  
4 3     3   17 use Carp;
  3         5  
  3         316  
5 3     3   13139 use URI;
  3         30022  
  3         101  
6 3     3   3163 use Web::Scraper;
  3         367203  
  3         25  
7 3     3   1673 use WWW::Mechanize;
  0            
  0            
8             use WWW::HatenaLogin;
9             use JSON::Syck 'Load';
10              
11             our $VERSION = '0.02';
12              
13             sub new {
14             my ($class, $args) = @_;
15             my $base = $args->{group} ? "http://$args->{group}.g.hatena.ne.jp/" :
16             'http://d.hatena.ne.jp/';
17             my $self = bless {
18             base => $base,
19             group => $args->{group},
20             login => $args->{login} || WWW::HatenaLogin->new({ nologin => 1, %{ $args } }),
21             verbose => $args->{verbose},
22             }, $class;
23              
24             if ($self->is_loggedin) {
25             my $username = scraper {
26             process '//td[@class="username"]/a', 'username' => 'TEXT';
27             result 'username';
28             }->scrape($self->{login}->mech->content, $self->{login}->login_uri);
29             $self->{login}->username($username) if !$self->{login}->username;
30             $self->{diary} = $self->{base}.$self->{login}->username.'/';
31             }
32              
33             $self;
34             }
35              
36             sub is_loggedin {
37             my $self = shift;
38             $self->{login}->is_loggedin;
39             }
40              
41             sub login {
42             my ($self, $args) = @_;
43              
44             $self->{login}->login($args);
45             $self->{diary} = $self->{base}.$self->{login}->username.'/';
46              
47             !!($self->{rkm} = $self->get_rkm) ||
48             croak 'Login failed. Please confirm your username/password';
49             }
50              
51             sub get_rkm {
52             my $self = shift;
53             my $rkm;
54              
55             $self->{login}->mech->get("$self->{diary}?mode=json");
56             eval {
57             $rkm = Load($self->{login}->mech->content)->{rkm};
58             };
59              
60             $rkm;
61             }
62              
63             sub create {
64             my ($self, $args) = @_;
65             $self->_post_entry($args);
66             }
67              
68             sub create_day {
69             shift->update_day(@_);
70             }
71              
72             sub retrieve {
73             my ($self, $args) = @_;
74              
75             croak('URI for the entry is required')
76             if !$args->{uri};
77              
78             $self->{login}->mech->get("$args->{uri}?mode=json");
79             Load($self->{login}->mech->content);
80             }
81              
82             sub retrieve_day {
83             my ($self, $args) = @_;
84              
85             croak('Date is required')
86             if !$args->{date};
87              
88             if ($args->{date} =~ /^(\d{4})-(\d{2})-(\d{2})$/) {
89             my ($y, $m, $d) = ($1, $2, $3);
90              
91             my $uri = "$self->{diary}edit?date=$y$m$d";
92             $self->{login}->mech->get($uri);
93             my $form = $self->{login}->mech->form_name('edit');
94              
95             {
96             title => $form->value('title'),
97             body => $form->value('body'),
98             };
99             } else {
100             carp "Invalid ymd format: $args->{date}. YYYY-MM-DD formatted date is required.";
101             }
102             }
103              
104             sub update {
105             my ($self, $args) = @_;
106              
107             croak('URI for the entry is required')
108             if !$args->{uri};
109              
110             $self->_post_entry($args);
111             $args->{uri};
112             }
113              
114             sub update_day {
115             my ($self, $args) = @_;
116              
117             croak('Date is required')
118             if !$args->{date};
119              
120             if ($args->{date} =~ /^(\d{4})-(\d{2})-(\d{2})$/) {
121             my ($y, $m, $d) = ($1, $2, $3);
122              
123             my $uri = "$self->{diary}edit?date=$y$m$d";
124             $self->{login}->mech->get($uri);
125             $self->{login}->mech->submit_form(
126             form_name => 'edit',
127             fields => {
128             title => $args->{title},
129             body => $args->{body},
130             year => $y,
131             month => $m,
132             day => $d,
133             },
134             );
135             }
136             else {
137             carp "Invalid ymd format: $args->{date}. YYYY-MM-DD formatted date is required.";
138             }
139              
140             $self->{login}->mech->success;
141             }
142              
143             # XXX: It's dubious if this implementation is correct...
144             sub delete {
145             my ($self, $args) = @_;
146              
147             croak('URI for the entry is required')
148             if !$args->{uri};
149              
150             my ($y, $m, $d, $slag) = $args->{uri} =~ m|^$self->{diary}(\d{4})(\d{2})(\d{2})/(.+)$|;
151             my $body = $self->retrieve_day({date => join('-', $y, $m, $d)})->{body};
152              
153             croak "Entry for $args->{uri} not found"
154             if !$body;
155              
156             my @update_body = ();
157             my $delete_flag = 0;
158             my $match = qr/\*$slag\*/;
159             my $unmatch = qr/\*(.+)\*/;
160              
161             for ($body =~ /^(.*)$/mg) {
162             $delete_flag = 0 if /$unmatch/ && $delete_flag;
163             $delete_flag = 1 if /$match/;
164             push @update_body, $_ if !$delete_flag;
165             }
166              
167             $self->update_day({
168             date => join('-', $y, $m, $d),
169             body => join("\n", @update_body),
170             });
171             }
172              
173             sub delete_day {
174             my ($self, $args) = @_;
175              
176             croak('Date is required')
177             if !$args->{date};
178              
179             if ($args->{date} =~ /^(\d{4})-(\d{2})-(\d{2})$/) {
180             my ($y, $m, $d) = ($1, $2, $3);
181             my $uri = "$self->{diary}edit?date=$y$m$d";
182              
183             $self->{login}->mech->get($uri);
184              
185             if ($self->{group}) {
186             for my $form ($self->{login}->mech->forms) {
187             if ($form->action =~ /deletediary$/) {
188             $self->{login}->mech->request($form->click);
189             }
190             }
191             }
192             else {
193             $self->{login}->mech->submit_form(form_number => 2);
194             }
195             }
196             else {
197             carp "Invalid ymd format: $args->{date}. YYYY-MM-DD formatted date is required.";
198             }
199              
200             $self->{login}->mech->success;
201             }
202              
203             sub _post_entry {
204             my ($self, $args) = @_;
205             my $uri = $args->{uri} || $self->{diary};
206              
207             $self->{login}->mech->post($uri, {
208             rkm => $self->{rkm},
209             %$args,
210             });
211              
212             $self->{login}->mech->get($uri);
213              
214             scraper {
215             process '//div[@class="section"][1]/h3[1]/a[1]', 'uri' => '@href';
216             result 'uri';
217             }->scrape($self->{login}->mech->content, URI->new($self->{diary}));
218             }
219              
220             1;
221              
222             __END__