mongoid_search 0.3.4 → 0.3.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 832d506c4a4b192adabbc3858899481804da533e
4
- data.tar.gz: ee2c35e2dc25e5de7cc7bb02c149260ff487ff04
3
+ metadata.gz: 790663a1de866f407ace368cc503cd724cf4ffc6
4
+ data.tar.gz: f95fc5e91b0eb1b12eb95a60bd9c57688ae12bb7
5
5
  SHA512:
6
- metadata.gz: 7f40a5e5437f1865b71bd929ff3c861c33f35197e5c561bfaff6d0ffd31671983c1c0c5699ccbe0f9fb9af7c3af253ff9b704f6b93c186be8c13168ea6dc03b4
7
- data.tar.gz: 63e5ee87ed079f03373951efc4cc6eb6accf13cf48ab4e8f53b76bcd689fb04bb097fbe2a2e66db6eccd71438db0876b4abd1f8e61608d23ff37aabc92a3eb8c
6
+ metadata.gz: ec1fd1b237c921939f66ca1b7a719f13a1275a19f42e86ef72f368ae7396b21c5fa6ab97e090a070ae656b45bccdaf6607e369a82754e9bfec828f2bca3a1c43
7
+ data.tar.gz: 3af9e42610b204de4a78e802bd3efaff38cabfa8a53a1f82b7af191cb9fe31e823e203f3087b606efe2d6fea38b0deb92b3751d2ab49674b410df06b1b40fb31
data/README.md CHANGED
@@ -1,177 +1,190 @@
1
- Mongoid Search
2
- ============
1
+ # Mongoid Search
3
2
 
4
- Mongoid Search is a simple full text search implementation for Mongoid ORM. It performs well for small data sets. If your searchable model is big (i.e. 1.000.000+ records), solr or sphinx may suit you better.
3
+ Mongoid Search is a simple full text search implementation for Mongoid ORM. It supports Mongoid 3, 4, 5 and 6 and performs well for small data sets. If your searchable model is big (i.e. 1.000.000+ records), [mongoid_fulltext](https://github.com/mongoid/mongoid_fulltext), ElasticSearch, Solr or Sphinx may suit you better.
5
4
 
6
- Installation
7
- --------
5
+ [![Build Status](https://travis-ci.org/mongoid/mongoid_search.svg?branch=master)](https://travis-ci.org/mongoid/mongoid_search)
8
6
 
9
- In your Gemfile:
10
-
11
- gem 'mongoid_search'
7
+ ## Installation
12
8
 
13
- If your project is still using mongoid 2.x.x, stick to mongoid_search 0.2.x:
9
+ In your Gemfile:
14
10
 
15
- gem 'mongoid_search', '~> 0.2.8'
11
+ ```ruby
12
+ gem 'mongoid_search'
13
+ ```
16
14
 
17
15
  Then:
18
16
 
19
- bundle install
17
+ ```
18
+ bundle install
19
+ ```
20
20
 
21
- Examples
22
- --------
21
+ ## Examples
23
22
 
24
- class Product
25
- include Mongoid::Document
26
- include Mongoid::Search
27
- field :brand
28
- field :name
29
- field :info, :type => Hash
23
+ ```ruby
24
+ class Product
25
+ include Mongoid::Document
26
+ include Mongoid::Search
27
+ field :brand
28
+ field :name
29
+ field :info, type: Hash
30
30
 
31
- has_many :tags
32
- belongs_to :category
31
+ has_many :tags
32
+ belongs_to :category
33
33
 
34
- search_in :brand, :name, :tags => :name, :category => :name, :info => [:summary, :description]
35
- end
34
+ search_in :brand, :name, tags: :name, category: :name, info: %i[summary description]
35
+ end
36
36
 
37
- class Tag
38
- include Mongoid::Document
39
- field :name
37
+ class Tag
38
+ include Mongoid::Document
39
+ field :name
40
40
 
41
- belongs_to :product
42
- end
41
+ belongs_to :product
42
+ end
43
43
 
44
- class Category
45
- include Mongoid::Document
46
- field :name
44
+ class Category
45
+ include Mongoid::Document
46
+ field :name
47
47
 
48
- has_many :products
49
- end
48
+ has_many :products
49
+ end
50
+ ```
50
51
 
51
- Now when you save a product, you get a _keywords field automatically:
52
+ Now when you save a product, you get a `_keywords` field automatically:
52
53
 
53
- p = Product.new :brand => "Apple", :name => "iPhone", :info => {:summary => "Info-summary", :description => "Info-description"}
54
- p.tags << Tag.new(:name => "Amazing")
55
- p.tags << Tag.new(:name => "Awesome")
56
- p.tags << Tag.new(:name => "Superb")
57
- p.save
58
- => true
59
- p._keywords
60
- => ["amazing", "apple", "awesome", "iphone", "superb", "Info-summary", "Info-description"]
54
+ ```ruby
55
+ p = Product.new brand: 'Apple', name: 'iPhone', info: { summary: 'Info-summary', description: 'Info-description' }
56
+ p.tags << Tag.new(name: 'Amazing')
57
+ p.tags << Tag.new(name: 'Awesome')
58
+ p.tags << Tag.new(name: 'Superb')
59
+ p.save
60
+ # => true
61
+ p._keywords
62
+ # => ["amazing", "apple", "awesome", "iphone", "superb", "Info-summary", "Info-description"]
63
+ ```
61
64
 
62
- Now you can run search, which will look in the _keywords field and return all matching results:
65
+ Now you can run search, which will look in the `_keywords` field and return all matching results:
63
66
 
64
- Product.full_text_search("apple iphone").size
65
- => 1
67
+ ```ruby
68
+ Product.full_text_search("apple iphone").size
69
+ # => 1
70
+ ```
66
71
 
67
72
  Note that the search is case insensitive, and accept partial searching too:
68
73
 
69
- Product.full_text_search("ipho").size
70
- => 1
74
+ ```ruby
75
+ Product.full_text_search('ipho').size
76
+ # => 1
77
+ ```
71
78
 
72
- Assuming you have a category with multiple products you can use the following
73
- code to search for 'iphone' in products cheaper than $499
79
+ Assuming you have a category with multiple products you can use the following code to search for 'iphone' in products cheaper than $499.
74
80
 
75
- @category.products.where(:price.lt => 499).full_text_search('iphone').asc(:price)
81
+ ```ruby
82
+ category.products.where(:price.lt => 499).full_text_search('iphone').asc(:price)
83
+ ```
76
84
 
77
85
  To index or reindex all existing records, run this rake task
78
86
 
79
- $ rake mongoid_search:index
80
-
81
- Options
82
- -------
83
-
84
- match:
85
-
86
- _:any_ - match any occurrence
87
+ ```
88
+ $ rake mongoid_search:index
89
+ ```
87
90
 
88
- _:all_ - match all ocurrences
91
+ ## Options
89
92
 
90
- Default is _:any_.
93
+ ### match
91
94
 
92
- Product.full_text_search("apple motorola", match: :any).size
93
- => 1
95
+ * `:any` - match any occurrence
96
+ * `:all` - match all occurrences
94
97
 
95
- Product.full_text_search("apple motorola", match: :all).size
96
- => 0
98
+ Default is `:any`.
97
99
 
98
- allow\_empty\_search:
100
+ ```ruby
101
+ Product.full_text_search('apple motorola', match: :any).size
102
+ # => 1
99
103
 
100
- _true_ - will return Model.all
104
+ Product.full_text_search('apple motorola', match: :all).size
105
+ # => 0
106
+ ```
101
107
 
102
- _false_ - will return []
108
+ ### allow\_empty\_search
103
109
 
104
- Default is _false_.
110
+ * `true` - will return `Model.all`
111
+ * `false` - will return `[]`
105
112
 
106
- Product.full_text_search("", allow_empty_search: true).size
107
- => 1
113
+ Default is `false`.
108
114
 
109
- relevant_search:
115
+ ```ruby
116
+ Product.full_text_search('', allow_empty_search: true).size
117
+ # => 1
118
+ ```
110
119
 
111
- _true_ - Adds relevance information to the results
120
+ ### relevant_search
112
121
 
113
- _false_ - No relevance information
122
+ * `true` - adds relevance information to the results
123
+ * `false` - no relevance information
114
124
 
115
- Default is _false_.
125
+ Default is `false`.
116
126
 
117
- Product.full_text_search('amazing apple', relevant_search: true)
118
- => [#<Product _id: 5016e7d16af54efe1c000001, _type: nil, brand: "Apple", name: "iPhone", attrs: nil, info: nil, category_id: nil, _keywords: ["amazing", "apple", "awesome", "iphone", "superb"], relevance: 2.0>]
127
+ ```ruby
128
+ Product.full_text_search('amazing apple', relevant_search: true)
129
+ # => [#<Product _id: 5016e7d16af54efe1c000001, _type: nil, brand: "Apple", name: "iPhone", attrs: nil, info: nil, category_id: nil, _keywords: ["amazing", "apple", "awesome", "iphone", "superb"], relevance: 2.0>]
130
+ ```
119
131
 
120
- Please note that relevant_search will return an Array and not a Criteria object. The search method should always be called in the end of the method chain.
132
+ Please note that relevant_search will return an Array and not a Criteria object. The search method should always be called in the end of the method chain.
121
133
 
122
- Initializer
123
- -----------
134
+ ## Initializer
124
135
 
125
136
  Alternatively, you can create an initializer to setup those options:
126
137
 
127
- Mongoid::Search.setup do |config|
128
- ## Default matching type. Match :any or :all searched keywords
129
- config.match = :any
138
+ ```ruby
139
+ Mongoid::Search.setup do |config|
140
+ ## Default matching type. Match :any or :all searched keywords
141
+ config.match = :any
130
142
 
131
- ## If true, an empty search will return all objects
132
- config.allow_empty_search = false
143
+ ## If true, an empty search will return all objects
144
+ config.allow_empty_search = false
133
145
 
134
- ## If true, will search with relevance information
135
- config.relevant_search = false
146
+ ## If true, will search with relevance information
147
+ config.relevant_search = false
136
148
 
137
- ## Stem keywords
138
- config.stem_keywords = false
149
+ ## Stem keywords
150
+ config.stem_keywords = false
139
151
 
140
- ## Add a custom proc returning strings to replace the default stemmer
141
- # For example using ruby-stemmer:
142
- # config.stem_proc = Proc.new { |word| Lingua.stemmer(word, :language => 'nl') }
152
+ ## Add a custom proc returning strings to replace the default stemmer
153
+ # For example using ruby-stemmer:
154
+ # config.stem_proc = Proc.new { |word| Lingua.stemmer(word, :language => 'nl') }
143
155
 
144
- ## Words to ignore
145
- config.ignore_list = []
156
+ ## Words to ignore
157
+ config.ignore_list = []
146
158
 
147
- ## An array of words
148
- # config.ignore_list = %w{ a an to from as }
159
+ ## An array of words
160
+ # config.ignore_list = %w{ a an to from as }
149
161
 
150
- ## Or from a file
151
- # config.ignore_list = YAML.load(File.open(File.dirname(__FILE__) + '/config/ignorelist.yml'))["ignorelist"]
162
+ ## Or from a file
163
+ # config.ignore_list = YAML.load(File.open(File.dirname(__FILE__) + '/config/ignorelist.yml'))["ignorelist"]
152
164
 
153
- ## Search using regex (slower)
154
- config.regex_search = true
165
+ ## Search using regex (slower)
166
+ config.regex_search = true
155
167
 
156
- ## Regex to search
168
+ ## Regex to search
157
169
 
158
- ## Match partial words on both sides (slower)
159
- config.regex = Proc.new { |query| /#{query}/ }
170
+ ## Match partial words on both sides (slower)
171
+ config.regex = Proc.new { |query| /#{query}/ }
160
172
 
161
- ## Match partial words on the beginning or in the end (slightly faster)
162
- # config.regex = Proc.new { |query| /^#{query}/ }
163
- # config.regex = Proc.new { |query| /#{query}$/ }
173
+ ## Match partial words on the beginning or in the end (slightly faster)
174
+ # config.regex = Proc.new { |query| /^#{query}/ }
175
+ # config.regex = Proc.new { |query| /#{query}$/ }
164
176
 
165
- # Ligatures to be replaced
166
- # http://en.wikipedia.org/wiki/Typographic_ligature
167
- config.ligatures = { "œ"=>"oe", "æ"=>"ae" }
177
+ # Ligatures to be replaced
178
+ # http://en.wikipedia.org/wiki/Typographic_ligature
179
+ config.ligatures = { "œ"=>"oe", "æ"=>"ae" }
168
180
 
169
- # Strip symbols regex to be replaced. These symbols will be replaced by space
170
- config.strip_symbols = /[._:;'\"`,?|+={}()!@#%^&*<>~\$\-\\\/\[\]]/
181
+ # Strip symbols regex to be replaced. These symbols will be replaced by space
182
+ config.strip_symbols = /[._:;'\"`,?|+={}()!@#%^&*<>~\$\-\\\/\[\]]/
171
183
 
172
- # Strip accents regex to be replaced. These sybols will be removed after strip_symbols replacing
173
- config.strip_accents = /[^\s\p{Alnum}]/
184
+ # Strip accents regex to be replaced. These sybols will be removed after strip_symbols replacing
185
+ config.strip_accents = /[^\s\p{Alnum}]/
174
186
 
175
- # Minimum word size. Words smaller than it won't be indexed
176
- config.minimum_word_size = 2
177
- end
187
+ # Minimum word size. Words smaller than it won't be indexed
188
+ config.minimum_word_size = 2
189
+ end
190
+ ```
data/Rakefile CHANGED
@@ -3,8 +3,11 @@ require 'rake'
3
3
 
4
4
  require 'rspec/core/rake_task'
5
5
  RSpec::Core::RakeTask.new(:spec) do |spec|
6
- spec.rspec_opts = ["-c", "-f progress"]
6
+ spec.rspec_opts = ['-c', '-f progress']
7
7
  spec.pattern = 'spec/**/*_spec.rb'
8
8
  end
9
9
 
10
- task :default => :spec
10
+ require 'rubocop/rake_task'
11
+ RuboCop::RakeTask.new(:rubocop)
12
+
13
+ task default: %i[rubocop spec]
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.4
1
+ 0.3.5
@@ -1,10 +1,6 @@
1
- # encoding: utf-8
2
-
3
1
  require 'mongoid_search/mongoid_search'
4
2
 
5
- if defined?(Rails)
6
- require 'mongoid_search/railtie'
7
- end
3
+ require 'mongoid_search/railtie' if defined?(Rails)
8
4
 
9
5
  module Mongoid::Search
10
6
  ## Default matching type. Match :any or :all searched keywords
@@ -25,7 +21,7 @@ module Mongoid::Search
25
21
 
26
22
  ## Stem procedure
27
23
  mattr_accessor :stem_proc
28
- @@stem_proc = Proc.new { |word| word.stem }
24
+ @@stem_proc = proc { |word| word.stem }
29
25
 
30
26
  ## Words to ignore
31
27
  mattr_accessor :ignore_list
@@ -45,7 +41,7 @@ module Mongoid::Search
45
41
  mattr_accessor :regex
46
42
 
47
43
  ## Match partial words on both sides (slower)
48
- @@regex = Proc.new { |query| /#{query}/ }
44
+ @@regex = proc { |query| /#{query}/ }
49
45
 
50
46
  ## Match partial words on the beginning or in the end (slightly faster)
51
47
  # @@regex = Proc.new { |query| /^#{query}/ }
@@ -54,7 +50,7 @@ module Mongoid::Search
54
50
  # Ligatures to be replaced
55
51
  # http://en.wikipedia.org/wiki/Typographic_ligature
56
52
  mattr_accessor :ligatures
57
- @@ligatures = { "œ"=>"oe", "æ"=>"ae" }
53
+ @@ligatures = { 'œ' => 'oe', 'æ' => 'ae' }
58
54
 
59
55
  # Minimum word size. Words smaller than it won't be indexed
60
56
  mattr_accessor :minimum_word_size
@@ -14,7 +14,8 @@ class Mongoid::Search::Log
14
14
  end
15
15
 
16
16
  private
17
+
17
18
  def self.colorize(text, code)
18
19
  "\033[#{code}m#{text}\033[0m"
19
20
  end
20
- end
21
+ end
@@ -15,16 +15,16 @@ module Mongoid::Search
15
15
  # Set a field or a number of fields as sources for search
16
16
  def search_in(*args)
17
17
  args, _options = args_and_options(args)
18
- self.search_fields = (self.search_fields || []).concat args
18
+ self.search_fields = (search_fields || []).concat args
19
19
 
20
- field :_keywords, :type => Array
20
+ field :_keywords, type: Array
21
21
 
22
- index({ :_keywords => 1 }, { :background => true })
22
+ index({ _keywords: 1 }, background: true)
23
23
 
24
24
  before_save :set_keywords
25
25
  end
26
26
 
27
- def full_text_search(query, options={})
27
+ def full_text_search(query, options = {})
28
28
  options = extract_options(options)
29
29
  attr_accessor :relevance if options[:relevant_search].eql? true
30
30
 
@@ -44,34 +44,37 @@ module Mongoid::Search
44
44
  # Goes through all documents in the class that includes Mongoid::Search
45
45
  # and indexes the keywords.
46
46
  def index_keywords!
47
- all.each { |d| d.index_keywords! ? Log.green(".") : Log.red("F") }
47
+ all.each { |d| d.index_keywords! ? Log.green('.') : Log.red('F') }
48
48
  end
49
49
 
50
50
  private
51
51
 
52
52
  def query(keywords, options)
53
53
  keywords_hash = keywords.map do |kw|
54
- kw = Mongoid::Search.regex.call(kw) if Mongoid::Search.regex_search
55
- { :_keywords => kw }
54
+ if Mongoid::Search.regex_search
55
+ escaped_kw = Regexp.escape(kw)
56
+ kw = Mongoid::Search.regex.call(escaped_kw)
57
+ end
58
+ { _keywords: kw }
56
59
  end
57
60
 
58
- criteria.send("#{(options[:match]).to_s}_of", *keywords_hash)
61
+ criteria.send("#{(options[:match])}_of", *keywords_hash)
59
62
  end
60
63
 
61
64
  def args_and_options(args)
62
65
  options = args.last.is_a?(Hash) &&
63
- [:match,
64
- :allow_empty_search,
65
- :relevant_search].include?(args.last.keys.first) ? args.pop : {}
66
+ %i[match
67
+ allow_empty_search
68
+ relevant_search].include?(args.last.keys.first) ? args.pop : {}
66
69
 
67
70
  [args, extract_options(options)]
68
71
  end
69
72
 
70
73
  def extract_options(options)
71
74
  {
72
- :match => options[:match] || Mongoid::Search.match,
73
- :allow_empty_search => options[:allow_empty_search] || Mongoid::Search.allow_empty_search,
74
- :relevant_search => options[:relevant_search] || Mongoid::Search.relevant_search
75
+ match: options[:match] || Mongoid::Search.match,
76
+ allow_empty_search: options[:allow_empty_search] || Mongoid::Search.allow_empty_search,
77
+ relevant_search: options[:relevant_search] || Mongoid::Search.relevant_search
75
78
  }
76
79
  end
77
80
 
@@ -81,20 +84,18 @@ module Mongoid::Search
81
84
 
82
85
  def search_relevant(query, options)
83
86
  results_with_relevance(query, options).sort { |o| o['value'] }.map do |r|
84
-
85
- new(r['_id'].merge(:relevance => r['value'])) do |o|
87
+ new(r['_id'].merge(relevance: r['value'])) do |o|
86
88
  # Need to match the actual object
87
89
  o.instance_variable_set('@new_record', false)
88
90
  o._id = r['_id']['_id']
89
91
  end
90
-
91
92
  end
92
93
  end
93
94
 
94
95
  def results_with_relevance(query, options)
95
96
  keywords = Mongoid::Search::Util.normalize_keywords(query)
96
97
 
97
- map = %Q{
98
+ map = %{
98
99
  function() {
99
100
  var entries = 0;
100
101
  for(i in keywords) {
@@ -110,13 +111,13 @@ module Mongoid::Search
110
111
  }
111
112
  }
112
113
 
113
- reduce = %Q{
114
+ reduce = %{
114
115
  function(key, values) {
115
116
  return(values);
116
117
  }
117
118
  }
118
119
 
119
- query(keywords, options).map_reduce(map, reduce).scope(:keywords => keywords).out(:inline => 1)
120
+ query(keywords, options).map_reduce(map, reduce).scope(keywords: keywords).out(inline: 1)
120
121
  end
121
122
  end
122
123
 
@@ -125,7 +126,7 @@ module Mongoid::Search
125
126
  end
126
127
 
127
128
  def set_keywords
128
- self._keywords = Mongoid::Search::Util.keywords(self, self.search_fields).
129
- flatten.reject{|k| k.nil? || k.empty?}.uniq.sort
129
+ self._keywords = Mongoid::Search::Util.keywords(self, search_fields)
130
+ .flatten.reject { |k| k.nil? || k.empty? }.uniq.sort
130
131
  end
131
132
  end