mongoid_search 0.3.2 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,10 +1,7 @@
1
- require 'mongoid_search'
2
- require 'rails'
3
-
4
1
  module Mongoid::Search
5
2
  class Railtie < Rails::Railtie
6
3
  rake_tasks do
7
- Dir[File.join(File.dirname(__FILE__), '../../tasks/*.rake')].each { |f| load f }
4
+ Dir[File.join(File.dirname(__FILE__), 'tasks/*.rake')].each { |f| load f }
8
5
  end
9
6
  end
10
- end
7
+ end
@@ -0,0 +1,16 @@
1
+ namespace :mongoid_search do
2
+ desc 'Goes through all documents with search enabled and indexes the keywords.'
3
+ task index: :environment do
4
+ ::Rails.application.eager_load!
5
+ if Mongoid::Search.classes.blank?
6
+ Mongoid::Search::Log.log "No model to index keywords.\n"
7
+ else
8
+ Mongoid::Search.classes.each do |klass|
9
+ Mongoid::Search::Log.silent = ENV['SILENT']
10
+ Mongoid::Search::Log.log "\nIndexing documents for #{klass.name}:\n"
11
+ klass.index_keywords!
12
+ end
13
+ Mongoid::Search::Log.log "\n\nDone.\n"
14
+ end
15
+ end
16
+ end
@@ -1,28 +1,28 @@
1
- # encoding: utf-8
1
+
2
2
  module Mongoid::Search::Util
3
3
  def self.keywords(klass, fields)
4
4
  if fields.is_a?(Array)
5
5
  fields.map do |field|
6
- self.keywords(klass, field)
6
+ keywords(klass, field)
7
7
  end
8
8
  elsif fields.is_a?(Hash)
9
9
  fields.keys.map do |field|
10
10
  attribute = klass.send(field)
11
11
  unless attribute.blank?
12
12
  if attribute.is_a?(Array)
13
- attribute.map{ |a| self.keywords(a, fields[field]) }
13
+ attribute.map { |a| keywords(a, fields[field]) }
14
14
  else
15
- self.keywords(attribute, fields[field])
15
+ keywords(attribute, fields[field])
16
16
  end
17
17
  end
18
18
  end
19
19
  else
20
- value = if klass.respond_to?(fields.to_s + "_translations")
21
- klass.send(fields.to_s + "_translations").values
20
+ value = if klass.respond_to?(fields.to_s + '_translations')
21
+ klass.send(fields.to_s + '_translations').values
22
22
  elsif klass.respond_to?(fields)
23
23
  klass.send(fields)
24
24
  else
25
- value = klass[fields];
25
+ value = klass[fields]
26
26
  end
27
27
  value = value.join(' ') if value.respond_to?(:join)
28
28
  normalize_keywords(value) if value
@@ -34,21 +34,22 @@ module Mongoid::Search::Util
34
34
  ignore_list = Mongoid::Search.ignore_list
35
35
  stem_keywords = Mongoid::Search.stem_keywords
36
36
  stem_proc = Mongoid::Search.stem_proc
37
+ strip_symbols = Mongoid::Search.strip_symbols
38
+ strip_accents = Mongoid::Search.strip_accents
37
39
 
38
40
  return [] if text.blank?
39
- text = text.to_s.
40
- mb_chars.
41
- normalize(:kd).
42
- downcase.
43
- to_s.
44
- gsub(/[._:;'"`,?|+={}()!@#%^&*<>~\$\-\\\/\[\]]/, ' '). # strip punctuation
45
- gsub(/[^[:alnum:]\s]/,''). # strip accents
46
- gsub(/[#{ligatures.keys.join("")}]/) {|c| ligatures[c]}.
47
- split(' ').
48
- reject { |word| word.size < Mongoid::Search.minimum_word_size }
41
+ text = text.to_s
42
+ .mb_chars
43
+ .unicode_normalize(:nfkd)
44
+ .downcase
45
+ .to_s
46
+ .gsub(strip_symbols, ' ') # strip symbols
47
+ .gsub(strip_accents, '') # strip accents
48
+ .gsub(/[#{ligatures.keys.join("")}]/) { |c| ligatures[c] }
49
+ .split(' ')
50
+ .reject { |word| word.size < Mongoid::Search.minimum_word_size }
49
51
  text = text.reject { |word| ignore_list.include?(word) } unless ignore_list.blank?
50
52
  text = text.map(&stem_proc) if stem_keywords
51
53
  text
52
54
  end
53
-
54
55
  end
@@ -1,5 +1,7 @@
1
1
  class Category
2
2
  include Mongoid::Document
3
+ include Mongoid::Attributes::Dynamic if ::Mongoid::VERSION >= '4'
4
+
3
5
  field :name, localize: true
4
6
  field :description
5
7
 
@@ -1,15 +1,24 @@
1
1
  class Product
2
2
  include Mongoid::Document
3
3
  include Mongoid::Search
4
+ include Mongoid::Attributes::Dynamic if ::Mongoid::VERSION >= '4'
5
+
4
6
  field :brand
5
7
  field :name
6
- field :attrs, :type => Array
7
- field :info, :type => Hash
8
+ field :unit
9
+ field :measures, type: Array
10
+ field :attrs, type: Array
11
+ field :info, type: Hash
8
12
 
9
- has_many :tags
10
- belongs_to :category
13
+ has_many :tags
14
+ if Mongoid::Compatibility::Version.mongoid6_or_newer?
15
+ belongs_to :category, required: false
16
+ else
17
+ belongs_to :category
18
+ end
11
19
  embeds_many :subproducts
12
20
 
13
- search_in :brand, :name, :outlet, :attrs, :tags => :name, :category => [:name, :description],
14
- :subproducts => [:brand, :name], :info => [ :summary, :description ]
21
+ search_in :brand, :name, :outlet, :attrs, tags: :name, category: %i[name description],
22
+ subproducts: %i[brand name], info: %i[summary description]
23
+ search_in :unit, :measures, index: :_unit_keywords
15
24
  end
@@ -1,8 +1,9 @@
1
1
  class Subproduct
2
2
  include Mongoid::Document
3
+ include Mongoid::Attributes::Dynamic if ::Mongoid::VERSION >= '4'
3
4
 
4
5
  field :brand
5
6
  field :name
6
7
 
7
- belongs_to :product, :inverse_of => :subproducts
8
+ embedded_in :product, inverse_of: :subproducts
8
9
  end
@@ -1,14 +1,15 @@
1
1
  class Tag
2
2
  include Mongoid::Document
3
3
  include Mongoid::Search
4
+ include Mongoid::Attributes::Dynamic if ::Mongoid::VERSION >= '4'
4
5
 
5
6
  field :name
6
7
 
7
8
  belongs_to :product
8
9
 
9
10
  def title
10
- self.name
11
+ name
11
12
  end
12
13
 
13
- search_in :title, :product => [:name, { :info => [ :summary, :description ], :category => [:name, :description]}]
14
+ search_in :title, product: [:name, { info: %i[summary description], category: %i[name description] }]
14
15
  end
@@ -1,5 +1,7 @@
1
- autoload :Product, "models/product.rb"
1
+ autoload :Product, 'models/product.rb'
2
2
  class Variant < Product
3
3
  field :color
4
+ field :size
4
5
  search_in :color
6
+ search_in :size, index: :_unit_keywords
5
7
  end
@@ -1,11 +1,10 @@
1
- # encoding: utf-8
2
-
3
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
4
2
 
5
3
  describe Mongoid::Search do
6
-
7
4
  before(:all) do
8
5
  @default_proc = Mongoid::Search.stem_proc
6
+ @default_strip_symbols = Mongoid::Search.strip_symbols
7
+ @default_strip_accents = Mongoid::Search.strip_accents
9
8
  end
10
9
 
11
10
  after(:all) do
@@ -17,257 +16,356 @@ describe Mongoid::Search do
17
16
  Mongoid::Search.stem_keywords = false
18
17
  Mongoid::Search.ignore_list = nil
19
18
  Mongoid::Search.stem_proc = @default_proc
20
- @product = Product.create :brand => "Apple",
21
- :name => "iPhone",
22
- :tags => (@tags = ["Amazing", "Awesome", "Olé"].map { |tag| Tag.new(:name => tag) }),
23
- :category => Category.new(:name => "Mobile", :description => "Reviews"),
24
- :subproducts => [Subproduct.new(:brand => "Apple", :name => "Craddle")],
25
- :info => { :summary => "Info-summary",
26
- :description => "Info-description"}
27
- end
28
-
29
- describe "Serialized hash fields" do
30
- context "when the hash is populated" do
31
- it "should return the product" do
32
- Product.full_text_search("Info-summary").first.should eq @product
33
- Product.full_text_search("Info-description").first.should eq @product
19
+ @product = Product.create brand: 'Apple',
20
+ name: 'iPhone',
21
+ unit: 'mobile olé awesome',
22
+ tags: (@tags = %w[Amazing Awesome Olé].map { |tag| Tag.new(name: tag) }),
23
+ category: Category.new(name: 'Mobile', description: 'Reviews'),
24
+ subproducts: [Subproduct.new(brand: 'Apple', name: 'Craddle')],
25
+ info: { summary: 'Info-summary',
26
+ description: 'Info-description' }
27
+ end
28
+
29
+ describe 'Serialized hash fields' do
30
+ context 'when the hash is populated' do
31
+ it 'should return the product' do
32
+ expect(Product.full_text_search('Info-summary').first).to eq @product
33
+ expect(Product.full_text_search('Info-description').first).to eq @product
34
34
  end
35
35
  end
36
36
 
37
- context "when the hash is empty" do
37
+ context 'when the hash is empty' do
38
38
  before(:each) do
39
39
  @product.info = nil
40
40
  @product.save
41
41
  end
42
42
 
43
- it "should not return the product" do
44
- Product.full_text_search("Info-description").size.should eq 0
45
- Product.full_text_search("Info-summary").size.should eq 0
43
+ it 'should not return the product' do
44
+ expect(Product.full_text_search('Info-description').size).to eq 0
45
+ expect(Product.full_text_search('Info-summary').size).to eq 0
46
46
  end
47
47
  end
48
48
  end
49
49
 
50
- context "utf-8 characters" do
50
+ context 'utf-8 characters' do
51
51
  before do
52
52
  Mongoid::Search.stem_keywords = false
53
53
  Mongoid::Search.ignore_list = nil
54
- @product = Product.create :brand => "Эльбрус",
55
- :name => "Процессор",
56
- :tags => ["Amazing", "Awesome", "Olé"].map { |tag| Tag.new(:name => tag) },
57
- :category => Category.new(:name => "процессоры"),
58
- :subproducts => []
54
+ @product = Product.create brand: 'Эльбрус',
55
+ name: 'Процессор',
56
+ unit: 'kílográm Olé',
57
+ tags: %w[Amazing Awesome Olé].map { |tag| Tag.new(name: tag) },
58
+ category: Category.new(name: 'процессоры'),
59
+ subproducts: []
59
60
  end
60
61
 
61
- it "should leave utf8 characters" do
62
- @product._keywords.should == ["amazing", "awesome", "ole", "процессор", "процессоры", "эльбрус"]
62
+ it 'should leave utf8 characters' do
63
+ expect(@product._keywords).to eq %w[amazing awesome ole процессор процессоры эльбрус]
64
+ expect(@product._unit_keywords).to eq %w[kilogram ole]
63
65
  end
64
66
 
65
67
  it "should return results in search when case doesn't match" do
66
- Product.full_text_search("ЭЛЬБРУС").size.should == 1
68
+ expect(Product.full_text_search('ЭЛЬБРУС').size).to eq 1
69
+ expect(Product.full_text_search('KILOGRAM', index: :_unit_keywords).size).to eq 1
67
70
  end
68
71
  end
69
72
 
70
- context "when references are nil" do
71
- context "when instance is being created" do
72
- it "should not complain about method missing" do
73
- lambda { Product.create! }.should_not raise_error
73
+ context 'when references are nil' do
74
+ context 'when instance is being created' do
75
+ it 'should not complain about method missing' do
76
+ expect { Product.create! }.not_to raise_error
74
77
  end
75
78
  end
76
79
 
77
- subject { Product.create :brand => "Apple", :name => "iPhone" }
78
-
79
- its(:_keywords) { should == ["apple", "iphone"] }
80
+ it 'should validate keywords' do
81
+ product = Product.create brand: 'Apple', name: 'iPhone', unit: 'box'
82
+ expect(product._keywords).to eq(%w[apple iphone])
83
+ expect(product._unit_keywords).to eq(%w[box])
84
+ end
80
85
  end
81
86
 
82
-
83
- it "should set the _keywords field for array fields also" do
87
+ it 'should set the _keywords field for array fields also' do
84
88
  @product.attrs = ['lightweight', 'plastic', :red]
89
+ @product.measures = ['box', 'bunch', :bag]
85
90
  @product.save!
86
- @product._keywords.should include 'lightweight', 'plastic', 'red'
91
+ expect(@product._keywords).to include 'lightweight', 'plastic', 'red'
92
+ expect(@product._unit_keywords).to include 'box', 'bunch', 'bag'
87
93
  end
88
94
 
89
- it "should inherit _keywords field and build upon" do
90
- variant = Variant.create :brand => "Apple",
91
- :name => "iPhone",
92
- :tags => ["Amazing", "Awesome", "Olé"].map { |tag| Tag.new(:name => tag) },
93
- :category => Category.new(:name => "Mobile"),
94
- :subproducts => [Subproduct.new(:brand => "Apple", :name => "Craddle")],
95
- :color => :white
96
- variant._keywords.should include 'white'
97
- Variant.full_text_search(:name => 'Apple', :color => :white).should eq [variant]
95
+ it 'should inherit _keywords field and build upon' do
96
+ variant = Variant.create brand: 'Apple',
97
+ name: 'iPhone',
98
+ tags: %w[Amazing Awesome Olé].map { |tag| Tag.new(name: tag) },
99
+ category: Category.new(name: 'Mobile'),
100
+ subproducts: [Subproduct.new(brand: 'Apple', name: 'Craddle')],
101
+ color: :white,
102
+ size: :big
103
+ expect(variant._keywords).to include 'white'
104
+ expect(variant._unit_keywords).to include 'big'
105
+ expect(Variant.full_text_search(name: 'Apple', color: :white)).to eq [variant]
106
+ expect(Variant.full_text_search({ size: 'big' }, index: :_unit_keywords)).to eq [variant]
98
107
  end
99
108
 
100
- it "should expand the ligature to ease searching" do
109
+ it 'should expand the ligature to ease searching' do
101
110
  # ref: http://en.wikipedia.org/wiki/Typographic_ligature, only for french right now. Rules for other languages are not know
102
- variant1 = Variant.create :tags => ["œuvre"].map {|tag| Tag.new(:name => tag)}
103
- variant2 = Variant.create :tags => ["æquo"].map {|tag| Tag.new(:name => tag)}
111
+ variant1 = Variant.create tags: ['œuvre'].map { |tag| Tag.new(name: tag) }
112
+ variant2 = Variant.create tags: ['æquo'].map { |tag| Tag.new(name: tag) }
113
+ variant3 = Variant.create measures: ['ꜵquo'].map { |measure| measure }
104
114
 
105
- Variant.full_text_search("œuvre").should eq [variant1]
106
- Variant.full_text_search("oeuvre").should eq [variant1]
107
- Variant.full_text_search("æquo").should eq [variant2]
108
- Variant.full_text_search("aequo").should eq [variant2]
115
+ expect(Variant.full_text_search('œuvre')).to eq [variant1]
116
+ expect(Variant.full_text_search('oeuvre')).to eq [variant1]
117
+ expect(Variant.full_text_search('æquo')).to eq [variant2]
118
+ expect(Variant.full_text_search('aequo')).to eq [variant2]
119
+ expect(Variant.full_text_search('aoquo', index: :_unit_keywords)).to eq [variant3]
120
+ expect(Variant.full_text_search('ꜵquo', index: :_unit_keywords)).to eq [variant3]
109
121
  end
110
122
 
111
- it "should set the _keywords field with stemmed words if stem is enabled" do
123
+ it 'should set the keywords fields with stemmed words if stem is enabled' do
112
124
  Mongoid::Search.stem_keywords = true
113
125
  @product.save!
114
- @product._keywords.sort.should == ["amaz", "appl", "awesom", "craddl", "iphon", "mobil", "review", "ol", "info", "descript", "summari"].sort
126
+ expect(@product._keywords.sort).to eq %w[amaz appl awesom craddl iphon mobil review ol info descript summari].sort
127
+ expect(@product._unit_keywords.sort).to eq %w[mobil awesom ol].sort
115
128
  end
116
129
 
117
- it "should set the _keywords field with custom stemmed words if stem is enabled with a custom lambda" do
130
+ it 'should set the keywords fields with custom stemmed words if stem is enabled with a custom lambda' do
118
131
  Mongoid::Search.stem_keywords = true
119
- Mongoid::Search.stem_proc = Proc.new { |word| word.upcase }
132
+ Mongoid::Search.stem_proc = proc { |word| word.upcase }
120
133
  @product.save!
121
- @product._keywords.sort.should == ["AMAZING", "APPLE", "AWESOME", "CRADDLE", "DESCRIPTION", "INFO", "IPHONE", "MOBILE", "OLE", "REVIEWS", "SUMMARY"]
134
+ expect(@product._keywords.sort).to eq %w[AMAZING APPLE AWESOME CRADDLE DESCRIPTION INFO IPHONE MOBILE OLE REVIEWS SUMMARY]
135
+ expect(@product._unit_keywords.sort).to eq %w[AWESOME MOBILE OLE]
122
136
  end
123
137
 
124
- it "should ignore keywords in an ignore list" do
125
- Mongoid::Search.ignore_list = YAML.load(File.open(File.dirname(__FILE__) + '/config/ignorelist.yml'))["ignorelist"]
138
+ it 'should ignore keywords in an ignore list' do
139
+ Mongoid::Search.ignore_list = YAML.safe_load(File.open(File.dirname(__FILE__) + '/config/ignorelist.yml'))['ignorelist']
126
140
  @product.save!
127
- @product._keywords.sort.should == ["apple", "craddle", "iphone", "mobile", "reviews", "ole", "info", "description", "summary"].sort
141
+ expect(@product._keywords.sort).to eq %w[apple craddle iphone mobile reviews ole info description summary].sort
142
+ expect(@product._unit_keywords.sort).to eq %w[mobile ole].sort
128
143
  end
129
144
 
130
- it "should incorporate numbers as keywords" do
131
- @product = Product.create :brand => "Ford",
132
- :name => "T 1908",
133
- :tags => ["Amazing", "First", "Car"].map { |tag| Tag.new(:name => tag) },
134
- :category => Category.new(:name => "Vehicle")
145
+ it 'should incorporate numbers as keywords' do
146
+ @product = Product.create brand: 'Ford',
147
+ name: 'T 1908',
148
+ tags: %w[Amazing First Car].map { |tag| Tag.new(name: tag) },
149
+ category: Category.new(name: 'Vehicle')
135
150
 
136
- @product.save!
137
- @product._keywords.should == ["1908", "amazing", "car", "first", "ford", "vehicle"]
138
- end
151
+ @product.save!
152
+ expect(@product._keywords).to eq %w[1908 amazing car first ford vehicle]
153
+ end
139
154
 
140
- it "should return results in search" do
141
- Product.full_text_search("apple").size.should == 1
155
+ it 'should return results in search' do
156
+ expect(Product.full_text_search('apple').size).to eq 1
142
157
  end
143
158
 
144
- it "should return results in search for dynamic attribute" do
145
- @product[:outlet] = "online shop"
159
+ it 'should return results in search for dynamic attribute' do
160
+ @product[:outlet] = 'online shop'
146
161
  @product.save!
147
- Product.full_text_search("online").size.should == 1
162
+ expect(Product.full_text_search('online').size).to eq 1
148
163
  end
149
164
 
150
- it "should return results in search even searching a accented word" do
151
- Product.full_text_search("Ole").size.should == 1
152
- Product.full_text_search("Olé").size.should == 1
165
+ it 'should return results in search even searching a accented word' do
166
+ expect(Product.full_text_search('Ole').size).to eq 1
167
+ expect(Product.full_text_search('Olé').size).to eq 1
153
168
  end
154
169
 
155
170
  it "should return results in search even if the case doesn't match" do
156
- Product.full_text_search("oLe").size.should == 1
171
+ expect(Product.full_text_search('oLe').size).to eq 1
157
172
  end
158
173
 
159
- it "should return results in search with a partial word by default" do
160
- Product.full_text_search("iph").size.should == 1
174
+ it 'should return results in search with a partial word by default' do
175
+ expect(Product.full_text_search('iph').size).to eq 1
161
176
  end
162
177
 
163
- it "should return results for any matching word with default search" do
164
- Product.full_text_search("apple motorola").size.should == 1
178
+ it 'should return results for any matching word with default search' do
179
+ expect(Product.full_text_search('apple motorola').size).to eq 1
165
180
  end
166
181
 
167
- it "should not return results when all words do not match, if using :match => :all" do
182
+ it 'should not return results when all words do not match, if using :match => :all' do
168
183
  Mongoid::Search.match = :all
169
- Product.full_text_search("apple motorola").size.should == 0
184
+ expect(Product.full_text_search('apple motorola').size).to eq 0
170
185
  end
171
186
 
172
- it "should return results for any matching word, using :match => :all, passing :match => :any to .full_text_search" do
187
+ it 'should return results for any matching word, using :match => :all, passing :match => :any to .full_text_search' do
173
188
  Mongoid::Search.match = :all
174
- Product.full_text_search("apple motorola", :match => :any).size.should == 1
189
+ expect(Product.full_text_search('apple motorola', match: :any).size).to eq 1
175
190
  end
176
191
 
177
- it "should not return results when all words do not match, passing :match => :all to .full_text_search" do
178
- Product.full_text_search("apple motorola", :match => :all).size.should == 0
192
+ it 'should not return results when all words do not match, passing :match => :all to .full_text_search' do
193
+ expect(Product.full_text_search('apple motorola', match: :all).size).to eq 0
179
194
  end
180
195
 
181
- it "should return no results when a blank search is made" do
196
+ it 'should return no results when a blank search is made' do
182
197
  Mongoid::Search.allow_empty_search = false
183
- Product.full_text_search("").size.should == 0
198
+ expect(Product.full_text_search('').size).to eq 0
184
199
  end
185
200
 
186
- it "should return results when a blank search is made when :allow_empty_search is true" do
201
+ it 'should return results when a blank search is made when :allow_empty_search is true' do
187
202
  Mongoid::Search.allow_empty_search = true
188
- Product.full_text_search("").size.should == 1
203
+ expect(Product.full_text_search('').size).to eq 1
189
204
  end
190
205
 
191
- it "should search for embedded documents" do
192
- Product.full_text_search("craddle").size.should == 1
206
+ it 'should search for embedded documents' do
207
+ expect(Product.full_text_search('craddle').size).to eq 1
193
208
  end
194
209
 
195
- it "should search for reference documents" do
196
- Product.full_text_search("reviews").size.should == 1
210
+ it 'should search for reference documents' do
211
+ expect(Product.full_text_search('reviews').size).to eq 1
197
212
  end
198
213
 
199
214
  it 'should work in a chainable fashion' do
200
- @product.category.products.where(:brand => 'Apple').full_text_search('apple').size.should == 1
201
- @product.category.products.full_text_search('craddle').where(:brand => 'Apple').size.should == 1
215
+ expect(@product.category.products.where(brand: 'Apple').full_text_search('apple').size).to eq 1
216
+ expect(@product.category.products.full_text_search('craddle').where(brand: 'Apple').size).to eq 1
202
217
  end
203
218
 
204
219
  it 'should return the classes that include the search module' do
205
- Mongoid::Search.classes.should == [Product, Tag]
220
+ expect(Mongoid::Search.classes.sort_by(&:name)).to eq [Product, Tag]
206
221
  end
207
222
 
208
223
  it 'should have a method to index keywords' do
209
- @product.index_keywords!.should == true
224
+ expect(@product.index_keywords!).to include(true)
210
225
  end
211
226
 
212
227
  it 'should have a class method to index all documents keywords' do
213
- Product.index_keywords!.should_not include(false)
228
+ expect(Product.index_keywords!).not_to include(false)
214
229
  end
215
230
 
216
- context "when regex search is false" do
231
+ context 'when regex search is false' do
217
232
  before do
218
233
  Mongoid::Search.regex_search = false
219
234
  end
220
235
 
221
- it "should not return results in search with a partial word if not using regex search" do
222
- Product.full_text_search("iph").size.should == 0
236
+ it 'should not return results in search with a partial word if not using regex search' do
237
+ expect(Product.full_text_search('iph').size).to eq 0
223
238
  end
224
239
 
225
- it "should return results in search with a full word if not using regex search" do
226
- Product.full_text_search("iphone").size.should == 1
240
+ it 'should return results in search with a full word if not using regex search' do
241
+ expect(Product.full_text_search('iphone').size).to eq 1
227
242
  end
228
243
  end
229
244
 
230
- context "relevant search" do
245
+ context 'when regex search is true' do
246
+ before do
247
+ Mongoid::Search.regex_search = true
248
+ end
249
+
250
+ after do
251
+ Mongoid::Search.regex_search = false
252
+ end
253
+
254
+ it 'should not return results in search with a partial word if using regex search' do
255
+ expect(Product.full_text_search('iph').size).to eq 1
256
+ end
257
+
258
+ it 'should return results in search with a full word if using regex search' do
259
+ expect(Product.full_text_search('iphone').size).to eq 1
260
+ end
261
+
262
+ context 'when query include special characters that should not be stripped' do
263
+ before do
264
+ Mongoid::Search.strip_symbols = /[\n]/
265
+ Mongoid::Search.strip_accents = /[^\s\p{Graph}]/
266
+ end
267
+
268
+ after do
269
+ Mongoid::Search.strip_symbols = @default_strip_symbols
270
+ Mongoid::Search.strip_accents = @default_strip_accents
271
+ end
272
+
273
+ it 'should escape regex special characters' do
274
+ expect(Product.full_text_search('iphone (steve').size).to eq 1
275
+ end
276
+ end
277
+
278
+ context 'Match partial words on the beginning' do
279
+ before do
280
+ Mongoid::Search.regex = proc { |query| /^#{query}/ }
281
+ end
282
+
283
+ it 'should return results in search which starts with query string' do
284
+ expect(Product.full_text_search('iphone').size).to eq 1
285
+ end
286
+
287
+ it 'should not return results in search which does not start with query string' do
288
+ expect(Product.full_text_search('phone').size).to eq 0
289
+ end
290
+ end
291
+
292
+ context 'Match partial words on the end' do
293
+ before do
294
+ Mongoid::Search.regex = proc { |query| /#{query}$/ }
295
+ end
296
+
297
+ it 'should return results in search which ends with query string' do
298
+ expect(Product.full_text_search('phone').size).to eq 1
299
+ end
300
+
301
+ it 'should not return results in search which does not end with query string' do
302
+ expect(Product.full_text_search('phon').size).to eq 0
303
+ end
304
+ end
305
+ end
306
+
307
+ context 'relevant search' do
231
308
  before do
232
309
  Mongoid::Search.relevant_search = true
233
- @imac = Product.create :name => 'apple imac'
310
+ @imac = Product.create name: 'apple imac'
311
+ end
312
+
313
+ it 'should return results ordered by relevance and with correct ids' do
314
+ expect(Product.full_text_search('apple imac').map(&:_id)).to eq [@imac._id, @product._id]
234
315
  end
235
316
 
236
- it "should return results ordered by relevance and with correct ids" do
237
- Product.full_text_search('apple imac').map(&:_id).should == [@imac._id, @product._id]
317
+ it 'results should be recognized as persisted objects' do
318
+ expect(Product.full_text_search('apple imac').map(&:persisted?)).not_to include false
238
319
  end
239
320
 
240
- it "results should be recognized as persisted objects" do
241
- Product.full_text_search('apple imac').map(&:persisted?).should_not include false
321
+ it 'should include relevance information' do
322
+ expect(Product.full_text_search('apple imac').map(&:relevance)).to eq [2, 1]
242
323
  end
324
+ end
243
325
 
244
- it "should include relevance information" do
245
- Product.full_text_search('apple imac').map(&:relevance).should == [2, 1]
326
+ context 'when using methods for keywords' do
327
+ it 'should set the _keywords from methods' do
328
+ expect(@tags.first._keywords).to include 'amazing'
246
329
  end
247
330
  end
248
331
 
249
- context "when using methods for keywords" do
250
- it "should set the _keywords from methods" do
251
- @tags.first._keywords.should include "amazing"
332
+ context 'when using deeply nested fields for keywords' do
333
+ context 'when explicitly calling set_keywords' do
334
+ it 'should set the _keywords from parent' do
335
+ @tags.first.send(:set_keywords)
336
+ expect(@tags.first._keywords).to eq %w[amazing description info iphone mobile reviews summary]
337
+ end
252
338
  end
253
339
  end
254
340
 
255
- context "when using deeply nested fields for keywords" do
256
- context "when explicitly calling set_keywords" do
257
- it "should set the _keywords from parent" do
258
- @tags.first.send(:set_keywords)
259
- @tags.first._keywords.should == ["amazing", "description", "info", "iphone", "mobile", "reviews", "summary"]
260
- end
341
+ context 'when using localized fields' do
342
+ it 'should set the keywords from all localizations' do
343
+ @product = Product.create brand: 'Ford',
344
+ name: 'T 1908',
345
+ tags: %w[Amazing First Car].map { |tag| Tag.new(name: tag) },
346
+ category: Category.new(name_translations: { en: 'Vehicle', de: 'Fahrzeug' })
347
+ expect(@product._keywords).to include('fahrzeug')
261
348
  end
262
349
  end
263
350
 
264
- context "when using localized fields" do
265
- it "should set the keywords from all localizations" do
266
- @product = Product.create :brand => "Ford",
267
- :name => "T 1908",
268
- :tags => ["Amazing", "First", "Car"].map { |tag| Tag.new(:name => tag) },
269
- :category => Category.new(:name_translations => { :en => "Vehicle", :de => "Fahrzeug" })
270
- @product._keywords.should include("fahrzeug")
351
+ context 'minimum word size' do
352
+ before(:each) do
353
+ Mongoid::Search.minimum_word_size = 3
354
+ end
355
+
356
+ after(:each) do
357
+ Mongoid::Search.minimum_word_size = 2
358
+ end
359
+
360
+ it 'should ignore keywords with length less than minimum word size' do
361
+ @product = Product.create name: 'a'
362
+ expect(@product._keywords.size).to eq 0
363
+
364
+ @product = Product.create name: 'ap'
365
+ expect(@product._keywords.size).to eq 0
366
+
367
+ @product = Product.create name: 'app'
368
+ expect(@product._keywords.size).to eq 1
271
369
  end
272
370
  end
273
371
  end