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