| blib/lib/WWW/UsePerl/Journal/Comment.pm | |||
|---|---|---|---|
| Criterion | Covered | Total | % |
| statement | 74 | 81 | 91.3 |
| branch | 22 | 30 | 73.3 |
| condition | n/a | ||
| subroutine | 14 | 15 | 93.3 |
| pod | 2 | 2 | 100.0 |
| total | 112 | 128 | 87.5 |
| line | stmt | bran | cond | sub | pod | time | code |
|---|---|---|---|---|---|---|---|
| 1 | package WWW::UsePerl::Journal::Comment; | ||||||
| 2 | |||||||
| 3 | 6 | 6 | 22821 | use strict; | |||
| 6 | 8 | ||||||
| 6 | 201 | ||||||
| 4 | 6 | 6 | 25 | use warnings; | |||
| 6 | 7 | ||||||
| 6 | 178 | ||||||
| 5 | |||||||
| 6 | 6 | 6 | 20 | use vars qw($VERSION $AUTOLOAD); | |||
| 6 | 10 | ||||||
| 6 | 394 | ||||||
| 7 | $VERSION = '0.15'; | ||||||
| 8 | |||||||
| 9 | #---------------------------------------------------------------------------- | ||||||
| 10 | |||||||
| 11 | =head1 NAME | ||||||
| 12 | |||||||
| 13 | WWW::UsePerl::Journal::Comment - Handles the retrieval of UsePerl journal entry comments. | ||||||
| 14 | |||||||
| 15 | =head1 SYNOPSIS | ||||||
| 16 | |||||||
| 17 | my $comment = WWW::UsePerl::Journal::Comment->new( | ||||||
| 18 | # required | ||||||
| 19 | j => $journal, | ||||||
| 20 | cid => $commentid, | ||||||
| 21 | eid => $entryid, | ||||||
| 22 | extract => $extract | ||||||
| 23 | ); | ||||||
| 24 | |||||||
| 25 | $comment->subject(); | ||||||
| 26 | |||||||
| 27 | # called from WWW::UsePerl::Journal::Thread object | ||||||
| 28 | $thread->comment( $cid )->content(); | ||||||
| 29 | |||||||
| 30 | =head1 DESCRIPTION | ||||||
| 31 | |||||||
| 32 | A collection of routines to handle the retrieval of comments from a | ||||||
| 33 | UsePerl (L |
||||||
| 34 | |||||||
| 35 | =cut | ||||||
| 36 | |||||||
| 37 | # ------------------------------------- | ||||||
| 38 | # Library Modules | ||||||
| 39 | |||||||
| 40 | 6 | 6 | 25 | use base qw(Class::Accessor::Fast); | |||
| 6 | 10 | ||||||
| 6 | 3051 | ||||||
| 41 | |||||||
| 42 | 6 | 6 | 13769 | use HTTP::Request::Common; | |||
| 6 | 59780 | ||||||
| 6 | 434 | ||||||
| 43 | 6 | 6 | 4247 | use LWP::UserAgent; | |||
| 6 | 65284 | ||||||
| 6 | 131 | ||||||
| 44 | 6 | 6 | 2026 | use Time::Piece; | |||
| 6 | 13670 | ||||||
| 6 | 33 | ||||||
| 45 | 6 | 6 | 6781 | use WWW::UsePerl::Journal; | |||
| 6 | 186988 | ||||||
| 6 | 2207 | ||||||
| 46 | |||||||
| 47 | # ------------------------------------- | ||||||
| 48 | # Constants & Variables | ||||||
| 49 | |||||||
| 50 | 6 | 6 | 64 | use constant USEPERL => 'http://use.perl.org/use.perl.org'; | |||
| 6 | 9 | ||||||
| 6 | 683 | ||||||
| 51 | 6 | 6 | 32 | use overload q{""} => sub { $_[0]->stringify() }; | |||
| 6 | 2 | 8 | |||||
| 6 | 63 | ||||||
| 2 | 7437 | ||||||
| 52 | |||||||
| 53 | my %months = ( | ||||||
| 54 | 'January' => 1, | ||||||
| 55 | 'February' => 2, | ||||||
| 56 | 'March' => 3, | ||||||
| 57 | 'April' => 4, | ||||||
| 58 | 'May' => 5, | ||||||
| 59 | 'June' => 6, | ||||||
| 60 | 'July' => 7, | ||||||
| 61 | 'August' => 8, | ||||||
| 62 | 'September' => 9, | ||||||
| 63 | 'October' => 10, | ||||||
| 64 | 'November' => 11, | ||||||
| 65 | 'December' => 12, | ||||||
| 66 | ); | ||||||
| 67 | |||||||
| 68 | # ------------------------------------- | ||||||
| 69 | # Public Interface | ||||||
| 70 | |||||||
| 71 | =head1 PUBLIC INTERFACE | ||||||
| 72 | |||||||
| 73 | =head2 The Constructor | ||||||
| 74 | |||||||
| 75 | =over 4 | ||||||
| 76 | |||||||
| 77 | =item new | ||||||
| 78 | |||||||
| 79 | Each comment is retrieved as an object. Note that the parent object | ||||||
| 80 | (from WWW::UsePerl::Journal), thread id and comment id are mandatory | ||||||
| 81 | requirements to create the object. | ||||||
| 82 | |||||||
| 83 | =back | ||||||
| 84 | |||||||
| 85 | =cut | ||||||
| 86 | |||||||
| 87 | sub new { | ||||||
| 88 | 10 | 10 | 1 | 3854 | my ($class,%opts) = @_; | ||
| 89 | |||||||
| 90 | 10 | 25 | for(qw/j eid cid extract/) { | ||||
| 91 | 37 | 100 | 89 | return unless(exists $opts{$_}); | |||
| 92 | } | ||||||
| 93 | |||||||
| 94 | 9 | 100 | 69 | die "No parent object" | |||
| 95 | unless $opts{j}->isa('WWW::UsePerl::Journal'); | ||||||
| 96 | |||||||
| 97 | 8 | 15 | my %atts = map {$_ => $opts{$_}} qw(j eid cid extract); | ||||
| 32 | 74 | ||||||
| 98 | 8 | 30 | my $self = bless \%atts, $class; | ||||
| 99 | |||||||
| 100 | 8 | 17 | $self->_get_content(); | ||||
| 101 | |||||||
| 102 | 8 | 55 | return $self; | ||||
| 103 | } | ||||||
| 104 | |||||||
| 105 | #---------------------------------------------------------------------------- | ||||||
| 106 | # Accessors | ||||||
| 107 | |||||||
| 108 | =head2 The Accessors | ||||||
| 109 | |||||||
| 110 | The following accessor methods are available: | ||||||
| 111 | |||||||
| 112 | id | ||||||
| 113 | date | ||||||
| 114 | subject | ||||||
| 115 | user | ||||||
| 116 | uid | ||||||
| 117 | score | ||||||
| 118 | content | ||||||
| 119 | |||||||
| 120 | All functions can be called to return the current value of the associated | ||||||
| 121 | object variable. | ||||||
| 122 | |||||||
| 123 | =cut | ||||||
| 124 | |||||||
| 125 | __PACKAGE__->mk_accessors($_) for qw(cid date subject user uid score content); | ||||||
| 126 | |||||||
| 127 | =head2 Methods | ||||||
| 128 | |||||||
| 129 | =over 4 | ||||||
| 130 | |||||||
| 131 | =item stringify - For String Context | ||||||
| 132 | |||||||
| 133 | When an object is called directly, stringification occurs. Safer to | ||||||
| 134 | use -E |
||||||
| 135 | |||||||
| 136 | =back | ||||||
| 137 | |||||||
| 138 | =cut | ||||||
| 139 | |||||||
| 140 | sub stringify { | ||||||
| 141 | 2 | 2 | 1 | 5 | my $self = shift; | ||
| 142 | 2 | 5 | return $self->content(); | ||||
| 143 | } | ||||||
| 144 | |||||||
| 145 | # ------------------------------------- | ||||||
| 146 | # The Private Subs | ||||||
| 147 | |||||||
| 148 | # name: _get_content | ||||||
| 149 | # args: self .... object itself | ||||||
| 150 | # retv: content text | ||||||
| 151 | # desc: Retrieves the content and additional information for a given | ||||||
| 152 | # comment. Splits the fields into object variables and returns | ||||||
| 153 | # the content text | ||||||
| 154 | |||||||
| 155 | sub _get_content { | ||||||
| 156 | 8 | 8 | 12 | my $self = shift; | |||
| 157 | |||||||
| 158 | 8 | 96 | my $content = $self->{extract}; | ||||
| 159 | |||||||
| 160 | 8 | 100 | 21 | if($self->{j}->debug) { | |||
| 161 | 3 | 23 | $self->{j}->log('mess' => "\n#_get_content: content=[$content]\n"); | ||||
| 162 | } | ||||||
| 163 | |||||||
| 164 | 8 | 100 | 77 | return $self->{j}->error("Error getting entry") unless $content; | |||
| 165 | |||||||
| 166 | # remember there are different presentations for dates!!!! | ||||||
| 167 | |||||||
| 168 | 7 | 8 | my ($string,$format); | ||||
| 169 | 7 | 97 | $content =~ s/\n//g; | ||||
| 170 | 7 | 131 | my @fields = ( $content =~ m! | ||||
| 171 | |
||||||
| 172 | .*? ]+>([^<]+) # subject |
||||||
| 173 | .*? | ||||||
| 174 | .*? Score:(\d+).*? # score | ||||||
| 175 | .*? \s*(\w+) # username | ||||||
| 176 | .*? \((\d+)\) # userid | ||||||
| 177 | (?:\s+ | ||||||
| 178 | .*? on\s+(\d+\.\d+.\d+\s\d+:\d+) # date/time - "2003.05.20 17:31" or "Friday August 08 2003, @01:51PM" | ||||||
| 179 | .*? )? | ||||||
| 180 | .*? (.*?) # text |
||||||
| 181 | !mixs ); | ||||||
| 182 | |||||||
| 183 | 7 | 32 | ($self->{pid}) = $content =~ m/id="commtree_(\d+)"/; | ||||
| 184 | |||||||
| 185 | 7 | 100 | 18 | if($self->{j}->debug) { | |||
| 186 | 3 | 100 | 17 | $self->{j}->log('mess' => "\n#_get_content: fields=[".(join("][",map {$_||''} @fields))."]\n"); | |||
| 21 | 49 | ||||||
| 187 | } | ||||||
| 188 | |||||||
| 189 | 7 | 100 | 56 | return unless(@fields); | |||
| 190 | |||||||
| 191 | 6 | 100 | 15 | if($fields[5]) { | |||
| 192 | 2 | 16 | my ($year, $month, $day, $hr, $mi) = $fields[5] =~ m! (\d+)\.(\d+)\.(\d+) .*? (\d+):(\d+) !smx; | ||||
| 193 | 2 | 50 | 6 | unless($day) { | |||
| 194 | 0 | 0 | my $amp; | ||||
| 195 | 0 | 0 | ($month, $day, $year, $hr, $mi, $amp) = $fields[5] =~ m! \w+\s+ (\w+) \s+(\d+)\s*(\d*), \s+ @(\d+):(\d+)([AP]M) !smx; | ||||
| 196 | 0 | 0 | $month = $months{$month}; | ||||
| 197 | 0 | 0 | 0 | $year = (localtime)[5] unless($year); # current year formatting drops the year. | |||
| 198 | 0 | 0 | 0 | $hr += 12 if ($amp eq 'PM'); | |||
| 199 | 0 | 0 | 0 | $hr = 0 if $hr == 24; | |||
| 200 | } | ||||||
| 201 | |||||||
| 202 | 2 | 100 | 7 | if($self->{j}->debug) { | |||
| 203 | 1 | 9 | $self->{j}->log('mess' => "\n#_get_content: date=[$year $month $day ${hr}:$mi]\n"); | ||||
| 204 | } | ||||||
| 205 | |||||||
| 206 | # sometimes Time::Piece can't parse the date :( | ||||||
| 207 | 2 | 15 | eval { | ||||
| 208 | 2 | 27 | $self->{date} = Time::Piece->strptime( | ||||
| 209 | "$month $day $year ${hr}:$mi", | ||||||
| 210 | '%m %d %Y %H:%M' | ||||||
| 211 | ); | ||||||
| 212 | }; | ||||||
| 213 | |||||||
| 214 | 2 | 100 | 87 | if($self->{j}->debug) { | |||
| 215 | 1 | 80 | $self->{j}->log('mess' => "\n#_get_content: date=[".$self->{date}."]\n"); | ||||
| 216 | } | ||||||
| 217 | } | ||||||
| 218 | |||||||
| 219 | 6 | 94 | $self->{subject} = $fields[1]; | ||||
| 220 | 6 | 10 | $self->{score} = $fields[2]; | ||||
| 221 | 6 | 13 | $self->{user} = $fields[3]; | ||||
| 222 | 6 | 9 | $self->{uid} = $fields[4]; | ||||
| 223 | 6 | 8 | $self->{content} = $fields[6]; | ||||
| 224 | |||||||
| 225 | 6 | 50 | 15 | return unless($self->{content}); # What no content! | |||
| 226 | |||||||
| 227 | 6 | 573 | $self->{content} =~ s!(\s+<(?:p|br /)>)*$!!gi; # remove trailing whitespace formatting | ||||
| 228 | 6 | 75 | $self->{content} =~ s!\s+(<(p|br /)>)!$1!gi; # remove whitespace before whitespace formatting | ||||
| 229 | 6 | 33 | $self->{content} =~ s!(<(p|br /)>){2,}! !gi; # remove repeated whitespace formatting |
||||
| 230 | |||||||
| 231 | 6 | 18 | return; | ||||
| 232 | } | ||||||
| 233 | |||||||
| 234 | 0 | 0 | sub DESTROY {} | ||||
| 235 | |||||||
| 236 | 1; | ||||||
| 237 | |||||||
| 238 | __END__ |