mongoid_search 0.1.2 → 0.2.0
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/Gemfile +4 -2
- data/Gemfile.lock +30 -33
- data/README.md +31 -5
- data/Rakefile +6 -6
- data/VERSION +1 -1
- data/lib/mongoid_search.rb +1 -1
- data/lib/mongoid_search/mongoid_search.rb +80 -11
- data/lib/mongoid_search/util.rb +19 -0
- data/mongoid_search.gemspec +53 -33
- data/spec/config/ignorelist.yml +2 -0
- data/spec/models/category.rb +6 -0
- data/spec/models/product.rb +3 -1
- data/spec/models/subproduct.rb +8 -0
- data/spec/mongoid_search_spec.rb +64 -2
- data/spec/spec_helper.rb +4 -2
- data/spec/util_spec.rb +40 -0
- metadata +109 -19
- data/.gitignore +0 -22
- data/lib/mongoid_search/keywords_extractor.rb +0 -6
- data/spec/keywords_extractor_spec.rb +0 -28
- data/spec/spec.opts +0 -1
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,44 +1,39 @@
|
|
1
1
|
GEM
|
2
2
|
remote: http://rubygems.org/
|
3
3
|
specs:
|
4
|
-
activemodel (3.0.
|
5
|
-
activesupport (= 3.0.
|
4
|
+
activemodel (3.0.5)
|
5
|
+
activesupport (= 3.0.5)
|
6
6
|
builder (~> 2.1.2)
|
7
|
-
i18n (~> 0.4
|
8
|
-
activesupport (3.0.
|
9
|
-
bson (1.
|
7
|
+
i18n (~> 0.4)
|
8
|
+
activesupport (3.0.5)
|
9
|
+
bson (1.2.4)
|
10
10
|
builder (2.1.2)
|
11
|
-
database_cleaner (0.
|
11
|
+
database_cleaner (0.6.4)
|
12
12
|
diff-lcs (1.1.2)
|
13
|
-
|
13
|
+
fast-stemmer (1.0.0)
|
14
14
|
git (1.2.5)
|
15
|
-
i18n (0.
|
16
|
-
jeweler (1.
|
17
|
-
|
15
|
+
i18n (0.5.0)
|
16
|
+
jeweler (1.5.2)
|
17
|
+
bundler (~> 1.0.0)
|
18
18
|
git (>= 1.2.5)
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
bson (= 1.0.4)
|
26
|
-
mongo (= 1.0.7)
|
19
|
+
rake
|
20
|
+
mongo (1.2.4)
|
21
|
+
bson (>= 1.2.4)
|
22
|
+
mongoid (2.0.0.rc.7)
|
23
|
+
activemodel (~> 3.0)
|
24
|
+
mongo (~> 1.2)
|
27
25
|
tzinfo (~> 0.3.22)
|
28
26
|
will_paginate (~> 3.0.pre)
|
29
|
-
|
30
|
-
|
31
|
-
rspec-
|
32
|
-
rspec-
|
33
|
-
|
34
|
-
rspec-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
rubyforge (2.0.4)
|
40
|
-
json_pure (>= 1.1.7)
|
41
|
-
tzinfo (0.3.23)
|
27
|
+
rake (0.8.7)
|
28
|
+
rspec (2.3.0)
|
29
|
+
rspec-core (~> 2.3.0)
|
30
|
+
rspec-expectations (~> 2.3.0)
|
31
|
+
rspec-mocks (~> 2.3.0)
|
32
|
+
rspec-core (2.3.1)
|
33
|
+
rspec-expectations (2.3.0)
|
34
|
+
diff-lcs (~> 1.1.2)
|
35
|
+
rspec-mocks (2.3.0)
|
36
|
+
tzinfo (0.3.24)
|
42
37
|
will_paginate (3.0.pre2)
|
43
38
|
|
44
39
|
PLATFORMS
|
@@ -46,6 +41,8 @@ PLATFORMS
|
|
46
41
|
|
47
42
|
DEPENDENCIES
|
48
43
|
database_cleaner
|
44
|
+
fast-stemmer (= 1.0.0)
|
49
45
|
jeweler
|
50
|
-
mongoid (
|
51
|
-
|
46
|
+
mongoid (~> 2.0.0.beta.19)
|
47
|
+
rake (= 0.8.7)
|
48
|
+
rspec (= 2.3.0)
|
data/README.md
CHANGED
@@ -24,8 +24,9 @@ Examples
|
|
24
24
|
field :name
|
25
25
|
|
26
26
|
references_many :tags
|
27
|
+
refereced_in :category
|
27
28
|
|
28
|
-
search_in :brand, :name, :tags => :name
|
29
|
+
search_in :brand, :name, :tags => :name, :category => :name
|
29
30
|
end
|
30
31
|
|
31
32
|
class Tag
|
@@ -34,6 +35,13 @@ Examples
|
|
34
35
|
|
35
36
|
referenced_in :product
|
36
37
|
end
|
38
|
+
|
39
|
+
class Category
|
40
|
+
include Mongoid::Document
|
41
|
+
field :name
|
42
|
+
|
43
|
+
references_many :products
|
44
|
+
end
|
37
45
|
|
38
46
|
Now when you save a product, you get a _keywords field automatically:
|
39
47
|
|
@@ -58,10 +66,10 @@ Note that the search is case insensitive, and accept partial searching too:
|
|
58
66
|
Options
|
59
67
|
-------
|
60
68
|
|
61
|
-
|
62
|
-
:
|
63
|
-
:
|
64
|
-
Default is :
|
69
|
+
match:
|
70
|
+
_:any_ - match any occurrence
|
71
|
+
_:all_ - match all ocurrences
|
72
|
+
Default is _:any_.
|
65
73
|
|
66
74
|
search_in :brand, :name, { :tags => :name }, { :match => :any }
|
67
75
|
|
@@ -72,3 +80,21 @@ Options
|
|
72
80
|
|
73
81
|
Product.search("apple motorola").size
|
74
82
|
=> 0
|
83
|
+
|
84
|
+
allow_empty_search:
|
85
|
+
_true_ - match any occurrence
|
86
|
+
_false_ - match all ocurrences
|
87
|
+
Default is _false_.
|
88
|
+
|
89
|
+
search_in :brand, :name, { :tags => :name }, { :allow_empty_search => true }
|
90
|
+
|
91
|
+
Product.search("").size
|
92
|
+
=> 1
|
93
|
+
|
94
|
+
TODO
|
95
|
+
----
|
96
|
+
|
97
|
+
* Strip html with sanitize (https://github.com/rgrove/sanitize)
|
98
|
+
* Test relevant search
|
99
|
+
* Move all configurations to a configuration file. Maybe /config/mongoid_search.yml.
|
100
|
+
|
data/Rakefile
CHANGED
@@ -10,8 +10,8 @@ begin
|
|
10
10
|
gem.email = "mauricio@papodenerd.net"
|
11
11
|
gem.homepage = "http://www.papodenerd.net/mongoid-search-full-text-search-for-your-mongoid-models/"
|
12
12
|
gem.authors = ["Mauricio Zaffari"]
|
13
|
-
gem.add_dependency("mongoid", ["~> 2.0.0
|
14
|
-
gem.add_development_dependency "rspec", ">=
|
13
|
+
gem.add_dependency("mongoid", ["~> 2.0.0"])
|
14
|
+
gem.add_development_dependency "rspec", ">= 2.0.1"
|
15
15
|
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
16
16
|
end
|
17
17
|
Jeweler::GemcutterTasks.new
|
@@ -19,10 +19,10 @@ rescue LoadError
|
|
19
19
|
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
20
20
|
end
|
21
21
|
|
22
|
-
require '
|
23
|
-
|
24
|
-
spec.
|
25
|
-
spec.
|
22
|
+
require 'rspec/core/rake_task'
|
23
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
24
|
+
spec.rspec_opts = ["-c", "-f progress"]
|
25
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
26
26
|
end
|
27
27
|
|
28
28
|
task :default => :spec
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
data/lib/mongoid_search.rb
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
require 'mongoid_search/
|
1
|
+
require 'mongoid_search/util'
|
2
2
|
require 'mongoid_search/mongoid_search'
|
@@ -2,15 +2,19 @@ module Mongoid::Search
|
|
2
2
|
extend ActiveSupport::Concern
|
3
3
|
|
4
4
|
included do
|
5
|
-
cattr_accessor :search_fields, :match
|
5
|
+
cattr_accessor :search_fields, :match, :allow_empty_search, :relevant_search, :stem_keywords, :ignore_list
|
6
6
|
end
|
7
7
|
|
8
8
|
module ClassMethods #:nodoc:
|
9
9
|
# Set a field or a number of fields as sources for search
|
10
10
|
def search_in(*args)
|
11
|
-
options = args.last.is_a?(Hash) && (args.last.keys.first
|
12
|
-
self.match
|
13
|
-
self.
|
11
|
+
options = args.last.is_a?(Hash) && [:match, :allow_empty_search, :relevant_search, :stem_keywords, :ignore_list].include?(args.last.keys.first) ? args.pop : {}
|
12
|
+
self.match = [:any, :all].include?(options[:match]) ? options[:match] : :any
|
13
|
+
self.allow_empty_search = [true, false].include?(options[:allow_empty_search]) ? options[:allow_empty_search] : false
|
14
|
+
self.relevant_search = [true, false].include?(options[:relevant_search]) ? options[:allow_empty_search] : false
|
15
|
+
self.stem_keywords = [true, false].include?(options[:stem_keywords]) ? options[:allow_empty_search] : false
|
16
|
+
self.ignore_list = YAML.load(File.open(options[:ignore_list]))["ignorelist"] if options[:ignore_list].present?
|
17
|
+
self.search_fields = args
|
14
18
|
|
15
19
|
field :_keywords, :type => Array
|
16
20
|
index :_keywords
|
@@ -18,20 +22,85 @@ module Mongoid::Search
|
|
18
22
|
before_save :set_keywords
|
19
23
|
end
|
20
24
|
|
21
|
-
def search(query)
|
22
|
-
|
25
|
+
def search(query, options={})
|
26
|
+
if relevant_search
|
27
|
+
search_relevant(query, options)
|
28
|
+
else
|
29
|
+
search_without_relevance(query, options)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
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}/ })
|
36
|
+
end
|
37
|
+
|
38
|
+
def search_relevant(query, options={})
|
39
|
+
return self.all if query.blank? && allow_empty_search
|
40
|
+
|
41
|
+
keywords = Util.keywords(query, stem_keywords, ignore_list)
|
42
|
+
|
43
|
+
map = <<-EOS
|
44
|
+
function() {
|
45
|
+
var entries = 0
|
46
|
+
for(i in keywords)
|
47
|
+
for(j in this._keywords) {
|
48
|
+
if(this._keywords[j] == keywords[i])
|
49
|
+
entries++
|
50
|
+
}
|
51
|
+
if(entries > 0)
|
52
|
+
emit(this._id, entries)
|
53
|
+
}
|
54
|
+
EOS
|
55
|
+
reduce = <<-EOS
|
56
|
+
function(key, values) {
|
57
|
+
return(values[0])
|
58
|
+
}
|
59
|
+
EOS
|
60
|
+
|
61
|
+
#raise [self.class, self.inspect].inspect
|
62
|
+
|
63
|
+
kw_conditions = keywords.map do |kw|
|
64
|
+
{:_keywords => kw}
|
65
|
+
end
|
66
|
+
|
67
|
+
criteria = self.any_of(*kw_conditions)
|
68
|
+
|
69
|
+
query = criteria.selector
|
70
|
+
|
71
|
+
options.delete(:limit)
|
72
|
+
options.delete(:skip)
|
73
|
+
options.merge! :scope => {:keywords => keywords}, :query => query
|
74
|
+
|
75
|
+
res = collection.map_reduce(map, reduce, options)
|
76
|
+
|
77
|
+
res.find.sort(['value', -1]) # Cursor
|
23
78
|
end
|
24
79
|
end
|
25
80
|
|
26
81
|
private
|
27
|
-
|
82
|
+
|
83
|
+
# TODO: This need some refatoring..
|
28
84
|
def set_keywords
|
29
85
|
self._keywords = self.search_fields.map do |field|
|
30
86
|
if field.is_a?(Hash)
|
31
|
-
field.keys.map
|
87
|
+
field.keys.map do |key|
|
88
|
+
attribute = self.send(key)
|
89
|
+
method = field[key]
|
90
|
+
if attribute.is_a?(Array)
|
91
|
+
if method.is_a?(Array)
|
92
|
+
method.map {|m| attribute.map { |a| Util.keywords a.send(m), stem_keywords, ignore_list } }
|
93
|
+
else
|
94
|
+
attribute.map(&method).map { |t| Util.keywords t, stem_keywords, ignore_list }
|
95
|
+
end
|
96
|
+
else
|
97
|
+
Util.keywords(attribute.send(method), stem_keywords, ignore_list)
|
98
|
+
end
|
99
|
+
end
|
32
100
|
else
|
33
|
-
|
101
|
+
text = self[field]
|
102
|
+
Util.keywords(text, stem_keywords, ignore_list) unless text.nil?
|
34
103
|
end
|
35
|
-
end.flatten.compact.
|
104
|
+
end.flatten.compact.sort
|
36
105
|
end
|
37
|
-
end
|
106
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Util
|
2
|
+
|
3
|
+
def self.keywords(text, stem_keywords, ignore_list)
|
4
|
+
return [] if text.blank?
|
5
|
+
text = text.
|
6
|
+
mb_chars.
|
7
|
+
normalize(:kd).
|
8
|
+
to_s.
|
9
|
+
gsub(/[._:;'"`,?|+={}()!@#%^&*<>~\$\-\\\/\[\]]/, ' '). # strip punctuation
|
10
|
+
gsub(/[^[:alpha:]\s]/,''). # strip accents
|
11
|
+
downcase.
|
12
|
+
split(' ').
|
13
|
+
reject { |word| word.size < 2 }
|
14
|
+
text = text.reject { |word| ignore_list.include?(word) } unless ignore_list.blank?
|
15
|
+
text = text.map(&:stem) if stem_keywords
|
16
|
+
text
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
data/mongoid_search.gemspec
CHANGED
@@ -1,52 +1,54 @@
|
|
1
1
|
# Generated by jeweler
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{mongoid_search}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.2.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Mauricio Zaffari"]
|
12
|
-
s.date = %q{
|
12
|
+
s.date = %q{2011-03-28}
|
13
13
|
s.description = %q{Simple full text search implementation.}
|
14
14
|
s.email = %q{mauricio@papodenerd.net}
|
15
15
|
s.extra_rdoc_files = [
|
16
16
|
"LICENSE",
|
17
|
-
|
17
|
+
"README.md"
|
18
18
|
]
|
19
19
|
s.files = [
|
20
20
|
".document",
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
21
|
+
"Gemfile",
|
22
|
+
"Gemfile.lock",
|
23
|
+
"LICENSE",
|
24
|
+
"README.md",
|
25
|
+
"Rakefile",
|
26
|
+
"VERSION",
|
27
|
+
"lib/mongoid_search.rb",
|
28
|
+
"lib/mongoid_search/mongoid_search.rb",
|
29
|
+
"lib/mongoid_search/util.rb",
|
30
|
+
"mongoid_search.gemspec",
|
31
|
+
"spec/config/ignorelist.yml",
|
32
|
+
"spec/models/category.rb",
|
33
|
+
"spec/models/product.rb",
|
34
|
+
"spec/models/subproduct.rb",
|
35
|
+
"spec/models/tag.rb",
|
36
|
+
"spec/mongoid_search_spec.rb",
|
37
|
+
"spec/spec_helper.rb",
|
38
|
+
"spec/util_spec.rb"
|
38
39
|
]
|
39
40
|
s.homepage = %q{http://www.papodenerd.net/mongoid-search-full-text-search-for-your-mongoid-models/}
|
40
|
-
s.rdoc_options = ["--charset=UTF-8"]
|
41
41
|
s.require_paths = ["lib"]
|
42
42
|
s.rubygems_version = %q{1.3.7}
|
43
43
|
s.summary = %q{Search implementation for Mongoid ORM}
|
44
44
|
s.test_files = [
|
45
|
-
"spec/
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
45
|
+
"spec/models/category.rb",
|
46
|
+
"spec/models/product.rb",
|
47
|
+
"spec/models/subproduct.rb",
|
48
|
+
"spec/models/tag.rb",
|
49
|
+
"spec/mongoid_search_spec.rb",
|
50
|
+
"spec/spec_helper.rb",
|
51
|
+
"spec/util_spec.rb"
|
50
52
|
]
|
51
53
|
|
52
54
|
if s.respond_to? :specification_version then
|
@@ -54,15 +56,33 @@ Gem::Specification.new do |s|
|
|
54
56
|
s.specification_version = 3
|
55
57
|
|
56
58
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
57
|
-
s.add_runtime_dependency(%q<
|
58
|
-
s.
|
59
|
+
s.add_runtime_dependency(%q<jeweler>, [">= 0"])
|
60
|
+
s.add_runtime_dependency(%q<database_cleaner>, [">= 0"])
|
61
|
+
s.add_runtime_dependency(%q<mongoid>, ["~> 2.0.0.beta.19"])
|
62
|
+
s.add_runtime_dependency(%q<rake>, ["= 0.8.7"])
|
63
|
+
s.add_runtime_dependency(%q<rspec>, ["= 2.3.0"])
|
64
|
+
s.add_runtime_dependency(%q<fast-stemmer>, ["= 1.0.0"])
|
65
|
+
s.add_runtime_dependency(%q<mongoid>, ["~> 2.0.0"])
|
66
|
+
s.add_development_dependency(%q<rspec>, [">= 2.0.1"])
|
59
67
|
else
|
60
|
-
s.add_dependency(%q<
|
61
|
-
s.add_dependency(%q<
|
68
|
+
s.add_dependency(%q<jeweler>, [">= 0"])
|
69
|
+
s.add_dependency(%q<database_cleaner>, [">= 0"])
|
70
|
+
s.add_dependency(%q<mongoid>, ["~> 2.0.0.beta.19"])
|
71
|
+
s.add_dependency(%q<rake>, ["= 0.8.7"])
|
72
|
+
s.add_dependency(%q<rspec>, ["= 2.3.0"])
|
73
|
+
s.add_dependency(%q<fast-stemmer>, ["= 1.0.0"])
|
74
|
+
s.add_dependency(%q<mongoid>, ["~> 2.0.0"])
|
75
|
+
s.add_dependency(%q<rspec>, [">= 2.0.1"])
|
62
76
|
end
|
63
77
|
else
|
64
|
-
s.add_dependency(%q<
|
65
|
-
s.add_dependency(%q<
|
78
|
+
s.add_dependency(%q<jeweler>, [">= 0"])
|
79
|
+
s.add_dependency(%q<database_cleaner>, [">= 0"])
|
80
|
+
s.add_dependency(%q<mongoid>, ["~> 2.0.0.beta.19"])
|
81
|
+
s.add_dependency(%q<rake>, ["= 0.8.7"])
|
82
|
+
s.add_dependency(%q<rspec>, ["= 2.3.0"])
|
83
|
+
s.add_dependency(%q<fast-stemmer>, ["= 1.0.0"])
|
84
|
+
s.add_dependency(%q<mongoid>, ["~> 2.0.0"])
|
85
|
+
s.add_dependency(%q<rspec>, [">= 2.0.1"])
|
66
86
|
end
|
67
87
|
end
|
68
88
|
|
data/spec/models/product.rb
CHANGED
data/spec/mongoid_search_spec.rb
CHANGED
@@ -5,16 +5,56 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
|
5
5
|
describe Mongoid::Search do
|
6
6
|
|
7
7
|
before(:each) do
|
8
|
-
|
8
|
+
Product.stem_keywords = false
|
9
|
+
Product.ignore_list = nil
|
10
|
+
@product = Product.create :brand => "Apple",
|
11
|
+
:name => "iPhone",
|
12
|
+
:tags => ["Amazing", "Awesome", "Olé"].map { |tag| Tag.new(:name => tag) },
|
13
|
+
:category => Category.new(:name => "Mobile"),
|
14
|
+
:subproducts => [Subproduct.new(:brand => "Apple", :name => "Craddle")]
|
15
|
+
end
|
16
|
+
|
17
|
+
context "utf-8 characters" do
|
18
|
+
before(:each) {
|
19
|
+
Product.stem_keywords = false
|
20
|
+
Product.ignore_list = nil
|
21
|
+
@product = Product.create :brand => "Эльбрус",
|
22
|
+
:name => "Процессор",
|
23
|
+
:tags => ["Amazing", "Awesome", "Olé"].map { |tag| Tag.new(:name => tag) },
|
24
|
+
:category => Category.new(:name => "процессоры"),
|
25
|
+
:subproducts => []
|
26
|
+
}
|
27
|
+
|
28
|
+
it "should leave utf8 characters" do
|
29
|
+
@product._keywords.should == ["amazing", "awesome", "ole", "Процессор", "Эльбрус", "процессоры"]
|
30
|
+
end
|
9
31
|
end
|
10
32
|
|
11
33
|
it "should set the _keywords field" do
|
12
|
-
@product._keywords.should == ["
|
34
|
+
@product._keywords.should == ["amazing", "apple", "apple", "awesome", "craddle", "iphone", "mobile", "ole"]
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should set the _keywords field with stemmed words if stem is enabled" do
|
38
|
+
Product.stem_keywords = true
|
39
|
+
@product.save!
|
40
|
+
@product._keywords.should == ["amaz", "appl", "appl", "awesom", "craddl", "iphon", "mobil", "ol"]
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should ignore keywords in an ignore list" do
|
44
|
+
Product.ignore_list = YAML.load(File.open(File.dirname(__FILE__) + '/config/ignorelist.yml'))["ignorelist"]
|
45
|
+
@product.save!
|
46
|
+
@product._keywords.should == ["apple", "apple", "craddle", "iphone", "mobile", "ole"]
|
13
47
|
end
|
14
48
|
|
15
49
|
it "should return results in search" do
|
16
50
|
Product.search("apple").size.should == 1
|
17
51
|
end
|
52
|
+
|
53
|
+
it "should return results in search for dynamic attribute" do
|
54
|
+
@product[:outlet] = "online shop"
|
55
|
+
@product.save!
|
56
|
+
Product.search("online").size.should == 1
|
57
|
+
end
|
18
58
|
|
19
59
|
it "should return results in search even searching a accented word" do
|
20
60
|
Product.search("Ole").size.should == 1
|
@@ -37,4 +77,26 @@ describe Mongoid::Search do
|
|
37
77
|
Product.match = :all
|
38
78
|
Product.search("apple motorola").size.should == 0
|
39
79
|
end
|
80
|
+
|
81
|
+
it "should return results for any matching word, using :match => :all, passing :match => :any to .search" do
|
82
|
+
Product.match = :all
|
83
|
+
Product.search("apple motorola", :match => :any).size.should == 1
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should not return results when all words do not match, passing :match => :all to .search" do
|
87
|
+
Product.search("apple motorola", :match => :all).size.should == 0
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should return no results when a blank search is made" do
|
91
|
+
Product.search("").size.should == 0
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should return results when a blank search is made when :allow_empty_search is true" do
|
95
|
+
Product.allow_empty_search = true
|
96
|
+
Product.search("").size.should == 1
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should search for embedded documents" do
|
100
|
+
Product.search("craddle").size.should == 1
|
101
|
+
end
|
40
102
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -2,6 +2,8 @@ $LOAD_PATH.unshift(File.dirname(__FILE__))
|
|
2
2
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
3
3
|
require 'mongoid'
|
4
4
|
require 'database_cleaner'
|
5
|
+
require 'fast_stemmer'
|
6
|
+
require 'yaml'
|
5
7
|
require 'mongoid_search'
|
6
8
|
|
7
9
|
Mongoid.configure do |config|
|
@@ -11,9 +13,9 @@ end
|
|
11
13
|
|
12
14
|
Dir["#{File.dirname(__FILE__)}/models/*.rb"].each { |file| require file }
|
13
15
|
|
14
|
-
DatabaseCleaner.orm =
|
16
|
+
DatabaseCleaner.orm = :mongoid
|
15
17
|
|
16
|
-
|
18
|
+
RSpec.configure do |config|
|
17
19
|
config.before(:all) do
|
18
20
|
DatabaseCleaner.strategy = :truncation
|
19
21
|
end
|
data/spec/util_spec.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
3
|
+
|
4
|
+
describe Util do
|
5
|
+
it "should return an empty array if no text is passed" do
|
6
|
+
Util.keywords("", false, "").should == []
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should return an array of keywords" do
|
10
|
+
Util.keywords("keyword", false, "").class.should == Array
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should return an array of strings" do
|
14
|
+
Util.keywords("keyword", false, "").first.class.should == String
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should remove accents from the text passed" do
|
18
|
+
Util.keywords("café", false, "").should == ["cafe"]
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should downcase the text passed" do
|
22
|
+
Util.keywords("CaFé", false, "").should == ["cafe"]
|
23
|
+
end
|
24
|
+
|
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"]
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should stem keywords" do
|
30
|
+
Util.keywords("A runner running and eating", true, "").should == ["runner", "run", "and", "eat"]
|
31
|
+
end
|
32
|
+
|
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"]
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should ignore keywords with less than two words" do
|
38
|
+
Util.keywords("A runner running", false, "").should_not include "a"
|
39
|
+
end
|
40
|
+
end
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
- 1
|
8
7
|
- 2
|
9
|
-
|
8
|
+
- 0
|
9
|
+
version: 0.2.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Mauricio Zaffari
|
@@ -14,13 +14,38 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date:
|
17
|
+
date: 2011-03-28 00:00:00 -03:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
|
-
name:
|
22
|
-
prerelease: false
|
21
|
+
name: jeweler
|
23
22
|
requirement: &id001 !ruby/object:Gem::Requirement
|
23
|
+
none: false
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 0
|
29
|
+
version: "0"
|
30
|
+
type: :runtime
|
31
|
+
prerelease: false
|
32
|
+
version_requirements: *id001
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: database_cleaner
|
35
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
36
|
+
none: false
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
segments:
|
41
|
+
- 0
|
42
|
+
version: "0"
|
43
|
+
type: :runtime
|
44
|
+
prerelease: false
|
45
|
+
version_requirements: *id002
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: mongoid
|
48
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
24
49
|
none: false
|
25
50
|
requirements:
|
26
51
|
- - ~>
|
@@ -30,24 +55,86 @@ dependencies:
|
|
30
55
|
- 0
|
31
56
|
- 0
|
32
57
|
- beta
|
33
|
-
|
58
|
+
- 19
|
59
|
+
version: 2.0.0.beta.19
|
34
60
|
type: :runtime
|
35
|
-
|
61
|
+
prerelease: false
|
62
|
+
version_requirements: *id003
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: rake
|
65
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - "="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
segments:
|
71
|
+
- 0
|
72
|
+
- 8
|
73
|
+
- 7
|
74
|
+
version: 0.8.7
|
75
|
+
type: :runtime
|
76
|
+
prerelease: false
|
77
|
+
version_requirements: *id004
|
36
78
|
- !ruby/object:Gem::Dependency
|
37
79
|
name: rspec
|
80
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - "="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
segments:
|
86
|
+
- 2
|
87
|
+
- 3
|
88
|
+
- 0
|
89
|
+
version: 2.3.0
|
90
|
+
type: :runtime
|
38
91
|
prerelease: false
|
39
|
-
|
92
|
+
version_requirements: *id005
|
93
|
+
- !ruby/object:Gem::Dependency
|
94
|
+
name: fast-stemmer
|
95
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
40
96
|
none: false
|
41
97
|
requirements:
|
42
|
-
- - "
|
98
|
+
- - "="
|
43
99
|
- !ruby/object:Gem::Version
|
44
100
|
segments:
|
45
101
|
- 1
|
102
|
+
- 0
|
103
|
+
- 0
|
104
|
+
version: 1.0.0
|
105
|
+
type: :runtime
|
106
|
+
prerelease: false
|
107
|
+
version_requirements: *id006
|
108
|
+
- !ruby/object:Gem::Dependency
|
109
|
+
name: mongoid
|
110
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
111
|
+
none: false
|
112
|
+
requirements:
|
113
|
+
- - ~>
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
segments:
|
116
|
+
- 2
|
117
|
+
- 0
|
118
|
+
- 0
|
119
|
+
version: 2.0.0
|
120
|
+
type: :runtime
|
121
|
+
prerelease: false
|
122
|
+
version_requirements: *id007
|
123
|
+
- !ruby/object:Gem::Dependency
|
124
|
+
name: rspec
|
125
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
126
|
+
none: false
|
127
|
+
requirements:
|
128
|
+
- - ">="
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
segments:
|
46
131
|
- 2
|
47
|
-
-
|
48
|
-
|
132
|
+
- 0
|
133
|
+
- 1
|
134
|
+
version: 2.0.1
|
49
135
|
type: :development
|
50
|
-
|
136
|
+
prerelease: false
|
137
|
+
version_requirements: *id008
|
51
138
|
description: Simple full text search implementation.
|
52
139
|
email: mauricio@papodenerd.net
|
53
140
|
executables: []
|
@@ -59,7 +146,6 @@ extra_rdoc_files:
|
|
59
146
|
- README.md
|
60
147
|
files:
|
61
148
|
- .document
|
62
|
-
- .gitignore
|
63
149
|
- Gemfile
|
64
150
|
- Gemfile.lock
|
65
151
|
- LICENSE
|
@@ -67,22 +153,24 @@ files:
|
|
67
153
|
- Rakefile
|
68
154
|
- VERSION
|
69
155
|
- lib/mongoid_search.rb
|
70
|
-
- lib/mongoid_search/keywords_extractor.rb
|
71
156
|
- lib/mongoid_search/mongoid_search.rb
|
157
|
+
- lib/mongoid_search/util.rb
|
72
158
|
- mongoid_search.gemspec
|
73
|
-
- spec/
|
159
|
+
- spec/config/ignorelist.yml
|
160
|
+
- spec/models/category.rb
|
74
161
|
- spec/models/product.rb
|
162
|
+
- spec/models/subproduct.rb
|
75
163
|
- spec/models/tag.rb
|
76
164
|
- spec/mongoid_search_spec.rb
|
77
|
-
- spec/spec.opts
|
78
165
|
- spec/spec_helper.rb
|
166
|
+
- spec/util_spec.rb
|
79
167
|
has_rdoc: true
|
80
168
|
homepage: http://www.papodenerd.net/mongoid-search-full-text-search-for-your-mongoid-models/
|
81
169
|
licenses: []
|
82
170
|
|
83
171
|
post_install_message:
|
84
|
-
rdoc_options:
|
85
|
-
|
172
|
+
rdoc_options: []
|
173
|
+
|
86
174
|
require_paths:
|
87
175
|
- lib
|
88
176
|
required_ruby_version: !ruby/object:Gem::Requirement
|
@@ -109,8 +197,10 @@ signing_key:
|
|
109
197
|
specification_version: 3
|
110
198
|
summary: Search implementation for Mongoid ORM
|
111
199
|
test_files:
|
112
|
-
- spec/
|
200
|
+
- spec/models/category.rb
|
113
201
|
- spec/models/product.rb
|
202
|
+
- spec/models/subproduct.rb
|
114
203
|
- spec/models/tag.rb
|
115
204
|
- spec/mongoid_search_spec.rb
|
116
205
|
- spec/spec_helper.rb
|
206
|
+
- spec/util_spec.rb
|
data/.gitignore
DELETED
@@ -1,28 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
3
|
-
|
4
|
-
describe KeywordsExtractor do
|
5
|
-
it "should return if no text is passed" do
|
6
|
-
KeywordsExtractor.extract("").should == nil
|
7
|
-
end
|
8
|
-
|
9
|
-
it "should return an array of keywords" do
|
10
|
-
KeywordsExtractor.extract("keyword").class.should == Array
|
11
|
-
end
|
12
|
-
|
13
|
-
it "should return an array of strings" do
|
14
|
-
KeywordsExtractor.extract("keyword").first.class.should == String
|
15
|
-
end
|
16
|
-
|
17
|
-
it "should remove accents from the text passed" do
|
18
|
-
KeywordsExtractor.extract("café").should == ["cafe"]
|
19
|
-
end
|
20
|
-
|
21
|
-
it "should downcase the text passed" do
|
22
|
-
KeywordsExtractor.extract("CaFé").should == ["cafe"]
|
23
|
-
end
|
24
|
-
|
25
|
-
it "should split whitespaces, hifens, dots and underlines" do
|
26
|
-
KeywordsExtractor.extract("CaFé-express.com delicious").should == ["cafe", "express", "com", "delicious"]
|
27
|
-
end
|
28
|
-
end
|
data/spec/spec.opts
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
--color
|