bcms_google_mini_search 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown CHANGED
@@ -1,13 +1,19 @@
1
1
  # Google Mini Search Module
2
2
 
3
- This module allows BrowserCMS to integrate with a Google Mini Search Appliance. Google Mini is a standalone search
4
- server, which can be configured to crawl your website. This module submits queries to a Mini server, and formats the results.
3
+ This module allows BrowserCMS to integrate with a Google Search Appliance (Mini or GSA). Google Search Appliance is a standalone search
4
+ server, which can be configured to crawl your website. This module submits queries to a GSA/Mini server, and formats the results.
5
5
  It consists of the following two portlets.
6
6
 
7
7
  1. Search Box - Displays an input box that submits a search query.
8
8
  2. Google Mini Search Results Portlet - Sends query to the Mini, formats the XML response and displays the results.
9
9
 
10
- Note: This module assume the BrowserCMS web site owner has access to their own Google Mini server, either hosted by
10
+ Features:
11
+ 1. Allows for formatted results of GSA search results.
12
+ 2. Will display Key Matches (as of 1.1)
13
+ 3. Will display Synonyms/Related Queries (as of 1.1)
14
+ 4. Allows conditional overriding of collections (i.e. by default it will search one collection, but a 'site=OTHER_COLLECTION' param can be passed to override that)
15
+
16
+ Note: This module assume the BrowserCMS web site owner has access to their own GSA/Google Mini server, either hosted by
11
17
  themselves or a third party service.
12
18
 
13
19
  ## A. Instructions
@@ -55,8 +61,8 @@ the module work, you will have to configure two portlets.
55
61
  1. In your sitemap, create a new section called 'Search', with a path '/search'.
56
62
  2. Create a page called 'Search Results', with a path '/search/search-results'.
57
63
  3. On that page, add a new 'Google Mini Search Engine' portlet. Keep the default for most fields.
58
- 4. In the Service URL, field, enter in the domain name to your google mini server (i.e. http://google.mini.mysite.com)
59
- 5. In the Colleciton Name field, enter the same name you gave your collection in B.2.2. (i.e. MYSITE)
64
+ 4. In the Service URL, field, enter in the domain name to your google mini server (i.e. http://google.mini.mysite.com). Note: This URL should be just the domain, i.e. no /search.
65
+ 5. In the Collection Name field, enter the same name you gave your collection in B.2.2. (i.e. MYSITE)
60
66
  6. In the Front End Name field, enter the same name you have your frontend in B.3.2 (i.e. MYSITE_frontend)
61
67
  7. Make sure the 'path' attribute is the same as the page you are adding the portlet to (i.e. /search/search-results
62
68
  8. Save the portlet
@@ -7,8 +7,9 @@ class SearchResult
7
7
  # a paging results of Search Results.
8
8
  #
9
9
  def self.find(query, options={})
10
+ return QueryResult.new unless query
10
11
  xml_doc = fetch_xml_doc(query, options)
11
- results = convert_to_results(xml_doc, options)
12
+ results = parse_xml(xml_doc, options)
12
13
  results.query = query
13
14
  portlet = find_search_engine_portlet(options)
14
15
  results.path = portlet.path
@@ -21,7 +22,7 @@ class SearchResult
21
22
  count ? count.text.to_i : 0
22
23
  end
23
24
 
24
- def self.parse_results(xml_doc)
25
+ def self.parse_hits(xml_doc)
25
26
  root = xml_doc.root
26
27
  results = []
27
28
  xml_doc.elements.each('GSP/RES/R') do |ele|
@@ -37,10 +38,11 @@ class SearchResult
37
38
  results
38
39
  end
39
40
 
40
- def self.convert_to_results(xml_doc, options={})
41
- array = parse_results(xml_doc)
42
-
43
- results = PagingResults.new(array)
41
+ def self.parse_xml(xml_doc, options={})
42
+ hits = parse_hits(xml_doc)
43
+ results = QueryResult.new(hits)
44
+ results.key_matches= parse_key_matches(xml_doc)
45
+ results.synonyms = parse_synonyms(xml_doc, results)
44
46
  results.results_count = parse_results_count(xml_doc)
45
47
  results.num_pages = calculate_results_pages(results.results_count)
46
48
  results.start = options[:start] ? options[:start] : 0
@@ -58,11 +60,18 @@ class SearchResult
58
60
 
59
61
  def self.build_mini_url(options, query)
60
62
  portlet = find_search_engine_portlet(options)
61
- url = "#{portlet.service_url}/search?q=#{query}&output=xml_no_dtd&client=#{portlet.front_end_name}&site=#{portlet.collection_name}&filter=0"
63
+ encoded_query = CGI::escape(query)
64
+
65
+ site = portlet.collection_name
66
+ if options[:site]
67
+ site = options[:site]
68
+ end
69
+ # encoded_query = query
70
+ url = "#{portlet.service_url}/search?q=#{encoded_query}&output=xml_no_dtd&client=#{portlet.front_end_name}&site=#{site}&filter=0"
62
71
  if options[:start]
63
72
  url = url + "&start=#{options[:start]}"
64
73
  end
65
- return url
74
+ return url
66
75
  end
67
76
 
68
77
  def self.find_search_engine_portlet(options)
@@ -83,13 +92,45 @@ class SearchResult
83
92
  return xml_doc
84
93
  end
85
94
 
95
+ def self.parse_key_matches(xml_doc)
96
+ matches = []
97
+ xml_doc.elements.each('GSP/GM') do |ele|
98
+ key_match = KeyMatch.new
99
+ key_match.url = ele.elements["GL"].text
100
+ key_match.title = ele.elements["GD"].text
101
+ matches << key_match
102
+ end
103
+ matches
104
+ end
86
105
 
106
+ def self.parse_synonyms(xml_doc, query_result)
107
+ synonyms = []
108
+ xml_doc.elements.each('GSP/Synonyms/OneSynonym') do |ele|
109
+ synonym = Synonym.new
110
+ synonym.query = ele.attributes["q"]
111
+ synonym.label = ele.text
112
+ synonym.query_result = query_result
113
+ synonyms << synonym
114
+ end
115
+ synonyms
116
+ end
117
+ # Represents the entire result of the query
118
+ class QueryResult < Array
87
119
 
88
- class PagingResults < Array
89
-
90
- attr_accessor :results_count, :num_pages, :current_page, :start, :query, :pages
120
+ attr_accessor :results_count, :num_pages, :current_page, :start, :query, :pages, :key_matches, :synonyms
91
121
  attr_writer :path
92
122
 
123
+ def initialize(array=[])
124
+ # Need to set defaults so an empty result set works.
125
+ self.start = 0
126
+ self.results_count=0
127
+ self.key_matches = []
128
+ self.synonyms = []
129
+ self.num_pages = 1
130
+ super(array)
131
+
132
+ end
133
+
93
134
  def path
94
135
  @path ? @path : "/search/search-results"
95
136
  end
@@ -138,6 +179,29 @@ class SearchResult
138
179
  def page_path(page_num)
139
180
  "#{path}?query=#{query}&start=#{page_num * 10 - 10}"
140
181
  end
182
+
183
+ def key_matches?
184
+ !key_matches.empty?
185
+ end
186
+
187
+ def synonyms?
188
+ !synonyms.empty?
189
+ end
190
+ end
191
+
192
+ # Sometimes refered to as 'Featured Links', though the GSA UI uses the KeyMatch
193
+ class KeyMatch
194
+ attr_accessor :url, :title
195
+ end
196
+
197
+ # AKA Related Query in Google UI
198
+ class Synonym
199
+ attr_accessor :query, :label, :query_result
200
+
201
+ # Return the url that should be
202
+ def url
203
+ "#{query_result.path}?query=#{query}"
204
+ end
141
205
  end
142
206
 
143
207
 
@@ -1,9 +1,12 @@
1
1
  class GoogleMiniSearchEnginePortlet < Portlet
2
-
2
+
3
+ enable_template_editor true
4
+
3
5
  def render
4
6
  @query = params[:query]
7
+ @site = params[:site]
5
8
  @start = params[:start] ? params[:start].to_i : 0
6
- @results = SearchResult.find(@query, {:start => @start, :portlet => @portlet})
9
+ @results = SearchResult.find(@query, {:start => @start, :portlet => @portlet, :site=>@site})
7
10
  end
8
11
 
9
12
  end
@@ -1,6 +1,6 @@
1
1
  <%= f.cms_text_field :name, :default_value => "Google Mini Search Engine", :instructions=>"The Search Box portlet will look this up by name, so make it unique." %>
2
2
  <%= f.cms_text_field :path, :default_value => "/search/search-results", :instructions=>"The path of the page this portlet will be embedded in." %>
3
3
  <%= f.cms_text_field :service_url, :default_value=> "http://", :instructions => "Full Domain name where the Google Mini server is hosted, i.e. 'http://mini.somedomain.com'." %>
4
- <%= f.cms_text_field :collection_name, :instructions => "Copy the name of the Collection from Google Mini here." %>
5
- <%= f.cms_text_field :front_end_name, :instructions => "Copy the name of the Collection front end from Google Mini here." %>
6
- <%= f.cms_text_area :template, :default_value => @block.class.default_template %>
4
+ <%= f.cms_text_field :collection_name, :instructions => "Copy the name of the Collection from Google Mini here. (Can pass 'site' param to override as well).", :default_value=>"default_collection" %>
5
+ <%= f.cms_text_field :front_end_name, :instructions => "Copy the name of the Collection front end from Google Mini here.", :default_value=>"default_frontend" %>
6
+ <%= f.cms_template_editor :template %>
@@ -2,7 +2,21 @@
2
2
  For '<%= @results.query %>', found <%= @results.results_count %> results. <br />
3
3
  <% if @results.previous_page? %><%= link_to h("< Back"), @results.previous_page_path %><% end %>
4
4
  <% if @results.next_page? %><%= link_to h("Next >"), @results.next_page_path %><% end %>
5
- <ul>
5
+ <% if @results.key_matches? %>
6
+ <ul class="key_matches">
7
+ <% @results.key_matches.each do |match| %>
8
+ <li><%= link_to match.title, match.url %></li>
9
+ <% end %>
10
+ </ul>
11
+ <% end %>
12
+ <% if @results.synonyms? %>
13
+ <span class="synonyms">You could also try:
14
+ <% @results.synonyms.each do |synonym| %>
15
+ <%= link_to synonym.label, synonym.url %>
16
+ <% end %>
17
+ </span>
18
+ <% end %>
19
+ <ul class="search_results">
6
20
  <% @results.each do |result|%>
7
21
  <li>
8
22
  <%= result.number %> <%= link_to result.title, result.url, :class=>"search_result_title" %><br />
@@ -1,4 +1,4 @@
1
1
  <% form_tag @search_engine.path, :method=>'GET' do %>
2
- <%= text_field_tag 'query' %>
2
+ <%= text_field_tag 'query', params[:query] %>
3
3
  <%= submit_tag 'Go' %>
4
4
  <% end %>
@@ -0,0 +1,9 @@
1
+ require 'test_helper'
2
+ require 'performance_test_help'
3
+
4
+ # Profiling results for each test method are written to tmp/performance.
5
+ class BrowsingTest < ActionController::PerformanceTest
6
+ def test_homepage
7
+ get '/'
8
+ end
9
+ end
@@ -0,0 +1,39 @@
1
+ ENV["RAILS_ENV"] = "test"
2
+ require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
3
+ require 'test_help'
4
+ require 'mocha'
5
+
6
+ class ActiveSupport::TestCase
7
+ # Transactional fixtures accelerate your tests by wrapping each test method
8
+ # in a transaction that's rolled back on completion. This ensures that the
9
+ # test database remains unchanged so your fixtures don't have to be reloaded
10
+ # between every test method. Fewer database queries means faster tests.
11
+ #
12
+ # Read Mike Clark's excellent walkthrough at
13
+ # http://clarkware.com/cgi/blosxom/2005/10/24#Rails10FastTesting
14
+ #
15
+ # Every Active Record database supports transactions except MyISAM tables
16
+ # in MySQL. Turn off transactional fixtures in this case; however, if you
17
+ # don't care one way or the other, switching from MyISAM to InnoDB tables
18
+ # is recommended.
19
+ #
20
+ # The only drawback to using transactional fixtures is when you actually
21
+ # need to test transactions. Since your test is bracketed by a transaction,
22
+ # any transactions started in your code will be automatically rolled back.
23
+ self.use_transactional_fixtures = true
24
+
25
+ # Instantiated fixtures are slow, but give you @david where otherwise you
26
+ # would need people(:david). If you don't want to migrate your existing
27
+ # test cases which use the @david style and don't mind the speed hit (each
28
+ # instantiated fixtures translates to a database query per test method),
29
+ # then set this back to true.
30
+ self.use_instantiated_fixtures = false
31
+
32
+ # Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order.
33
+ #
34
+ # Note: You'll currently still have to declare fixtures explicitly in integration tests
35
+ # -- they do not yet inherit this setting
36
+ fixtures :all
37
+
38
+ # Add more helper methods to be used by all tests here...
39
+ end
@@ -0,0 +1,4 @@
1
+ require 'test_helper'
2
+
3
+ class SearchEngineHelperTest < ActionView::TestCase
4
+ end
@@ -0,0 +1,15 @@
1
+ require File.join(File.dirname(__FILE__), '/../../test_helper')
2
+
3
+ class GoogleMiniSearchEngineTest < ActiveSupport::TestCase
4
+
5
+ test "Should be able to create new instance of a portlet" do
6
+ assert GoogleMiniSearchEnginePortlet.create!(:name => "New Portlet")
7
+ end
8
+
9
+
10
+
11
+ test "Path attribute can be set in constructor" do
12
+ portlet = GoogleMiniSearchEnginePortlet.create!(:name=>"Engine", :path => "/engine")
13
+ assert_equal "/engine", portlet.path
14
+ end
15
+ end
@@ -0,0 +1,9 @@
1
+ require File.join(File.dirname(__FILE__), '/../../test_helper')
2
+
3
+ class SearchBoxTest < ActiveSupport::TestCase
4
+
5
+ test "Should be able to create new instance of a portlet" do
6
+ assert SearchBoxPortlet.create!(:name => "New Portlet")
7
+ end
8
+
9
+ end
@@ -0,0 +1,428 @@
1
+ require File.join(File.dirname(__FILE__), '/../test_helper')
2
+
3
+ class SearchResultTest < ActiveSupport::TestCase
4
+
5
+ def setup
6
+ @xml_string = <<EOF
7
+ <GSP>
8
+ <RES>
9
+ <M>2</M>
10
+ <R N="1">
11
+ <U>http://someurl.com</U>
12
+ <T>TITLE</T>
13
+ <S>BLURB</S>
14
+ <HAS>
15
+ <C SZ="1k" />
16
+ </HAS>
17
+ </R>
18
+ <R N="2">
19
+ <U>http://someurl2.com</U>
20
+ <T>TITLE 2</T>
21
+ <S>BLURB 2</S>
22
+ <HAS>
23
+ <C SZ="2k"/>
24
+ </HAS>
25
+ </R>
26
+ </RES>
27
+ </GSP>
28
+ EOF
29
+ @xml_doc = REXML::Document.new @xml_string
30
+
31
+ @large_results_set = <<EOF
32
+ <GSP>
33
+ <RES>
34
+ <M>35</M>
35
+ <R N="1">
36
+ <U>http://someurl.com</U>
37
+ <T>TITLE</T>
38
+ <S>BLURB</S>
39
+ <HAS>
40
+ <C SZ="1k" />
41
+ </HAS>
42
+ </R>
43
+ <R N="2">
44
+ <U>http://someurl2.com</U>
45
+ <T>TITLE 2</T>
46
+ <S>BLURB 2</S>
47
+ <HAS>
48
+ <C SZ="2k"/>
49
+ </HAS>
50
+ </R>
51
+ </RES>
52
+ </GSP>
53
+ EOF
54
+ @large_xml_doc = REXML::Document.new(@large_results_set)
55
+
56
+
57
+ end
58
+
59
+ test "Parse result count from google mini results xml." do
60
+
61
+ xml = <<EOF
62
+ <GSP>
63
+ <RES>
64
+ <M>35</M>
65
+ </RES>
66
+ </GSP>
67
+ EOF
68
+ empty_doc = REXML::Document.new xml
69
+ assert_equal 35, SearchResult.parse_results_count(empty_doc)
70
+ assert_equal 35, SearchResult.parse_xml(empty_doc).results_count
71
+ assert_equal 4, SearchResult.parse_xml(empty_doc).num_pages
72
+
73
+ end
74
+
75
+ test "Default result count is zero." do
76
+
77
+ xml = <<EOF
78
+ <GSP>
79
+ <RES>
80
+ </RES>
81
+ </GSP>
82
+ EOF
83
+ empty_doc = REXML::Document.new xml
84
+ assert_equal 0, SearchResult.parse_results_count(empty_doc)
85
+
86
+ end
87
+
88
+ test "Empty xml gives empty results" do
89
+ xml = <<EOF
90
+ <GSP>
91
+ <RES>
92
+ </RES>
93
+ </GSP>
94
+ EOF
95
+ empty_doc = REXML::Document.new xml
96
+ SearchResult.expects(:fetch_xml_doc).with("therapy", {}).returns(empty_doc)
97
+
98
+ assert_equal [], SearchResult.find("therapy", {})
99
+ end
100
+
101
+ test "Parse result set" do
102
+
103
+ results = SearchResult.parse_hits(@xml_doc)
104
+ assert_equal 2, results.size
105
+
106
+ assert_equal "1", results[0].number
107
+ assert_equal "http://someurl.com", results[0].url
108
+ assert_equal "TITLE", results[0].title
109
+ assert_equal "BLURB", results[0].description
110
+ assert_equal "1k", results[0].size
111
+
112
+ assert_equal "2", results[1].number
113
+ assert_equal "http://someurl2.com", results[1].url
114
+ assert_equal "TITLE 2", results[1].title
115
+ assert_equal "BLURB 2", results[1].description
116
+ assert_equal "2k", results[1].size
117
+ end
118
+
119
+
120
+ test "Calculates the results pages" do
121
+ assert_equal 1, SearchResult.calculate_results_pages(9)
122
+ assert_equal 1, SearchResult.calculate_results_pages(10)
123
+ assert_equal 2, SearchResult.calculate_results_pages(19)
124
+ assert_equal 2, SearchResult.calculate_results_pages(20)
125
+ assert_equal 3, SearchResult.calculate_results_pages(21)
126
+ assert_equal 4, SearchResult.calculate_results_pages(40)
127
+ assert_equal 0, SearchResult.calculate_results_pages(0)
128
+
129
+ end
130
+
131
+ test "Calculates current page based on total results and start" do
132
+ results = SearchResult::QueryResult.new
133
+ results.start = 0
134
+ assert_equal 1, results.current_page
135
+
136
+ results.start = 10
137
+ assert_equal 2, results.current_page
138
+
139
+ results.start = 20
140
+ assert_equal 3, results.current_page
141
+
142
+ results.start = 30
143
+ assert_equal 4, results.current_page
144
+ end
145
+
146
+ test "Next start" do
147
+ r = SearchResult::QueryResult.new
148
+ r.start = 0
149
+ assert_equal 10, r.next_start
150
+ r.start = 10
151
+ assert_equal 20, r.next_start
152
+ r.start = 20
153
+ assert_equal 30, r.next_start
154
+ end
155
+
156
+ test "Find results should return a paging list of documents with no start" do
157
+ SearchResult.expects(:fetch_xml_doc).with("therapy", {}).returns(@large_xml_doc)
158
+
159
+ results = SearchResult.find("therapy")
160
+ assert_equal "therapy", results.query
161
+ assert_equal 35, results.results_count
162
+ assert_equal 4, results.num_pages
163
+ assert_equal 0, results.start
164
+ assert_equal 2, results.size
165
+ assert_equal 1, results.current_page
166
+ assert_equal 10, results.next_start
167
+ assert results.next_page?
168
+ assert_equal -10, results.previous_start
169
+ assert_equal false, results.previous_page?
170
+ assert_equal (1..4), results.pages
171
+
172
+ end
173
+
174
+
175
+ test "Find results starts on page 2, if a start is specified" do
176
+ SearchResult.expects(:fetch_xml_doc).with("therapy", :start=>10).returns(@large_xml_doc)
177
+
178
+ results = SearchResult.find("therapy", :start => 10)
179
+ assert_equal 35, results.results_count
180
+ assert_equal 4, results.num_pages
181
+ assert_equal 10, results.start
182
+ assert_equal 2, results.size
183
+ assert_equal 2, results.current_page
184
+ assert_equal 20, results.next_start
185
+ assert results.next_page?
186
+ assert_equal 0, results.previous_start
187
+ assert_equal true, results.previous_page?
188
+ end
189
+
190
+ test "No next start when on the last page" do
191
+ SearchResult.expects(:fetch_xml_doc).with("therapy", {:start => 30}).returns(@large_xml_doc)
192
+
193
+ results = SearchResult.find("therapy", :start => 30)
194
+ assert_equal 40, results.next_start
195
+ assert_equal false, results.next_page?
196
+ assert_equal 20, results.previous_start
197
+ assert_equal true, results.previous_page?
198
+ end
199
+
200
+ test "Should be no previous or next for a single page of results" do
201
+ SearchResult.expects(:fetch_xml_doc).with("therapy", {}).returns(@xml_doc)
202
+
203
+ results = SearchResult.find("therapy")
204
+ assert_equal false, results.next_page?
205
+ assert_equal false, results.previous_page?
206
+ assert_equal [], results.pages
207
+ end
208
+
209
+ test "Behavior of ranges" do
210
+ c = 0
211
+ (1..4).each_with_index do |i, count|
212
+ assert_equal count + 1, i
213
+ c = count
214
+ end
215
+ assert_equal 3, c
216
+ end
217
+
218
+ test "current_page should check to see if the current page matches" do
219
+ results = SearchResult::QueryResult.new
220
+ results.start = 0
221
+
222
+ assert_equal true, results.current_page?(1)
223
+ assert_equal false, results.current_page?(2)
224
+ assert_equal false, results.current_page?(3)
225
+ assert_equal false, results.current_page?(4)
226
+
227
+ end
228
+
229
+ test "Path to next page" do
230
+ results = SearchResult::QueryResult.new
231
+ results.start = 0
232
+ results.path = "/search/search-results"
233
+ results.query = "X"
234
+
235
+ assert_equal "/search/search-results?query=X&start=10", results.next_page_path
236
+ end
237
+
238
+ test "Path to previous page" do
239
+ results = SearchResult::QueryResult.new
240
+ results.start = 20
241
+ results.path = "/search/search-results"
242
+ results.query = "X"
243
+
244
+ assert_equal "/search/search-results?query=X&start=10", results.previous_page_path
245
+ end
246
+
247
+ test "Sets path to default search-results" do
248
+ results = SearchResult::QueryResult.new
249
+ assert_equal "/search/search-results", results.path
250
+ end
251
+
252
+ test "Setting path overrides the defaults" do
253
+ results = SearchResult::QueryResult.new
254
+ results.path = "/other"
255
+ assert_equal "/other", results.path
256
+ end
257
+
258
+ test "page_path" do
259
+ results = SearchResult::QueryResult.new
260
+ results.query = "X"
261
+
262
+ assert_equal "/search/search-results?query=X&start=0", results.page_path(1)
263
+ assert_equal "/search/search-results?query=X&start=10", results.page_path(2)
264
+ assert_equal "/search/search-results?query=X&start=20", results.page_path(3)
265
+ assert_equal "/search/search-results?query=X&start=30", results.page_path(4)
266
+
267
+ end
268
+
269
+ test "Portlet attributes are used to look up path" do
270
+ portlet = GoogleMiniSearchEnginePortlet.new(:name=>"Engine", :path => "/engine")
271
+ SearchResult.expects(:fetch_xml_doc).with("therapy", {:portlet=> portlet}).returns(@xml_doc)
272
+
273
+ results = SearchResult.find("therapy", {:portlet=> portlet})
274
+
275
+ assert_equal "/engine", results.path
276
+ end
277
+
278
+ test "Default path is used if no portlet specified" do
279
+ SearchResult.expects(:fetch_xml_doc).with("therapy", {}).returns(@xml_doc)
280
+ results = SearchResult.find("therapy", {})
281
+ assert_equal "/search/search-results", results.path
282
+ end
283
+
284
+ test "Uses service URL from portlet" do
285
+ portlet = GoogleMiniSearchEnginePortlet.new(
286
+ :name=>"Engine", :path => "/engine", :service_url => "http://mini.someurl.com",
287
+ :collection_name => "COLLECT", :front_end_name => "FRONT_END")
288
+
289
+ url = SearchResult.build_mini_url({:portlet => portlet}, "STUFF")
290
+ assert_equal "http://mini.someurl.com/search?q=STUFF&output=xml_no_dtd&client=FRONT_END&site=COLLECT&filter=0", url
291
+
292
+ url = SearchResult.build_mini_url({:portlet => portlet, :start=>100}, "STUFF")
293
+ assert_equal "http://mini.someurl.com/search?q=STUFF&output=xml_no_dtd&client=FRONT_END&site=COLLECT&filter=0&start=100", url
294
+
295
+ end
296
+
297
+ test "Explicitly passing a collection in will query with that rather than a default collection" do
298
+ portlet = GoogleMiniSearchEnginePortlet.new(
299
+ :name=>"Engine", :path => "/engine", :service_url => "http://mini.someurl.com",
300
+ :collection_name => "COLLECT", :front_end_name => "FRONT_END")
301
+
302
+ url = SearchResult.build_mini_url({:portlet => portlet, :site=>"ANOTHER_COLLECTION"}, "STUFF")
303
+ assert_equal "http://mini.someurl.com/search?q=STUFF&output=xml_no_dtd&client=FRONT_END&site=ANOTHER_COLLECTION&filter=0", url
304
+ end
305
+
306
+ test "Handles multiword queries" do
307
+ url = SearchResult.build_mini_url({}, "One Two")
308
+ assert_equal "/search?q=One+Two&output=xml_no_dtd&client=&site=&filter=0", url
309
+ end
310
+
311
+ test "Handles keymatches in results" do
312
+ @xml_with_keymatches = <<XML
313
+ <GSP>
314
+ <GM>
315
+ <GL>http://url1.org</GL>
316
+ <GD>URL 1</GD>
317
+ </GM>
318
+ <GM>
319
+ <GL>http://url2.org</GL>
320
+ <GD>URL 2</GD>
321
+ </GM>
322
+ <RES>
323
+ <M>35</M>
324
+ <R N="1">
325
+ <U>http://someurl.com</U>
326
+ <T>TITLE</T>
327
+ <S>BLURB</S>
328
+ <HAS>
329
+ <C SZ="1k" />
330
+ </HAS>
331
+ </R>
332
+ <R N="2">
333
+ <U>http://someurl2.com</U>
334
+ <T>TITLE 2</T>
335
+ <S>BLURB 2</S>
336
+ <HAS>
337
+ <C SZ="2k"/>
338
+ </HAS>
339
+ </R>
340
+ </RES>
341
+ </GSP>
342
+ XML
343
+ @results_with_keymatches = REXML::Document.new @xml_with_keymatches
344
+
345
+ result = SearchResult.parse_xml @results_with_keymatches
346
+
347
+ assert_equal true, result.key_matches?
348
+ assert_equal 2, result.key_matches.size
349
+ assert_equal "http://url1.org", result.key_matches[0].url
350
+ assert_equal "URL 1", result.key_matches[0].title
351
+ assert_equal "http://url2.org", result.key_matches[1].url
352
+ assert_equal "URL 2", result.key_matches[1].title
353
+ end
354
+
355
+ test "Handles results with no keymatches" do
356
+ result = SearchResult.parse_xml @xml_doc
357
+ assert_equal false, result.key_matches?
358
+ end
359
+
360
+ test "Handle Synonyms / Related Queries" do
361
+ xml_with_synonyms = <<XML
362
+ <GSP>
363
+ <Synonyms>
364
+ <OneSynonym q="Query 1">Label 1</OneSynonym>
365
+ <OneSynonym q="Query 2">Label 2</OneSynonym>
366
+ </Synonyms>
367
+ <RES>
368
+ <M>35</M>
369
+ <R N="1">
370
+ <U>http://someurl.com</U>
371
+ <T>TITLE</T>
372
+ <S>BLURB</S>
373
+ <HAS>
374
+ <C SZ="1k" />
375
+ </HAS>
376
+ </R>
377
+ <R N="2">
378
+ <U>http://someurl2.com</U>
379
+ <T>TITLE 2</T>
380
+ <S>BLURB 2</S>
381
+ <HAS>
382
+ <C SZ="2k"/>
383
+ </HAS>
384
+ </R>
385
+ </RES>
386
+ </GSP>
387
+ XML
388
+ xml_doc_with_synonyms = REXML::Document.new xml_with_synonyms
389
+
390
+ result = SearchResult.parse_xml xml_doc_with_synonyms
391
+
392
+ result.expects(:path).returns("/search").twice
393
+ assert_equal true, result.synonyms?
394
+ assert_equal 2, result.synonyms.size
395
+ assert_equal "Label 1", result.synonyms[0].label
396
+ assert_equal "Query 1", result.synonyms[0].query
397
+ assert_equal "/search?query=Query 1", result.synonyms[0].url
398
+ assert_equal "Label 2", result.synonyms[1].label
399
+ assert_equal "Query 2", result.synonyms[1].query
400
+ assert_equal "/search?query=Query 2", result.synonyms[1].url
401
+
402
+ end
403
+
404
+ test "Handles results with no Synonyms" do
405
+ result = SearchResult.parse_xml @xml_doc
406
+ assert_equal false, result.synonyms?
407
+ end
408
+
409
+ test "Calculate URL for Related Queries/Synonyms" do
410
+ syn = SearchResult::Synonym.new
411
+ syn.query = "Testing"
412
+ mock_result = mock()
413
+ mock_result.expects(:path).returns("/random")
414
+ syn.query_result = mock_result
415
+ assert_equal "/random?query=Testing", syn.url
416
+ end
417
+
418
+ test "No query = empty results" do
419
+ result = SearchResult.find(nil)
420
+ assert_equal 0, result.size
421
+ assert_equal 0, result.start
422
+ assert_equal false, result.next_page?
423
+ assert_equal false, result.previous_page?
424
+ assert_equal false, result.key_matches?
425
+ assert_equal false, result.synonyms?
426
+ assert_equal [], result.pages
427
+ end
428
+ end
metadata CHANGED
@@ -1,7 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bcms_google_mini_search
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ hash: 19
5
+ prerelease: false
6
+ segments:
7
+ - 1
8
+ - 1
9
+ - 0
10
+ version: 1.1.0
5
11
  platform: ruby
6
12
  authors:
7
13
  - BrowserMedia
@@ -9,11 +15,11 @@ autorequire:
9
15
  bindir: bin
10
16
  cert_chain: []
11
17
 
12
- date: 2009-11-24 00:00:00 -05:00
18
+ date: 2010-08-18 00:00:00 -04:00
13
19
  default_executable:
14
20
  dependencies: []
15
21
 
16
- description:
22
+ description: Allows developers to integrate Google Mini or Google Search Appliance into their CMS sites. Can be used to fetch search results and format them.
17
23
  email: github@browsermedia.com
18
24
  executables: []
19
25
 
@@ -24,44 +30,61 @@ extra_rdoc_files:
24
30
  files:
25
31
  - app/controllers/application_controller.rb
26
32
  - app/helpers/application_helper.rb
33
+ - app/models/search_result.rb
27
34
  - app/portlets/google_mini_search_engine_portlet.rb
28
35
  - app/portlets/search_box_portlet.rb
29
- - app/models/search_result.rb
30
- - app/views/portlets/search_box/render.html.erb
31
- - app/views/portlets/search_box/_form.html.erb
32
- - app/views/portlets/google_mini_search_engine/render.html.erb
33
36
  - app/views/portlets/google_mini_search_engine/_form.html.erb
37
+ - app/views/portlets/google_mini_search_engine/render.html.erb
38
+ - app/views/portlets/search_box/_form.html.erb
39
+ - app/views/portlets/search_box/render.html.erb
34
40
  - lib/bcms_google_mini_search.rb
35
41
  - lib/bcms_google_mini_search/routes.rb
36
42
  - rails/init.rb
37
43
  - README.markdown
44
+ - test/performance/browsing_test.rb
45
+ - test/test_helper.rb
46
+ - test/unit/helpers/search_engine_helper_test.rb
47
+ - test/unit/portlets/google_mini_search_engine_portlet_test.rb
48
+ - test/unit/portlets/search_box_portlet_test.rb
49
+ - test/unit/search_result_test.rb
38
50
  has_rdoc: true
39
- homepage: http://www.browsercms.org
51
+ homepage: http://github.com/browsermedia/bcms_google_mini_search
40
52
  licenses: []
41
53
 
42
54
  post_install_message:
43
- rdoc_options: []
44
-
55
+ rdoc_options:
56
+ - --charset=UTF-8
45
57
  require_paths:
46
58
  - lib
47
59
  required_ruby_version: !ruby/object:Gem::Requirement
60
+ none: false
48
61
  requirements:
49
62
  - - ">="
50
63
  - !ruby/object:Gem::Version
64
+ hash: 3
65
+ segments:
66
+ - 0
51
67
  version: "0"
52
- version:
53
68
  required_rubygems_version: !ruby/object:Gem::Requirement
69
+ none: false
54
70
  requirements:
55
71
  - - ">="
56
72
  - !ruby/object:Gem::Version
73
+ hash: 3
74
+ segments:
75
+ - 0
57
76
  version: "0"
58
- version:
59
77
  requirements: []
60
78
 
61
79
  rubyforge_project: bcms_google_mini_search
62
- rubygems_version: 1.3.5
80
+ rubygems_version: 1.3.7
63
81
  signing_key:
64
82
  specification_version: 3
65
83
  summary: A Google Mini Search Module for BrowserCMS
66
- test_files: []
67
-
84
+ test_files:
85
+ - test/performance/browsing_test.rb
86
+ - test/test_helper.rb
87
+ - test/unit/helpers/search_engine_helper_test.rb
88
+ - test/unit/portlets/google_mini_search_engine_portlet_test.rb
89
+ - test/unit/portlets/search_box_portlet_test.rb
90
+ - test/unit/search_result_test.rb