| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  |  | 
| 2 |  |  |  |  |  |  | package CGI::RSS; | 
| 3 |  |  |  |  |  |  |  | 
| 4 | 8 |  |  | 8 |  | 23277 | use strict; | 
|  | 8 |  |  |  |  | 11 |  | 
|  | 8 |  |  |  |  | 240 |  | 
| 5 | 8 |  |  | 8 |  | 3129 | use Date::Manip; | 
|  | 8 |  |  |  |  | 906221 |  | 
|  | 8 |  |  |  |  | 972 |  | 
| 6 | 8 |  |  | 8 |  | 4582 | use AutoLoader; | 
|  | 8 |  |  |  |  | 8793 |  | 
|  | 8 |  |  |  |  | 38 |  | 
| 7 | 8 |  |  | 8 |  | 8983 | use CGI; | 
|  | 8 |  |  |  |  | 93761 |  | 
|  | 8 |  |  |  |  | 49 |  | 
| 8 | 8 |  |  | 8 |  | 438 | use Carp; | 
|  | 8 |  |  |  |  | 11 |  | 
|  | 8 |  |  |  |  | 523 |  | 
| 9 | 8 |  |  | 8 |  | 35 | use Scalar::Util qw(blessed); | 
|  | 8 |  |  |  |  | 8 |  | 
|  | 8 |  |  |  |  | 526 |  | 
| 10 |  |  |  |  |  |  |  | 
| 11 | 8 |  |  | 8 |  | 36 | no warnings; | 
|  | 8 |  |  |  |  | 12 |  | 
|  | 8 |  |  |  |  | 1801 |  | 
| 12 |  |  |  |  |  |  |  | 
| 13 |  |  |  |  |  |  | our $VERSION = '0.9658'; | 
| 14 |  |  |  |  |  |  | our $pubDate_format = '%a, %d %b %Y %H:%M:%S %z'; | 
| 15 |  |  |  |  |  |  |  | 
| 16 |  |  |  |  |  |  | # Make sure we have a TZ | 
| 17 |  |  |  |  |  |  | unless( eval {Date_TimeZone(); 1} ) { | 
| 18 |  |  |  |  |  |  | $ENV{TZ} = "UTC" if $@ =~ m/unable to determine Time Zone/i; | 
| 19 |  |  |  |  |  |  | } | 
| 20 |  |  |  |  |  |  |  | 
| 21 |  |  |  |  |  |  | sub pubDate_format { | 
| 22 | 1 |  |  | 1 | 0 | 781 | my $class_or_instance = shift; | 
| 23 | 1 |  |  |  |  | 3 | my $proposed = shift; | 
| 24 |  |  |  |  |  |  |  | 
| 25 | 1 |  |  |  |  | 2 | $pubDate_format = $proposed; | 
| 26 | 1 |  |  |  |  | 2 | $pubDate_format | 
| 27 |  |  |  |  |  |  | } | 
| 28 |  |  |  |  |  |  |  | 
| 29 |  |  |  |  |  |  | our @TAGS = qw( | 
| 30 |  |  |  |  |  |  | rss channel item | 
| 31 |  |  |  |  |  |  |  | 
| 32 |  |  |  |  |  |  | title link description | 
| 33 |  |  |  |  |  |  |  | 
| 34 |  |  |  |  |  |  | language copyright managingEditor webMaster pubDate lastBuildDate category generator docs | 
| 35 |  |  |  |  |  |  | cloud ttl image rating textInput skipHours skipDays | 
| 36 |  |  |  |  |  |  |  | 
| 37 |  |  |  |  |  |  | link description author category comments enclosure guid pubDate source | 
| 38 |  |  |  |  |  |  |  | 
| 39 |  |  |  |  |  |  | pubDate url | 
| 40 |  |  |  |  |  |  | ); | 
| 41 |  |  |  |  |  |  |  | 
| 42 |  |  |  |  |  |  | setup_tag($_) for @TAGS; | 
| 43 |  |  |  |  |  |  |  | 
| 44 |  |  |  |  |  |  | sub grok_args { | 
| 45 | 38 | 100 |  | 38 | 0 | 103 | my $this  = blessed($_[0]) ? shift : __PACKAGE__->new; | 
| 46 | 38 | 100 |  |  |  | 66 | my $attrs = ref($_[0]) eq "HASH" ? shift : undef; | 
| 47 |  |  |  |  |  |  |  | 
| 48 | 38 | 100 |  |  |  | 55 | if( ref($_[0]) eq "ARRAY" ) { | 
| 49 | 4 |  |  |  |  | 9 | return ($this,$attrs,undef,$_[0]); | 
| 50 |  |  |  |  |  |  | } | 
| 51 |  |  |  |  |  |  |  | 
| 52 | 34 |  |  |  |  | 66 | return ($this,$attrs,join(" ", @_),undef); | 
| 53 |  |  |  |  |  |  | } | 
| 54 |  |  |  |  |  |  |  | 
| 55 |  |  |  |  |  |  | sub setup_tag { | 
| 56 | 264 |  |  | 264 | 0 | 258 | my $tag = shift; | 
| 57 |  |  |  |  |  |  |  | 
| 58 |  |  |  |  |  |  | # try to mimick CGI.pm (which is very unfriendly about new tags now) | 
| 59 |  |  |  |  |  |  |  | 
| 60 | 8 |  |  | 8 |  | 39 | no strict 'refs'; | 
|  | 8 |  |  |  |  | 11 |  | 
|  | 8 |  |  |  |  | 4224 |  | 
| 61 |  |  |  |  |  |  |  | 
| 62 | 264 |  |  |  |  | 949 | *{ __PACKAGE__ . "::$tag" } = sub { | 
| 63 | 36 |  |  | 36 |  | 45068 | my ($this, $attrs, $contents, $subs) = grok_args(@_); | 
| 64 | 36 |  |  |  |  | 35 | my $res; | 
| 65 |  |  |  |  |  |  |  | 
| 66 | 36 | 100 |  |  |  | 41 | if( $subs ) { | 
| 67 | 4 | 100 |  |  |  | 22 | $res = join("", map { $this->$tag( ($attrs ? $attrs : ()), $_ ) } @$subs ); | 
|  | 16 |  |  |  |  | 58 |  | 
| 68 |  |  |  |  |  |  |  | 
| 69 |  |  |  |  |  |  | } else { | 
| 70 | 32 |  |  |  |  | 26 | $res = "<$tag"; | 
| 71 |  |  |  |  |  |  |  | 
| 72 | 32 | 100 |  |  |  | 48 | if( $attrs ) { | 
| 73 | 10 |  |  |  |  | 14 | for(values %$attrs) { | 
| 74 |  |  |  |  |  |  | # XXX: this is a terrible way to do this, better than nothing for now | 
| 75 | 10 |  |  |  |  | 15 | s/(? | 
| 76 |  |  |  |  |  |  | } | 
| 77 |  |  |  |  |  |  |  | 
| 78 | 10 |  |  |  |  | 12 | $res .= " " . join(" ", map {"$_=\"$attrs->{$_}\""} keys %$attrs); | 
|  | 10 |  |  |  |  | 19 |  | 
| 79 |  |  |  |  |  |  | } | 
| 80 |  |  |  |  |  |  |  | 
| 81 | 32 |  |  |  |  | 46 | $res .= ">$contents$tag>"; | 
| 82 |  |  |  |  |  |  | } | 
| 83 |  |  |  |  |  |  |  | 
| 84 | 36 |  |  |  |  | 149 | return $res; | 
| 85 | 264 |  |  |  |  | 802 | }; | 
| 86 |  |  |  |  |  |  |  | 
| 87 | 264 |  |  |  |  | 752 | *{ __PACKAGE__ . "::start_$tag" } = sub { | 
| 88 | 2 |  |  | 2 |  | 14 | my ($this, $attrs) = grok_args(@_); | 
| 89 | 2 |  |  |  |  | 5 | my $res = "<$tag"; | 
| 90 |  |  |  |  |  |  |  | 
| 91 | 2 | 50 |  |  |  | 11 | if( $attrs ) { | 
| 92 | 0 |  |  |  |  | 0 | for(values %$attrs) { | 
| 93 |  |  |  |  |  |  | # XXX: this is a terrible way to do this, better than nothing for now | 
| 94 | 0 |  |  |  |  | 0 | s/(? | 
| 95 |  |  |  |  |  |  | } | 
| 96 |  |  |  |  |  |  |  | 
| 97 | 0 |  |  |  |  | 0 | $res .= " " . join(" ", map {"$_=\"$attrs->{$_}\""} keys %$attrs); | 
|  | 0 |  |  |  |  | 0 |  | 
| 98 |  |  |  |  |  |  | } | 
| 99 |  |  |  |  |  |  |  | 
| 100 | 2 |  |  |  |  | 18 | return $res . ">"; | 
| 101 | 264 |  |  |  |  | 639 | }; | 
| 102 |  |  |  |  |  |  |  | 
| 103 | 264 |  |  | 0 |  | 488 | *{ __PACKAGE__ . "::end_$tag" } = sub { "$tag>" }; | 
|  | 264 |  |  |  |  | 904 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 104 |  |  |  |  |  |  | } | 
| 105 |  |  |  |  |  |  |  | 
| 106 |  |  |  |  |  |  | sub AUTOLOAD { | 
| 107 | 0 |  |  | 0 |  | 0 | my $this = shift; | 
| 108 | 0 |  |  |  |  | 0 | our $AUTOLOAD; | 
| 109 |  |  |  |  |  |  |  | 
| 110 | 0 | 0 |  |  |  | 0 | if( my ($fname) = $AUTOLOAD =~ m/::([^:]+)$/ ) { | 
| 111 | 0 | 0 |  |  |  | 0 | if( CGI->can($fname) ) { | 
| 112 | 0 |  |  |  |  | 0 | *{ __PACKAGE__ . "::$fname" } = sub { | 
| 113 | 0 |  |  | 0 |  | 0 | my $this = shift; | 
| 114 | 0 |  |  |  |  | 0 | return CGI->$fname(@_); | 
| 115 |  |  |  |  |  |  | } | 
| 116 | 0 |  |  |  |  | 0 | } | 
| 117 |  |  |  |  |  |  |  | 
| 118 |  |  |  |  |  |  | else { | 
| 119 | 0 |  |  |  |  | 0 | croak "can't figure out what to do with $fname() call"; | 
| 120 |  |  |  |  |  |  | } | 
| 121 |  |  |  |  |  |  | } | 
| 122 |  |  |  |  |  |  | } | 
| 123 |  |  |  |  |  |  |  | 
| 124 |  |  |  |  |  |  | sub new { | 
| 125 | 12 |  |  | 12 | 0 | 5403 | my $class = shift; | 
| 126 | 12 |  |  |  |  | 29 | my $this = bless {}, $class; | 
| 127 |  |  |  |  |  |  |  | 
| 128 | 12 |  |  |  |  | 21 | return $this; | 
| 129 |  |  |  |  |  |  | } | 
| 130 |  |  |  |  |  |  |  | 
| 131 |  |  |  |  |  |  | sub date { | 
| 132 | 2 |  |  | 2 | 0 | 3 | my $this = shift; | 
| 133 |  |  |  |  |  |  |  | 
| 134 | 2 | 50 |  |  |  | 35 | if( my $pd = ParseDate($_[-1]) ) { | 
| 135 | 2 |  |  |  |  | 839 | my $date = UnixDate($pd, $pubDate_format); | 
| 136 | 2 |  |  |  |  | 827 | return $this->pubDate($date); | 
| 137 |  |  |  |  |  |  | } | 
| 138 |  |  |  |  |  |  |  | 
| 139 | 0 |  |  |  |  |  | $this->pubDate(@_); | 
| 140 |  |  |  |  |  |  | } | 
| 141 |  |  |  |  |  |  |  | 
| 142 |  |  |  |  |  |  | sub header { | 
| 143 | 0 |  |  | 0 | 0 |  | my $this = shift; | 
| 144 |  |  |  |  |  |  |  | 
| 145 | 0 |  |  |  |  |  | my $charset = "UTF-8"; | 
| 146 | 0 |  |  |  |  |  | my $mime    = "application/xml"; | 
| 147 |  |  |  |  |  |  |  | 
| 148 | 0 |  |  |  |  |  | eval { | 
| 149 | 8 |  |  | 8 |  | 40 | no warnings; | 
|  | 8 |  |  |  |  | 9 |  | 
|  | 8 |  |  |  |  | 2048 |  | 
| 150 | 0 |  |  | 0 |  |  | local $SIG{WARN} = sub{}; | 
|  | 0 |  |  |  |  |  |  | 
| 151 | 0 |  |  |  |  |  | my %opts = @_; | 
| 152 | 0 |  | 0 |  |  |  | $charset = $opts{'-charset'} || $opts{charset} || $charset; | 
| 153 | 0 |  | 0 |  |  |  | $mime    = $opts{'-type'} || $opts{type} || (@_==1 && $_[0]) || $mime; | 
| 154 |  |  |  |  |  |  | }; | 
| 155 |  |  |  |  |  |  |  | 
| 156 | 0 |  |  |  |  |  | return CGI::header(-type=>$mime, -charset=>$charset) . "\n\n"; | 
| 157 |  |  |  |  |  |  | } | 
| 158 |  |  |  |  |  |  |  | 
| 159 |  |  |  |  |  |  | sub begin_rss { | 
| 160 | 0 |  |  | 0 | 0 |  | my $this = shift; | 
| 161 | 0 |  |  |  |  |  | my $opts = $_[0]; | 
| 162 | 0 | 0 |  |  |  |  | $opts = {@_} unless ref $opts; | 
| 163 |  |  |  |  |  |  |  | 
| 164 |  |  |  |  |  |  | # NOTE: This isn't nearly as smart as CGI.pm's argument parsing... | 
| 165 |  |  |  |  |  |  | # I assume I could call it, but but I'm only mortal. | 
| 166 |  |  |  |  |  |  |  | 
| 167 | 0 |  | 0 |  |  |  | my $ver = $opts->{version} || "2.0"; | 
| 168 | 0 |  |  |  |  |  | my $ret = $this->start_rss({version=>$ver}); | 
| 169 | 0 |  |  |  |  |  | $ret .= $this->start_channel; | 
| 170 | 0 | 0 |  |  |  |  | $ret .= $this->link($opts->{link})        if exists $opts->{link}; | 
| 171 | 0 | 0 |  |  |  |  | $ret .= $this->title($opts->{title})      if exists $opts->{title}; | 
| 172 | 0 | 0 |  |  |  |  | $ret .= $this->description($opts->{desc}) if exists $opts->{desc}; | 
| 173 |  |  |  |  |  |  |  | 
| 174 | 0 |  |  |  |  |  | return $ret; | 
| 175 |  |  |  |  |  |  | } | 
| 176 |  |  |  |  |  |  |  | 
| 177 |  |  |  |  |  |  | sub finish_rss { | 
| 178 | 0 |  |  | 0 | 0 |  | my $this = shift; | 
| 179 |  |  |  |  |  |  |  | 
| 180 | 0 |  |  |  |  |  | return $this->end_channel . $this->end_rss; | 
| 181 |  |  |  |  |  |  | } | 
| 182 |  |  |  |  |  |  |  | 
| 183 |  |  |  |  |  |  | "This file is true." | 
| 184 |  |  |  |  |  |  |  | 
| 185 |  |  |  |  |  |  | __END__ |