-package WWW::OpenSearch::Response;\r
-\r
-use strict;\r
-use warnings;\r
-\r
-use base qw( HTTP::Response Class::Accessor::Fast );\r
-\r
+package WWW::OpenSearch::Response;
+
+use strict;
+use warnings;
+
+use base qw( HTTP::Response Class::Accessor::Fast );
+
use XML::Feed;
-use URI;\r
-use Data::Page;\r
-\r
-__PACKAGE__->mk_accessors( qw( feed pager parent ) );\r
-\r
-=head1 NAME\r
-\r
-WWW::OpenSearch::Response - Encapsulate a response received from\r
-an A9 OpenSearch compatible engine\r
-\r
-=head1 SYNOPSIS\r
- \r
- use WWW::OpenSearch;\r
- \r
- my $url = "http://bulkfeeds.net/opensearch.xml";\r
- my $engine = WWW::OpenSearch->new($url);\r
- \r
- # Retrieve page 4 of search results for "iPod"\r
- my $response = $engine->search("iPod",{ startPage => 4 });\r
- for my $item (@{$response->feed->items}) {\r
- print $item->{description};\r
- }\r
- \r
- # Retrieve page 3 of results\r
- $response = $response->previous_page;\r
- \r
- # Retrieve page 5 of results\r
- $response = $response->next_page;\r
- \r
-=head1 DESCRIPTION\r
-\r
-WWW::OpenSearch::Response is a module designed to encapsulate a\r
-response received from an A9 OpenSearch compatible engine.\r
-See http://opensearch.a9.com/spec/1.1/response/ for details.\r
-\r
-=head1 CONSTRUCTOR\r
-\r
-=head2 new( $parent, $response )\r
-\r
-Constructs a new instance of WWW::OpenSearch::Response. Arguments\r
-include the WWW::OpenSearch object which initiated the search (parent)\r
-and the HTTP::Response returned by the search request.\r
-\r
-=head1 METHODS\r
-\r
-=head2 parse_response( )\r
-\r
-Parses the content of the HTTP response using XML::Feed. If successful,\r
-parse_feed( ) is also called.\r
-\r
-=head2 parse_feed( )\r
-\r
-Parses the XML::Feed originally parsed from the HTTP response content.\r
-Sets the pager object appropriately.\r
-\r
-=head2 previous_page( ) / next_page( )\r
-\r
-Performs another search on the parent object, returning a\r
-WWW::OpenSearch::Response instance containing the previous/next page\r
-of results. If the current response includes a <link rel="previous/next"\r
-href="..." /> tag, the page will simply be the parsed content of the URL\r
-specified by the tag's href attribute. However, if the current response does not\r
-include the appropriate link, a new query is constructed using the startPage\r
-or startIndex query arguments.\r
-\r
-=head2 _get_link( $type )\r
-\r
-Gets the href attribute of the first link whose rel attribute\r
-is equal to $type.\r
-\r
-=head1 ACCESSORS\r
-\r
-=head2 feed( )\r
-\r
-=head2 pager( )\r
-\r
-=head2 parent( )\r
-\r
-=head1 AUTHOR\r
-\r
-=over 4\r
-\r
-=item * Tatsuhiko Miyagawa E<lt>miyagawa@bulknews.netE<gt>\r
-\r
-=item * Brian Cassidy E<lt>bricas@cpan.orgE<gt>\r
-\r
-=back\r
-\r
-=head1 COPYRIGHT AND LICENSE\r
-\r
-Copyright 2006 by Tatsuhiko Miyagawa and Brian Cassidy\r
-\r
-This library is free software; you can redistribute it and/or modify\r
-it under the same terms as Perl itself. \r
-\r
-=cut\r
-\r
-sub new {\r
- my $class = shift;\r
- my $parent = shift;\r
- my $response = shift;\r
- \r
- my $self = bless $response, $class;\r
-\r
- $self->parent( $parent );\r
- return $self unless $self->is_success;\r
- \r
- $self->parse_response;\r
- \r
- return $self;\r
-}\r
-\r
-sub parse_response {\r
- my $self = shift;\r
-\r
- my $content = $self->content;\r
- my $feed = XML::Feed->parse( \$content );\r
-\r
- return if XML::Feed->errstr;\r
- $self->feed( $feed );\r
- \r
- $self->parse_feed;\r
-}\r
-\r
-sub parse_feed {\r
- my $self = shift;\r
- my $pager = Data::Page->new;\r
-\r
- my $feed = $self->feed;\r
- my $format = $feed->format;\r
- my $ns = $self->parent->description->ns;\r
- \r
- # TODO\r
- # adapt these for any number of opensearch elements in\r
- # the feed or in each entry\r
- \r
- if( my $atom = $feed->{ atom } ) {\r
- my $total = $atom->get( $ns, 'totalResults' );\r
- my $perpage = $atom->get( $ns, 'itemsPerPage' );\r
- my $start = $atom->get( $ns, 'startIndex' );\r
- \r
- $pager->total_entries( $total );\r
- $pager->entries_per_page( $perpage );\r
- $pager->current_page( $start ? ( $start - 1 ) / $perpage + 1 : 0 )\r
- }\r
- elsif( my $rss = $feed->{ rss } ) {\r
- if ( my $page = $rss->channel->{ $ns } ) {\r
- $pager->total_entries( $page->{ totalResults } );\r
- $pager->entries_per_page( $page->{ itemsPerPage } );\r
- my $start = $page->{ startIndex };\r
- $pager->current_page( $start ? ( $start - 1 ) / $page->{ itemsPerPage } + 1 : 0 )\r
- }\r
- } \r
- $self->pager( $pager );\r
-}\r
-\r
-sub next_page {\r
- my $self = shift;\r
- return $self->_get_page( 'next' );\r
-}\r
-\r
-sub previous_page {\r
+use Data::Page;
+use WWW::OpenSearch::Agent;
+use WWW::OpenSearch::Request;
+
+__PACKAGE__->mk_accessors( qw( feed pager ) );
+
+=head1 NAME
+
+WWW::OpenSearch::Response - Encapsulate a response received from
+an A9 OpenSearch compatible engine
+
+=head1 SYNOPSIS
+
+ use WWW::OpenSearch;
+
+ my $url = "http://bulkfeeds.net/opensearch.xml";
+ my $engine = WWW::OpenSearch->new($url);
+
+ # Retrieve page 4 of search results for "iPod"
+ my $response = $engine->search("iPod",{ startPage => 4 });
+ for my $item (@{$response->feed->items}) {
+ print $item->{description};
+ }
+
+ # Retrieve page 3 of results
+ $response = $response->previous_page;
+
+ # Retrieve page 5 of results
+ $response = $response->next_page;
+
+=head1 DESCRIPTION
+
+WWW::OpenSearch::Response is a module designed to encapsulate a
+response received from an A9 OpenSearch compatible engine.
+See http://opensearch.a9.com/spec/1.1/response/ for details.
+
+=head1 CONSTRUCTOR
+
+=head2 new( $response )
+
+Constructs a new instance of WWW::OpenSearch::Response from the
+WWWW::OpenSearch:Response returned by the search request.
+
+=head1 METHODS
+
+=head2 parse_response( )
+
+Parses the content of the HTTP response using XML::Feed. If successful,
+parse_feed( ) is also called.
+
+=head2 parse_feed( )
+
+Parses the XML::Feed originally parsed from the HTTP response content.
+Sets the pager object appropriately.
+
+=head2 previous_page( ) / next_page( )
+
+Performs another search on the parent object, returning a
+WWW::OpenSearch::Response instance containing the previous/next page
+of results. If the current response includes a <link rel="previous/next"
+href="..." /> tag, the page will simply be the parsed content of the URL
+specified by the tag's href attribute. However, if the current response does not
+include the appropriate link, a new query is constructed using the startPage
+or startIndex query arguments.
+
+=head2 _get_link( $type )
+
+Gets the href attribute of the first link whose rel attribute
+is equal to $type.
+
+=head1 ACCESSORS
+
+=head2 feed( )
+
+=head2 pager( )
+
+=head1 AUTHOR
+
+=over 4
+
+=item * Tatsuhiko Miyagawa E<lt>miyagawa@bulknews.netE<gt>
+
+=item * Brian Cassidy E<lt>bricas@cpan.orgE<gt>
+
+=back
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright 2005-2013 by Tatsuhiko Miyagawa and Brian Cassidy
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself.
+
+=cut
+
+sub new {
+ my $class = shift;
+ my $response = shift;
+
+ my $self = bless $response, $class;
+
+ return $self unless $self->is_success;
+
+ $self->parse_response;
+
+ return $self;
+}
+
+sub parse_response {
+ my $self = shift;
+
+ my $content = $self->content;
+ my $feed = XML::Feed->parse( \$content );
+
+ return if XML::Feed->errstr;
+ $self->feed( $feed );
+
+ $self->parse_feed;
+}
+
+sub parse_feed {
my $self = shift;
- return $self->_get_page( 'previous' );\r
+ my $pager = Data::Page->new;
+
+ my $feed = $self->feed;
+ my $format = $feed->format;
+ my $ns = $self->request->opensearch_url->ns;
+
+ # TODO
+ # adapt these for any number of opensearch elements in
+ # the feed or in each entry
+
+ if ( my $atom = $feed->{ atom } ) {
+ my $total = $atom->get( $ns, 'totalResults' );
+ my $perpage = $atom->get( $ns, 'itemsPerPage' );
+ my $start = $atom->get( $ns, 'startIndex' );
+
+ $pager->total_entries( $total );
+ $pager->entries_per_page( $perpage );
+ $pager->current_page( $start ? ( $start - 1 ) / $perpage + 1 : 0 );
+ }
+ elsif ( my $rss = $feed->{ rss } ) {
+ if ( my $page = $rss->channel->{ $ns } ) {
+ $pager->total_entries( $page->{ totalResults } );
+ $pager->entries_per_page( $page->{ itemsPerPage } );
+ my $start = $page->{ startIndex };
+ $pager->current_page(
+ $start ? ( $start - 1 ) / $page->{ itemsPerPage } + 1 : 0 );
+ }
+ }
+ $self->pager( $pager );
+}
+
+sub next_page {
+ my $self = shift;
+ return $self->_get_page( 'next' );
+}
+
+sub previous_page {
+ my $self = shift;
+ return $self->_get_page( 'previous' );
}
sub _get_page {
- my( $self, $direction ) = @_;
+ my ( $self, $direction ) = @_;
my $pager = $self->pager;
- my $pagermethod = "${direction}_page";\r
- my $page = $pager->$pagermethod;\r
- return unless $page;\r
-
- my $request = $self->request;
- my $method = lc $request->method;
-
- if( $method ne 'post' ) { # force query build on POST\r
- my $link = $self->_get_link( $direction );\r
- return $self->parent->do_search( $link, $method ) if $link;
- }\r
- \r
- my $template = $self->parent->description->get_best_url;
- my( $param, $query );
- if( $method eq 'post' ) {
- my $uri = URI->new( 'http://foo.com/?' . $request->content );
- $query = { $uri->query_form };
- }
- else {
- $query = { $self->request->uri->query_form };
- }\r
-\r
- if( $param = $template->macros->{ startPage } ) {\r
- $query->{ $param } = $pager->$pagermethod\r
- }\r
- elsif( $param = $template->macros->{ startIndex } ) {
- if( $query->{ $param } ) {
- $query->{ $param } = $direction eq 'previous'
- ? $query->{ $param } -= $pager->entries_per_page
- : $query->{ $param } += $pager->entries_per_page;
+ my $pagermethod = "${direction}_page";
+ my $page = $pager->$pagermethod;
+ return unless $page;
+
+ my $params;
+ my $osu = $self->request->opensearch_url;
+
+ # this code is too fragile -- deparse depends on the order of query
+ # params and the like. best just to use the last query params and
+ # do the paging from there.
+ #
+ # if( lc $osu->method ne 'post' ) { # force query build on POST
+ # my $link = $self->_get_link( $direction );
+ # if( $link ) {
+ # $params = $osu->deparse( $link );
+ # }
+ # }
+
+ # rebuild the query
+ if ( !$params ) {
+ $params = $self->request->opensearch_params;
+
+ # handle paging via a page #
+ $params->{ startPage } = $page;
+
+ # handle paging via an index
+ if ( exists $params->{ startIndex } ) {
+
+ # start index is pre-existing
+ if ( $params->{ startIndex } ) {
+ if ( $direction eq 'previous' ) {
+ $params->{ startIndex } -= $pager->entries_per_page;
+ }
+ else {
+ $params->{ startIndex } += $pager->entries_per_page;
+ }
+ }
+
+ # start index did not exist previously
+ else {
+ if ( $direction eq 'previous' ) {
+ $params->{ startIndex } = 1;
+ }
+ else {
+ $params->{ startIndex } = $pager->entries_per_page + 1;
+ }
+
+ }
}
- else {
- $query->{ $param } = $direction eq 'previous'
- ? 1
- : $pager->entries_per_page + 1;
- }\r
- }\r
-\r
- return $self->parent->do_search( $template->prepare_query( $query ), $method );\r
-}\r
-\r
-sub _get_link {\r
- my $self = shift;\r
- my $type = shift;\r
- my $feed = $self->feed->{ atom };\r
- \r
- return unless $feed;\r
- \r
- for( $feed->link ) {\r
- return $_->get( 'href' ) if $_->get( 'rel' ) eq $type;\r
}
- return;\r
-}\r
-\r
-1;\r
+ my $agent = WWW::OpenSearch::Agent->new;
+ return $agent->search( WWW::OpenSearch::Request->new( $osu, $params ) );
+}
+
+sub _get_link {
+ my $self = shift;
+ my $type = shift;
+ my $feed = $self->feed->{ atom };
+
+ return unless $feed;
+
+ for ( $feed->link ) {
+ return $_->href if $_->rel eq $type;
+ }
+
+ return;
+}
+
+1;