xapit 0.2.7 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/{CHANGELOG → CHANGELOG.rdoc} +7 -2
- data/Gemfile +19 -0
- data/LICENSE +4 -4
- data/README.rdoc +61 -108
- data/Rakefile +11 -10
- data/features/facets.feature +93 -82
- data/features/finding.feature +196 -138
- data/features/indexing.feature +35 -37
- data/features/remote_server.feature +10 -0
- data/features/step_definitions/xapit_steps.rb +53 -25
- data/features/suggestions.feature +20 -14
- data/features/support/env.rb +13 -6
- data/features/support/xapit_helpers.rb +8 -9
- data/lib/generators/xapit/install_generator.rb +14 -0
- data/lib/generators/xapit/templates/xapit.ru +6 -0
- data/lib/generators/xapit/templates/xapit.yml +11 -0
- data/lib/xapit.rb +106 -64
- data/lib/xapit/client/collection.rb +150 -0
- data/lib/xapit/client/facet.rb +11 -0
- data/lib/xapit/client/facet_option.rb +29 -0
- data/lib/xapit/client/index_builder.rb +67 -0
- data/lib/xapit/client/membership.rb +46 -0
- data/lib/xapit/client/model_adapters/abstract_model_adapter.rb +30 -0
- data/lib/xapit/client/model_adapters/active_record_adapter.rb +27 -0
- data/lib/xapit/client/model_adapters/default_model_adapter.rb +7 -0
- data/lib/xapit/client/railtie.rb +18 -0
- data/lib/xapit/client/remote_database.rb +21 -0
- data/lib/xapit/client/tasks.rb +18 -0
- data/lib/xapit/server/app.rb +27 -0
- data/lib/xapit/server/database.rb +47 -0
- data/lib/xapit/server/indexer.rb +138 -0
- data/lib/xapit/server/query.rb +240 -0
- data/spec/fixtures/blankdb/flintlock +0 -0
- data/spec/fixtures/blankdb/iamchert +1 -0
- data/spec/fixtures/blankdb/postlist.DB +0 -0
- data/spec/fixtures/blankdb/postlist.baseA +0 -0
- data/spec/fixtures/blankdb/record.DB +0 -0
- data/spec/fixtures/blankdb/record.baseA +0 -0
- data/spec/fixtures/blankdb/termlist.DB +0 -0
- data/spec/fixtures/blankdb/termlist.baseA +0 -0
- data/spec/fixtures/xapit.ru +13 -0
- data/spec/fixtures/xapit.yml +4 -0
- data/spec/spec_helper.rb +8 -9
- data/spec/support/spec_macros.rb +6 -0
- data/spec/{xapit_member.rb → support/xapit_member.rb} +14 -16
- data/spec/xapit/client/collection_spec.rb +63 -0
- data/spec/xapit/client/facet_option_spec.rb +26 -0
- data/spec/xapit/client/facet_spec.rb +13 -0
- data/spec/xapit/client/index_builder_spec.rb +66 -0
- data/spec/xapit/client/membership_spec.rb +43 -0
- data/spec/xapit/client/model_adapters/active_record_adapter_spec.rb +62 -0
- data/spec/xapit/client/model_adapters/default_model_adapter_spec.rb +7 -0
- data/spec/xapit/client/remote_database_spec.rb +19 -0
- data/spec/xapit/server/app_spec.rb +22 -0
- data/spec/xapit/server/database_spec.rb +37 -0
- data/spec/xapit/server/indexer_spec.rb +82 -0
- data/spec/xapit/server/query_spec.rb +43 -0
- data/spec/xapit/xapit_spec.rb +28 -0
- metadata +124 -93
- data/Manifest +0 -60
- data/features/sorting.feature +0 -29
- data/init.rb +0 -1
- data/install.rb +0 -8
- data/lib/xapit/adapters/abstract_adapter.rb +0 -47
- data/lib/xapit/adapters/active_record_adapter.rb +0 -20
- data/lib/xapit/adapters/data_mapper_adapter.rb +0 -10
- data/lib/xapit/collection.rb +0 -187
- data/lib/xapit/config.rb +0 -84
- data/lib/xapit/facet.rb +0 -67
- data/lib/xapit/facet_blueprint.rb +0 -59
- data/lib/xapit/facet_option.rb +0 -56
- data/lib/xapit/index_blueprint.rb +0 -147
- data/lib/xapit/indexers/abstract_indexer.rb +0 -116
- data/lib/xapit/indexers/classic_indexer.rb +0 -29
- data/lib/xapit/indexers/simple_indexer.rb +0 -38
- data/lib/xapit/membership.rb +0 -137
- data/lib/xapit/query.rb +0 -89
- data/lib/xapit/query_parsers/abstract_query_parser.rb +0 -174
- data/lib/xapit/query_parsers/classic_query_parser.rb +0 -29
- data/lib/xapit/query_parsers/simple_query_parser.rb +0 -75
- data/lib/xapit/rake_tasks.rb +0 -13
- data/rails_generators/xapit/USAGE +0 -13
- data/rails_generators/xapit/templates/setup_xapit.rb +0 -1
- data/rails_generators/xapit/templates/xapit.rake +0 -4
- data/rails_generators/xapit/xapit_generator.rb +0 -20
- data/spec/xapit/adapters/active_record_adapter_spec.rb +0 -31
- data/spec/xapit/adapters/data_mapper_adapter_spec.rb +0 -10
- data/spec/xapit/collection_spec.rb +0 -176
- data/spec/xapit/config_spec.rb +0 -62
- data/spec/xapit/facet_blueprint_spec.rb +0 -29
- data/spec/xapit/facet_option_spec.rb +0 -80
- data/spec/xapit/facet_spec.rb +0 -73
- data/spec/xapit/index_blueprint_spec.rb +0 -112
- data/spec/xapit/indexers/abstract_indexer_spec.rb +0 -111
- data/spec/xapit/indexers/classic_indexer_spec.rb +0 -35
- data/spec/xapit/indexers/simple_indexer_spec.rb +0 -69
- data/spec/xapit/membership_spec.rb +0 -55
- data/spec/xapit/query_parsers/abstract_query_parser_spec.rb +0 -60
- data/spec/xapit/query_parsers/classic_query_parser_spec.rb +0 -20
- data/spec/xapit/query_parsers/simple_query_parser_spec.rb +0 -86
- data/spec/xapit/query_spec.rb +0 -60
- data/tasks/spec.rb +0 -9
- data/tasks/xapit.rake +0 -1
- data/uninstall.rb +0 -5
- data/xapit.gemspec +0 -30
@@ -0,0 +1,240 @@
|
|
1
|
+
module Xapit
|
2
|
+
module Server
|
3
|
+
class Query
|
4
|
+
def initialize(clauses)
|
5
|
+
@clauses = clauses
|
6
|
+
@xapian_query = nil
|
7
|
+
end
|
8
|
+
|
9
|
+
def matches
|
10
|
+
enquire = Xapian::Enquire.new(Xapit.database.xapian_database)
|
11
|
+
enquire.query = xapian_query
|
12
|
+
enquire.set_sort_by_key_then_relevance(sorter, false) if sorter
|
13
|
+
enquire.mset((page.to_i-1)*per_page.to_i, per_page.to_i).matches
|
14
|
+
end
|
15
|
+
|
16
|
+
def records
|
17
|
+
matches.map do |match|
|
18
|
+
class_name, id = match.document.data.split('-')
|
19
|
+
{:class => class_name, :id => id, :relevance => match.percent}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def spelling_suggestion
|
24
|
+
text = @clauses.map { |clause| clause[:search] }.compact.join(" ")
|
25
|
+
if [text, *text.scan(/\w+/)].all? { |term| term_suggestion(term).nil? }
|
26
|
+
nil
|
27
|
+
else
|
28
|
+
return term_suggestion(text) unless term_suggestion(text).to_s.empty?
|
29
|
+
text.downcase.gsub(/\w+/) do |term|
|
30
|
+
term_suggestion(term) || term
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def facets
|
36
|
+
facets = {}
|
37
|
+
enquire = Xapian::Enquire.new(Xapit.database.xapian_database)
|
38
|
+
enquire.query = xapian_query
|
39
|
+
spies = facet_spies
|
40
|
+
spies.values.each do |spy|
|
41
|
+
enquire.add_matchspy(spy)
|
42
|
+
end
|
43
|
+
enquire.mset(0, 200)
|
44
|
+
spies.each do |attribute, spy|
|
45
|
+
values = {}
|
46
|
+
spy.values.map do |spy_value|
|
47
|
+
spy_value.term.split("\3").each do |term| # used to support multiple facet values
|
48
|
+
values[term] ||= 0
|
49
|
+
values[term] += spy_value.termfreq.to_i
|
50
|
+
end
|
51
|
+
end
|
52
|
+
facets[attribute] = values.map { |value, count| {:value => value, :count => count} }
|
53
|
+
end
|
54
|
+
facets
|
55
|
+
end
|
56
|
+
|
57
|
+
def applied_facet_options
|
58
|
+
facet_options = []
|
59
|
+
@clauses.each do |clause|
|
60
|
+
if clause[:with_facets]
|
61
|
+
clause[:with_facets].each do |identifier|
|
62
|
+
facet_options << facet_option(identifier)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
facet_options
|
67
|
+
end
|
68
|
+
|
69
|
+
def facet_option(identifier)
|
70
|
+
match = self.class.new([{:in_classes => ["FacetOption"]}, {:where => {:id => identifier}}]).matches.first
|
71
|
+
if match.nil?
|
72
|
+
raise "Unable to find facet option for #{identifier}."
|
73
|
+
else
|
74
|
+
name, value = match.document.data.split('|||')
|
75
|
+
{:id => identifier, :name => name, :value => value}
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def total
|
80
|
+
enquire = Xapian::Enquire.new(Xapit.database.xapian_database)
|
81
|
+
enquire.query = xapian_query
|
82
|
+
enquire.mset(0, Xapit.database.xapian_database.doccount).matches_estimated
|
83
|
+
end
|
84
|
+
|
85
|
+
def data
|
86
|
+
{:records => records, :facets => facets, :applied_facet_options => applied_facet_options, :total => total}
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
def page
|
92
|
+
@clauses.map { |clause| clause[:page] }.compact.last || 1
|
93
|
+
end
|
94
|
+
|
95
|
+
def per_page
|
96
|
+
@clauses.map { |clause| clause[:per_page] }.compact.last || Xapit::Client::Collection::DEFAULT_PER_PAGE
|
97
|
+
end
|
98
|
+
|
99
|
+
def term_suggestion(term)
|
100
|
+
suggestion = Xapit.database.xapian_database.get_spelling_suggestion(term.downcase)
|
101
|
+
suggestion.to_s.empty? ? nil : suggestion
|
102
|
+
end
|
103
|
+
|
104
|
+
def sorter
|
105
|
+
if @clauses.any? { |c| c[:order] }
|
106
|
+
sorter = Xapian::MultiValueKeyMaker.new
|
107
|
+
@clauses.each do |clause|
|
108
|
+
if clause[:order]
|
109
|
+
attribute, direction = clause[:order]
|
110
|
+
sorter.add_value(Xapit.value_index(:sortable, attribute), direction.to_sym == :desc)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
sorter
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def facet_spies
|
118
|
+
spies = {}
|
119
|
+
@clauses.each do |clause|
|
120
|
+
if clause[:include_facets]
|
121
|
+
clause[:include_facets].each do |facet|
|
122
|
+
spies[facet] = Xapian::ValueCountMatchSpy.new(Xapit.value_index(:facet, facet))
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
spies
|
127
|
+
end
|
128
|
+
|
129
|
+
def xapian_query
|
130
|
+
build_xapian_query if @query.nil?
|
131
|
+
@xapian_query
|
132
|
+
end
|
133
|
+
|
134
|
+
def build_xapian_query
|
135
|
+
@xapian_query = Xapian::Query.new("")
|
136
|
+
@clauses.each do |clause|
|
137
|
+
clause.each do |type, options|
|
138
|
+
apply_clause(type, options)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def apply_clause(type, value)
|
144
|
+
case type
|
145
|
+
when :search
|
146
|
+
merge(:and, search_query(value))
|
147
|
+
when :where
|
148
|
+
merge(:and, where_query(value))
|
149
|
+
when :or_where
|
150
|
+
merge(:or, where_query(value))
|
151
|
+
when :not_where
|
152
|
+
merge(:not, where_query(value))
|
153
|
+
when :in_classes
|
154
|
+
merge(:and, value.map { |c| "C#{c}" })
|
155
|
+
when :not_in_classes
|
156
|
+
merge(:not, value.map { |c| "C#{c}" })
|
157
|
+
when :similar_to
|
158
|
+
similar_to(value)
|
159
|
+
when :with_facets
|
160
|
+
merge(:and, facet_terms(value))
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def similar_to(data)
|
165
|
+
indexer = Indexer.new(data)
|
166
|
+
terms = (indexer.text_terms + indexer.field_terms).map { |a| a.first }
|
167
|
+
merge(:and, Xapian::Query.new(xapian_operator(:or), terms))
|
168
|
+
merge(:not, ["Q#{data[:class]}-#{data[:id]}"])
|
169
|
+
end
|
170
|
+
|
171
|
+
def where_query(conditions)
|
172
|
+
queries = []
|
173
|
+
terms = []
|
174
|
+
conditions.each do |name, value|
|
175
|
+
if value.kind_of?(Hash) && value[:from] && value[:to]
|
176
|
+
queries << Xapian::Query.new(xapian_operator(:range), Xapit.value_index(:field, name), Xapit.serialize_value(value[:from]), Xapit.serialize_value(value[:to]))
|
177
|
+
else
|
178
|
+
terms << "X#{name}-#{value.to_s.downcase}"
|
179
|
+
end
|
180
|
+
end
|
181
|
+
queries << Xapian::Query.new(xapian_operator(:and), terms) unless terms.empty?
|
182
|
+
queries.inject(queries.shift) do |merged_query, query|
|
183
|
+
Xapian::Query.new(xapian_operator(:and), merged_query, query)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def where_terms(conditions)
|
188
|
+
conditions.map do |name, value|
|
189
|
+
"X#{name}-#{value.to_s.downcase}"
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
def facet_terms(facets)
|
194
|
+
facets.map { |facet| "F#{facet}" }
|
195
|
+
end
|
196
|
+
|
197
|
+
def search_query(text)
|
198
|
+
clean_text = text.gsub(/\b([a-z])\*/i, "\\1").gsub(/[^\w\*\s:]/u, "")
|
199
|
+
xapian_parser.parse_query(clean_text, Xapian::QueryParser::FLAG_WILDCARD | Xapian::QueryParser::FLAG_BOOLEAN) # Xapian::QueryParser::FLAG_LOVEHATE
|
200
|
+
end
|
201
|
+
|
202
|
+
def merge(operator, query)
|
203
|
+
query = Xapian::Query.new(xapian_operator(:and), query) unless query.kind_of? Xapian::Query
|
204
|
+
@xapian_query = Xapian::Query.new(xapian_operator(operator), @xapian_query, query)
|
205
|
+
end
|
206
|
+
|
207
|
+
def xapian_operator(operator)
|
208
|
+
case operator
|
209
|
+
when :and then Xapian::Query::OP_AND
|
210
|
+
when :or then Xapian::Query::OP_OR
|
211
|
+
when :not then Xapian::Query::OP_AND_NOT
|
212
|
+
when :range then Xapian::Query::OP_VALUE_RANGE
|
213
|
+
else raise "Unknown Xapian operator #{operator}"
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def xapian_parser
|
218
|
+
@xapian_parser ||= build_xapian_parser
|
219
|
+
end
|
220
|
+
|
221
|
+
def build_xapian_parser
|
222
|
+
parser = Xapian::QueryParser.new
|
223
|
+
parser.database = Xapit.database.xapian_database
|
224
|
+
if Xapit.config[:stemming]
|
225
|
+
parser.stemmer = Xapian::Stem.new(Xapit.config[:stemming])
|
226
|
+
parser.stemming_strategy = Xapian::QueryParser::STEM_SOME
|
227
|
+
end
|
228
|
+
parser.default_op = xapian_operator(:and)
|
229
|
+
@clauses.each do |clause|
|
230
|
+
if clause[:search]
|
231
|
+
clause[:search].scan(/([a-z0-9_]+)\:/i).each do
|
232
|
+
parser.add_prefix($1, "X#{$1}-")
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
parser
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
IAmChert�����pn�N3��gf�]
|
File without changes
|
Binary file
|
File without changes
|
Binary file
|
File without changes
|
Binary file
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
|
3
|
+
# Add lib directory so we can include xapit, this isn't necessary when a gem is available
|
4
|
+
root = File.expand_path('../../..', __FILE__)
|
5
|
+
$:.unshift "#{root}/lib"
|
6
|
+
require "xapit"
|
7
|
+
|
8
|
+
|
9
|
+
FileUtils.rm_rf("#{root}/tmp/testdb") # quick hack to start with a fresh database every time
|
10
|
+
Xapit.config[:database_path] = "#{root}/tmp/testdb"
|
11
|
+
Xapit.config[:template_path] = "#{root}/spec/fixtures/blankdb"
|
12
|
+
|
13
|
+
run Xapit::Server::App.new
|
data/spec/spec_helper.rb
CHANGED
@@ -1,15 +1,14 @@
|
|
1
1
|
require 'rubygems'
|
2
|
-
require '
|
3
|
-
require
|
4
|
-
require 'fileutils'
|
5
|
-
require File.dirname(__FILE__) + '/../lib/xapit'
|
6
|
-
require File.dirname(__FILE__) + '/xapit_member'
|
2
|
+
require 'bundler/setup'
|
3
|
+
Bundler.require(:default)
|
7
4
|
|
8
|
-
|
9
|
-
|
5
|
+
require "support/spec_macros"
|
6
|
+
require "support/xapit_member"
|
7
|
+
|
8
|
+
RSpec.configure do |config|
|
9
|
+
config.include SpecMacros
|
10
10
|
config.before(:each) do
|
11
|
-
Xapit.
|
12
|
-
Xapit.remove_database
|
11
|
+
Xapit.reset_config
|
13
12
|
XapitMember.delete_all
|
14
13
|
end
|
15
14
|
end
|
@@ -1,22 +1,17 @@
|
|
1
1
|
class XapitMember
|
2
|
-
include Xapit::Membership
|
3
|
-
|
2
|
+
include Xapit::Client::Membership
|
3
|
+
xapit { } # loads Xapit member methods
|
4
|
+
|
4
5
|
attr_reader :id
|
5
|
-
|
6
|
-
# Make it look like this inherits from ActiveRecord::Base
|
7
|
-
# so it will use the ActiveRecord adapter.
|
8
|
-
def self.ancestors
|
9
|
-
["ActiveRecord::Base"]
|
10
|
-
end
|
11
|
-
|
6
|
+
|
12
7
|
def self.find_each(&block)
|
13
8
|
@@records.each(&block) if @@records
|
14
9
|
end
|
15
|
-
|
10
|
+
|
16
11
|
def self.delete_all
|
17
12
|
@@records = []
|
18
13
|
end
|
19
|
-
|
14
|
+
|
20
15
|
def self.find(ids)
|
21
16
|
if ids.kind_of? Array
|
22
17
|
# change the order to mimic database where we can't predict the order
|
@@ -25,18 +20,21 @@ class XapitMember
|
|
25
20
|
@@records.detect { |r| r.id == ids.to_i }
|
26
21
|
end
|
27
22
|
end
|
28
|
-
|
23
|
+
|
29
24
|
def self.find_by_id(id)
|
30
25
|
find(id)
|
31
26
|
end
|
32
|
-
|
27
|
+
|
33
28
|
def initialize(attributes = {})
|
34
29
|
@@records ||= []
|
35
30
|
@id = @@records.size + 1
|
36
|
-
@attributes =
|
31
|
+
@attributes = {}
|
32
|
+
attributes.each do |key, value|
|
33
|
+
@attributes[key.to_sym] = value
|
34
|
+
end
|
37
35
|
@@records << self
|
38
36
|
end
|
39
|
-
|
37
|
+
|
40
38
|
def method_missing(name, *args)
|
41
39
|
if @attributes.has_key? name
|
42
40
|
@attributes[name]
|
@@ -44,7 +42,7 @@ class XapitMember
|
|
44
42
|
super
|
45
43
|
end
|
46
44
|
end
|
47
|
-
|
45
|
+
|
48
46
|
def update_attribute(name, value)
|
49
47
|
@attributes[name] = value
|
50
48
|
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Xapit::Client::Collection do
|
4
|
+
it "builds up clauses with in_classes, search, where, order calls" do
|
5
|
+
collection1 = Xapit::Client::Collection.new([:initial])
|
6
|
+
collection2 = collection1.in_classes(String).search("hello").where(:foo => "bar").order(:bar)
|
7
|
+
collection1.clauses.should eq([:initial])
|
8
|
+
collection2.clauses.should eq([:initial, {:in_classes => [String]}, {:search => "hello"}, {:where => {:foo => "bar"}}, {:order => [:bar, :asc]}])
|
9
|
+
end
|
10
|
+
|
11
|
+
it "returns same collection when searching nil or empty string" do
|
12
|
+
collection1 = Xapit::Client::Collection.new
|
13
|
+
collection1.search("").should eq(collection1)
|
14
|
+
collection1.search(nil).should eq(collection1)
|
15
|
+
collection1.search.should eq(collection1)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "returns indexed records and delegates array methods to it" do
|
19
|
+
load_xapit_database
|
20
|
+
member = XapitMember.new
|
21
|
+
member.class.xapit_index_builder.add_document(member)
|
22
|
+
collection = Xapit::Client::Collection.new
|
23
|
+
collection.records.should eq([member])
|
24
|
+
collection.should respond_to(:flatten)
|
25
|
+
collection.flatten.should eq([member])
|
26
|
+
end
|
27
|
+
|
28
|
+
it "splits up matching facets into an array" do
|
29
|
+
collection = Xapit::Client::Collection.new.with_facets("foo-bar")
|
30
|
+
collection.clauses.should eq([{:with_facets => %w[foo bar]}])
|
31
|
+
end
|
32
|
+
|
33
|
+
it "splits range into from/to hash" do
|
34
|
+
collection = Xapit::Client::Collection.new.where(:priority => 3..5)
|
35
|
+
collection.clauses.should eq([{:where => {:priority => {:from => 3, :to => 5}}}])
|
36
|
+
end
|
37
|
+
|
38
|
+
it "does not raise an exception when passing nil to with_facets" do
|
39
|
+
lambda {
|
40
|
+
Xapit::Client::Collection.new.with_facets(nil).should be_kind_of(Xapit::Client::Collection)
|
41
|
+
}.should_not raise_exception
|
42
|
+
end
|
43
|
+
|
44
|
+
it "defaults to 20 per page and page 1" do
|
45
|
+
Xapit::Client::Collection.new.limit_value.should eq(20)
|
46
|
+
Xapit::Client::Collection.new.current_page.should eq(1)
|
47
|
+
end
|
48
|
+
|
49
|
+
it "supports kaminari pagination" do
|
50
|
+
collection = Xapit::Client::Collection.new.page("2").per("10")
|
51
|
+
collection.stub(:total_entries) { 29 }
|
52
|
+
collection.current_page.should eq(2)
|
53
|
+
collection.num_pages.should eq(3)
|
54
|
+
collection.limit_value.should eq(10)
|
55
|
+
end
|
56
|
+
|
57
|
+
it "supports will_paginate pagination" do
|
58
|
+
collection = Xapit::Client::Collection.new.page("2").per("10")
|
59
|
+
collection.stub(:total_entries) { 29 }
|
60
|
+
collection.current_page.should eq(2)
|
61
|
+
collection.total_pages.should eq(3)
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Xapit::Client::FacetOption do
|
4
|
+
it "has an identifier using attribute and value" do
|
5
|
+
option = Xapit::Client::FacetOption.new("greeting", :value => "Hello")
|
6
|
+
option.identifier.should eq(Xapit.facet_identifier("greeting", "Hello"))
|
7
|
+
end
|
8
|
+
|
9
|
+
it "has a name and count matching passed options" do
|
10
|
+
option = Xapit::Client::FacetOption.new("greeting", :value => "Hello", :count => "3")
|
11
|
+
option.name.should eq("Hello")
|
12
|
+
option.count.should eq(3)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "combines previous identifiers with current one on to_param" do
|
16
|
+
id = Xapit.facet_identifier("greeting", "Hello")
|
17
|
+
option = Xapit::Client::FacetOption.new("greeting", {:value => "Hello"}, %w[abc 123])
|
18
|
+
option.to_param.should == "abc-123-#{id}"
|
19
|
+
end
|
20
|
+
|
21
|
+
it "removes current identifier from previous identifiers if it exists" do
|
22
|
+
id = Xapit.facet_identifier("greeting", "Hello")
|
23
|
+
option = Xapit::Client::FacetOption.new("greeting", {:value => "Hello"}, %w[abc 123] + [id])
|
24
|
+
option.to_param.should == "abc-123"
|
25
|
+
end
|
26
|
+
end
|