File Coverage

blib/lib/Net/Google/Code/Role/Pageable.pm
Criterion Covered Total %
statement 79 84 94.0
branch 28 40 70.0
condition 4 5 80.0
subroutine 7 7 100.0
pod 1 1 100.0
total 119 137 86.8


line stmt bran cond sub pod time code
1             package Net::Google::Code::Role::Pageable;
2 10     10   7516 use Any::Moose 'Role';
  10         21  
  10         70  
3 10     10   4187 use Params::Validate ':all';
  10         19  
  10         2350  
4 10     10   57 use WWW::Mechanize;
  10         34  
  10         413  
5             with 'Net::Google::Code::Role::Fetchable';
6             with 'Net::Google::Code::Role::HTMLTree';
7 10     10   62 use Scalar::Util qw/blessed/;
  10         28  
  10         10967  
8              
9             sub rows {
10 4     4 1 10 my $self = shift;
11 4         751 my %args = validate(
12             @_,
13             {
14             html => { type => SCALAR | OBJECT },
15             limit => {
16             type => SCALAR | UNDEF,
17             optional => 1,
18             },
19             }
20             );
21              
22 4   100     44 $args{limit} ||= 999_999_999; # the impossible huge limit
23 4         8 my $tree = $args{html};
24 4         21 my $need_delete = not blessed $tree;
25 4 50       44 $tree = $self->html_tree( html => $tree ) unless blessed $tree;
26              
27             # assuming there's at most 20 columns
28 4         14 my @titles;
29             my $label_column;
30 4         19 for my $num ( 0 .. 20 ) {
31 30         141 my $title_tag = $tree->look_down( class => "col_$num" );
32 30 100       43184 if ( $title_tag ) {
33 26         102 my $title = $title_tag->as_text;
34 26 100       756 if ( $title eq "\x{a0}" ) {
35 3         16 $title_tag = ($tree->look_down( class => "col_$num" ))[1];
36 3         12612 $title = $title_tag->as_text;
37             }
38              
39 26 50       240 if ( $title =~ /(\w+)/ ) {
40 26         85 push @titles, lc $1;
41              
42 26 100       98 if ( $title =~ /label/i ) {
43 4         18 $label_column = $num;
44             }
45             }
46             }
47             else {
48 4         16 last;
49             }
50             }
51              
52 4 50       21 die "no idea what the column spec is" unless @titles;
53              
54 4         9 my @rows;
55              
56 4         27 my $pagination = $tree->look_down( class => 'pagination' );
57 4 50       4159 return unless $pagination;
58              
59 4 50       26 if ( $pagination->as_text =~ /\d+\s+-\s+\d+\s+of\s+\d+/ ) {
60             # all the rows in a page
61 4         178 push @rows, $self->_rows(
62             html => $tree,
63             titles => \@titles,
64             label_column => $label_column,
65             );
66              
67 4         24 while ( scalar @rows < $args{limit} ) {
68 4         42 my $next_link = $self->mech->find_link( text_regex => qr/Next\s+/ );
69 4 50       450 if ($next_link) {
70 0         0 $self->mech->get( $next_link->url );
71 0 0       0 if ( $self->mech->response->is_success ) {
72 0         0 push @rows, $self->_rows(
73             html => $self->mech->content,
74             titles => \@titles,
75             label_column => $label_column,
76             );
77             }
78             else {
79 0         0 die "failed to follow 'Next' link";
80             }
81             }
82             else {
83 4         13 last;
84             }
85             }
86             }
87              
88 4 50       38 $tree->delete if $need_delete;
89 4 50       23189 if ( scalar @rows > $args{limit} ) {
90             # this happens when limit is less than the 1st page's number, so in
91             # some similar situations
92 0         0 return @rows[0 .. $args{limit}-1];
93             }
94             else {
95 4         107 return @rows;
96             }
97             }
98              
99             sub _rows {
100 4     4   9 my $self = shift;
101 4         245 my %args = validate(
102             @_,
103             {
104             html => { type => SCALAR | OBJECT },
105             titles => { type => ARRAYREF, },
106             label_column => { optional => 1 },
107             }
108             );
109 4         36 my $tree = $args{html};
110 4         30 my $need_delete = not blessed $tree;
111 4 50       29 $tree = $self->html_tree( html => $tree ) unless blessed $tree;
112 4         12 my @titles = @{$args{titles}};
  4         24  
113 4         10 my $label_column = $args{label_column};
114              
115 4         9 my @columns;
116             my @rows;
117              
118 4         27 for ( my $i = 0 ; $i < @titles ; $i++ ) {
119 26         1027 my @tags = $tree->look_down( class => qr/^vt (id )?col_$i/ );
120 26         100110 my $k = 0;
121 26         131 for ( my $j = 0 ; $j < @tags ; $j++ ) {
122 202         695 my $column = $tags[$j]->as_text;
123 202 100       5929 next unless $column =~ /[-\w]/; # skip the '›' thing or alike
124              
125 178         488 my @elements = split /\x{a0}/, $column;
126 178         306 for ( @elements ) {
127 186         497 s/^\s+//;
128 186         671 s/\s+$//;
129             }
130 178         267 $column = shift @elements;
131 178 100       357 $column = '' if $column eq '----';
132              
133 178 100       322 if ( $i == 0 ) {
134 26         80 push @rows, { $titles[0] => $column };
135             }
136             else {
137 152         401 $rows[$k]{ $titles[$i] } = $column;
138             }
139              
140 178 100 66     767 if ( $label_column && $i == $label_column ) {
141 26         35 my @labels;
142 26 100       47 if (@elements) {
143 8         30 @labels = split /\s+/, shift @elements;
144             }
145 26 100       95 $rows[$k]{labels} = \@labels if @labels;
146             }
147 178         548 $k++;
148             }
149             }
150 4 50       16 $tree->delete if $need_delete;
151 4         37 return @rows;
152             }
153              
154 10     10   66 no Any::Moose;
  10         19  
  10         56  
155             1;
156              
157             __END__