mongoid_search 0.2.3 → 0.2.4

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
@@ -62,6 +62,15 @@ Note that the search is case insensitive, and accept partial searching too:
62
62
 
63
63
  Product.search("ipho").size
64
64
  => 1
65
+
66
+ Assuming you have a category with multiple products you can now use the following
67
+ code to search for 'iphone' in products cheaper than $499
68
+
69
+ @category.products.where(:price.lt => 499).asc(:price).csearch('iphone')
70
+
71
+ In this case we have to use csearch, an alias for search, because since v2.0.0
72
+ Mongoid defines it's own Criteria.search method.
73
+
65
74
 
66
75
  Options
67
76
  -------
@@ -90,11 +99,23 @@ allow_empty_search:
90
99
 
91
100
  Product.search("").size
92
101
  => 1
102
+
103
+ ignore_list:
104
+ Pass in an ignore list location. Keywords in that list will be ignored.
105
+
106
+ search_in :brand, :name, { :tags => :name }, { :ignore_list => Rails.root.join("config", "ignorelist.yml") }
107
+
108
+ The list should look like:
109
+
110
+ ignorelist:
111
+ a, an, to, from, as
112
+
113
+ You can include how many keywords you like.
93
114
 
94
115
  TODO
95
116
  ----
96
117
 
97
118
  * Strip html with sanitize (https://github.com/rgrove/sanitize)
98
- * Test relevant search
119
+ * Rewrite and test relevant search
99
120
  * Move all configurations to a configuration file. Maybe /config/mongoid_search.yml.
100
121
 
@@ -14,7 +14,7 @@ module Mongoid::Search
14
14
  self.relevant_search = [true, false].include?(options[:relevant_search]) ? options[:allow_empty_search] : false
15
15
  self.stem_keywords = [true, false].include?(options[:stem_keywords]) ? options[:allow_empty_search] : false
16
16
  self.ignore_list = YAML.load(File.open(options[:ignore_list]))["ignorelist"] if options[:ignore_list].present?
17
- self.search_fields = args
17
+ self.search_fields = (self.search_fields || []).concat args
18
18
 
19
19
  field :_keywords, :type => Array
20
20
  index :_keywords
@@ -29,14 +29,20 @@ module Mongoid::Search
29
29
  search_without_relevance(query, options)
30
30
  end
31
31
  end
32
+
33
+ # Mongoid 2.0.0 introduces Criteria.seach so we need to provide
34
+ # alternate method
35
+ alias csearch search
32
36
 
33
37
  def search_without_relevance(query, options={})
34
- return self.all if query.blank? && allow_empty_search
35
- self.send("#{(options[:match]||self.match).to_s}_in", :_keywords => Util.keywords(query, stem_keywords, ignore_list).map { |q| /#{q}/ })
38
+ return criteria.all if query.blank? && allow_empty_search
39
+ criteria.send("#{(options[:match]||self.match).to_s}_in", :_keywords => Util.keywords(query, stem_keywords, ignore_list).map { |q| /#{q}/ })
36
40
  end
37
-
41
+
42
+ # I know what this method should do, but I don't really know what it does.
43
+ # It was a pull from another fork, with no tests on it. Proably should be rewrited (and tested).
38
44
  def search_relevant(query, options={})
39
- return self.all if query.blank? && allow_empty_search
45
+ return criteria.all if query.blank? && allow_empty_search
40
46
 
41
47
  keywords = Util.keywords(query, stem_keywords, ignore_list)
42
48
 
@@ -64,7 +70,7 @@ module Mongoid::Search
64
70
  {:_keywords => kw}
65
71
  end
66
72
 
67
- criteria = self.any_of(*kw_conditions)
73
+ criteria = (criteria || self).any_of(*kw_conditions)
68
74
 
69
75
  query = criteria.selector
70
76
 
@@ -72,15 +78,15 @@ module Mongoid::Search
72
78
  options.delete(:skip)
73
79
  options.merge! :scope => {:keywords => keywords}, :query => query
74
80
 
75
- res = collection.map_reduce(map, reduce, options)
76
-
77
- res.find.sort(['value', -1]) # Cursor
81
+ # res = collection.map_reduce(map, reduce, options)
82
+ # res.find.sort(['value', -1]) # Cursor
83
+ collection.map_reduce(map, reduce, options)
78
84
  end
79
85
  end
80
86
 
81
87
  private
82
88
 
83
- # TODO: This need some refatoring..
89
+ # TODO: This need some refactoring..
84
90
  def set_keywords
85
91
  self._keywords = self.search_fields.map do |field|
86
92
  if field.is_a?(Hash)
@@ -98,9 +104,13 @@ module Mongoid::Search
98
104
  end
99
105
  end
100
106
  else
101
- text = self[field]
102
- Util.keywords(text, stem_keywords, ignore_list) unless text.nil?
107
+ value = self[field]
108
+ if value.is_a?(Array)
109
+ value.each {|v| Util.keywords(v, stem_keywords, ignore_list) if v}
110
+ else
111
+ Util.keywords(value, stem_keywords, ignore_list) if value
112
+ end
103
113
  end
104
- end.flatten.compact.sort
114
+ end.flatten.map(&:to_s).select{|f| not f.empty? }.uniq.sort
105
115
  end
106
116
  end
@@ -2,12 +2,12 @@ module Util
2
2
 
3
3
  def self.keywords(text, stem_keywords, ignore_list)
4
4
  return [] if text.blank?
5
- text = text.
5
+ text = text.to_s.
6
6
  mb_chars.
7
7
  normalize(:kd).
8
8
  to_s.
9
9
  gsub(/[._:;'"`,?|+={}()!@#%^&*<>~\$\-\\\/\[\]]/, ' '). # strip punctuation
10
- gsub(/[^[:alpha:]\s]/,''). # strip accents
10
+ gsub(/[^[:alnum:]\s]/,''). # strip accents
11
11
  downcase.
12
12
  split(' ').
13
13
  reject { |word| word.size < 2 }
@@ -3,10 +3,11 @@ class Product
3
3
  include Mongoid::Search
4
4
  field :brand
5
5
  field :name
6
+ field :attrs, :type => Array
6
7
 
7
8
  references_many :tags
8
9
  referenced_in :category
9
10
  embeds_many :subproducts
10
11
 
11
- search_in :brand, :name, :outlet, :tags => :name, :category => :name, :subproducts => [:brand, :name]
12
+ search_in :brand, :name, :outlet, :attrs, :tags => :name, :category => :name, :subproducts => [:brand, :name]
12
13
  end
@@ -0,0 +1,4 @@
1
+ class Variant < Product
2
+ field :color
3
+ search_in :color
4
+ end
@@ -31,21 +31,45 @@ describe Mongoid::Search do
31
31
  end
32
32
 
33
33
  it "should set the _keywords field" do
34
- @product._keywords.should == ["amazing", "apple", "apple", "awesome", "craddle", "iphone", "mobile", "ole"]
34
+ @product.attrs = ['lightweight', 'rugged', :red]
35
+ @product.save!
36
+ @product._keywords.should include "amazing", "apple", "awesome", "craddle", "iphone", "mobile", "ole", "lightweight", "rugged", "red"
37
+ end
38
+
39
+ it "should inherit _keywords field and build upon" do
40
+ variant = Variant.create :brand => "Apple",
41
+ :name => "iPhone",
42
+ :tags => ["Amazing", "Awesome", "Olé"].map { |tag| Tag.new(:name => tag) },
43
+ :category => Category.new(:name => "Mobile"),
44
+ :subproducts => [Subproduct.new(:brand => "Apple", :name => "Craddle")],
45
+ :color => :white
46
+ variant._keywords.should include "amazing", "apple", "awesome", "craddle", "iphone", "mobile", "ole", "white"
47
+ Variant.search(:name => 'Apple', :color => :white).size.should == 1
35
48
  end
36
49
 
37
50
  it "should set the _keywords field with stemmed words if stem is enabled" do
38
51
  Product.stem_keywords = true
39
52
  @product.save!
40
- @product._keywords.should == ["amaz", "appl", "appl", "awesom", "craddl", "iphon", "mobil", "ol"]
53
+ @product._keywords.should == ["amaz", "appl", "awesom", "craddl", "iphon", "mobil", "ol"]
41
54
  end
42
55
 
43
56
  it "should ignore keywords in an ignore list" do
44
57
  Product.ignore_list = YAML.load(File.open(File.dirname(__FILE__) + '/config/ignorelist.yml'))["ignorelist"]
45
58
  @product.save!
46
- @product._keywords.should == ["apple", "apple", "craddle", "iphone", "mobile", "ole"]
59
+ @product._keywords.should == ["apple", "craddle", "iphone", "mobile", "ole"]
47
60
  end
48
61
 
62
+ it "should incorporate numbers as keywords" do
63
+ @product = Product.create :brand => "Ford",
64
+ :name => "T 1908",
65
+ :tags => ["Amazing", "First", "Car"].map { |tag| Tag.new(:name => tag) },
66
+ :category => Category.new(:name => "Vehicle")
67
+
68
+ @product.save!
69
+ @product._keywords.should == ["1908","amazing", "car", "first", "ford", "vehicle"]
70
+ end
71
+
72
+
49
73
  it "should return results in search" do
50
74
  Product.search("apple").size.should == 1
51
75
  end
@@ -99,4 +123,10 @@ describe Mongoid::Search do
99
123
  it "should search for embedded documents" do
100
124
  Product.search("craddle").size.should == 1
101
125
  end
126
+
127
+ it 'should work in a chainable fashion' do
128
+ @product.category.products.where(:brand => 'Apple').csearch('apple').size.should == 1
129
+ @product.category.products.csearch('craddle').where(:brand => 'Apple').size.should == 1
130
+ end
131
+
102
132
  end
@@ -37,4 +37,8 @@ describe Util do
37
37
  it "should ignore keywords with less than two words" do
38
38
  Util.keywords("A runner running", false, "").should_not include "a"
39
39
  end
40
+
41
+ it "should not ignore numbers" do
42
+ Util.keywords("Ford T 1908", false, "").should include "1908"
43
+ end
40
44
  end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 2
8
- - 3
9
- version: 0.2.3
8
+ - 4
9
+ version: 0.2.4
10
10
  platform: ruby
11
11
  authors:
12
12
  - Mauricio Zaffari
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2011-04-07 00:00:00 -03:00
17
+ date: 2011-04-14 00:00:00 -03:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -127,6 +127,7 @@ files:
127
127
  - spec/models/product.rb
128
128
  - spec/models/subproduct.rb
129
129
  - spec/models/tag.rb
130
+ - spec/models/variant.rb
130
131
  - spec/mongoid_search_spec.rb
131
132
  - spec/spec_helper.rb
132
133
  - spec/util_spec.rb
@@ -170,6 +171,7 @@ test_files:
170
171
  - spec/models/product.rb
171
172
  - spec/models/subproduct.rb
172
173
  - spec/models/tag.rb
174
+ - spec/models/variant.rb
173
175
  - spec/mongoid_search_spec.rb
174
176
  - spec/spec_helper.rb
175
177
  - spec/util_spec.rb