bcms_google_mini_search 1.3.0 → 1.3.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -8,10 +8,14 @@ It consists of the following two portlets.
8
8
  2. Google Mini Search Results Portlet - Sends query to the Mini, formats the XML response and displays the results.
9
9
 
10
10
  Features:
11
+
11
12
  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)
13
+ 2. Will display Key Matches
14
+ 3. Will display Synonyms/Related Queries
15
+ 4. Allows conditional overriding of collections (i.e. by default it will search one default collection, but a 'site=OTHER_COLLECTION' param can be passed to override that)
16
+ 5. Sort by Date/Relevance - Users can now toggle the results display between date and relevance.
17
+ 6. Cached Links - Each result now correctly generate a link to the cached version of the document as stored by the GSA.
18
+ 7. [GSA Only] Narrow Your Search - Shows users a set of other suggested queries to allow them to 'Narrow Your Search', based on the current query and what results are stored in GSA. Only available for GSA instances, as Google Mini does not support Dynamic Result Clustering.
15
19
 
16
20
  Note: This module assume the BrowserCMS web site owner has access to their own GSA/Google Mini server, either hosted by
17
21
  themselves or a third party service.
@@ -3,12 +3,19 @@ require 'net/http'
3
3
 
4
4
  class SearchResult
5
5
 
6
- attr_accessor :number, :title, :url, :description, :size
6
+ # Creates a new GSA::Appliance from a GoogleMiniSearchPortlet.
7
+ #
8
+ def self.new_gsa(portlet)
9
+ options = {:portlet=>portlet}
10
+ normalize_query_options(options)
11
+ GSA::Appliance.new(options)
12
+ end
7
13
 
8
14
  #
9
15
  # Queries google mini by a specific URL to find all the results. Converts XML results to
10
16
  # a paging results of Search Results.
11
17
  #
18
+ # See SearchResult#query_url for acceptable _options_ params
12
19
  def self.find(query, options={})
13
20
  return QueryResult.new unless query
14
21
  xml_doc = fetch_xml_doc(query, options)
@@ -19,6 +26,14 @@ class SearchResult
19
26
  results
20
27
  end
21
28
 
29
+ def self.create_query(query, options={})
30
+ opts = options.clone
31
+ normalize_query_options(opts)
32
+ opts[:query] = query
33
+ opts[:engine] = GSA::Engine.new({:host => opts[:host]})
34
+ GSA::Query.new(opts)
35
+ end
36
+
22
37
  def self.parse_results_count(xml_doc)
23
38
  root = xml_doc.root
24
39
  count = root.elements["RES/M"]
@@ -29,16 +44,7 @@ class SearchResult
29
44
  root = xml_doc.root
30
45
  results = []
31
46
  xml_doc.elements.each('GSP/RES/R') do |ele|
32
- result = SearchResult.new
33
- result.number = ele.attributes["N"]
34
- result.title = ele.elements["T"].text
35
- result.url = ele.elements["U"].text
36
- result.description = ele.elements["S"].text
37
-
38
- doc_size_ele = ele.elements["HAS/C"]
39
- result.size = doc_size_ele ? doc_size_ele.attributes["SZ"] : ""
40
-
41
- results << result
47
+ results << GSA::Result.new(ele)
42
48
  end
43
49
  results
44
50
  end
@@ -62,39 +68,76 @@ class SearchResult
62
68
  num_pages
63
69
  end
64
70
 
71
+ # Construct a query url for the GSA.
72
+ #
73
+ # @param [String] query
74
+ # @param [Hash] options
75
+ # @option :host
76
+ # @option :start
77
+ # @option :front_end
78
+ # @option :collection
79
+ # @option :sort
80
+ # @option :as_xml [Boolean] Determines if the results are returned as xml or html. Default to false.
81
+ def self.query_url(query, options)
82
+ options[:as_xml] = true if options[:as_xml].nil?
65
83
 
66
- def self.build_mini_url(options, query)
67
- portlet = find_search_engine_portlet(options)
68
84
  encoded_query = CGI::escape(query)
69
85
 
70
- site = portlet.collection_name
71
- if options[:site]
72
- site = options[:site]
73
- end
74
- # encoded_query = query
75
- url = "#{portlet.service_url}/search?q=#{encoded_query}&output=xml_no_dtd&client=#{portlet.front_end_name}&site=#{site}&filter=0"
86
+ # Turns off automatic results filter (filter=0), which when set to 1, allows mini to reduces the # of similar/duplicate results,
87
+ # but makes it hard to determine the total # of results.
88
+ url = "#{options[:host]}/search?q=#{encoded_query}&output=xml_no_dtd&client=#{options[:front_end]}&site=#{options[:collection]}&filter=0"
76
89
  if options[:start]
77
90
  url = url + "&start=#{options[:start]}"
78
91
  end
79
- return url
92
+
93
+ if options[:sort]
94
+ url += "&sort=#{CGI::escape(options[:sort])}"
95
+ end
96
+
97
+ unless options[:as_xml]
98
+ url += "&proxystylesheet=#{options[:front_end]}"
99
+ end
100
+
101
+ # Ensure both results (oe) and query/input values (ie) are interpreted as UTF-8.
102
+ # See http://code.google.com/apis/searchappliance/documentation/46/xml_reference.html#request_i18n
103
+ url += "&oe=UTF-8&ie=UTF-8"
104
+ return url
105
+ end
106
+
107
+ def self.create_url_for_query(options, query)
108
+ normalize_query_options(options)
109
+ return query_url(query, options)
110
+ end
111
+
112
+ def self.normalize_query_options(options)
113
+ portlet = find_search_engine_portlet(options)
114
+ options[:front_end] = portlet.front_end_name
115
+ options[:collection] = portlet.collection_name
116
+ options[:host] = portlet.service_url
117
+
118
+ options[:collection] = options.delete(:site) if options[:site]
80
119
  end
81
120
 
82
121
  def self.find_search_engine_portlet(options)
83
122
  portlet = GoogleMiniSearchEnginePortlet.new
84
123
  if options[:portlet]
85
- portlet = options[:portlet]
124
+ portlet = options.delete(:portlet)
86
125
  end
87
126
  portlet
88
127
  end
89
128
 
129
+ # Given a URL, GET it and return the contents
130
+ # @param [String] url A URL formatted string
131
+ def self.fetch_document(url)
132
+ Rails.logger.debug {"GSA: Fetching '#{url}'"}
133
+ Net::HTTP.get(URI.parse(url))
134
+ end
135
+
90
136
  # Fetches the xml response from the google mini server.
91
137
  def self.fetch_xml_doc(query, options={})
92
- # Turns off automatic results filter (filter=0), which when set to 1, allows mini to reduces the # of similar/duplicate results,
93
- # but makes it hard to determine the total # of results.
94
- url = build_mini_url(options, query)
95
- response = Net::HTTP.get(URI.parse(url))
96
- xml_doc = REXML::Document.new(response)
97
- return xml_doc
138
+ url = create_url_for_query(options, query)
139
+ response = fetch_document(url)
140
+ REXML::Document.new(response)
98
141
  end
99
142
 
100
143
  def self.parse_key_matches(xml_doc)
@@ -125,6 +168,10 @@ class SearchResult
125
168
  attr_accessor :results_count, :num_pages, :current_page, :start, :query, :pages, :key_matches, :synonyms
126
169
  attr_writer :path
127
170
 
171
+ # For what these codes mean, see http://code.google.com/apis/searchappliance/documentation/46/xml_reference.html#request_sort
172
+ SORT_BY_DATE_PARAM = "date:D:S:d1"
173
+ SORT_BY_RELEVANCE_PARAM = "date:D:L:d1"
174
+
128
175
  def initialize(array=[])
129
176
  # Need to set defaults so an empty result set works.
130
177
  self.start = 0
@@ -149,11 +196,15 @@ class SearchResult
149
196
  previous_start >= 0 && num_pages > 1
150
197
  end
151
198
 
199
+ # Returns a range of pages that should appear in the pager control. This is design to mimic GSA's pager control,
200
+ # which will show up to 20 pages at a time, based on the 'range' of pages around the current page.
201
+ #
202
+ # i.e. on page 12: < 2 3 4 5 6 7 8 9 10 11 _12_ 13 14 15 16 17 18 19 20 21 22 >
152
203
  def pages
153
- if num_pages > 1
154
- return (1..num_pages)
155
- end
156
- []
204
+ return [] if num_pages <= 1
205
+ first_page = current_page - 10 > 1 ? current_page - 10 : 1
206
+ last_page = current_page + 9 > num_pages ? num_pages : current_page + 9
207
+ (first_page..last_page)
157
208
  end
158
209
 
159
210
  def next_start
@@ -173,6 +224,28 @@ class SearchResult
173
224
  1
174
225
  end
175
226
 
227
+ # Determines the current Query is sorting by date.
228
+ #
229
+ # @param [Hash] params The query parameter from the search page. (same as Rails params)
230
+ def sorting_by_date?(params)
231
+ params[:sort] == SearchResult::QueryResult::SORT_BY_DATE_PARAM
232
+ end
233
+
234
+ def path_for(new_query)
235
+ "#{path}?query=#{new_query}"
236
+ end
237
+ # Return the path to sort the current search results by date.
238
+ #
239
+ # Based on http://code.google.com/apis/searchappliance/documentation/46/xml_reference.html#request_sort
240
+ def sort_by_date_path
241
+ "#{path}?query=#{query}&sort=#{SORT_BY_DATE_PARAM}"
242
+ end
243
+
244
+ # Returns the path to sort the current results by relevance (inverse of sort_by_date_path).
245
+ def sort_by_relevance_path
246
+ "#{path}?query=#{query}&sort=#{SORT_BY_RELEVANCE_PARAM}"
247
+ end
248
+
176
249
  def next_page_path
177
250
  "#{path}?query=#{query}&start=#{next_start}"
178
251
  end
@@ -1,12 +1,28 @@
1
1
  class GoogleMiniSearchEnginePortlet < Portlet
2
2
 
3
3
  enable_template_editor true
4
-
4
+
5
5
  def render
6
- @query = params[:query]
7
6
  @site = params[:site]
8
7
  @start = params[:start] ? params[:start].to_i : 0
9
- @results = SearchResult.find(@query, {:start => @start, :portlet => @portlet, :site=>@site})
8
+ options = {:start => @start, :portlet => self, :site=>@site, :sort=>params[:sort]}
9
+ query_string = params[:query]
10
+
11
+ @results = SearchResult.find(query_string, options.clone) # Need to clone, so that :portlet isn't removed for the 2nd call.
12
+
13
+ # This is temporary, while the API is being reworked. Ideally, the search results would contain a reference
14
+ # to the query, so that two X calls isn't needed.
15
+ @query = SearchResult.create_query(query_string, options.clone)
16
+
17
+ if narrow_your_search?
18
+ @appliance = SearchResult.new_gsa(self)
19
+ @suggested_queries = @appliance.find_narrow_search_results(query_string)
20
+ end
10
21
  end
11
-
22
+
23
+ # Handles the fact that all portlet attributes, including checkboxes like enable_your_search are stored as strings.
24
+ def narrow_your_search?
25
+ self.enable_narrow_your_search == "1"
26
+ end
27
+
12
28
  end
@@ -0,0 +1,17 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
3
+ <head>
4
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
5
+ <title><%= page_title %></title>
6
+ <%= yield :html_head %>
7
+ </head>
8
+ <body style="margin: 0; padding: 0; text-align: center;">
9
+ <%= cms_toolbar %>
10
+ <div id="wrapper" style="width: 700px; margin: 0 auto; text-align: left; padding: 30px">
11
+ Breadcrumbs: <%= render_breadcrumbs %>
12
+ Main Menu: <%= render_menu %>
13
+ <h1><%= page_title %></h1>
14
+ <%= container :main %>
15
+ </div>
16
+ </body>
17
+ </html>
@@ -3,4 +3,6 @@
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
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
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_check_box :enable_narrow_your_search, :instructions => "The 'Narrow Your Search' feature is a only available for Google Search Appliance, not with Google Mini.",
7
+ :label=>"Enable Narrowing?" %>
6
8
  <%= f.cms_template_editor :template %>
@@ -1,17 +1,22 @@
1
+
1
2
  <h2>Search Results</h2>
2
- For '<%= @results.query %>', found <%= @results.results_count %> results. <br />
3
- <% if @results.previous_page? %><%= link_to h("< Back"), @results.previous_page_path %><% end %>
4
- <% if @results.next_page? %><%= link_to h("Next >"), @results.next_page_path %><% end %>
3
+ For '<%= @results.query %>', found <%= @results.results_count %> results. <br/>
4
+ <%= link_to_unless @results.sorting_by_date?(params), "Sort by Date", @results.sort_by_date_path %> /
5
+ <%= link_to_if @results.sorting_by_date?(params), "Sort by Relevance", @results.sort_by_relevance_path %> <br/>
6
+ <% if @results.previous_page? %><%= link_to h("< Back"), @results.previous_page_path %>
7
+ <% end %>
8
+ <% if @results.next_page? %><%= link_to h("Next >"), @results.next_page_path %>
9
+ <% end %>
5
10
  <% if @results.key_matches? %>
6
11
  <ul class="key_matches">
7
- <% @results.key_matches.each do |match| %>
8
- <li><%= link_to match.title, match.url %></li>
9
- <% end %>
12
+ <% @results.key_matches.each do |match| %>
13
+ <li><%= link_to match.title, match.url %></li>
14
+ <% end %>
10
15
  </ul>
11
16
  <% end %>
12
17
  <% if @results.synonyms? %>
13
18
  <span class="synonyms">You could also try:
14
- <% @results.synonyms.each do |synonym| %>
19
+ <% @results.synonyms.each do |synonym| %>
15
20
  <%= link_to synonym.label, synonym.url %>
16
21
  <% end %>
17
22
  </span>
@@ -20,14 +25,30 @@ For '<%= @results.query %>', found <%= @results.results_count %> results. <br />
20
25
  <% @results.each do |result|%>
21
26
  <li>
22
27
  <%= result.number %> <%= link_to result.title, result.url, :class=>"search_result_title" %><br />
23
- <span class="search_result_description"><%= result.description.html_safe %></span> <br />
28
+ <span class="search_result_description"><%= result.description.try(:html_safe) %></span> <br />
24
29
  <span class="search_result_url"><%= result.url %></span> -
25
30
  <span class="search_result_size"><%= result.size %></span>
26
- </li>
31
+ <span class="search_result_cached"><%= link_to "Cached", result.cached_document_url(@query) %></span>
32
+
33
+ </li>
27
34
  <% end %>
28
35
  </ul>
29
- <% if @results.previous_page? %><%= link_to h("< Back"), @results.previous_page_path %><% end %>
30
- <% @results.pages.each do |p| %>
31
- <%= link_to_unless @results.current_page?(p), p, @results.page_path(p) %>
36
+
37
+ <% if @portlet.narrow_your_search? %>
38
+ <div id="clustering">
39
+ <h3>Narrow your search</h3>
40
+ <ul>
41
+ <% @suggested_queries.each_with_index do |suggestion, i| %>
42
+ <li id="cluster_label<%= i %>"><%= link_to suggestion.query, @results.path_for(suggestion.query) %></li>
43
+ <% end %>
44
+ </ul>
45
+ </div>
46
+ <% end %>
47
+
48
+ <% if @results.previous_page? %><%= link_to h("< Back"), @results.previous_page_path %>
49
+ <% end %>
50
+ <% @results.pages.each do |p| %>
51
+ <%= link_to_unless @results.current_page?(p), p, @results.page_path(p) %>
52
+ <% end %>
53
+ <% if @results.next_page? %><%= link_to h("Next >"), @results.next_page_path %>
32
54
  <% end %>
33
- <% if @results.next_page? %><%= link_to h("Next >"), @results.next_page_path %><% end %>
@@ -8,13 +8,12 @@ Gem::Specification.new do |s|
8
8
  s.authors = ["BrowserMedia"]
9
9
  s.email = %q{github@browsermedia.com}
10
10
  s.homepage = %q{http://github.com/browsermedia/bcms_google_mini_search}
11
- s.description = %q{A Google Appliance modules for BrowserCMS. Used to display search results from a Google Mini/Search Appliance on a site.}
11
+ s.description = %q{A Google Appliance module for BrowserCMS. Used to display search results from a Google Mini/Search Appliance on a site.}
12
12
  s.summary = %q{A Google Mini Search Module for BrowserCMS}
13
13
  s.extra_rdoc_files = [
14
14
  "README.markdown"
15
15
  ]
16
16
  s.rdoc_options = ["--charset=UTF-8"]
17
-
18
17
  s.rubyforge_project = "bcms_google_mini_search"
19
18
 
20
19
  s.files = `git ls-files`.split("\n")
@@ -28,7 +27,6 @@ Gem::Specification.new do |s|
28
27
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
29
28
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
30
29
  s.require_paths = ["lib"]
31
-
32
30
  s.add_dependency(%q<browsercms>, ["~> 3.3.0"])
33
31
  end
34
32
 
@@ -0,0 +1,39 @@
1
+ <?xml version="1.0"?>
2
+ <toplevel>
3
+ <Response>
4
+ <algorithm data="Concepts"/>
5
+ <t_cluster int="95"/>
6
+ <cluster>
7
+ <gcluster>
8
+ <label data="nonalcoholic fatty liver disease"/>
9
+ </gcluster>
10
+ <gcluster>
11
+ <label data="advanced liver disease"/>
12
+ </gcluster>
13
+ <gcluster>
14
+ <label data="liver disease patients"/>
15
+ </gcluster>
16
+ <gcluster>
17
+ <label data="chronic liver disease"/>
18
+ </gcluster>
19
+ <gcluster>
20
+ <label data="patients nonalcoholic fatty liver"/>
21
+ </gcluster>
22
+ <gcluster>
23
+ <label data="end stage liver disease"/>
24
+ </gcluster>
25
+ <gcluster>
26
+ <label data="cholestatic liver disease"/>
27
+ </gcluster>
28
+ <gcluster>
29
+ <label data="patients advanced liver disease"/>
30
+ </gcluster>
31
+ <gcluster>
32
+ <label data="safe patients advanced liver"/>
33
+ </gcluster>
34
+ <gcluster>
35
+ <label data="model end stage liver"/>
36
+ </gcluster>
37
+ </cluster>
38
+ </Response>
39
+ </toplevel>
@@ -1,2 +1,4 @@
1
1
  require 'bcms_google_mini_search/engine'
2
+ require 'rexml/document'
2
3
  require 'bcms_google_mini_search/routes'
4
+ require 'bcms_google_mini_search/gsa'
@@ -0,0 +1,144 @@
1
+ # A general purpose API for querying a Google Search Appliance for results.
2
+ module GSA
3
+
4
+ # Represents a single instance of a Google Mini
5
+ class Engine
6
+ attr_accessor :host, :port, :path, :default_collection, :default_front_end
7
+
8
+ def initialize(options = {})
9
+ self.port = 8080
10
+ self.path = "/search"
11
+ self.host = options[:host]
12
+ self.default_front_end = options[:front_end]
13
+ self.default_collection = options[:collection]
14
+ end
15
+
16
+ # Return a Hash suitable to be passed to SearchResult.find()
17
+ def options_for_query
18
+ {:host=>host, :front_end=>default_front_end, :collection=>default_collection}
19
+ end
20
+ end
21
+
22
+ # GSA support slightly different features than Google Mini.
23
+ class Appliance < Engine
24
+
25
+
26
+
27
+ # Fetch a set of Suggested queries, based on a given query.
28
+ #
29
+ # See http://code.google.com/apis/searchappliance/documentation/50/admin_searchexp/ce_understanding.html#h3drc for the spec.
30
+ # See http://groups.google.com/group/Google-Search-Appliance-Help/browse_thread/thread/8a821fc8475a5e24/34a5c3c8ab74ed35?hl=en&lnk=gst#34a5c3c8ab74ed35
31
+ # for details about how this is implemented.
32
+ #
33
+ # Clustering (aka Narrow your search) is only supported by GSA.
34
+ # @param [String] query A term to fetch 'suggested' queries for/
35
+ # @return [GSA::SuggestedQueries] A set of suggested queries
36
+ def find_narrow_search_results(query)
37
+ return [] unless query
38
+
39
+ url = narrow_search_results_url(query)
40
+ document = SearchResult.fetch_document(url)
41
+ SuggestedQueries.new(document)
42
+ end
43
+
44
+ private
45
+
46
+ # Returns the URL to GET a set of Dynamic Search Clusters for a particular query.
47
+ def narrow_search_results_url(query)
48
+ "#{host}/cluster?coutput=xml&q=#{CGI::escape(query)}&site=#{default_collection}&client=#{default_front_end}&output=xml_no_dtd&oe=UTF-8&ie=UTF-8"
49
+ end
50
+ end
51
+
52
+ # Represents a set of suggested search terms, based on results from a GSA.
53
+ # AKA DynamicResultClusters
54
+ class SuggestedQueries
55
+ def initialize(xml_as_string)
56
+ @clusters = []
57
+ doc = REXML::Document.new(xml_as_string)
58
+ doc.elements.each('toplevel/Response/cluster/gcluster') do |ele|
59
+ @clusters << Suggestion.new(ele.elements["label"].attributes["data"])
60
+ end
61
+
62
+ end
63
+
64
+ delegate :each, :each_with_index, :size, '[]', :to=>:clusters
65
+
66
+ private
67
+
68
+ def clusters
69
+ @clusters
70
+ end
71
+
72
+
73
+ # Since generating are handled in the view, this might no longer be necessary a separate class, and could probably be converted into a String.
74
+ class Suggestion
75
+ attr_accessor :query
76
+
77
+ def initialize(query)
78
+ self.query = query
79
+ end
80
+
81
+ end
82
+ end
83
+
84
+
85
+
86
+
87
+ class Query
88
+ attr_reader :engine, :query, :front_end, :collection
89
+
90
+ def initialize(options={})
91
+ @engine = options[:engine]
92
+ @query = options[:query]
93
+ @front_end = options[:front_end]
94
+ @collection = options[:collection]
95
+ end
96
+ end
97
+
98
+ # Represent a collection of results from a GSA search.
99
+ class Results
100
+
101
+ attr_accessor :query
102
+
103
+
104
+ end
105
+
106
+ # Represents a single result (aka Hit) from a GSA query.
107
+ # Defined by http://code.google.com/apis/searchappliance/documentation/46/xml_reference.html#results_xml_tag_r
108
+ class Result
109
+ attr_accessor :number, :title, :url, :description, :size, :cache_id, :results
110
+
111
+ # @param [RXEML::Element] xml_element The <R> result from GSA a search.
112
+ def initialize(xml_element = nil)
113
+ return if xml_element == nil
114
+ self.number = xml_element.attributes["N"]
115
+ self.title = xml_element.elements["T"].try(:text)
116
+ self.url = xml_element.elements["U"].try(:text)
117
+ self.description = xml_element.elements["S"].try(:text)
118
+
119
+ cache_element = xml_element.elements["HAS/C"]
120
+
121
+ if cache_element
122
+ self.size = cache_element.attributes["SZ"]
123
+ self.cache_id = cache_element.attributes["CID"]
124
+ else
125
+ self.size = ""
126
+ self.cache_id=""
127
+ end
128
+
129
+ end
130
+
131
+ # Returns the value for q if a user wants to request the cached version of this document.
132
+ def cached_document_param
133
+ param = "cache:#{cache_id}:#{url}"
134
+ if results
135
+ param += "+#{results.query}"
136
+ end
137
+ param
138
+ end
139
+
140
+ def cached_document_url(gsa_query)
141
+ SearchResult.query_url(cached_document_param, {:host=>gsa_query.engine.host, :collection=>gsa_query.collection, :front_end=>gsa_query.front_end, :as_xml=>false})
142
+ end
143
+ end
144
+ end
@@ -1,3 +1,3 @@
1
1
  module BcmsGoogleMiniSearch
2
- VERSION = "1.3.0"
2
+ VERSION = "1.3.1"
3
3
  end
@@ -0,0 +1,40 @@
1
+ v1.3.1
2
+ ======
3
+
4
+ * Merge changes from 1.2.2 into 1.3.x line
5
+ * Ensure documents with empty titles work correctly
6
+ * Endure Narowing/Caching/Paging/etc are available for rails 3
7
+
8
+ v1.3.0
9
+ ======
10
+
11
+ * Upgrade GSA module to be Rails 3/BrowserCMS 3.3.x compatible (Did not include some v1.2.x changes)
12
+
13
+ v1.2.0
14
+ ======
15
+
16
+ This release adds several refinements to the gmini/gsa module, including:
17
+
18
+ * Better Paging - The results pages control now behaves like the test center does, where it shows a maximum of 20 page links, based on the 'current' page the user is on.
19
+ * Sort by Date/Relevance - Users can now toggle the results display between date and relevance.
20
+ * Caching - Each result now correctly generate a link to the cached version of the document as stored by the GSA.
21
+ * Narrow Your Search - Shows users a set of other suggested queries to allow them to 'Narrow Your Search', based on the current query and what results are stored in GSA. Only available for GSA instances, as Google Mini does not support Dynamic Result Clustering.
22
+ * [Bug Fix] Queries and results are now interpreted as UTF-8. Should avoid weird encoding issues with results.
23
+
24
+ How Google Results Pager works
25
+ ====================
26
+ * Start with 1 - 9.
27
+ * Add current page plus 9,
28
+ * Show a maximum of 20 results, plus Previous and Next
29
+ * Range is 10 previous, current, next 9
30
+ CP = 11, range = 1 - 20
31
+ CP = 1, range = 1-10
32
+ CP = 12, range = 2 - 21
33
+
34
+ v1.1
35
+ ====
36
+
37
+ Adds the following features:
38
+
39
+ * Displays Key Matches for queries
40
+ * Display Synonyms for queries
@@ -0,0 +1,197 @@
1
+ require "test_helper"
2
+
3
+ class GSA::ApplianceTest < ActiveSupport::TestCase
4
+
5
+ test "Create Engine" do
6
+ app = GSA::Engine.new
7
+ app.host = "http://example.com"
8
+ assert_equal "http://example.com", app.host
9
+ assert_equal 8080, app.port
10
+ assert_equal "/search", app.path
11
+ end
12
+
13
+ test "Create from options" do
14
+ app = GSA::Engine.new({:host=>"http://example.com", :front_end=>"F", :collection=>"C"})
15
+ assert_equal "http://example.com", app.host
16
+ assert_equal "F", app.default_front_end
17
+ assert_equal "C", app.default_collection
18
+ end
19
+
20
+ test "options_for_query" do
21
+ options = {:host=>"http://example.com", :front_end=>"F", :collection=>"C"}
22
+ app = GSA::Engine.new(options)
23
+ assert_equal options, app.options_for_query
24
+ end
25
+ end
26
+
27
+ class SuggestedQueries < ActiveSupport::TestCase
28
+
29
+ def setup
30
+ @cluster_xml = <<XML
31
+ <toplevel>
32
+ <Response>
33
+ <algorithm data="Concepts"/>
34
+ <t_cluster int="95"/>
35
+ <cluster>
36
+ <gcluster>
37
+ <label data="label 0"/>
38
+ </gcluster>
39
+ <gcluster>
40
+ <label data="label 1"/>
41
+ </gcluster>
42
+ <gcluster>
43
+ <label data="label 2"/>
44
+ </gcluster>
45
+ <gcluster>
46
+ <label data="label 3"/>
47
+ </gcluster>
48
+ <gcluster>
49
+ <label data="label 4"/>
50
+ </gcluster>
51
+ <gcluster>
52
+ <label data="label 5"/>
53
+ </gcluster>
54
+ <gcluster>
55
+ <label data="label 6"/>
56
+ </gcluster>
57
+ <gcluster>
58
+ <label data="label 7"/>
59
+ </gcluster>
60
+ <gcluster>
61
+ <label data="label 8"/>
62
+ </gcluster>
63
+ <gcluster>
64
+ <label data="label 9"/>
65
+ </gcluster>
66
+ </cluster>
67
+ </Response>
68
+ </toplevel>
69
+ XML
70
+
71
+ @app = GSA::Appliance.new(:host=>"http://example.com", :collection=>"My_Collection", :front_end=>"My_Front")
72
+
73
+ end
74
+
75
+ test "parse results" do
76
+ suggested_queries = GSA::SuggestedQueries.new(@cluster_xml)
77
+ assert_equal 10, suggested_queries.size
78
+ assert_equal "label 0", suggested_queries[0].query
79
+ assert_equal "label 9", suggested_queries[9].query
80
+ end
81
+
82
+ test "Google Search Appliances should generate the URL for Dynamic Results Clustering" do
83
+ expected = "http://example.com/cluster?coutput=xml&q=TEST&site=My_Collection&client=My_Front&output=xml_no_dtd&oe=UTF-8&ie=UTF-8"
84
+ assert_equal expected, @app.send(:narrow_search_results_url, "TEST")
85
+ end
86
+
87
+ test "URLs will escape queries" do
88
+ expected = "http://example.com/cluster?coutput=xml&q=TWO+WORDS&site=My_Collection&client=My_Front&output=xml_no_dtd&oe=UTF-8&ie=UTF-8"
89
+ assert_equal expected, @app.send(:narrow_search_results_url, "TWO WORDS")
90
+ end
91
+
92
+ test "find narrowed search results" do
93
+ @app.expects(:narrow_search_results_url).with("TEST").returns("EXPECTED URL")
94
+ SearchResult.expects(:fetch_document).with("EXPECTED URL").returns("XML Content")
95
+ expected_suggestions = mock()
96
+ GSA::SuggestedQueries.expects(:new).with("XML Content").returns(expected_suggestions)
97
+
98
+ assert_equal expected_suggestions, @app.find_narrow_search_results("TEST")
99
+
100
+ end
101
+
102
+ test "each_with_index" do
103
+ suggestions = GSA::SuggestedQueries.new(@cluster_xml)
104
+ count = 0
105
+ suggestions.each_with_index do |s, i|
106
+ assert_not_nil s
107
+ assert_not_nil i
108
+ count += 1
109
+ end
110
+ assert_equal suggestions.size, count
111
+ end
112
+
113
+ test "each" do
114
+ suggestions = GSA::SuggestedQueries.new(@cluster_xml)
115
+ count = 0
116
+ suggestions.each do |s|
117
+ assert_not_nil s
118
+ count += 1
119
+ end
120
+ assert_equal suggestions.size, count
121
+ end
122
+
123
+ test "A nil query should return an empty set of Suggested Queries" do
124
+ r = @app.find_narrow_search_results(nil)
125
+ assert_equal 0, r.size
126
+ end
127
+ end
128
+
129
+ class ResultsTest < ActiveSupport::TestCase
130
+
131
+ def setup
132
+ @results = GSA::Results.new
133
+ @results.query = "QUERY"
134
+ @result = GSA::Result.new
135
+ @result.results = @results
136
+
137
+ @engine = GSA::Engine.new(:host=>"http://mini.someurl.com")
138
+ @query = GSA::Query.new(:engine=>@engine, :collection=>"COLLECT", :front_end=>"FRONT_END")
139
+ end
140
+
141
+ test "Handles missing elements that we kinda expect to be there" do
142
+ xml = <<XML
143
+ <R N="1">
144
+ <HAS>
145
+ <C SZ="1k" CID="Ax1j5"/>
146
+ </HAS>
147
+ </R>
148
+ XML
149
+ xml_doc = REXML::Document.new(xml)
150
+ result = GSA::Result.new(xml_doc.elements.first)
151
+ assert_nil result.url
152
+ assert_nil result.title
153
+ assert_nil result.description
154
+ end
155
+
156
+ test "Create result from xml" do
157
+ xml = <<XML
158
+ <R N="1">
159
+ <U>http://someurl.com</U>
160
+ <T>TITLE</T>
161
+ <S>BLURB</S>
162
+ <HAS>
163
+ <C SZ="1k" CID="Ax1j5"/>
164
+ </HAS>
165
+ </R>
166
+ XML
167
+ xml_doc = REXML::Document.new(xml)
168
+ result = GSA::Result.new(xml_doc.elements.first)
169
+ assert_equal "http://someurl.com", result.url
170
+ assert_equal "TITLE", result.title
171
+ assert_equal "BLURB", result.description
172
+ assert_equal "1k", result.size
173
+ assert_equal "1", result.number
174
+ assert_equal "Ax1j5", result.cache_id
175
+ end
176
+
177
+ test "cached_document_param" do
178
+ @result.cache_id = "A2B"
179
+ @result.url = "http://example.com"
180
+
181
+ assert_equal "cache:A2B:http://example.com+QUERY", @result.cached_document_param
182
+ end
183
+
184
+ test "cached_document_param with no result attached" do
185
+ @result.results = nil
186
+ @result.cache_id = "A2B"
187
+ @result.url = "http://example.com"
188
+
189
+ assert_equal "cache:A2B:http://example.com", @result.cached_document_param
190
+ end
191
+
192
+ test "cached_document_url" do
193
+ @result.expects(:cached_document_param).returns("cache:something")
194
+ expected_url = "http://mini.someurl.com/search?q=cache%3Asomething&output=xml_no_dtd&client=FRONT_END&site=COLLECT&filter=0&proxystylesheet=FRONT_END&oe=UTF-8&ie=UTF-8"
195
+ assert_equal expected_url, @result.cached_document_url(@query)
196
+ end
197
+ end
@@ -2,14 +2,52 @@ require 'test_helper'
2
2
 
3
3
  class GoogleMiniSearchEngineTest < ActiveSupport::TestCase
4
4
 
5
+ def setup
6
+ @portlet = GoogleMiniSearchEnginePortlet.new(:name=>"Engine", :path => "/engine")
7
+ end
8
+
5
9
  test "Should be able to create new instance of a portlet" do
6
10
  assert GoogleMiniSearchEnginePortlet.create!(:name => "New Portlet")
7
11
  end
8
12
 
9
-
10
-
11
13
  test "Path attribute can be set in constructor" do
12
14
  portlet = GoogleMiniSearchEnginePortlet.create!(:name=>"Engine", :path => "/engine")
13
15
  assert_equal "/engine", portlet.path
14
16
  end
17
+
18
+ test "Determine if Narrow Your Search is enabled?" do
19
+ @portlet.enable_narrow_your_search = "1"
20
+ assert_equal true, @portlet.narrow_your_search?
21
+
22
+ @portlet.enable_narrow_your_search = "0"
23
+ assert_equal false, @portlet.narrow_your_search?
24
+
25
+ @portlet.enable_narrow_your_search = ""
26
+ assert_equal false, @portlet.narrow_your_search?
27
+
28
+ @portlet.enable_narrow_your_search = nil
29
+ assert_equal false, @portlet.narrow_your_search?
30
+ end
31
+
32
+
33
+ end
34
+
35
+ class RenderTest < ActiveSupport::TestCase
36
+ def setup
37
+ @portlet = GoogleMiniSearchEnginePortlet.new(:name=>"Engine", :path => "/engine")
38
+ @params = {:start => 10, :query => "X", :site=>'default_collection', :sort=>"date:D:S:d1"}
39
+ @portlet.expects('params').returns(@params).at_least_once
40
+ end
41
+
42
+ test "Sort params" do
43
+ SearchResult.expects(:find).with("X", {:start => 10, :portlet => @portlet, :site=>'default_collection', :sort=>"date:D:S:d1"})
44
+ @portlet.render
45
+ end
46
+
47
+ test "Find narrow queries only if enabled" do
48
+ @portlet.enable_narrow_your_search = "1"
49
+ GSA::Appliance.any_instance.expects(:find_narrow_search_results).with("X")
50
+ SearchResult.expects(:find).with("X", {:start => 10, :portlet => @portlet, :site=>'default_collection', :sort=>"date:D:S:d1"})
51
+ @portlet.render
52
+ end
15
53
  end
@@ -1,5 +1,7 @@
1
1
  require 'test_helper'
2
2
 
3
+
4
+
3
5
  class SearchResultTest < ActiveSupport::TestCase
4
6
 
5
7
  def setup
@@ -56,8 +58,9 @@ EOF
56
58
  end
57
59
 
58
60
  test "fetch_xml_doc should download and parse the xml results from the GSA" do
59
- SearchResult.expects(:build_mini_url).returns("http://example.com")
60
- REXML::Document.expects(:new).returns("EXPECTED_RESULTS")
61
+ SearchResult.expects(:create_url_for_query).returns("http://example.com")
62
+ SearchResult.expects(:fetch_document).with("http://example.com").returns(nil)
63
+ REXML::Document.expects(:new).with(nil).returns("EXPECTED_RESULTS")
61
64
  assert_equal "EXPECTED_RESULTS", SearchResult.fetch_xml_doc("")
62
65
  end
63
66
 
@@ -211,14 +214,7 @@ EOF
211
214
  assert_equal [], results.pages
212
215
  end
213
216
 
214
- test "Behavior of ranges" do
215
- c = 0
216
- (1..4).each_with_index do |i, count|
217
- assert_equal count + 1, i
218
- c = count
219
- end
220
- assert_equal 3, c
221
- end
217
+
222
218
 
223
219
  test "current_page should check to see if the current page matches" do
224
220
  results = SearchResult::QueryResult.new
@@ -231,45 +227,6 @@ EOF
231
227
 
232
228
  end
233
229
 
234
- test "Path to next page" do
235
- results = SearchResult::QueryResult.new
236
- results.start = 0
237
- results.path = "/search/search-results"
238
- results.query = "X"
239
-
240
- assert_equal "/search/search-results?query=X&start=10", results.next_page_path
241
- end
242
-
243
- test "Path to previous page" do
244
- results = SearchResult::QueryResult.new
245
- results.start = 20
246
- results.path = "/search/search-results"
247
- results.query = "X"
248
-
249
- assert_equal "/search/search-results?query=X&start=10", results.previous_page_path
250
- end
251
-
252
- test "Sets path to default search-results" do
253
- results = SearchResult::QueryResult.new
254
- assert_equal "/search/search-results", results.path
255
- end
256
-
257
- test "Setting path overrides the defaults" do
258
- results = SearchResult::QueryResult.new
259
- results.path = "/other"
260
- assert_equal "/other", results.path
261
- end
262
-
263
- test "page_path" do
264
- results = SearchResult::QueryResult.new
265
- results.query = "X"
266
-
267
- assert_equal "/search/search-results?query=X&start=0", results.page_path(1)
268
- assert_equal "/search/search-results?query=X&start=10", results.page_path(2)
269
- assert_equal "/search/search-results?query=X&start=20", results.page_path(3)
270
- assert_equal "/search/search-results?query=X&start=30", results.page_path(4)
271
-
272
- end
273
230
 
274
231
  test "Portlet attributes are used to look up path" do
275
232
  portlet = GoogleMiniSearchEnginePortlet.new(:name=>"Engine", :path => "/engine")
@@ -291,12 +248,48 @@ EOF
291
248
  :name=>"Engine", :path => "/engine", :service_url => "http://mini.someurl.com",
292
249
  :collection_name => "COLLECT", :front_end_name => "FRONT_END")
293
250
 
294
- url = SearchResult.build_mini_url({:portlet => portlet}, "STUFF")
295
- assert_equal "http://mini.someurl.com/search?q=STUFF&output=xml_no_dtd&client=FRONT_END&site=COLLECT&filter=0", url
251
+ url = SearchResult.create_url_for_query({:portlet => portlet}, "STUFF")
252
+ assert_equal "http://mini.someurl.com/search?q=STUFF&output=xml_no_dtd&client=FRONT_END&site=COLLECT&filter=0&oe=UTF-8&ie=UTF-8", url
296
253
 
297
- url = SearchResult.build_mini_url({:portlet => portlet, :start=>100}, "STUFF")
298
- assert_equal "http://mini.someurl.com/search?q=STUFF&output=xml_no_dtd&client=FRONT_END&site=COLLECT&filter=0&start=100", url
254
+ url = SearchResult.create_url_for_query({:portlet => portlet, :start=>100}, "STUFF")
255
+ assert_equal "http://mini.someurl.com/search?q=STUFF&output=xml_no_dtd&client=FRONT_END&site=COLLECT&filter=0&start=100&oe=UTF-8&ie=UTF-8", url
256
+ end
257
+
258
+
259
+ test "Create Engine and Query from portlet attributes" do
260
+ portlet = GoogleMiniSearchEnginePortlet.new(
261
+ :name=>"Engine", :path => "/engine", :service_url => "http://mini.someurl.com",
262
+ :collection_name => "COLLECT", :front_end_name => "FRONT_END")
299
263
 
264
+ query = SearchResult.create_query("therapy", {:portlet=>portlet})
265
+ assert_equal "http://mini.someurl.com", query.engine.host
266
+ assert_equal portlet.front_end_name, query.front_end
267
+ assert_equal portlet.collection_name, query.collection
268
+ assert_equal "therapy", query.query
269
+ end
270
+
271
+ test "should look up options from portlet and add to hash" do
272
+ portlet = GoogleMiniSearchEnginePortlet.new(
273
+ :name=>"Engine", :path => "/engine", :service_url => "http://mini.someurl.com",
274
+ :collection_name => "COLLECT", :front_end_name => "FRONT_END")
275
+ options = {:portlet=>portlet}
276
+ SearchResult.normalize_query_options(options)
277
+
278
+ assert_equal "FRONT_END", options[:front_end]
279
+ assert_equal "COLLECT", options[:collection]
280
+ assert_equal "http://mini.someurl.com", options[:host]
281
+ assert_equal nil, options[:portlet]
282
+ end
283
+
284
+ test "Create an appliance from attributes in the 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
+ gsa = SearchResult.new_gsa(portlet)
290
+ assert_equal "http://mini.someurl.com", gsa.host
291
+ assert_equal "FRONT_END", gsa.default_front_end
292
+ assert_equal "COLLECT", gsa.default_collection
300
293
  end
301
294
 
302
295
  test "Explicitly passing a collection in will query with that rather than a default collection" do
@@ -304,13 +297,23 @@ EOF
304
297
  :name=>"Engine", :path => "/engine", :service_url => "http://mini.someurl.com",
305
298
  :collection_name => "COLLECT", :front_end_name => "FRONT_END")
306
299
 
307
- url = SearchResult.build_mini_url({:portlet => portlet, :site=>"ANOTHER_COLLECTION"}, "STUFF")
308
- assert_equal "http://mini.someurl.com/search?q=STUFF&output=xml_no_dtd&client=FRONT_END&site=ANOTHER_COLLECTION&filter=0", url
300
+ url = SearchResult.create_url_for_query({:portlet => portlet, :site=>"ANOTHER_COLLECTION"}, "STUFF")
301
+ assert_equal "http://mini.someurl.com/search?q=STUFF&output=xml_no_dtd&client=FRONT_END&site=ANOTHER_COLLECTION&filter=0&oe=UTF-8&ie=UTF-8", url
309
302
  end
310
303
 
311
304
  test "Handles multiword queries" do
312
- url = SearchResult.build_mini_url({}, "One Two")
313
- assert_equal "/search?q=One+Two&output=xml_no_dtd&client=&site=&filter=0", url
305
+ url = SearchResult.create_url_for_query({}, "One Two")
306
+ assert_equal "/search?q=One+Two&output=xml_no_dtd&client=&site=&filter=0&oe=UTF-8&ie=UTF-8", url
307
+ end
308
+
309
+ test "sort is added to google mini query" do
310
+ url = SearchResult.create_url_for_query({:sort=>"XYZ"}, "STUFF")
311
+ assert_equal "/search?q=STUFF&output=xml_no_dtd&client=&site=&filter=0&sort=XYZ&oe=UTF-8&ie=UTF-8", url
312
+ end
313
+
314
+ test "sort params are escaped" do
315
+ url = SearchResult.create_url_for_query({:sort=>"date:D:S:d1"}, "STUFF")
316
+ assert_equal "/search?q=STUFF&output=xml_no_dtd&client=&site=&filter=0&sort=date%3AD%3AS%3Ad1&oe=UTF-8&ie=UTF-8", url
314
317
  end
315
318
 
316
319
  test "Handles keymatches in results" do
@@ -470,5 +473,123 @@ EOF
470
473
  assert_equal "TITLE 2", results[1].title
471
474
  assert_equal "BLURB 2", results[1].description
472
475
  assert_equal "", results[1].size
476
+ end
477
+
478
+ end
479
+
480
+ class SearchPathsTest < ActiveSupport::TestCase
481
+
482
+ def setup
483
+ @results = SearchResult::QueryResult.new
484
+ @results.start = 0
485
+ @results.path = "/search/search-results"
486
+ @results.query = "X"
487
+ end
488
+
489
+ test "path_for" do
490
+ assert_equal "/search/search-results?query=Y", @results.path_for("Y")
491
+ end
492
+
493
+ test "sort by date" do
494
+ assert_equal "#{@results.path}?query=#{@results.query}&sort=#{SearchResult::QueryResult::SORT_BY_DATE_PARAM}", @results.sort_by_date_path
495
+ end
496
+
497
+ test "sort by relevance" do
498
+ assert @results.sort_by_relevance_path != @results.sort_by_date_path, "Paths should not be the same."
499
+ assert_equal "#{@results.path}?query=#{@results.query}&sort=#{SearchResult::QueryResult::SORT_BY_RELEVANCE_PARAM}", @results.sort_by_relevance_path
500
+ end
501
+
502
+ test "Path to next page" do
503
+ assert_equal "/search/search-results?query=X&start=10", @results.next_page_path
504
+ end
505
+
506
+ test "Path to previous page" do
507
+ @results.start = 20
508
+ assert_equal "/search/search-results?query=X&start=10", @results.previous_page_path
509
+ end
510
+
511
+ test "Sets path to default search-results" do
512
+ assert_equal "/search/search-results", @results.path
513
+ end
514
+
515
+ test "Setting path overrides the defaults" do
516
+ @results.path = "/other"
517
+ assert_equal "/other", @results.path
518
+ end
519
+
520
+ test "page_path" do
521
+ assert_equal "/search/search-results?query=X&start=0", @results.page_path(1)
522
+ assert_equal "/search/search-results?query=X&start=10", @results.page_path(2)
523
+ assert_equal "/search/search-results?query=X&start=20", @results.page_path(3)
524
+ assert_equal "/search/search-results?query=X&start=30", @results.page_path(4)
525
+ end
526
+
527
+ test "sorting_by_date?" do
528
+ assert_equal true, @results.sorting_by_date?({:sort=>SearchResult::QueryResult::SORT_BY_DATE_PARAM})
529
+ assert_equal false, @results.sorting_by_date?({:sort=>SearchResult::QueryResult::SORT_BY_RELEVANCE_PARAM})
530
+ assert_equal false, @results.sorting_by_date?({})
531
+ end
532
+ end
533
+
534
+
535
+ class PagingTest < ActiveSupport::TestCase
536
+
537
+ def setup
538
+ @results = SearchResult::QueryResult.new
539
+ and_the_max_number_pages_is 100
540
+ end
541
+
542
+ test "Behavior of Ruby Ranges" do
543
+ c = 0
544
+ (1..4).each_with_index do |i, count|
545
+ assert_equal count + 1, i
546
+ c = count
547
+ end
548
+ assert_equal 3, c
473
549
  end
550
+
551
+
552
+ test "When on page 1, show links for pages 1 - 10" do
553
+ when_current_page_is(1)
554
+ assert_equal (1..10), @results.pages
555
+ end
556
+
557
+ test "When on page 11, show links for pages 1-20" do
558
+ when_current_page_is(11)
559
+ assert_equal (1..20), @results.pages
560
+ end
561
+
562
+ test "When on page 12, show links for pages 2-22" do
563
+ when_current_page_is 12
564
+ assert_equal (2..21), @results.pages
565
+ end
566
+
567
+ test "When less than 10 pages only show up to last page" do
568
+ when_current_page_is 1
569
+ and_the_max_number_pages_is 4
570
+
571
+ assert_equal (1..4), @results.pages
572
+ end
573
+
574
+ test "When no results, should be empty set of pages." do
575
+ when_current_page_is 1
576
+ and_the_max_number_pages_is 0
577
+ assert_equal [], @results.pages
578
+ end
579
+
580
+ test "With one page, return a single page." do
581
+ when_current_page_is 1
582
+ and_the_max_number_pages_is 1
583
+ assert_equal [], @results.pages, "A single page of results needs no pager control"
584
+ end
585
+
586
+ private
587
+
588
+ def and_the_max_number_pages_is(number)
589
+ @results.expects(:num_pages).returns(number).times(0..5)
590
+ end
591
+
592
+ def when_current_page_is(current_page)
593
+ @results.expects(:current_page).returns(current_page).times(0..5)
594
+ end
474
595
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bcms_google_mini_search
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 1.3.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-01-05 00:00:00.000000000Z
12
+ date: 2012-02-03 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: browsercms
16
- requirement: &70196917091400 !ruby/object:Gem::Requirement
16
+ requirement: &70256812077540 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,8 +21,8 @@ dependencies:
21
21
  version: 3.3.0
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70196917091400
25
- description: A Google Appliance modules for BrowserCMS. Used to display search results
24
+ version_requirements: *70256812077540
25
+ description: A Google Appliance module for BrowserCMS. Used to display search results
26
26
  from a Google Mini/Search Appliance on a site.
27
27
  email: github@browsermedia.com
28
28
  executables: []
@@ -42,22 +42,26 @@ files:
42
42
  - app/portlets/google_mini_search_engine_portlet.rb
43
43
  - app/portlets/search_box_portlet.rb
44
44
  - app/views/layouts/templates/default.html.erb
45
+ - app/views/layouts/templates/default.html.erb.html.erb
45
46
  - app/views/portlets/google_mini_search_engine/_form.html.erb
46
47
  - app/views/portlets/google_mini_search_engine/render.html.erb
47
48
  - app/views/portlets/search_box/_form.html.erb
48
49
  - app/views/portlets/search_box/render.html.erb
49
50
  - bcms_google_mini_search.gemspec
50
- - doc/README_FOR_APP
51
+ - doc/sample_clustering_result.xml
51
52
  - lib/bcms_google_mini_search.rb
52
53
  - lib/bcms_google_mini_search/engine.rb
54
+ - lib/bcms_google_mini_search/gsa.rb
53
55
  - lib/bcms_google_mini_search/routes.rb
54
56
  - lib/bcms_google_mini_search/version.rb
55
57
  - lib/generators/bcms_google_mini_search/install/USAGE
56
58
  - lib/generators/bcms_google_mini_search/install/install_generator.rb
57
59
  - lib/tasks/.gitkeep
58
60
  - public/stylesheets/.gitkeep
61
+ - release_notes.txt
59
62
  - test/performance/browsing_test.rb
60
63
  - test/test_helper.rb
64
+ - test/unit/gsa_test.rb
61
65
  - test/unit/helpers/search_engine_helper_test.rb
62
66
  - test/unit/portlets/google_mini_search_engine_portlet_test.rb
63
67
  - test/unit/portlets/search_box_portlet_test.rb
@@ -78,7 +82,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
78
82
  version: '0'
79
83
  segments:
80
84
  - 0
81
- hash: 1363344703138389246
85
+ hash: -1846199177349674308
82
86
  required_rubygems_version: !ruby/object:Gem::Requirement
83
87
  none: false
84
88
  requirements:
@@ -87,16 +91,17 @@ required_rubygems_version: !ruby/object:Gem::Requirement
87
91
  version: '0'
88
92
  segments:
89
93
  - 0
90
- hash: 1363344703138389246
94
+ hash: -1846199177349674308
91
95
  requirements: []
92
96
  rubyforge_project: bcms_google_mini_search
93
- rubygems_version: 1.8.10
97
+ rubygems_version: 1.8.15
94
98
  signing_key:
95
99
  specification_version: 3
96
100
  summary: A Google Mini Search Module for BrowserCMS
97
101
  test_files:
98
102
  - test/performance/browsing_test.rb
99
103
  - test/test_helper.rb
104
+ - test/unit/gsa_test.rb
100
105
  - test/unit/helpers/search_engine_helper_test.rb
101
106
  - test/unit/portlets/google_mini_search_engine_portlet_test.rb
102
107
  - test/unit/portlets/search_box_portlet_test.rb
@@ -1,2 +0,0 @@
1
- Use this README file to introduce your application and point to useful places in the API for learning more.
2
- Run "rake doc:app" to generate API documentation for your models, controllers, helpers, and libraries.