opensearch 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/CHANGES ADDED
@@ -0,0 +1,6 @@
1
+ = OpenSearch Changelog
2
+
3
+ == Version 0.0.1
4
+ initial release
5
+
6
+ * initial release
data/README ADDED
@@ -0,0 +1,31 @@
1
+ = OpenSearch
2
+
3
+ Ruby/OpenSearch - Search A9 OpenSearch compatible engines
4
+
5
+ OpenSearch is simple format of sharing of search results by A9. See http://opensearch.a9.com/ for detail.
6
+
7
+ This library is for OpenSearch version 1.0 or 1.1
8
+
9
+ == Usage
10
+
11
+ require 'rubygems'
12
+ require 'opensearch'
13
+
14
+ # initialize
15
+ engine = OpenSearch::OpenSearch.new "http://search.hatena.ne.jp/osxml"
16
+
17
+ # get information of Description Document
18
+ name = engine.short_name
19
+ tags = engine.tags
20
+
21
+ # search (retrun value is RSS::Rss)
22
+ feed = engine.search("some text")
23
+
24
+ # OpenSearch Version 1.1
25
+ feed = engine.search("some text", "type") # type is like "application/rss+xml"
26
+
27
+ == Author
28
+ - drawnboy ( http://nowherenear.net ) <drawn.boy@gmail.com.nospam>
29
+
30
+ == License
31
+ - Same as Ruby.
@@ -0,0 +1,154 @@
1
+ # Rakefile for MetaProject
2
+
3
+ # Copyright 2005 by Aslak Hellesoy (aslak.hellesoy@gmail.org)
4
+ # All rights reserved.
5
+
6
+ # This file is may be distributed under an MIT style license. See
7
+ # MIT-LICENSE for details.
8
+
9
+ $:.unshift('lib')
10
+ require 'meta_project'
11
+ require 'rake/gempackagetask'
12
+ require 'rake/contrib/rubyforgepublisher'
13
+ require 'rake/contrib/xforge'
14
+ require 'rake/clean'
15
+ require 'rake/testtask'
16
+ require 'rake/rdoctask'
17
+
18
+ # Versioning scheme: MAJOR.MINOR.PATCH
19
+ # MAJOR bumps when API is broken backwards
20
+ # MINOR bumps when the API is broken backwards in a very slight/subtle (but not fatal) way
21
+ # -OR when a new release is made and propaganda is sent out.
22
+ # PATCH is bumped for every API addition and/or bugfix (ideally for every commit)
23
+ # Later DamageControl can bump PATCH automatically.
24
+ #
25
+ # REMEMBER TO KEEP PKG_VERSION IN SYNC WITH THE CHANGES FILE!
26
+ PKG_NAME = "opensearch"
27
+ PKG_VERSION = "0.0.1"
28
+ PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
29
+ PKG_FILES = FileList[
30
+ '[A-Z]*',
31
+ 'lib/**/*.rb',
32
+ 'doc/**/*'
33
+ ]
34
+
35
+ task :default => [:gem]
36
+
37
+ desc "Execute RSpec specifications (rspec gem must be installed)"
38
+ task :spec do
39
+ ruby 'behaviours/suite.rb'
40
+ end
41
+
42
+ # Create a task to build the RDOC documentation tree.
43
+ rd = Rake::RDocTask.new("rdoc") do |rdoc|
44
+ rdoc.rdoc_dir = 'html'
45
+ # rdoc.template = 'kilmer'
46
+ # rdoc.template = 'css2'
47
+ # rdoc.template = 'doc/jamis.rb'
48
+ rdoc.title = "opensearch"
49
+ rdoc.options << '--line-numbers' << '--inline-source' << '--main' << 'README'
50
+ rdoc.rdoc_files.include('README', 'CHANGES')
51
+ rdoc.rdoc_files.include('lib/**/*.rb', 'doc/**/*.rdoc')
52
+ rdoc.rdoc_files.exclude('doc/**/*_attrs.rdoc')
53
+ end
54
+
55
+ # ====================================================================
56
+ # Create a task that will package the Rake software into distributable
57
+ # tar, zip and gem files.
58
+
59
+ spec = Gem::Specification.new do |s|
60
+
61
+ #### Basic information.
62
+
63
+ s.name = PKG_NAME
64
+ s.version = PKG_VERSION
65
+ s.summary = "Search A9 OpenSearch compatible engines"
66
+ s.description = <<-EOF
67
+ OpenSearch is simple format of sharing of search results by A9. See opensearch.a9.com/ for detail.
68
+
69
+ This library is for OpenSearch version 1.0 or 1.1
70
+ EOF
71
+
72
+ s.files = PKG_FILES.to_a
73
+ s.require_path = 'lib'
74
+ #s.autorequire = 'meta_project'
75
+
76
+ #### Documentation and testing.
77
+
78
+ s.has_rdoc = true
79
+ s.extra_rdoc_files = rd.rdoc_files.reject { |fn| fn =~ /\.rb$/ }.to_a
80
+ s.rdoc_options <<
81
+ '--title' << 'OpenSearch' <<
82
+ '--main' << 'README' <<
83
+ '--line-numbers'
84
+
85
+ #### Author and project details.
86
+
87
+ s.author = "drawnboy"
88
+ s.email = "drawn.boy@gmail.com"
89
+ s.homepage = "http://opensearch.rubyforge.org"
90
+ s.rubyforge_project = "opensearch"
91
+ end
92
+
93
+ desc "Build Gem"
94
+ Rake::GemPackageTask.new(spec) do |pkg|
95
+ pkg.need_zip = true
96
+ pkg.need_tar = true
97
+ end
98
+
99
+ # Support Tasks ------------------------------------------------------
100
+
101
+ desc "Look for TODO and FIXME tags in the code"
102
+ task :todo do
103
+ Pathname.new(File.dirname(__FILE__)).egrep(/#.*(FIXME|TODO|TBD|DEPRECATED)/) do |match|
104
+ puts match
105
+ end
106
+ end
107
+
108
+ task :release => [:verify_env_vars, :release_files, :publish_doc, :publish_news, :tag]
109
+
110
+ task :verify_env_vars do
111
+ raise "RUBYFORGE_USER environment variable not set!" unless ENV['RUBYFORGE_USER']
112
+ raise "RUBYFORGE_PASSWORD environment variable not set!" unless ENV['RUBYFORGE_PASSWORD']
113
+ end
114
+
115
+ task :publish_doc do
116
+ publisher = Rake::RubyForgePublisher.new('opensearch', ENV['RUBYFORGE_USER'])
117
+ publisher.upload
118
+ end
119
+
120
+ desc "Release files on RubyForge"
121
+ task :release_files => [:gem] do
122
+ release_files = FileList[
123
+ "pkg/#{PKG_FILE_NAME}.gem"
124
+ ]
125
+
126
+ Rake::XForge::Release.new(MetaProject::Project::XForge::RubyForge.new('opensearch')) do |release|
127
+ # Never hardcode user name and password in the Rakefile!
128
+ release.user_name = ENV['RUBYFORGE_USER']
129
+ release.password = ENV['RUBYFORGE_PASSWORD']
130
+ release.files = release_files.to_a
131
+ release.release_name = "#{PKG_NAME} #{PKG_VERSION}"
132
+ # The rest of the options are defaults (among others, release_notes and release_changes, parsed from CHANGES)
133
+ end
134
+ end
135
+
136
+ desc "Publish news on RubyForge"
137
+ task :publish_news => [:gem] do
138
+ release_files = FileList[
139
+ "pkg/#{PKG_FILE_NAME}.gem"
140
+ ]
141
+
142
+ Rake::XForge::NewsPublisher.new(MetaProject::Project::XForge::RubyForge.new('opensearch')) do |news|
143
+ # Never hardcode user name and password in the Rakefile!
144
+ news.user_name = ENV['RUBYFORGE_USER']
145
+ news.password = ENV['RUBYFORGE_PASSWORD']
146
+ end
147
+ end
148
+
149
+ desc "Tag all the CVS files with the latest release number (REL=x.y.z)"
150
+ task :tag do
151
+ reltag = "REL_#{PKG_VERSION.gsub(/\./, '_')}"
152
+ puts "Tagging CVS with [#{reltag}]"
153
+ sh %{cvs tag #{reltag}}
154
+ end
@@ -0,0 +1,57 @@
1
+ #
2
+ # Copyright (C) 2006 drawnboy (drawn.boy@gmail.com)
3
+ #
4
+ # This program is free software.
5
+ # You can distribute/modify this program under the terms of the Ruby License.
6
+ #
7
+
8
+ require 'open-uri'
9
+ require 'rexml/document'
10
+
11
+ require 'opensearch/1.0'
12
+ require 'opensearch/1.1'
13
+
14
+ module OpenSearch
15
+ class OpenSearch
16
+ class << self
17
+ def new(url)
18
+ engine = nil
19
+ ns_uri, doc = fetch_description url
20
+
21
+ case ns_uri
22
+ when %r"http://a9.com/-/spec/opensearch(rss|)/1.0/"
23
+ engine = OpenSearch10.new doc
24
+ when %r"http://a9.com/-/spec/opensearch/1.1/"
25
+ engine = OpenSearch11.new doc
26
+ end
27
+
28
+ raise "Cannot detect description of opensearch version 1.0 or 1.1" if engine.nil?
29
+ engine
30
+ end
31
+
32
+ private
33
+ def fetch_description(url)
34
+ content = open(url) {|f| content = f.read }
35
+ doc = REXML::Document.new content
36
+ ns_uri = nil
37
+ REXML::XPath.each(doc, "//Format") do |node|
38
+ ns_uri = node.text
39
+ end
40
+ if ns_uri.nil?
41
+ REXML::XPath.each(doc, "//OpenSearchDescription") do |node|
42
+ ns_uri = node.attributes.get_attribute("xmlns").to_s
43
+ end
44
+ end
45
+ return ns_uri, doc
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+ if __FILE__ == $0
52
+ #engine = OpenSearch::OpenSearch.new "http://bulkfeeds.net/opensearch.xml"
53
+ engine = OpenSearch::OpenSearch.new "http://127.0.0.1/example.xml"
54
+ engine.set_custom("items_per_page", 20)
55
+ feed = engine.search("test", "text/html")
56
+ p feed
57
+ end
@@ -0,0 +1,46 @@
1
+ require 'opensearch/base'
2
+
3
+ module OpenSearch
4
+ class OpenSearch10 < OpenSearchBase
5
+ Nodes = %w(url format short_name long_name description tags image sample_search developer contact attribution syndication_right adult_content)
6
+ Pagers = {
7
+ "count" => 20,
8
+ "start_index" => 1,
9
+ "start_page" => 1
10
+ }
11
+
12
+ def initialize(doc)
13
+ @description = Hash.new
14
+ @pager = Pagers.dup
15
+ super
16
+ end
17
+
18
+ def search(query)
19
+ url = @description["url"]
20
+ rss = super(url, query)
21
+ parse_rss(rss)
22
+ end
23
+
24
+ private
25
+ def install_accessor
26
+ class << self
27
+ Nodes.each do |node|
28
+ define_method(node){ @description[node] }
29
+ end
30
+
31
+ Pagers.each_key do |pager|
32
+ define_method(pager){ @pager[pager] }
33
+ define_method("#{pager}="){|value| @pager[pager] = value }
34
+ end
35
+ end
36
+ end
37
+
38
+ def setup_description(doc)
39
+ Nodes.each do |node|
40
+ REXML::XPath.each(doc, "//#{node.gsub(/(^|_)(.)/){$2.upcase}}") do |n|
41
+ @description[node] = n.text
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,103 @@
1
+ require 'opensearch/base'
2
+
3
+ module OpenSearch
4
+ class OpenSearch11 < OpenSearch::OpenSearchBase
5
+ Nodes = {
6
+ "url" => { :format => {}, :requirements => [] },
7
+ "short_name" => { :format => "", :requirements => nil },
8
+ "long_name" => { :format => "", :requirements => nil },
9
+ "description" => { :format => "", :requirements => nil },
10
+ "tags" => { :format => "", :requirements => nil },
11
+ "image" => { :format => {}, :requirements => [] },
12
+ "query" => { :format => {}, :requirements => [] },
13
+ "developer" => { :format => "", :requirements => nil },
14
+ "contact" => { :format => "", :requirements => nil },
15
+ "attribution" => { :format => "", :requirements => nil },
16
+ "syndication_right" => { :format => "", :requirements => nil },
17
+ "adult_content" => { :format => "", :requirements => nil },
18
+ "language" => { :format => "", :requirements => [] },
19
+ "input_encoding" => { :format => "", :requirements => [] },
20
+ "output_encoding" => { :format => "", :requirements => [] },
21
+ }
22
+ Pagers = {
23
+ "count" => 20,
24
+ "start_index" => 1,
25
+ "start_page" => 1,
26
+ "language" => "*",
27
+ "output_encoding" => "UTF-8",
28
+ "input_encoding" => "UTF-8",
29
+ }
30
+
31
+ def initialize(doc)
32
+ @description = Hash.new
33
+ @pager = Pagers.dup
34
+ super
35
+ end
36
+
37
+ def search(query, type = nil)
38
+ url = nil
39
+ post = false
40
+ if type.nil?
41
+ url = @description["url"][0]["template"]
42
+ else
43
+ @description["url"].each do |u|
44
+ if u["type"] == type
45
+ url = u["template"]
46
+ if u["method"] =~ /post/i
47
+ post = u["param"]
48
+ post = setup_query(post, query)
49
+ end
50
+ end
51
+ end
52
+ end
53
+ raise "cannot find strict url from Description." if url.nil?
54
+ super(url, query, post)
55
+ end
56
+
57
+ private
58
+ def install_accessor
59
+ class << self
60
+ Nodes.each_key do |node|
61
+ define_method(node){ @description[node] }
62
+ end
63
+
64
+ Pagers.each_key do |pager|
65
+ define_method(pager){ @pager[pager] }
66
+ define_method("#{pager}="){|value| @pager[pager] = value }
67
+ define_method("set_custom"){|pager, value| @pager[pager] = value }
68
+ define_method("get_pager"){|pager| @pager[pager] }
69
+ end
70
+ end
71
+ end
72
+
73
+ def setup_description(doc)
74
+ Nodes.each_key do |node|
75
+ REXML::XPath.each(doc, "//#{node.gsub(/(^|_)(.)/){$2.upcase}}") do |n|
76
+ description = nil
77
+ if Nodes[node][:format].class == Hash
78
+ description = Hash.new
79
+ n.attributes.each do |key, value|
80
+ description[key] = value
81
+ end
82
+ description[node] = n.text unless n.text.nil?
83
+ if node == "url" && n.has_elements?
84
+ description["param"] = ""
85
+ REXML::XPath.each(n, "//Param") do |param|
86
+ param.attributes.each do |k, v|
87
+ description["param"] << "#{k}=#{v}&"
88
+ end
89
+ end
90
+ end
91
+ else
92
+ description = n.text
93
+ end
94
+ if Nodes[node][:requirements].class == Array
95
+ @description[node] = @description[node].to_a.push(description)
96
+ else
97
+ @description[node] = description
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,70 @@
1
+ require 'uri'
2
+ require 'net/http'
3
+ require 'rexml/document'
4
+ require "rss/1.0"
5
+ require "rss/2.0"
6
+ require "rss/dublincore"
7
+
8
+ module OpenSearch
9
+ class OpenSearchBase
10
+ def initialize(doc)
11
+ install_accessor
12
+ setup_description doc
13
+ self
14
+ end
15
+
16
+ def search(url, query, post = false)
17
+ query = setup_query(url, query)
18
+ post ? post_content(query, post) : get_content(query)
19
+ end
20
+
21
+ private
22
+ def install_accessor
23
+ end
24
+
25
+ def setup_description(doc)
26
+ end
27
+
28
+ def setup_query(url, query)
29
+ search_terms = URI.escape(query)
30
+ url.gsub!("{searchTerms}", search_terms)
31
+ @pager.each do |key, value|
32
+ key = key.gsub(/_(.)/){$1.upcase}
33
+ url.gsub!(/\{#{key}(\?|)\}/, value.to_s)
34
+ end
35
+ url
36
+ end
37
+
38
+ def get_content(uri)
39
+ uri = URI.parse(uri)
40
+ Net::HTTP.version_1_2
41
+ Net::HTTP.start(uri.host, uri.port) do |http|
42
+ response = http.get("#{uri.path}?#{uri.query}")
43
+ raise "Get Error : #{response.code} - #{response.message}" unless response.code == "200"
44
+ response.body
45
+ end
46
+ end
47
+
48
+ def post_content(uri, data)
49
+ uri = URI.parse(uri)
50
+ Net::HTTP.version_1_2
51
+ Net::HTTP.start(uri.host, uri.port) do |http|
52
+ response = http.get("#{uri.path}?#{uri.query}", data)
53
+ raise "Post Error : #{response.code} - #{response.message}" unless response.code == "200"
54
+ response.body
55
+ end
56
+ end
57
+
58
+ def parse_rss(rss)
59
+ begin
60
+ RSS::Parser.parse(rss)
61
+ rescue RSS::InvalidRSSError
62
+ RSS::Parser.parse(rss, false)
63
+ end
64
+ end
65
+
66
+ ## No implementation of atom format parser, not yet...
67
+ # def atom_parser(xml)
68
+ # end
69
+ end
70
+ end
metadata ADDED
@@ -0,0 +1,56 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.8.11
3
+ specification_version: 1
4
+ name: opensearch
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.0.1
7
+ date: 2006-01-11 00:00:00 +09:00
8
+ summary: Search A9 OpenSearch compatible engines
9
+ require_paths:
10
+ - lib
11
+ email: drawn.boy@gmail.com
12
+ homepage: http://opensearch.rubyforge.org
13
+ rubyforge_project: opensearch
14
+ description: OpenSearch is simple format of sharing of search results by A9. See opensearch.a9.com/ for detail. This library is for OpenSearch version 1.0 or 1.1
15
+ autorequire:
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ authors:
29
+ - drawnboy
30
+ files:
31
+ - README
32
+ - Rakefile
33
+ - CHANGES
34
+ - lib/opensearch.rb
35
+ - lib/opensearch/1.1.rb
36
+ - lib/opensearch/base.rb
37
+ - lib/opensearch/1.0.rb
38
+ test_files: []
39
+
40
+ rdoc_options:
41
+ - --title
42
+ - OpenSearch
43
+ - --main
44
+ - README
45
+ - --line-numbers
46
+ extra_rdoc_files:
47
+ - README
48
+ - CHANGES
49
+ executables: []
50
+
51
+ extensions: []
52
+
53
+ requirements: []
54
+
55
+ dependencies: []
56
+