mongoid_search 0.2.6 → 0.2.7
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/lib/mongoid_search/log.rb +20 -0
- data/lib/mongoid_search/mongoid_search.rb +28 -28
- data/lib/mongoid_search/railtie.rb +10 -0
- data/lib/mongoid_search/util.rb +26 -2
- data/lib/mongoid_search.rb +2 -0
- data/spec/mongoid_search_spec.rb +27 -2
- data/spec/spec_helper.rb +3 -0
- data/spec/util_spec.rb +10 -10
- metadata +102 -78
@@ -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
|
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.
|
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.
|
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
|
-
|
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
|
-
|
107
|
+
private
|
90
108
|
def set_keywords
|
91
109
|
self._keywords = self.search_fields.map do |field|
|
92
|
-
|
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
|
data/lib/mongoid_search/util.rb
CHANGED
@@ -1,13 +1,37 @@
|
|
1
1
|
module Util
|
2
2
|
|
3
|
-
def self.keywords(
|
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 }
|
data/lib/mongoid_search.rb
CHANGED
data/spec/mongoid_search_spec.rb
CHANGED
@@ -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
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.
|
6
|
+
Util.normalize_keywords("", false, "").should == []
|
7
7
|
end
|
8
8
|
|
9
9
|
it "should return an array of keywords" do
|
10
|
-
Util.
|
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.
|
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.
|
18
|
+
Util.normalize_keywords("café", false, "").should == ["cafe"]
|
19
19
|
end
|
20
20
|
|
21
21
|
it "should downcase the text passed" do
|
22
|
-
Util.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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
|
-
|
5
|
-
|
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
|
-
|
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
|
-
|
18
|
-
|
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
|
-
|
25
|
-
|
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
|
-
|
37
|
-
|
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
|
-
|
40
|
-
|
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
|
-
|
47
|
-
|
48
|
-
- !ruby/object:Gem::Dependency
|
60
|
+
version_requirements: *id003
|
61
|
+
- !ruby/object:Gem::Dependency
|
49
62
|
name: database_cleaner
|
50
|
-
|
51
|
-
|
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
|
-
|
58
|
-
|
59
|
-
- !ruby/object:Gem::Dependency
|
74
|
+
version_requirements: *id004
|
75
|
+
- !ruby/object:Gem::Dependency
|
60
76
|
name: rake
|
61
|
-
|
62
|
-
|
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
|
-
|
69
|
-
|
70
|
-
- !ruby/object:Gem::Dependency
|
88
|
+
version_requirements: *id005
|
89
|
+
- !ruby/object:Gem::Dependency
|
71
90
|
name: rspec
|
72
|
-
|
73
|
-
|
74
|
-
requirements:
|
91
|
+
prerelease: false
|
92
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
75
94
|
- - ~>
|
76
|
-
- !ruby/object:Gem::Version
|
77
|
-
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
segments:
|
97
|
+
- 2
|
98
|
+
- 4
|
99
|
+
version: "2.4"
|
78
100
|
type: :development
|
79
|
-
|
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
|
-
|
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
|
-
|
127
|
+
|
128
|
+
require_paths:
|
110
129
|
- lib
|
111
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
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
|
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
|