opensearch 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+