site_search 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/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem "rails", "3.0.3"
4
+ gem "capybara", ">= 0.4.0"
5
+ gem "launchy"
6
+ gem "sqlite3"
7
+
8
+ # To use debugger (ruby-debug for Ruby 1.8.7+, ruby-debug19 for Ruby 1.9.2+)
9
+ # gem 'ruby-debug'
10
+ # gem 'ruby-debug19'
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2011 Gareth Allen
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,107 @@
1
+ # SiteSearch
2
+
3
+ This gem provides a simple and extremely flexible way to include site-wide searching in Rack based web applications, such as Ruby on Rails.
4
+
5
+ ## Installation
6
+
7
+ Install the latest stable release:
8
+
9
+ [sudo] gem install site_search
10
+
11
+ In Rails, add it to your Gemfile:
12
+
13
+ ``` ruby
14
+ gem 'site_search'
15
+ ```
16
+
17
+ ## Getting Started
18
+
19
+ Start off by generating the required config and initializer files:
20
+
21
+ Rails 3
22
+
23
+ rails generate site_search:google_custom_search
24
+
25
+ Rails 2.3
26
+
27
+ ruby script/generate site_search:google_custom_search
28
+
29
+ this should give you files in:
30
+
31
+ config/initializers/load_site_search_config.rb
32
+ config/google_custom_search.yml
33
+
34
+ ## Configuring SiteSearch
35
+
36
+ SiteSearch currently only supports Google Custom Search and allows for multiple search engines to be configured and utilized.
37
+
38
+ Edit the google_custom_search.yml file in config/
39
+
40
+ ``` yaml
41
+ production:
42
+ api_key: "YOUR-API-KEY"
43
+ search_engines:
44
+ your_search_engine:
45
+ cx: "YOUR-CX-RECORD"
46
+ ```
47
+
48
+ An initializer file is required to load the config settings, if you're using Rails, one is created for you:
49
+
50
+ ## Using SiteSearch
51
+
52
+ In your controller create an instance of the GoogleSearch class by passing the name of the search engine and the search arguments:
53
+
54
+ ``` ruby
55
+ @search = SiteSearch::GoogleSearch.new(:your_search_engine, params[:query_string])
56
+ ```
57
+
58
+ You can then access the results in the view like so:
59
+
60
+ ``` ruby
61
+ <% @search.results.each do |result| %>
62
+ <%= results.title %>
63
+ <%= result.text %>
64
+ <%= result.url %>
65
+ <% end %>
66
+ ```
67
+
68
+ You can also access the raw document that is received from the Google Custom Search API.
69
+
70
+ ``` ruby
71
+ @search.raw
72
+ ```
73
+
74
+ The GoogleSearch class also accepts a optional parameters, for example the alt parameter for specifying the format
75
+ of the response, can either be json(default) or atom.
76
+
77
+ ``` ruby
78
+ @search = SiteSearch::GoogleSearch.new(:your_search_engine, params[:query_string], {:alt=>'atom'})
79
+ ```
80
+
81
+ ## Contributing to SiteSearch
82
+
83
+ Contributions are appreciated and pull requests are very welcome. Before submitting a pull request,
84
+ please make sure that your changes are well tested.
85
+
86
+ ## License
87
+
88
+ Copyright (c) 20011 Gareth Allen
89
+
90
+ Permission is hereby granted, free of charge, to any person obtaining
91
+ a copy of this software and associated documentation files (the
92
+ "Software"), to deal in the Software without restriction, including
93
+ without limitation the rights to use, copy, modify, merge, publish,
94
+ distribute, sublicense, and/or sell copies of the Software, and to
95
+ permit persons to whom the Software is furnished to do so, subject to
96
+ the following conditions:
97
+
98
+ The above copyright notice and this permission notice shall be
99
+ included in all copies or substantial portions of the Software.
100
+
101
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
102
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
103
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
104
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
105
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
106
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
107
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,29 @@
1
+ # encoding: UTF-8
2
+ require 'rubygems'
3
+ begin
4
+ require 'bundler/setup'
5
+ rescue LoadError
6
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
7
+ end
8
+
9
+ require 'rake'
10
+ require 'rake/rdoctask'
11
+
12
+ require 'rake/testtask'
13
+
14
+ Rake::TestTask.new(:test) do |t|
15
+ t.libs << 'lib'
16
+ t.libs << 'test'
17
+ t.pattern = 'test/**/*_test.rb'
18
+ t.verbose = false
19
+ end
20
+
21
+ task :default => :test
22
+
23
+ Rake::RDocTask.new(:rdoc) do |rdoc|
24
+ rdoc.rdoc_dir = 'rdoc'
25
+ rdoc.title = 'SiteSearch'
26
+ rdoc.options << '--line-numbers' << '--inline-source'
27
+ rdoc.rdoc_files.include('README.rdoc')
28
+ rdoc.rdoc_files.include('lib/**/*.rb')
29
+ end
@@ -0,0 +1,3 @@
1
+ Description:
2
+ The site_search:google_custom_search generator creates a google_custom_search.yml file in the config
3
+ directory. This is required for loading the api key and cx records for your custom searches.
@@ -0,0 +1,12 @@
1
+ module SiteSearch
2
+ module Generators
3
+ class GoogleCustomSearchGenerator < Rails::Generators::Base
4
+ source_root File.expand_path('../templates', __FILE__)
5
+
6
+ def generate_google_custom_search
7
+ copy_file "google_custom_search.yml", "config/google_custom_search.yml"
8
+ copy_file "load_site_search_config.rb", "config/initializers/load_site_search_config.rb"
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,25 @@
1
+ # Put your Google Custom Search API key and any search engines you have set up.
2
+
3
+ development: &defaults
4
+ api_key: "YOUR-API-KEY"
5
+ search_engines:
6
+ my_search_engine:
7
+ cx: "CX-RECORD-FOR-MY-SEARCH-ENGINE"
8
+ #cref: "{optional}-YOUR-SEARCH-ENGINE-URL"
9
+ #lr: "{optional}-LANGUAGE-RESTRICTION"
10
+
11
+ # The following options can be supplied or overridden in the options hash
12
+ #num: "{optional}-NUM-OF-RESULTS-1-10(*default)"
13
+ #safe: "{optional}-high/medium/off(*default)"
14
+ #start: "{optional}start-index-between-1(*default)-101"
15
+ #filter: "{optional}-0(duplicates-off)/1(duplicated-on-*default)"
16
+ #alt: "{optional}-json(*default)/atom"
17
+
18
+ production:
19
+ <<: *defaults
20
+
21
+ test:
22
+ <<: *defaults
23
+
24
+
25
+
@@ -0,0 +1 @@
1
+ GOOGLE_SEARCH_CONFIG = YAML.load_file("#{Rails.root}/config/google_custom_search.yml")[Rails.env]
@@ -0,0 +1,30 @@
1
+ module SiteSearch
2
+ # A general SiteSearch exception
3
+ class Error < StandardError; end
4
+
5
+ # The search engine could not be located due to an invalid cx record
6
+ class InvalidSearchRequest < Error; end
7
+
8
+ # The search engine has not been configured in the config yaml file
9
+ class UndefinedSearchEngine < Error; end
10
+
11
+ # The search engine has restricted access, likely cause is exceeding the Google Custom Search request limit
12
+ class ForbiddenAccessToSearchEngine < Error; end
13
+
14
+ # You can rescue from this error in the controller to display the error message provided or the default message
15
+ class NoResults < Error
16
+ attr_reader :query
17
+ attr_writer :default_message
18
+
19
+ def initialize(message = nil, query = nil)
20
+ @message = message
21
+ @query = query
22
+ @default_message = "No results for '#{@query}'"
23
+ end
24
+
25
+ def to_s
26
+ @message || @default_message
27
+ end
28
+ end
29
+
30
+ end
@@ -0,0 +1,105 @@
1
+ module SiteSearch
2
+ require 'uri'
3
+ require 'net/https'
4
+
5
+ class GoogleSearch
6
+ require 'json'
7
+ require 'rexml/document'
8
+ attr_reader :results, :total, :start_index, :raw
9
+
10
+ alias_method :raw?, :raw
11
+
12
+ def initialize(search_engine, query, options={})
13
+ raise NoResults.new if query.blank?
14
+ @query = escape_html(query).gsub(" ", '+')
15
+ @results = []
16
+ doc = get_document(set_uri(options, search_engine.to_s))
17
+ @raw = doc.body
18
+ case options[:alt]
19
+ when 'atom' then parse_atom(doc)
20
+ else parse_json(doc)
21
+ end
22
+ end
23
+
24
+ private
25
+ def escape_html(str)
26
+ str.gsub(/<\/?[^>]*>/, "")
27
+ end
28
+
29
+ def set_uri(options, search_engine)
30
+ raise(UndefinedSearchEngine, "'#{search_engine}' is undefined for #{self.class}") if !GOOGLE_SEARCH_CONFIG['search_engines'].has_key? search_engine
31
+
32
+ key = GOOGLE_SEARCH_CONFIG['api_key']
33
+ cx = GOOGLE_SEARCH_CONFIG['search_engines'][search_engine]['cx']
34
+
35
+ params = "key=#{key}&cx=#{cx}&q=#{@query}"
36
+
37
+ options_hash = {}
38
+
39
+ options_hash.store('cref', GOOGLE_SEARCH_CONFIG['search_engines'][search_engine]['cref'])
40
+ options_hash.store('lr', GOOGLE_SEARCH_CONFIG['search_engines'][search_engine]['lr'])
41
+ options_hash.store('num', options[:num] || GOOGLE_SEARCH_CONFIG['search_engines'][search_engine]['num'])
42
+ options_hash.store('safe', options[:safe] || GOOGLE_SEARCH_CONFIG['search_engines'][search_engine]['safe'])
43
+ options_hash.store('start', options[:start] || GOOGLE_SEARCH_CONFIG['search_engines'][search_engine]['start'])
44
+ options_hash.store('filter', options[:filter] || GOOGLE_SEARCH_CONFIG['search_engines'][search_engine]['filter'])
45
+ options_hash.store('alt', options[:alt] || GOOGLE_SEARCH_CONFIG['search_engines'][search_engine]['alt'])
46
+
47
+ options_hash.each do |k, v|
48
+ params = params + "&#{k}=#{v}" if v.present?
49
+ end
50
+
51
+ return URI.parse("https://www.googleapis.com/customsearch/v1?#{params}")
52
+ end
53
+
54
+ def get_document(uri)
55
+ http = Net::HTTP.new(uri.host, uri.port)
56
+ http.use_ssl = true
57
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
58
+ return http.request(Net::HTTP::Get.new(uri.request_uri))
59
+ end
60
+
61
+ def parse_json(doc)
62
+ json = JSON.parse(doc.body)
63
+ case doc
64
+ when Net::HTTPSuccess
65
+ then
66
+ json['queries']['request'].each do |r|
67
+ @total =r['totalResults']
68
+ @start_index = r['startIndex']
69
+ end
70
+ raise NoResults.new(nil, @query) if @total.to_i < 1
71
+ items = json['items']
72
+ items.each do |item|
73
+ @results << ResultItem.new(item)
74
+ end
75
+ when Net::HTTPForbidden then raise ForbiddenAccessToSearchEngine, json['error']['message']
76
+ else raise InvalidSearchRequest, json['error']['message']
77
+ end
78
+ end
79
+
80
+ def parse_atom(doc)
81
+ atom = REXML::Document.new(doc.body)
82
+ case doc
83
+ when Net::HTTPSuccess
84
+ then
85
+ @total = atom.elements["//opensearch:totalResults"].text
86
+ raise NoResults.new(nil, @query) if @total.to_i < 1
87
+ @start_index = atom.elements["//opensearch:startIndex"].text
88
+ REXML::XPath.each(atom, "//entry").each do |el|
89
+ item = {}
90
+ item.store('link', el.elements["link"].attributes["href"])
91
+ item.store('displayLink', el.elements["link"].attributes["title"])
92
+ item.store('htmlSnippet', el.elements["summary"].text)
93
+ if item['htmlSnippet'].is_a? String
94
+ item.store('snippet', escape_html(item['htmlSnippet']))
95
+ end
96
+ @results << ResultItem.new(item)
97
+ end
98
+ when Net::HTTPForbidden then raise ForbiddenAccessToSearchEngine, atom.elements["//internalReason"].text
99
+ else raise InvalidSearchRequest, atom.elements["//internalReason"].text
100
+ end
101
+ end
102
+
103
+ end
104
+
105
+ end
@@ -0,0 +1,12 @@
1
+ class ResultItem
2
+ attr_reader :url, :text, :title, :html
3
+
4
+ # Creates attributes that can easily be accessed from the view
5
+ def initialize(item)
6
+ @url = item['link']
7
+ @text = item['snippet']
8
+ @title = item['displayLink']
9
+ @html = item['htmlSnippet']
10
+ end
11
+
12
+ end
@@ -0,0 +1,3 @@
1
+ require "site_search/google_search"
2
+ require 'site_search/result_item'
3
+ require "site_search/exceptions"
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: site_search
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Gareth Allen
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-08-16 00:00:00 +01:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: SiteSearch allows for multiple Google Custom Search engines to be configured, and provides JSON and Atom formats
23
+ email: gaz.allen12@gmail.co.uk
24
+ executables: []
25
+
26
+ extensions: []
27
+
28
+ extra_rdoc_files: []
29
+
30
+ files:
31
+ - lib/generators/site_search/google_custom_search_generator.rb
32
+ - lib/generators/site_search/templates/google_custom_search.yml
33
+ - lib/generators/site_search/templates/load_site_search_config.rb
34
+ - lib/generators/site_search/USAGE
35
+ - lib/site_search/exceptions.rb
36
+ - lib/site_search/google_search.rb
37
+ - lib/site_search/result_item.rb
38
+ - lib/site_search.rb
39
+ - MIT-LICENSE
40
+ - Rakefile
41
+ - Gemfile
42
+ - README.md
43
+ has_rdoc: true
44
+ homepage: http://github.com/garetha/site_search
45
+ licenses: []
46
+
47
+ post_install_message:
48
+ rdoc_options: []
49
+
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ hash: 3
58
+ segments:
59
+ - 0
60
+ version: "0"
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ hash: 3
67
+ segments:
68
+ - 0
69
+ version: "0"
70
+ requirements: []
71
+
72
+ rubyforge_project:
73
+ rubygems_version: 1.3.7
74
+ signing_key:
75
+ specification_version: 3
76
+ summary: Provides site searching capabilities to rack applications using the Google Custom Search API
77
+ test_files: []
78
+