| lib/WWW/Mixi/Scraper/Plugin.pm | |||
|---|---|---|---|
| Criterion | Covered | Total | % |
| statement | 48 | 121 | 39.6 |
| branch | 6 | 48 | 12.5 |
| condition | 0 | 17 | 0.0 |
| subroutine | 11 | 24 | 45.8 |
| pod | 7 | 7 | 100.0 |
| total | 72 | 217 | 33.1 |
| line | stmt | bran | cond | sub | pod | time | code |
|---|---|---|---|---|---|---|---|
| 1 | package WWW::Mixi::Scraper::Plugin; | ||||||
| 2 | |||||||
| 3 | 1 | 1 | 9 | use strict; | |||
| 1 | 2 | ||||||
| 1 | 30 | ||||||
| 4 | 1 | 1 | 5 | use warnings; | |||
| 1 | 1 | ||||||
| 1 | 22 | ||||||
| 5 | 1 | 1 | 869 | use Web::Scraper; | |||
| 1 | 184574 | ||||||
| 1 | 6 | ||||||
| 6 | 1 | 1 | 820 | use String::CamelCase qw( decamelize ); | |||
| 1 | 649 | ||||||
| 1 | 84 | ||||||
| 7 | 1 | 1 | 389 | use WWW::Mixi::Scraper::Utils qw( _force_arrayref _uri _datetime ); | |||
| 1 | 2 | ||||||
| 1 | 182 | ||||||
| 8 | |||||||
| 9 | sub import { | ||||||
| 10 | 21 | 21 | 622 | my $class = shift; | |||
| 11 | 21 | 38 | my $pkg = caller; | ||||
| 12 | |||||||
| 13 | 21 | 131 | my @subs = qw( | ||||
| 14 | new parse | ||||||
| 15 | scraper process process_first result | ||||||
| 16 | get_content post_process | ||||||
| 17 | validator build_uri | ||||||
| 18 | html_or_text _extract_name | ||||||
| 19 | ); | ||||||
| 20 | |||||||
| 21 | 1 | 1 | 17 | no strict 'refs'; | |||
| 1 | 2 | ||||||
| 1 | 28 | ||||||
| 22 | 1 | 1 | 5 | no warnings 'redefine'; | |||
| 1 | 2 | ||||||
| 1 | 668 | ||||||
| 23 | 21 | 33 | foreach my $sub ( @subs ) { | ||||
| 24 | 252 | 232 | *{"$pkg\::$sub"} = *{"$class\::$sub"}; | ||||
| 252 | 10282 | ||||||
| 252 | 1157 | ||||||
| 25 | } | ||||||
| 26 | } | ||||||
| 27 | |||||||
| 28 | sub new { | ||||||
| 29 | 0 | 0 | 1 | 0 | my ($class, %options) = @_; | ||
| 30 | |||||||
| 31 | 0 | 0 | bless \%options, $class; | ||||
| 32 | } | ||||||
| 33 | |||||||
| 34 | 0 | 0 | 0 | 1 | 0 | sub html_or_text { shift->{mode} || 'HTML' } | |
| 35 | |||||||
| 36 | sub parse { | ||||||
| 37 | 0 | 0 | 1 | 0 | my $self = shift; | ||
| 38 | |||||||
| 39 | 0 | 0 | my $res = $self->scrape($self->get_content(@_)); | ||||
| 40 | |||||||
| 41 | 0 | 0 | 0 | return ( wantarray and ref $res eq 'ARRAY' ) | |||
| 42 | 0 | 0 | 0 | 0 | ? @{ $res || [] } | ||
| 43 | : $res; | ||||||
| 44 | } | ||||||
| 45 | |||||||
| 46 | sub get_content { | ||||||
| 47 | 0 | 0 | 1 | 0 | my ($self, %options) = @_; | ||
| 48 | |||||||
| 49 | 0 | 0 | my $content = delete $options{html}; | ||||
| 50 | |||||||
| 51 | 0 | 0 | 0 | unless ( $content ) { | |||
| 52 | 0 | 0 | $content = $self->{mech}->get_content($self->build_uri(%options)); | ||||
| 53 | } | ||||||
| 54 | 0 | 0 | 0 | die "no content" unless $content; | |||
| 55 | |||||||
| 56 | # XXX: preserve some tags like ? |
||||||
| 57 | # $content =~ s/ ]*)?>/\n/g; # at least preserve as a space |
||||||
| 58 | 0 | 0 | $content =~ s/ / /g; # as it'd be converted as '?' | ||||
| 59 | |||||||
| 60 | 0 | 0 | return $content; | ||||
| 61 | } | ||||||
| 62 | |||||||
| 63 | sub build_uri { | ||||||
| 64 | 0 | 0 | 1 | 0 | my ($self, %query) = @_; | ||
| 65 | |||||||
| 66 | 0 | 0 | my ($name) = (ref $self) =~ /::(\w+)$/; | ||||
| 67 | 0 | 0 | my $path = sprintf '/%s.pl', decamelize($name); | ||||
| 68 | 0 | 0 | my $uri = URI->new($path); | ||||
| 69 | |||||||
| 70 | 0 | 0 | foreach my $key ( keys %query ) { | ||||
| 71 | 0 | 0 | 0 | if ( $self->_is_valid( $key, $query{$key} ) ) { | |||
| 72 | 0 | 0 | $uri->query_param( $key => $query{$key} ); | ||||
| 73 | } | ||||||
| 74 | } | ||||||
| 75 | |||||||
| 76 | 0 | 0 | 0 | $uri = $self->tweak_uri($uri) if $self->can('tweak_uri'); | |||
| 77 | |||||||
| 78 | 0 | 0 | $self->{uri} = $uri; # preserve for later use. | ||||
| 79 | |||||||
| 80 | 0 | 0 | return $uri; | ||||
| 81 | } | ||||||
| 82 | |||||||
| 83 | sub validator ($) { | ||||||
| 84 | 12 | 12 | 1 | 28 | my $hashref = shift; | ||
| 85 | 12 | 27 | my $pkg = caller; | ||||
| 86 | |||||||
| 87 | 12 | 20 | my %rules; | ||||
| 88 | 12 | 33 | foreach my $key ( keys %{ $hashref } ) { | ||||
| 12 | 45 | ||||||
| 89 | 24 | 39 | my $rule = $hashref->{$key}; | ||||
| 90 | 24 | 100 | 72 | if ( $rule eq 'is_number' ) { | |||
| 91 | $rules{$key} = sub { | ||||||
| 92 | 0 | 0 | 0 | my $value = shift; | |||
| 93 | 0 | 0 | 0 | 0 | $value && $value =~ /^\d+$/ ? 1 : 0; | ||
| 94 | 16 | 62 | }; | ||||
| 95 | } | ||||||
| 96 | 24 | 100 | 57 | if ( $rule eq 'is_number_or_all' ) { | |||
| 97 | $rules{$key} = sub { | ||||||
| 98 | 0 | 0 | 0 | my $value = shift; | |||
| 99 | 0 | 0 | 0 | 0 | $value && $value =~ /^(?:\d+|all)$/ ? 1 : 0; | ||
| 100 | 2 | 15 | }; | ||||
| 101 | } | ||||||
| 102 | 24 | 100 | 63 | if ( $rule eq 'is_anything' ) { | |||
| 103 | 3 | 0 | 15 | $rules{$key} = sub { 1 }; | |||
| 0 | 0 | ||||||
| 104 | } | ||||||
| 105 | } | ||||||
| 106 | |||||||
| 107 | 1 | 1 | 6 | no strict 'refs'; | |||
| 1 | 1 | ||||||
| 1 | 32 | ||||||
| 108 | 1 | 1 | 10 | no warnings 'redefine'; | |||
| 1 | 1 | ||||||
| 1 | 719 | ||||||
| 109 | 12 | 0 | 0 | 44 | *{"$pkg\::_is_valid"} = sub { return $rules{$_[1]} && $rules{$_[1]}->($_[2]) }; | ||
| 12 | 101 | ||||||
| 0 | |||||||
| 110 | } | ||||||
| 111 | |||||||
| 112 | sub post_process { | ||||||
| 113 | 0 | 0 | 1 | my ($self, $data, $callback) = @_; | |||
| 114 | |||||||
| 115 | 0 | my $arrayref = _force_arrayref($data); | |||||
| 116 | |||||||
| 117 | 0 | foreach my $item ( @{ $arrayref } ) { | |||||
| 0 | |||||||
| 118 | 0 | 0 | if ( ref $callback eq 'CODE' ) { | ||||
| 119 | 0 | $callback->($item); | |||||
| 120 | } | ||||||
| 121 | 0 | foreach my $key ( keys %{ $item } ) { | |||||
| 0 | |||||||
| 122 | 0 | 0 | next unless $item->{$key}; | ||||
| 123 | 0 | 0 | if ( $key =~ /time$/ ) { | ||||
| 0 | |||||||
| 0 | |||||||
| 124 | 0 | $item->{$key} = _datetime($item->{$key}) | |||||
| 125 | } | ||||||
| 126 | elsif ( $key =~ /(?:link|envelope|image|background|src|icon)$/ ) { | ||||||
| 127 | 0 | $item->{$key} = _uri($item->{$key}); | |||||
| 128 | } | ||||||
| 129 | elsif ( $key eq 'images' ) { | ||||||
| 130 | 0 | $item->{$key} = _images($item->{$key}); | |||||
| 131 | } | ||||||
| 132 | } | ||||||
| 133 | } | ||||||
| 134 | |||||||
| 135 | 0 | 0 | $arrayref = [ grep { %{ $_ } && !$_->{_delete} } @{ $arrayref } ]; | ||||
| 0 | |||||||
| 0 | |||||||
| 0 | |||||||
| 136 | |||||||
| 137 | 0 | return $arrayref; | |||||
| 138 | } | ||||||
| 139 | |||||||
| 140 | sub _images { | ||||||
| 141 | 0 | 0 | my $item = shift; | ||||
| 142 | |||||||
| 143 | 0 | 0 | $item = [ $item ] unless ref $item; # a thumbnail | ||||
| 144 | |||||||
| 145 | 0 | my @images; | |||||
| 146 | 0 | 0 | foreach my $i ( @{ $item || [] } ) { | ||||
| 0 | |||||||
| 147 | 0 | 0 | next unless $item; | ||||
| 148 | 0 | push @images, __images($i); | |||||
| 149 | } | ||||||
| 150 | 0 | return \@images; | |||||
| 151 | } | ||||||
| 152 | |||||||
| 153 | sub __images { | ||||||
| 154 | 0 | 0 | my $item = shift; | ||||
| 155 | 0 | my ($link, $thumb); | |||||
| 156 | 0 | 0 | unless ( ref $item eq 'HASH' ) { | ||||
| 157 | 0 | $link = $thumb = $item; | |||||
| 158 | 0 | $link =~ s/s\.jpg$/\.jpg/; | |||||
| 159 | 0 | $thumb =~ s/(?:[^s])\.jpg$/s\.jpg/; | |||||
| 160 | } | ||||||
| 161 | else { | ||||||
| 162 | 0 | 0 | $link = $item->{link} || ''; | ||||
| 163 | 0 | $thumb = $item->{thumb_link}; | |||||
| 164 | |||||||
| 165 | 0 | 0 | if ( $link =~ /MM_openBrWindow\(\s*'([^']+)'/ ) { $link = $1; } | ||||
| 0 | |||||||
| 166 | } | ||||||
| 167 | 0 | return { link => _uri($link), thumb_link => _uri($thumb) }; | |||||
| 168 | } | ||||||
| 169 | |||||||
| 170 | sub _extract_name { | ||||||
| 171 | 0 | 0 | my $item = shift; | ||||
| 172 | |||||||
| 173 | 0 | 0 | 0 | return unless defined $item->{string} && defined $item->{subject}; | |||
| 174 | |||||||
| 175 | 0 | my $name = substr( delete $item->{string}, length $item->{subject} ); | |||||
| 176 | 0 | $name =~ s/^\s*\(//; | |||||
| 177 | 0 | $name =~ s/\)\s*$//; | |||||
| 178 | 0 | $item->{name} = $name; | |||||
| 179 | } | ||||||
| 180 | |||||||
| 181 | 1; | ||||||
| 182 | |||||||
| 183 | __END__ |