mongoid_search 0.2.3 → 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
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