mongoid_search 0.2.6 → 0.2.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,20 @@
1
+ class Log
2
+ cattr_accessor :silent
3
+
4
+ def self.log(message)
5
+ print message unless silent
6
+ end
7
+
8
+ def self.red(text)
9
+ log(colorize(text, 31))
10
+ end
11
+
12
+ def self.green(text)
13
+ log(colorize(text, 32))
14
+ end
15
+
16
+ private
17
+ def self.colorize(text, code)
18
+ "\033[#{code}m#{text}\033[0m"
19
+ end
20
+ end
@@ -5,6 +5,15 @@ module Mongoid::Search
5
5
  cattr_accessor :search_fields, :match, :allow_empty_search, :relevant_search, :stem_keywords, :ignore_list
6
6
  end
7
7
 
8
+ def self.included(base)
9
+ @classes ||= []
10
+ @classes << base
11
+ end
12
+
13
+ def self.classes
14
+ @classes
15
+ end
16
+
8
17
  module ClassMethods #:nodoc:
9
18
  # Set a field or a number of fields as sources for search
10
19
  def search_in(*args)
@@ -17,7 +26,7 @@ module Mongoid::Search
17
26
  self.search_fields = (self.search_fields || []).concat args
18
27
 
19
28
  field :_keywords, :type => Array
20
- index :_keywords, background: true
29
+ index :_keywords, :background => true
21
30
 
22
31
  before_save :set_keywords
23
32
  end
@@ -29,22 +38,20 @@ module Mongoid::Search
29
38
  search_without_relevance(query, options)
30
39
  end
31
40
  end
32
-
41
+
33
42
  # Mongoid 2.0.0 introduces Criteria.seach so we need to provide
34
43
  # alternate method
35
44
  alias csearch search
36
45
 
37
46
  def search_without_relevance(query, options={})
38
47
  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}/ })
48
+ criteria.send("#{(options[:match]||self.match).to_s}_in", :_keywords => Util.normalize_keywords(query, stem_keywords, ignore_list).map { |q| /#{q}/ })
40
49
  end
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).
50
+
44
51
  def search_relevant(query, options={})
45
52
  return criteria.all if query.blank? && allow_empty_search
46
53
 
47
- keywords = Util.keywords(query, stem_keywords, ignore_list)
54
+ keywords = Util.normalize_keywords(query, stem_keywords, ignore_list)
48
55
 
49
56
  map = <<-EOS
50
57
  function() {
@@ -82,32 +89,25 @@ module Mongoid::Search
82
89
  # res.find.sort(['value', -1]) # Cursor
83
90
  collection.map_reduce(map, reduce, options)
84
91
  end
92
+
93
+ # Goes through all documents in the class that includes Mongoid::Search
94
+ # and indexes the keywords.
95
+ def index_keywords!
96
+ all.each { |d| d.index_keywords! ? Log.green(".") : Log.red("F") }
97
+ end
85
98
  end
86
99
 
87
- private
100
+ module InstanceMethods #:nodoc:
101
+ # Indexes the document keywords
102
+ def index_keywords!
103
+ update_attribute(:_keywords, set_keywords)
104
+ end
105
+ end
88
106
 
89
- # TODO: This need some refactoring..
107
+ private
90
108
  def set_keywords
91
109
  self._keywords = self.search_fields.map do |field|
92
- if field.is_a?(Hash)
93
- field.keys.map do |key|
94
- attribute = self.send(key)
95
- method = field[key]
96
- if attribute.is_a?(Array)
97
- if method.is_a?(Array)
98
- method.map {|m| attribute.map { |a| Util.keywords a.send(m), stem_keywords, ignore_list } }
99
- else
100
- attribute.map(&method).map { |t| Util.keywords t, stem_keywords, ignore_list }
101
- end
102
- else
103
- Util.keywords(attribute.send(method), stem_keywords, ignore_list)
104
- end
105
- end
106
- else
107
- value = self[field]
108
- value = value.join(' ') if value.respond_to?(:join)
109
- Util.keywords(value, stem_keywords, ignore_list) if value
110
- end
110
+ Util.keywords(self, field, stem_keywords, ignore_list)
111
111
  end.flatten.reject{|k| k.nil? || k.empty?}.uniq.sort
112
112
  end
113
113
  end
@@ -0,0 +1,10 @@
1
+ require 'mongoid_search'
2
+ require 'rails'
3
+
4
+ module Mongoid::Search
5
+ class Railtie < Rails::Railtie
6
+ rake_tasks do
7
+ Dir[File.join(File.dirname(__FILE__), '../../tasks/*.rake')].each { |f| load f }
8
+ end
9
+ end
10
+ end
@@ -1,13 +1,37 @@
1
1
  module Util
2
2
 
3
- def self.keywords(text, stem_keywords, ignore_list)
3
+ def self.keywords(klass, field, stem_keywords, ignore_list)
4
+ if field.is_a?(Hash)
5
+ field.keys.map do |key|
6
+ attribute = klass.send(key)
7
+ unless attribute.blank?
8
+ method = field[key]
9
+ if attribute.is_a?(Array)
10
+ if method.is_a?(Array)
11
+ method.map {|m| attribute.map { |a| Util.normalize_keywords a.send(m), stem_keywords, ignore_list } }
12
+ else
13
+ attribute.map(&method).map { |t| Util.normalize_keywords t, stem_keywords, ignore_list }
14
+ end
15
+ else
16
+ Util.normalize_keywords(attribute.send(method), stem_keywords, ignore_list)
17
+ end
18
+ end
19
+ end
20
+ else
21
+ value = klass[field]
22
+ value = value.join(' ') if value.respond_to?(:join)
23
+ Util.normalize_keywords(value, stem_keywords, ignore_list) if value
24
+ end
25
+ end
26
+
27
+ def self.normalize_keywords(text, stem_keywords, ignore_list)
4
28
  return [] if text.blank?
5
29
  text = text.to_s.
6
30
  mb_chars.
7
31
  normalize(:kd).
8
32
  to_s.
9
33
  gsub(/[._:;'"`,?|+={}()!@#%^&*<>~\$\-\\\/\[\]]/, ' '). # strip punctuation
10
- gsub(/[^[:alnum:]\s]/,''). # strip accents
34
+ gsub(/[^[:alnum:]\s]/,''). # strip accents
11
35
  downcase.
12
36
  split(' ').
13
37
  reject { |word| word.size < 2 }
@@ -1,2 +1,4 @@
1
+ require 'mongoid_search/railtie' if defined?(Rails)
1
2
  require 'mongoid_search/util'
3
+ require 'mongoid_search/log'
2
4
  require 'mongoid_search/mongoid_search'
@@ -30,12 +30,24 @@ describe Mongoid::Search do
30
30
  end
31
31
  end
32
32
 
33
+ context "when references are nil" do
34
+ context "when instance is being created" do
35
+ it "should not complain about method missing" do
36
+ lambda { Product.create! }.should_not raise_error
37
+ end
38
+ end
39
+
40
+ subject { Product.create :brand => "Apple", :name => "iPhone" }
41
+
42
+ its(:_keywords) { should == ["apple", "iphone"] }
43
+ end
44
+
33
45
  it "should set the _keywords field for array fields also" do
34
46
  @product.attrs = ['lightweight', 'plastic', :red]
35
47
  @product.save!
36
48
  @product._keywords.should include 'lightweight', 'plastic', 'red'
37
49
  end
38
-
50
+
39
51
  it "should inherit _keywords field and build upon" do
40
52
  variant = Variant.create :brand => "Apple",
41
53
  :name => "iPhone",
@@ -123,10 +135,23 @@ describe Mongoid::Search do
123
135
  it "should search for embedded documents" do
124
136
  Product.search("craddle").size.should == 1
125
137
  end
126
-
138
+
127
139
  it 'should work in a chainable fashion' do
128
140
  @product.category.products.where(:brand => 'Apple').csearch('apple').size.should == 1
129
141
  @product.category.products.csearch('craddle').where(:brand => 'Apple').size.should == 1
130
142
  end
143
+
144
+ it 'should return the classes that include the search module' do
145
+ Mongoid::Search.classes.should == [Product]
146
+ end
147
+
148
+ it 'should have a method to index keywords' do
149
+ @product.index_keywords!.should == true
150
+ end
151
+
152
+ it 'should have a class method to index all documents keywords' do
153
+ Product.index_keywords!.should_not include(false)
154
+ end
155
+
131
156
 
132
157
  end
data/spec/spec_helper.rb CHANGED
@@ -1,3 +1,6 @@
1
+ require 'simplecov'
2
+ SimpleCov.start
3
+
1
4
  $LOAD_PATH.unshift(File.dirname(__FILE__))
2
5
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
6
  require 'mongoid'
data/spec/util_spec.rb CHANGED
@@ -3,42 +3,42 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
3
3
 
4
4
  describe Util do
5
5
  it "should return an empty array if no text is passed" do
6
- Util.keywords("", false, "").should == []
6
+ Util.normalize_keywords("", false, "").should == []
7
7
  end
8
8
 
9
9
  it "should return an array of keywords" do
10
- Util.keywords("keyword", false, "").class.should == Array
10
+ Util.normalize_keywords("keyword", false, "").class.should == Array
11
11
  end
12
12
 
13
13
  it "should return an array of strings" do
14
- Util.keywords("keyword", false, "").first.class.should == String
14
+ Util.normalize_keywords("keyword", false, "").first.class.should == String
15
15
  end
16
16
 
17
17
  it "should remove accents from the text passed" do
18
- Util.keywords("café", false, "").should == ["cafe"]
18
+ Util.normalize_keywords("café", false, "").should == ["cafe"]
19
19
  end
20
20
 
21
21
  it "should downcase the text passed" do
22
- Util.keywords("CaFé", false, "").should == ["cafe"]
22
+ Util.normalize_keywords("CaFé", false, "").should == ["cafe"]
23
23
  end
24
24
 
25
25
  it "should split whitespaces, hifens, dots, underlines, etc.." do
26
- Util.keywords("CaFé-express.com delicious;come visit, and 'win' an \"iPad\"", false, "").should == ["cafe", "express", "com", "delicious", "come", "visit", "and", "win", "an", "ipad"]
26
+ Util.normalize_keywords("CaFé-express.com delicious;come visit, and 'win' an \"iPad\"", false, "").should == ["cafe", "express", "com", "delicious", "come", "visit", "and", "win", "an", "ipad"]
27
27
  end
28
28
 
29
29
  it "should stem keywords" do
30
- Util.keywords("A runner running and eating", true, "").should == ["runner", "run", "and", "eat"]
30
+ Util.normalize_keywords("A runner running and eating", true, "").should == ["runner", "run", "and", "eat"]
31
31
  end
32
32
 
33
33
  it "should ignore keywords from ignore list" do
34
- Util.keywords("An amazing awesome runner running and eating", true, YAML.load(File.open(File.dirname(__FILE__) + '/config/ignorelist.yml'))["ignorelist"]).should == ["an", "runner", "run", "and", "eat"]
34
+ Util.normalize_keywords("An amazing awesome runner running and eating", true, YAML.load(File.open(File.dirname(__FILE__) + '/config/ignorelist.yml'))["ignorelist"]).should == ["an", "runner", "run", "and", "eat"]
35
35
  end
36
36
 
37
37
  it "should ignore keywords with less than two words" do
38
- Util.keywords("A runner running", false, "").should_not include "a"
38
+ Util.normalize_keywords("A runner running", false, "").should_not include "a"
39
39
  end
40
40
 
41
41
  it "should not ignore numbers" do
42
- Util.keywords("Ford T 1908", false, "").should include "1908"
42
+ Util.normalize_keywords("Ford T 1908", false, "").should include "1908"
43
43
  end
44
44
  end
metadata CHANGED
@@ -1,132 +1,156 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: mongoid_search
3
- version: !ruby/object:Gem::Version
4
- version: 0.2.6
5
- prerelease:
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 2
8
+ - 7
9
+ version: 0.2.7
6
10
  platform: ruby
7
- authors:
11
+ authors:
8
12
  - Mauricio Zaffari
9
13
  autorequire:
10
14
  bindir: bin
11
15
  cert_chain: []
12
- date: 2011-05-31 00:00:00.000000000 -03:00
16
+
17
+ date: 2011-08-10 00:00:00 -03:00
13
18
  default_executable:
14
- dependencies:
15
- - !ruby/object:Gem::Dependency
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
16
21
  name: mongoid
17
- requirement: &2155959000 !ruby/object:Gem::Requirement
18
- none: false
19
- requirements:
20
- - - ~>
21
- - !ruby/object:Gem::Version
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 2
29
+ - 0
30
+ - 0
22
31
  version: 2.0.0
23
32
  type: :runtime
24
- prerelease: false
25
- version_requirements: *2155959000
26
- - !ruby/object:Gem::Dependency
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
27
35
  name: bson_ext
28
- requirement: &2155958360 !ruby/object:Gem::Requirement
29
- none: false
30
- requirements:
31
- - - ~>
32
- - !ruby/object:Gem::Version
33
- version: '1.2'
34
- type: :runtime
35
36
  prerelease: false
36
- version_requirements: *2155958360
37
- - !ruby/object:Gem::Dependency
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ segments:
42
+ - 1
43
+ - 2
44
+ version: "1.2"
45
+ type: :runtime
46
+ version_requirements: *id002
47
+ - !ruby/object:Gem::Dependency
38
48
  name: fast-stemmer
39
- requirement: &2155957680 !ruby/object:Gem::Requirement
40
- none: false
41
- requirements:
49
+ prerelease: false
50
+ requirement: &id003 !ruby/object:Gem::Requirement
51
+ requirements:
42
52
  - - ~>
43
- - !ruby/object:Gem::Version
53
+ - !ruby/object:Gem::Version
54
+ segments:
55
+ - 1
56
+ - 0
57
+ - 0
44
58
  version: 1.0.0
45
59
  type: :runtime
46
- prerelease: false
47
- version_requirements: *2155957680
48
- - !ruby/object:Gem::Dependency
60
+ version_requirements: *id003
61
+ - !ruby/object:Gem::Dependency
49
62
  name: database_cleaner
50
- requirement: &2155957100 !ruby/object:Gem::Requirement
51
- none: false
52
- requirements:
63
+ prerelease: false
64
+ requirement: &id004 !ruby/object:Gem::Requirement
65
+ requirements:
53
66
  - - ~>
54
- - !ruby/object:Gem::Version
67
+ - !ruby/object:Gem::Version
68
+ segments:
69
+ - 0
70
+ - 6
71
+ - 4
55
72
  version: 0.6.4
56
73
  type: :development
57
- prerelease: false
58
- version_requirements: *2155957100
59
- - !ruby/object:Gem::Dependency
74
+ version_requirements: *id004
75
+ - !ruby/object:Gem::Dependency
60
76
  name: rake
61
- requirement: &2155956180 !ruby/object:Gem::Requirement
62
- none: false
63
- requirements:
77
+ prerelease: false
78
+ requirement: &id005 !ruby/object:Gem::Requirement
79
+ requirements:
64
80
  - - ~>
65
- - !ruby/object:Gem::Version
81
+ - !ruby/object:Gem::Version
82
+ segments:
83
+ - 0
84
+ - 8
85
+ - 7
66
86
  version: 0.8.7
67
87
  type: :development
68
- prerelease: false
69
- version_requirements: *2155956180
70
- - !ruby/object:Gem::Dependency
88
+ version_requirements: *id005
89
+ - !ruby/object:Gem::Dependency
71
90
  name: rspec
72
- requirement: &2155955460 !ruby/object:Gem::Requirement
73
- none: false
74
- requirements:
91
+ prerelease: false
92
+ requirement: &id006 !ruby/object:Gem::Requirement
93
+ requirements:
75
94
  - - ~>
76
- - !ruby/object:Gem::Version
77
- version: '2.4'
95
+ - !ruby/object:Gem::Version
96
+ segments:
97
+ - 2
98
+ - 4
99
+ version: "2.4"
78
100
  type: :development
79
- prerelease: false
80
- version_requirements: *2155955460
101
+ version_requirements: *id006
81
102
  description: Simple full text search implementation.
82
- email:
103
+ email:
83
104
  - mauricio@papodenerd.net
84
105
  executables: []
106
+
85
107
  extensions: []
108
+
86
109
  extra_rdoc_files: []
87
- files:
110
+
111
+ files:
112
+ - lib/mongoid_search/log.rb
88
113
  - lib/mongoid_search/mongoid_search.rb
114
+ - lib/mongoid_search/railtie.rb
89
115
  - lib/mongoid_search/util.rb
90
116
  - lib/mongoid_search.rb
91
117
  - LICENSE
92
118
  - README.md
93
119
  - Rakefile
94
120
  - VERSION
95
- - spec/config/ignorelist.yml
96
- - spec/models/category.rb
97
- - spec/models/product.rb
98
- - spec/models/subproduct.rb
99
- - spec/models/tag.rb
100
- - spec/models/variant.rb
101
- - spec/mongoid_search_spec.rb
102
- - spec/spec_helper.rb
103
- - spec/util_spec.rb
104
121
  has_rdoc: true
105
122
  homepage: http://www.papodenerd.net/mongoid-search-full-text-search-for-your-mongoid-models/
106
123
  licenses: []
124
+
107
125
  post_install_message:
108
126
  rdoc_options: []
109
- require_paths:
127
+
128
+ require_paths:
110
129
  - lib
111
- required_ruby_version: !ruby/object:Gem::Requirement
112
- none: false
113
- requirements:
114
- - - ! '>='
115
- - !ruby/object:Gem::Version
116
- version: '0'
117
- required_rubygems_version: !ruby/object:Gem::Requirement
118
- none: false
119
- requirements:
120
- - - ! '>='
121
- - !ruby/object:Gem::Version
130
+ required_ruby_version: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ segments:
135
+ - 0
136
+ version: "0"
137
+ required_rubygems_version: !ruby/object:Gem::Requirement
138
+ requirements:
139
+ - - ">="
140
+ - !ruby/object:Gem::Version
141
+ segments:
142
+ - 1
143
+ - 3
144
+ - 6
122
145
  version: 1.3.6
123
146
  requirements: []
147
+
124
148
  rubyforge_project:
125
- rubygems_version: 1.6.2
149
+ rubygems_version: 1.3.6
126
150
  signing_key:
127
151
  specification_version: 3
128
152
  summary: Search implementation for Mongoid ORM
129
- test_files:
153
+ test_files:
130
154
  - spec/config/ignorelist.yml
131
155
  - spec/models/category.rb
132
156
  - spec/models/product.rb