Revision history for Perl extension WWW::OpenSearch
+0.11 Tue Apr 17 2007
+ - added a simple OSD parsing test
+
+0.10_02 Tue Jan 23 2007
+ - fix Request.pm to clone the extra attributes we've
+ added (Marc Tobias)
+
+0.10_01 Mon Jan 22 2007
+ - use URI::Template for parsing OSD uri templates
+ - added opensearch-specific Request and Agent classes
+ - un-break get_best_url()
+ - you can now pass a WWW::OpenSearch::Url to WWW::OpenSearch's
+ search() method
+ - added ns() (namespace) field to Url.pm
+ - re-worked paging to use the new Request object
+
+ [ THINGS THAT MAY BREAK YOUR CODE ]
+ - using URI::Template means some methods are now proxied to
+ that class
+ - removed agent argument in new() in OpenSearch.pm
+ - handling of POST requests in prepare_query() in Url.pm now
+ returns data suitable for passing to HTTP::Request
+ - un-link Response.pm and the parent WWW::OpenSearch object --
+ a Response is now in the context of whatever
+ WWW::OpenSearch::Url was used
+
+0.09 Thu Dec 07 2006
+ - fix link fetching from atom feeds
+
0.08 Wed Sep 13 2006
- fix optional attributes for Image
- added strict to Url object
Changes
lib/WWW/OpenSearch.pm
+lib/WWW/OpenSearch/Agent.pm
lib/WWW/OpenSearch/Description.pm
lib/WWW/OpenSearch/Image.pm
lib/WWW/OpenSearch/Query.pm
+lib/WWW/OpenSearch/Request.pm
lib/WWW/OpenSearch/Response.pm
lib/WWW/OpenSearch/Url.pm
Makefile.PL
-MANIFEST This list of files\r
-META.yml Module meta-data (added by MakeMaker)
+MANIFEST This list of files
README
t/00_compile.t
t/01_live.t
+t/09-opensearch.t
t/10-description.t
t/11-url.t
t/12-response.t
+t/13-request.t
t/98_pod.t
t/99_pod_coverage.t
+t/data/osd.xml
+META.yml Module meta-data (added by MakeMaker)
-# http://module-build.sourceforge.net/META-spec.html
-#XXXXXXX This is a prototype!!! It will change in the future!!! XXXXX#
-name: WWW-OpenSearch
-version: 0.08
-version_from: lib/WWW/OpenSearch.pm
-installdirs: site
-requires:
+--- #YAML:1.0
+name: WWW-OpenSearch
+version: 0.11
+abstract: Search A9 OpenSearch compatible engines
+license: perl
+generated_by: ExtUtils::MakeMaker version 6.32
+distribution_type: module
+requires:
Data::Page: 2
Encode: 0
LWP: 5.6
Test::More: 0.32
URI: 0
+ URI::Template: 0
XML::Feed: 0.08
XML::LibXML: 1.58
-
-distribution_type: module
-generated_by: ExtUtils::MakeMaker version 6.17
+meta-spec:
+ url: http://module-build.sourceforge.net/META-spec-v1.2.html
+ version: 1.2
+author:
+ - Brian Cassidy <bricas@cpan.org>
use ExtUtils::MakeMaker;
WriteMakefile(
- 'NAME' => 'WWW::OpenSearch',
- 'VERSION_FROM' => 'lib/WWW/OpenSearch.pm',
+ 'NAME' => 'WWW::OpenSearch',
+ 'VERSION_FROM' => 'lib/WWW/OpenSearch.pm',
+ 'ABSTRACT_FROM' => 'lib/WWW/OpenSearch.pm',
+ 'AUTHOR' => 'Brian Cassidy <bricas@cpan.org>',
+ 'LICENSE' => 'perl',
'PREREQ_PM' => {
- 'Data::Page' => 2.00,
- 'Encode' => 0,
- 'LWP' => 5.60,
- 'Test::More' => 0.32,
- 'URI' => 0,
- 'XML::Feed' => 0.08,
- 'XML::LibXML' => 1.58
+ 'Data::Page' => 2.00,
+ 'Encode' => 0,
+ 'LWP' => 5.60,
+ 'Test::More' => 0.32,
+ 'URI' => 0,
+ 'XML::Feed' => 0.08,
+ 'XML::LibXML' => 1.58,
+ 'URI::Template' => 0,
},
);
-NAME\r
- WWW::OpenSearch - Search A9 OpenSearch compatible engines\r
-\r
-SYNOPSIS\r
- use WWW::OpenSearch;\r
- \r
- my $url = "http://bulkfeeds.net/opensearch.xml";\r
- my $engine = WWW::OpenSearch->new($url);\r
- \r
- my $name = $engine->description->ShortName;\r
- my $tags = $engine->description->Tags;\r
- \r
- # Perform search for "iPod"\r
- my $response = $engine->search("iPod");\r
- for my $item (@{$response->feed->items}) {\r
- print $item->{description};\r
- }\r
- \r
- # Retrieve the next page of results\r
- my $next_page = $response->next_page;\r
- for my $item (@{$next_page->feed->items}) {\r
- print $item->{description};\r
- }\r
-\r
-DESCRIPTION\r
- WWW::OpenSearch is a module to search A9's OpenSearch compatible search\r
- engines. See http://opensearch.a9.com/ for details.\r
-\r
-CONSTRUCTOR\r
- new( $url )\r
- Constructs a new instance of WWW::OpenSearch using the given URL as the\r
- location of the engine's OpenSearch Description document (retrievable\r
- via the description_url accessor).\r
-\r
-METHODS\r
- fetch_description( [ $url ] )\r
- Fetches the OpenSearch Descsription found either at the given URL or at\r
- the URL specified by the description_url accessor. Fetched description\r
- may be accessed via the description accessor.\r
-\r
- search( $query [, \%params] )\r
- Searches the engine for the given query using the given search\r
- parameters. Valid search parameters include:\r
-\r
- * startPage\r
- * totalResults\r
- * startIndex\r
- * itemsPerPage\r
-\r
- See http://opensearch.a9.com/spec/1.1/response/#elements for details.\r
-\r
- do_search( $url [, $method] )\r
- Performs a request for the given URL and returns a\r
- WWW::OpenSearch::Response object. Method defaults to 'GET'.\r
-\r
-ACCESSORS\r
- description_url( [$description_url] )\r
- agent( [$agent] )\r
- description( [$description] )\r
-AUTHOR\r
- * Tatsuhiko Miyagawa <miyagawa@bulknews.net>\r
- * Brian Cassidy <bricas@cpan.org>\r
-\r
-COPYRIGHT AND LICENSE\r
- Copyright 2006 by Tatsuhiko Miyagawa and Brian Cassidy\r
-\r
- This library is free software; you can redistribute it and/or modify it\r
- under the same terms as Perl itself.\r
-\r
+NAME
+ WWW::OpenSearch - Search A9 OpenSearch compatible engines
+
+SYNOPSIS
+ use WWW::OpenSearch;
+
+ my $url = "http://bulkfeeds.net/opensearch.xml";
+ my $engine = WWW::OpenSearch->new($url);
+
+ my $name = $engine->description->ShortName;
+ my $tags = $engine->description->Tags;
+
+ # Perform search for "iPod"
+ my $response = $engine->search("iPod");
+ for my $item (@{$response->feed->items}) {
+ print $item->{description};
+ }
+
+ # Retrieve the next page of results
+ my $next_page = $response->next_page;
+ for my $item (@{$next_page->feed->items}) {
+ print $item->{description};
+ }
+
+DESCRIPTION
+ WWW::OpenSearch is a module to search A9's OpenSearch compatible search
+ engines. See http://opensearch.a9.com/ for details.
+
+CONSTRUCTOR
+ new( $url )
+ Constructs a new instance of WWW::OpenSearch using the given URL as the
+ location of the engine's OpenSearch Description document (retrievable
+ via the description_url accessor).
+
+METHODS
+ fetch_description( [ $url ] )
+ Fetches the OpenSearch Descsription found either at the given URL or at
+ the URL specified by the description_url accessor. Fetched description
+ may be accessed via the description accessor.
+
+ search( $query [, \%params] )
+ Searches the engine for the given query using the given search
+ parameters. Valid search parameters include:
+
+ * startPage
+ * totalResults
+ * startIndex
+ * itemsPerPage
+
+ See http://opensearch.a9.com/spec/1.1/response/#elements for details.
+
+ do_search( $url [, $method] )
+ Performs a request for the given URL and returns a
+ WWW::OpenSearch::Response object. Method defaults to 'GET'.
+
+ACCESSORS
+ description_url( [$description_url] )
+ agent( [$agent] )
+ description( [$description] )
+AUTHOR
+ * Tatsuhiko Miyagawa <miyagawa@bulknews.net>
+ * Brian Cassidy <bricas@cpan.org>
+
+COPYRIGHT AND LICENSE
+ Copyright 2007 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.
+
use base qw( Class::Accessor::Fast );
use Carp;
-use WWW::OpenSearch::Response;
+use WWW::OpenSearch::Agent;
+use WWW::OpenSearch::Request;
use WWW::OpenSearch::Description;
-use Encode qw( _utf8_off );
+
+use Encode ();
__PACKAGE__->mk_accessors( qw( description_url agent description ) );
-our $VERSION = '0.08';
+our $VERSION = '0.11';
=head1 NAME
=head1 DESCRIPTION
-WWW::OpenSearch is a module to search A9's OpenSearch compatible search engines. See http://opensearch.a9.com/ for details.
+WWW::OpenSearch is a module to search A9's OpenSearch compatible search
+engines. See http://opensearch.a9.com/ for details.
=head1 CONSTRUCTOR
-=head2 new( $url [, $useragent] )
+=head2 new( $url )
Constructs a new instance of WWW::OpenSearch using the given
URL as the location of the engine's OpenSearch Description
-document (retrievable via the description_url accessor). Pass any
-LWP::UserAgent compatible object if you wish to override the default
-agent.
+document (retrievable via the description_url accessor).
=head1 METHODS
=head1 COPYRIGHT AND LICENSE
-Copyright 2006 by Tatsuhiko Miyagawa and Brian Cassidy
+Copyright 2007 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, $url, $agent ) = @_;
+ my( $class, $url ) = @_;
croak( "No OpenSearch Description url provided" ) unless $url;
my $self = $class->SUPER::new;
- unless( $agent ) {
- require LWP::UserAgent;
- $agent = LWP::UserAgent->new( agent => join( '/', ref $self, $VERSION ) );
- }
-
$self->description_url( $url );
- $self->agent( $agent );
+ $self->agent( WWW::OpenSearch::Agent->new() );
$self->fetch_description;
}
sub search {
- my( $self, $query, $params ) = @_;
+ my( $self, $query, $params, $url ) = @_;
$params ||= { };
$params->{ searchTerms } = $query;
- _utf8_off( $params->{ searchTerms } );
-
- my $url = $self->description->get_best_url;
- return $self->do_search( $url->prepare_query( $params ), $url->method );
-}
-
-sub do_search {
- my( $self, $url, $method ) = @_;
-
- $method = lc( $method ) || 'get';
-
- my $response;
- if( $method eq 'post' ) {
- $response = $self->agent->post( @$url );
- }
- else {
- $response = $self->agent->$method( $url );
- }
+ Encode::_utf8_off( $params->{ searchTerms } );
- return WWW::OpenSearch::Response->new( $self, $response );
+ $url ||= $self->description->get_best_url;
+ return $self->agent->search( WWW::OpenSearch::Request->new( $url, $params ) );
}
1;
--- /dev/null
+package WWW::OpenSearch::Agent;
+
+use strict;
+use warnings;
+
+use base qw( LWP::UserAgent );
+
+use WWW::OpenSearch;
+use WWW::OpenSearch::Response;
+
+=head1 NAME
+
+WWW::OpenSearch::Agent - An agent for doing OpenSearch requests
+
+=head1 SYNOPSIS
+
+=head1 DESCRIPTION
+
+=head1 CONSTRUCTOR
+
+=head2 new( [%options] )
+
+=head1 METHODS
+
+=head2 request( $request | $url, \%params )
+
+=head2 search( )
+
+An alias for request()
+
+=head1 AUTHOR
+
+=over 4
+
+=item * Brian Cassidy E<lt>bricas@cpan.orgE<gt>
+
+=back
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright 2007 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, @rest ) = @_;
+ return $class->SUPER::new(
+ agent => join( '/', __PACKAGE__, $WWW::OpenSearch::VERSION ),
+ @rest,
+ );
+}
+
+*search = \&request;
+
+sub request {
+ my $self = shift;
+ my $request = shift; ;
+ my $response = $self->SUPER::request( $request, @_ );
+
+ # allow regular HTTP::Requests to flow through
+ return $response unless $request->isa( 'WWW::OpenSearch::Request' );
+ return WWW::OpenSearch::Response->new( $response );
+}
+
+1;
=head1 COPYRIGHT AND LICENSE
-Copyright 2006 by Tatsuhiko Miyagawa and Brian Cassidy
+Copyright 2007 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.
my $ns = $element->getNamespace->value;
my $version;
- if( $ns eq 'http://a9.com/-/spec/opensearch/1.1/' ) {
- $self->ns( $ns );
- $version = '1.1';
+ if( $ns eq 'http://a9.com/-/spec/opensearchdescription/1.0/' ) {
+ $self->ns( 'http://a9.com/-/spec/opensearchrss/1.0/' );
+ $version = '1.0';
}
else {
- $version = '1.0';
+ $self->ns( $ns );
+ ( $version ) = $ns =~ m{([^/]+)/?$};
}
$self->version( $version );
my $node = $doc->documentElement->getChildrenByTagName( $column ) or next;
if( $column eq 'Url' ) {
if( $version eq '1.0' ) {
- $self->Url( [ WWW::OpenSearch::Url->new( template => $node->string_value, type => 'application/rss+xml' ) ] );
+ $self->Url( [ WWW::OpenSearch::Url->new( template => $node->string_value, type => 'application/rss+xml', ns => $self->ns ) ] );
next;
}
$params{ $param } = $value;
}
- push @url, WWW::OpenSearch::Url->new( template => $url, type => $type, method => $method, params => \%params );
+ push @url, WWW::OpenSearch::Url->new( template => $url, type => $type, method => $method, params => \%params, ns => $self->ns );
}
$self->Url( \@url );
}
$self->image( $images );
}
- elsif( $version eq '1.0' and $column eq 'Format' ) {
- $self->Format( $node->string_value );
- $self->ns( $self->Format );
- }
else {
$self->$column( $node->string_value );
}
my $self = shift;
my $type = shift;
- my $template;
for( $self->urls ) {
- $template = $_ if $_->type eq $type;
- last;
+ return $_ if $_->type eq $type;
};
- return $template;
+ return;
}
sub urls {
=head1 COPYRIGHT AND LICENSE
-Copyright 2006 by Tatsuhiko Miyagawa and Brian Cassidy
+Copyright 2007 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.
=head1 COPYRIGHT AND LICENSE
-Copyright 2006 by Tatsuhiko Miyagawa and Brian Cassidy
+Copyright 2007 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.
--- /dev/null
+package WWW::OpenSearch::Request;
+
+use strict;
+use warnings;
+
+use base qw( HTTP::Request Class::Accessor::Fast );
+
+use HTTP::Request::Common ();
+
+__PACKAGE__->mk_accessors( qw( opensearch_url opensearch_params ) );
+
+=head1 NAME
+
+WWW::OpenSearch::Request - Encapsulate an opensearch request
+
+=head1 SYNOPSIS
+
+=head1 DESCRIPTION
+
+=head1 CONSTRUCTOR
+
+=head2 new( $url, \%params )
+
+=head1 METHODS
+
+=head2 clone( )
+
+=head1 ACCESSORS
+
+=over 4
+
+=item * opensearch_url
+
+=item * opensearch_params
+
+=back
+
+=head1 AUTHOR
+
+=over 4
+
+=item * Brian Cassidy E<lt>bricas@cpan.orgE<gt>
+
+=back
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright 2007 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, $os_url, $params ) = @_;
+
+ my( $uri, $post ) = $os_url->prepare_query( $params );
+
+ my $self;
+ if( lc $os_url->method eq 'post' ) {
+ $self = HTTP::Request::Common::POST( $uri, $post );
+ bless $self, $class;
+ }
+ else {
+ $self = $class->SUPER::new( $os_url->method => $uri );
+ }
+
+ $self->opensearch_url( $os_url );
+ $self->opensearch_params( $params );
+
+ return $self;
+}
+
+sub clone {
+ my $self = shift;
+ my $clone = bless $self->SUPER::clone, ref( $self );
+
+ $clone->opensearch_url( $self->opensearch_url );
+ $clone->opensearch_params( $self->opensearch_params );
+
+ return $clone;
+}
+
+1;
use base qw( HTTP::Response Class::Accessor::Fast );
use XML::Feed;
-use URI;
use Data::Page;
+use WWW::OpenSearch::Agent;
+use WWW::OpenSearch::Request;
-__PACKAGE__->mk_accessors( qw( feed pager parent ) );
+__PACKAGE__->mk_accessors( qw( feed pager ) );
=head1 NAME
=head1 CONSTRUCTOR
-=head2 new( $parent, $response )
+=head2 new( $response )
-Constructs a new instance of WWW::OpenSearch::Response. Arguments
-include the WWW::OpenSearch object which initiated the search (parent)
-and the HTTP::Response returned by the search request.
+Constructs a new instance of WWW::OpenSearch::Response from the
+WWWW::OpenSearch:Response returned by the search request.
=head1 METHODS
=head2 pager( )
-=head2 parent( )
-
=head1 AUTHOR
=over 4
=head1 COPYRIGHT AND LICENSE
-Copyright 2006 by Tatsuhiko Miyagawa and Brian Cassidy
+Copyright 2007 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.
sub new {
my $class = shift;
- my $parent = shift;
my $response = shift;
my $self = bless $response, $class;
- $self->parent( $parent );
return $self unless $self->is_success;
$self->parse_response;
my $feed = $self->feed;
my $format = $feed->format;
- my $ns = $self->parent->description->ns;
+ my $ns = $self->request->opensearch_url->ns;
# TODO
# adapt these for any number of opensearch elements in
my $pagermethod = "${direction}_page";
my $page = $pager->$pagermethod;
return unless $page;
-
- my $request = $self->request;
- my $method = lc $request->method;
- if( $method ne 'post' ) { # force query build on POST
- my $link = $self->_get_link( $direction );
- return $self->parent->do_search( $link, $method ) if $link;
- }
-
- 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 };
- }
-
- if( $param = $template->macros->{ startPage } ) {
- $query->{ $param } = $pager->$pagermethod
- }
- 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;
- }
- else {
- $query->{ $param } = $direction eq 'previous'
- ? 1
- : $pager->entries_per_page + 1;
+ 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;
+ }
+
+ }
}
}
- return $self->parent->do_search( $template->prepare_query( $query ), $method );
+ my $agent = WWW::OpenSearch::Agent->new;
+ return $agent->search( WWW::OpenSearch::Request->new(
+ $osu, $params
+ ) );
}
sub _get_link {
return unless $feed;
for( $feed->link ) {
- return $_->get( 'href' ) if $_->get( 'rel' ) eq $type;
+ return $_->href if $_->rel eq $type;
}
return;
use base qw( Class::Accessor::Fast );
-use URI;
-use URI::Escape;
+use URI::Template;
-__PACKAGE__->mk_accessors( qw( type template method params macros ) );
+__PACKAGE__->mk_accessors( qw( type template method params ns ) );
=head1 NAME
=head1 METHODS
-=head2 parse_macros( )
-
=head2 prepare_query( [ \%params ] )
=head1 ACCESSORS
=item * params
-=item * macros
+=item * ns
=back
=head1 COPYRIGHT AND LICENSE
-Copyright 2006 by Tatsuhiko Miyagawa and Brian Cassidy
+Copyright 2007 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.
my( $class, %options ) = @_;
$options{ method } ||= 'GET';
- $options{ template } = URI->new( $options{ template } );
+ $options{ template } = URI::Template->new( $options{ template } );
my $self = $class->SUPER::new( \%options );
- $self->parse_macros;
return $self;
}
-sub parse_macros {
- my $self = shift;
-
- my %query = $self->method eq 'post'
- ? %{ $self->params }
- : $self->template->query_form;
-
- my %macros;
- for( keys %query ) {
- if( $query{ $_ } =~ /^{(.+)}$/ ) {
- $macros{ $1 } = $_;
- }
- }
-
- $self->macros( \%macros );
-}
-
sub prepare_query {
my( $self, $params ) = @_;
- my $url = $self->template->clone;
+ my $tmpl = $self->template;
$params->{ startIndex } ||= 1;
$params->{ startPage } ||= 1;
$params->{ outputEncoding } ||= 'UTF-8';
$params->{ inputEncoding } ||= 'UTF-8';
- my $macros = $self->macros;
+ # fill the uri template
+ my $url = $tmpl->process( %$params );
# attempt to handle POST
if( $self->method eq 'post' ) {
my $post = $self->params;
- for( keys %$macros ) {
- $post->{ $macros->{ $_ } } = $params->{ $_ };
+ for my $key ( keys %$post ) {
+ $post->{ $key } =~ s/{(.+)}/$params->{ $1 } || ''/eg;
}
- return [ $url, $post ];
- }
- my $query = { $url->query_form };
- for( keys %$macros ) {
- $query->{ $macros->{ $_ } } = $params->{ $_ };
+ return $url, [ %$post ];
}
- $url->query_form( $query );
return $url;
}
use strict;
-use Test::More tests => 6;
+use Test::More tests => 8;
BEGIN {
use_ok 'WWW::OpenSearch';
use_ok 'WWW::OpenSearch::Url';
use_ok 'WWW::OpenSearch::Query';
use_ok 'WWW::OpenSearch::Image';
+ use_ok 'WWW::OpenSearch::Agent';
+ use_ok 'WWW::OpenSearch::Request';
}
--- /dev/null
+use Test::More tests => 2;
+
+use_ok( 'WWW::OpenSearch' );
+use URI::file;
+
+my $uri = URI::file->new_abs( 't/data/osd.xml' );
+
+my $engine = WWW::OpenSearch->new( $uri );
+isa_ok( $engine, 'WWW::OpenSearch' );
my $osd = WWW::OpenSearch::Description->new( $description );
isa_ok( $osd, 'WWW::OpenSearch::Description' );
- is( $osd->shortname, 'Web Search' );
- ok( !defined $osd->longname );
- is( $osd->description, 'Use Example.com to search the Web.' );
- is( $osd->tags, 'example web' );
- is( $osd->contact, 'admin@example.com' );
+ is( $osd->shortname, 'Web Search', 'shortname' );
+ ok( !defined $osd->longname, 'longname' );
+ is( $osd->description, 'Use Example.com to search the Web.', 'description' );
+ is( $osd->tags, 'example web', 'tags' );
+ is( $osd->contact, 'admin@example.com', 'contact' );
# count the urls
is( $osd->urls, 1, 'number of url objects' );
my $osd = WWW::OpenSearch::Description->new( $description );
isa_ok( $osd, 'WWW::OpenSearch::Description' );
- is( $osd->shortname, 'Web Search' );
- is( $osd->longname, 'Example.com Web Search' );
- is( $osd->description, 'Use Example.com to search the Web.' );
- is( $osd->tags, 'example web' );
- is( $osd->contact, 'admin@example.com' );
- is( $osd->developer, 'Example.com Development Team' );
+ is( $osd->shortname, 'Web Search', 'shortname' );
+ is( $osd->longname, 'Example.com Web Search', 'longname' );
+ is( $osd->description, 'Use Example.com to search the Web.', 'description' );
+ is( $osd->tags, 'example web', 'tags' );
+ is( $osd->contact, 'admin@example.com', 'contact' );
+ is( $osd->developer, 'Example.com Development Team', 'developer' );
is( $osd->attribution, '
Search data © 2005, Example.com, Inc., All Rights Reserved
- ' );
- is( $osd->inputencoding, 'UTF-8' );
- is( $osd->outputencoding, 'UTF-8' );
- is( $osd->language, 'en-us' );
- is( $osd->adultcontent, 'false' );
- is( $osd->syndicationright, 'open' );
+ ', 'attribution' );
+ is( $osd->inputencoding, 'UTF-8', 'inputencoding' );
+ is( $osd->outputencoding, 'UTF-8', 'outputencoding' );
+ is( $osd->language, 'en-us', 'language' );
+ is( $osd->adultcontent, 'false', 'adultcontent' );
+ is( $osd->syndicationright, 'open', 'syndicationright' );
my $queries = $osd->query;
is( scalar @$queries, 1, 'number of query objects' );
- is( $queries->[ 0 ]->role, 'example' );
- is( $queries->[ 0 ]->searchTerms, 'cat' );
+ is( $queries->[ 0 ]->role, 'example', 'role' );
+ is( $queries->[ 0 ]->searchTerms, 'cat', 'searchTerms' );
my $images = $osd->image;
is( scalar @$images, 2, 'number of image objects' );
- is( $images->[ 0 ]->height, 64 );
- is( $images->[ 0 ]->width, 64 );
- is( $images->[ 0 ]->type, 'image/png' );
- is( $images->[ 0 ]->url, 'http://example.com/websearch.png' );
- is( $images->[ 1 ]->height, 16 );
- is( $images->[ 1 ]->width, 16 );
- is( $images->[ 1 ]->type, 'image/vnd.microsoft.icon' );
- is( $images->[ 1 ]->url, 'http://example.com/websearch.ico' );
+ is( $images->[ 0 ]->height, 64, 'height' );
+ is( $images->[ 0 ]->width, 64, 'width' );
+ is( $images->[ 0 ]->type, 'image/png', 'content type' );
+ is( $images->[ 0 ]->url, 'http://example.com/websearch.png', 'url' );
+ is( $images->[ 1 ]->height, 16, 'height' );
+ is( $images->[ 1 ]->width, 16, 'width' );
+ is( $images->[ 1 ]->type, 'image/vnd.microsoft.icon', 'content type' );
+ is( $images->[ 1 ]->url, 'http://example.com/websearch.ico', 'url' );
# count the urls
is( $osd->urls, 3, 'number of url objects' );
my $osd = WWW::OpenSearch::Description->new( $description );
isa_ok( $osd, 'WWW::OpenSearch::Description' );
- is( $osd->shortname, 'Electronics' );
- is( $osd->longname, 'Amazon Electronics' );
- is( $osd->description, 'Search for electronics on Amazon.com.' );
- is( $osd->tags, 'amazon electronics' );
- is( $osd->contact, 'dewitt@unto.net' );
- is( $osd->format, 'http://a9.com/-/spec/opensearchrss/1.0/' );
- is( $osd->image, 'http://www.unto.net/search/amazon_electronics.gif' );
- is( $osd->samplesearch, 'ipod' );
- is( $osd->developer, 'DeWitt Clinton' );
+ is( $osd->shortname, 'Electronics', 'shortname' );
+ is( $osd->longname, 'Amazon Electronics', 'longname' );
+ is( $osd->description, 'Search for electronics on Amazon.com.', 'descrpiton' );
+ is( $osd->tags, 'amazon electronics', 'tags' );
+ is( $osd->contact, 'dewitt@unto.net', 'contact' );
+ is( $osd->format, 'http://a9.com/-/spec/opensearchrss/1.0/', 'format' );
+ is( $osd->image, 'http://www.unto.net/search/amazon_electronics.gif', 'image' );
+ is( $osd->samplesearch, 'ipod', 'samplesearch' );
+ is( $osd->developer, 'DeWitt Clinton', 'developer' );
is( $osd->attribution, 'Product and search data © 2005, Amazon, Inc.,
- All Rights Reserved' );
- is( $osd->syndicationright, 'open' );
- is( $osd->adultcontent, 'false' );
+ All Rights Reserved', 'attribution' );
+ is( $osd->syndicationright, 'open', 'syndicationright' );
+ is( $osd->adultcontent, 'false', 'adultcontent' );
# count the urls
- is( $osd->urls, 1 );
+ is( $osd->urls, 1, 'urls' );
}
-
use strict;
use warnings;
-use Test::More tests => 27;
+use Test::More tests => 36;
use_ok( 'WWW::OpenSearch::Description' );
use_ok( 'WWW::OpenSearch::Url' );
my $osd = WWW::OpenSearch::Description->new( $description );
isa_ok( $osd, 'WWW::OpenSearch::Description' );
- is( $osd->urls, 1 );
+ is( $osd->version, '1.1', 'version' );
+ is( $osd->ns, 'http://a9.com/-/spec/opensearch/1.1/', 'namespace' );
+ is( $osd->urls, 1, 'number of urls' );
my( $url ) = $osd->urls;
isa_ok( $url, 'WWW::OpenSearch::Url' );
- is( $url->type, 'application/rss+xml' );
- is( lc $url->method, 'get' );
- is( $url->template, 'http://example.com/?q=%7BsearchTerms%7D&pw=%7BstartPage%7D&format=rss' );
+ is( $url->type, 'application/rss+xml', 'content type' );
+ is( lc $url->method, 'get', 'method' );
+ is( $url->template, 'http://example.com/?q={searchTerms}&pw={startPage}&format=rss', 'template' );
+ my $result = $url->prepare_query( { searchTerms => 'x', startPage => 1 } );
+ is( $result, 'http://example.com/?q=x&pw=1&format=rss', 'prepare_query' );
}
{
my $osd = WWW::OpenSearch::Description->new( $description );
isa_ok( $osd, 'WWW::OpenSearch::Description' );
- is( $osd->urls, 3 );
+ is( $osd->urls, 3, 'number of urls' );
+ is( $osd->get_best_url, $osd->url->[ 1 ], 'get_best_url' );
{
my $url = $osd->url->[ 0 ];
isa_ok( $url, 'WWW::OpenSearch::Url' );
- is( $url->type, 'application/rss+xml' );
- is( lc $url->method, 'get' );
- is( $url->template, 'http://example.com/?q=%7BsearchTerms%7D&pw=%7BstartPage%7D&format=rss' );
+ is( $url->type, 'application/rss+xml', 'content type' );
+ is( lc $url->method, 'get', 'method' );
+ is( $url->template, 'http://example.com/?q={searchTerms}&pw={startPage}&format=rss', 'template' );
}
{
my $url = $osd->url->[ 1 ];
isa_ok( $url, 'WWW::OpenSearch::Url' );
- is( $url->type, 'application/atom+xml' );
- is( lc $url->method, 'get' );
- is( $url->template, 'http://example.com/?q=%7BsearchTerms%7D&pw=%7BstartPage%7D&format=atom' );
+ is( $url->type, 'application/atom+xml', 'content type' );
+ is( lc $url->method, 'get', 'method' );
+ is( $url->template, 'http://example.com/?q={searchTerms}&pw={startPage}&format=atom', 'template' );
}
{
my $url = $osd->url->[ 2 ];
isa_ok( $url, 'WWW::OpenSearch::Url' );
- is( $url->type, 'text/html' );
- is( lc $url->method, 'post' );
- is( $url->template, 'https://intranet/search?format=html' );
+ is( $url->type, 'text/html', 'content type' );
+ is( lc $url->method, 'post', 'method' );
+ is( $url->template, 'https://intranet/search?format=html', 'template' );
+ is_deeply( $url->params, { s => '{searchTerms}', o => '{startIndex}', c => '{itemsPerPage}', l => '{language}' }, 'params' );
+ my( $result, $post ) = $url->prepare_query( { searchTerms => 'x', startIndex => '1', itemsPerPage => 1, language => 'en' } );
+ is( $result, 'https://intranet/search?format=html', 'prepare_query (uri)' );
+ $post = { @$post };
+ is_deeply( $post, { s => 'x', o => 1, c => 1, l => 'en' }, 'prepare_query (params)' );
}
}
my $osd = WWW::OpenSearch::Description->new( $description );
isa_ok( $osd, 'WWW::OpenSearch::Description' );
- is( $osd->urls, 1 );
+ is( $osd->version, '1.0', 'version' );
+ is( $osd->ns, 'http://a9.com/-/spec/opensearchrss/1.0/', 'namespace' );
+ is( $osd->urls, 1, 'number of urls' );
my( $url ) = $osd->urls;
isa_ok( $url, 'WWW::OpenSearch::Url' );
- is( lc $url->method, 'get' );
- is( $url->template, 'http://www.unto.net/aws?q=%7BsearchTerms%7D&searchindex=Electronics&flavor=osrss&itempage=%7BstartPage%7D' );
+ is( lc $url->method, 'get', 'method' );
+ is( $url->template, 'http://www.unto.net/aws?q={searchTerms}&searchindex=Electronics&flavor=osrss&itempage={startPage}', 'template' );
}
--- /dev/null
+use Test::More tests => 9;
+
+use strict;
+use warnings;
+
+use_ok( 'WWW::OpenSearch::Description' );
+use_ok( 'WWW::OpenSearch::Request' );
+
+{
+ my $description = q(<?xml version="1.0" encoding="UTF-8"?>
+<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">
+ <Url type="application/rss+xml"
+ template="http://example.com/?q={searchTerms}&pw={startPage}&format=rss"/>
+ <Url type="application/atom+xml"
+ template="http://example.com/?q={searchTerms}&pw={startPage?}&format=atom"/>
+ <Url type="text/html"
+ method="post"
+ template="https://intranet/search?format=html">
+ <Param name="s" value="{searchTerms}"/>
+ <Param name="o" value="{startIndex?}"/>
+ <Param name="c" value="{itemsPerPage?}"/>
+ <Param name="l" value="{language?}"/>
+ </Url>
+</OpenSearchDescription>
+);
+
+ my $osd = WWW::OpenSearch::Description->new( $description );
+
+ {
+ my $req = WWW::OpenSearch::Request->new( $osd->url->[ 2 ], { searchTerms => 'iPod' } );
+ isa_ok( $req, 'WWW::OpenSearch::Request' );
+ is( lc $req->method, 'post', 'method' );
+ is( $req->uri, 'https://intranet/search?format=html', 'uri' );
+ is( $req->content, 'l=*&c=&s=iPod&o=1', 'content' );
+ }
+
+ {
+ my $req = WWW::OpenSearch::Request->new( $osd->url->[ 1 ], { searchTerms => 'iPod' } );
+ isa_ok( $req, 'WWW::OpenSearch::Request' );
+ is( lc $req->method, 'get', 'method' );
+ is( $req->uri, 'http://example.com/?q=iPod&pw=1&format=atom', 'uri' );
+ }
+}
--- /dev/null
+<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">
+ <ShortName>Web Search</ShortName>
+ <Description>Use Example.com to search the Web.</Description>
+ <Tags>example web</Tags>
+ <Contact>admin@example.com</Contact>
+ <Url type="application/rss+xml"
+ template="http://example.com/?q={searchTerms}&pw={startPage}&format=rss"/>
+ <Url type="application/atom+xml"
+ template="http://example.com/?q={searchTerms}&pw={startPage?}&format=atom"/>
+ <Url type="text/html"
+ method="post"
+ template="https://intranet/search?format=html">
+ <Param name="s" value="{searchTerms}"/>
+ <Param name="o" value="{startIndex?}"/>
+ <Param name="c" value="{itemsPerPage?}"/>
+ <Param name="l" value="{language?}"/>
+ </Url>
+ <LongName>Example.com Web Search</LongName>
+ <Image height="64" width="64" type="image/png">http://example.com/websearch.png</Image>
+ <Image height="16" width="16" type="image/vnd.microsoft.icon">http://example.com/websearch.ico</Image>
+ <Query role="example" searchTerms="cat" />
+ <Developer>Example.com Development Team</Developer>
+ <Attribution>
+ Search data &copy; 2005, Example.com, Inc., All Rights Reserved
+ </Attribution>
+ <SyndicationRight>open</SyndicationRight>
+ <AdultContent>false</AdultContent>
+ <Language>en-us</Language>
+ <OutputEncoding>UTF-8</OutputEncoding>
+ <InputEncoding>UTF-8</InputEncoding>
+</OpenSearchDescription>