scoped_search 3.3.0 → 4.0.0

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: 8d62827c492fb99894adbd0b01e0a1341c6744a5
4
- data.tar.gz: 2ee3ede28bcd6b96e12ca1a7629b7cbef38aee4d
3
+ metadata.gz: df5ac5265b984d6208df025b20dd336950d9bdbb
4
+ data.tar.gz: 3643c8835b43e6333e24d44473b1b29c3ec7ac91
5
5
  SHA512:
6
- metadata.gz: 9e26efdc791ad2fde5e975f44c8512a5089c4774f41f299e68f2c03fab3657323be4668e0668deb86f448dce2b02fe92b95d8d180cfff76b6f7dacd6e4bb01df
7
- data.tar.gz: 206daf327aa65a9de4b2ac8ed049620b4df5c4b71330b846413c9140d0f83aed95f612db37d9154d624d2f8c3a54a8d9fd785e41a76fa9e223b0b4e9b81a7497
6
+ metadata.gz: 7d760759a261eda13744cad755263a056213315859bc925e5ea814cd0e214e19941dc6b3e07572f80b0bf10058359d6895f663a9249b894fa53297c9f81a7efa
7
+ data.tar.gz: 4b9580f1b55aeaf6f74b64847318361d58f1e3a7477376b1db4921861ec95db3ba8594f7a6f5915f097fdd9313b2fb9bd30b26afc53c2199d3f367d8fa54c336
@@ -11,7 +11,6 @@ script:
11
11
  - bundle exec rake
12
12
 
13
13
  rvm:
14
- - "1.9"
15
14
  - "2.0"
16
15
  - "2.1"
17
16
  - "2.2.2"
@@ -21,9 +20,6 @@ rvm:
21
20
  - jruby-head
22
21
 
23
22
  gemfile:
24
- - Gemfile.activerecord32
25
- - Gemfile.activerecord40
26
- - Gemfile.activerecord41
27
23
  - Gemfile.activerecord42
28
24
  - Gemfile.activerecord50
29
25
 
@@ -33,11 +29,7 @@ matrix:
33
29
  - rvm: jruby-head
34
30
  - rvm: jruby-19mode
35
31
  exclude:
36
- - rvm: "1.9"
37
- gemfile: Gemfile.activerecord50
38
32
  - rvm: "2.0"
39
33
  gemfile: Gemfile.activerecord50
40
34
  - rvm: "2.1"
41
35
  gemfile: Gemfile.activerecord50
42
- - rvm: "2.3.1"
43
- gemfile: Gemfile.activerecord32
@@ -8,6 +8,26 @@ Please add an entry to the "Unreleased changes" section in your pull requests.
8
8
 
9
9
  *Nothing yet*
10
10
 
11
+ === Version 4.0.0
12
+
13
+ - Drop support for Ruby 1.9
14
+ - Drop support for ActiveRecord 3, 4.0, and 4.1
15
+ - `scoped_search` registration deprecates `:in` in favor of `:relation`, and
16
+ `:alias` in favor of `aliases: [..]` to avoid clash with Ruby reserved words.
17
+ - `sort` helper: any HTML options must now be given as a keyword argument,
18
+ instead of the third argument, i.e. `html_options: {..}`
19
+ - `sort` helper now takes hash of `url_options`, defaulting to an unfiltered
20
+ `params`. Call `params.permit(..)` and pass in the result to safely generate
21
+ URLs and prevent non-sanitized errors under Rails 5.
22
+ - Auto completion: remove autocomplete_* JavaScript helpers in favor of jQuery
23
+ method provided via asset pipeline. Call `$(..).scopedSearch` on autocomplete
24
+ text boxes to activate.
25
+ - Auto completion: escape quotes in listed values (#138)
26
+ - Add :validator option to definitions to validate user's search inputs
27
+ - Fix incorrect association conditions being used on through relations
28
+ - Use `#distinct` on Rails 4+
29
+ - Test Rails 5.0.x releases, test latest AR adapters
30
+
11
31
  === Version 3.3.0
12
32
 
13
33
  - Support for ActiveRecord 5.0
@@ -10,7 +10,7 @@ platforms :jruby do
10
10
  end
11
11
 
12
12
  platforms :ruby do
13
- gem 'sqlite3'
14
- gem 'mysql2', '~> 0.3.11'
15
- gem 'pg'
13
+ gem 'sqlite3', '~> 1.3.6'
14
+ gem 'mysql2', '>= 0.3.13', '< 0.5'
15
+ gem 'pg', '~> 0.15'
16
16
  end
@@ -1,7 +1,7 @@
1
1
  source 'https://rubygems.org'
2
2
  gemspec
3
3
 
4
- gem 'activerecord', '5.0.0.rc1'
4
+ gem 'activerecord', '~> 5.0.0'
5
5
 
6
6
  platforms :jruby do
7
7
  gem 'activerecord-jdbcsqlite3-adapter'
@@ -10,7 +10,7 @@ platforms :jruby do
10
10
  end
11
11
 
12
12
  platforms :ruby do
13
- gem 'sqlite3'
14
- gem 'mysql2', '~> 0.3.11'
15
- gem 'pg'
13
+ gem 'sqlite3', '~> 1.3.6'
14
+ gem 'mysql2', '>= 0.3.18', '< 0.5'
15
+ gem 'pg', '~> 0.18'
16
16
  end
@@ -22,6 +22,9 @@ Add the following line in your Gemfile, and run <tt>bundle install</tt>:
22
22
 
23
23
  gem "scoped_search"
24
24
 
25
+ Scoped search 4.x supports Rails 4.2 to 5.0, with Ruby 2.0.0 or higher. Use
26
+ previous versions, e.g. 3.x to support older versions of Rails or Ruby.
27
+
25
28
  == Usage
26
29
 
27
30
  Scoped search requires you to define the fields you want to search in:
@@ -65,6 +65,7 @@ require 'scoped_search/definition'
65
65
  require 'scoped_search/query_language'
66
66
  require 'scoped_search/query_builder'
67
67
  require 'scoped_search/auto_complete_builder'
68
+ require 'scoped_search/validators'
68
69
 
69
70
  # Import the search_on method in the ActiveReocrd::Base class
70
71
  ActiveRecord::Base.send(:extend, ScopedSearch::ClassMethods)
@@ -178,7 +178,7 @@ module ScopedSearch
178
178
  .where(value_conditions(field_name, val))
179
179
  .select(field_name)
180
180
  .limit(20)
181
- .uniq
181
+ .distinct
182
182
  .map(&field.key_field)
183
183
  .compact
184
184
  .map { |f| "#{name}.#{f} " }
@@ -205,10 +205,10 @@ module ScopedSearch
205
205
  .where(value_conditions(field.quoted_field, val))
206
206
  .select(field.quoted_field)
207
207
  .limit(20)
208
- .uniq
208
+ .distinct
209
209
  .map(&field.field)
210
210
  .compact
211
- .map { |v| v.to_s =~ /\s/ ? "\"#{v}\"" : v }
211
+ .map { |v| v.to_s =~ /\s/ ? "\"#{v.gsub('"', '\"')}\"" : v }
212
212
  end
213
213
 
214
214
  def completer_scope(field)
@@ -16,44 +16,76 @@ module ScopedSearch
16
16
  class Field
17
17
 
18
18
  attr_reader :definition, :field, :only_explicit, :relation, :key_relation, :full_text_search,
19
- :key_field, :complete_value, :complete_enabled, :offset, :word_size, :ext_method, :operators
19
+ :key_field, :complete_value, :complete_enabled, :offset, :word_size, :ext_method, :operators,
20
+ :validator
20
21
 
21
22
  # Initializes a Field instance given the definition passed to the
22
23
  # scoped_search call on the ActiveRecord-based model class.
23
- def initialize(definition, options = {})
24
- @definition = definition
25
- @definition.profile = options[:profile] if options[:profile]
26
- @definition.default_order ||= default_order(options)
27
-
28
- case options
29
- when Symbol, String
30
- @field = field.to_sym
31
- when Hash
32
- @field = options.delete(:on)
33
-
34
- # Set attributes from options hash
35
- @complete_value = options[:complete_value]
36
- @relation = options[:in]
37
- @key_relation = options[:in_key]
38
- @key_field = options[:on_key]
39
- @offset = options[:offset]
40
- @word_size = options[:word_size] || 1
41
- @ext_method = options[:ext_method]
42
- @operators = options[:operators]
43
- @only_explicit = !!options[:only_explicit]
44
- @full_text_search = options[:full_text_search]
45
- @default_operator = options[:default_operator] if options.has_key?(:default_operator)
46
- @complete_enabled = options[:complete_enabled].nil? ? true : options[:complete_enabled]
24
+ #
25
+ # Field name may be given in positional 'field' argument or 'on' named
26
+ # argument.
27
+ def initialize(definition,
28
+ field = nil,
29
+ aliases: [],
30
+ complete_enabled: true,
31
+ complete_value: nil,
32
+ default_operator: nil,
33
+ default_order: nil,
34
+ ext_method: nil,
35
+ full_text_search: nil,
36
+ in_key: nil,
37
+ offset: nil,
38
+ on: field,
39
+ on_key: nil,
40
+ only_explicit: nil,
41
+ operators: nil,
42
+ profile: nil,
43
+ relation: nil,
44
+ rename: nil,
45
+ validator: nil,
46
+ word_size: 1,
47
+ **kwargs)
48
+
49
+ # Prefer 'on' kw arg if given, defaults to the 'field' positional to allow either syntax
50
+ raise ArgumentError, "Missing field or 'on' keyword argument" if on.nil?
51
+ @field = on.to_sym
52
+
53
+ # Reserved Ruby keywords so access via kwargs instead, but deprecate them for future versions
54
+ if kwargs.key?(:in)
55
+ relation = kwargs.delete(:in)
56
+ ActiveSupport::Deprecation.warn("'in' argument deprecated, prefer 'relation' since scoped_search 4.0.0", caller(6))
47
57
  end
58
+ if kwargs.key?(:alias)
59
+ aliases += [kwargs.delete(:alias)]
60
+ ActiveSupport::Deprecation.warn("'alias' argument deprecated, prefer aliases: [..] since scoped_search 4.0.0", caller(6))
61
+ end
62
+ raise ArgumentError, "Unknown arguments to scoped_search: #{kwargs.keys.join(', ')}" unless kwargs.empty?
48
63
 
49
- # Store this field is the field array
50
- definition.fields[@field] ||= self unless options[:rename]
51
- definition.fields[options[:rename].to_sym] ||= self if options[:rename]
52
- definition.unique_fields << self
53
-
54
- # Store definition for alias / aliases as well
55
- definition.fields[options[:alias].to_sym] ||= self if options[:alias]
56
- options[:aliases].each { |al| definition.fields[al.to_sym] ||= self } if options[:aliases]
64
+ @definition = definition
65
+ @definition.profile = profile if profile
66
+ @definition.default_order ||= generate_default_order(default_order, rename || @field) if default_order
67
+
68
+ # Set attributes from keyword arguments
69
+ @complete_enabled = complete_enabled
70
+ @complete_value = complete_value
71
+ @default_operator = default_operator
72
+ @ext_method = ext_method
73
+ @full_text_search = full_text_search
74
+ @key_field = on_key
75
+ @key_relation = in_key
76
+ @offset = offset
77
+ @only_explicit = !!only_explicit
78
+ @operators = operators
79
+ @relation = relation
80
+ @validator = validator
81
+ @word_size = word_size
82
+
83
+ # Store this field in the field array
84
+ definition.fields[rename ? rename.to_sym : @field] ||= self
85
+ definition.unique_fields << self
86
+
87
+ # Store definition for aliases as well
88
+ aliases.each { |al| definition.fields[al.to_sym] ||= self }
57
89
  end
58
90
 
59
91
  # The ActiveRecord-based class that belongs to this field.
@@ -82,11 +114,7 @@ module ScopedSearch
82
114
  if klass.columns_hash.has_key?(field.to_s)
83
115
  klass.columns_hash[field.to_s]
84
116
  else
85
- if "#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}".to_f < 4.1
86
- raise ActiveRecord::UnknownAttributeError, "#{klass.inspect} doesn't have column #{field.inspect}."
87
- else
88
- raise ActiveRecord::UnknownAttributeError.new(klass, field)
89
- end
117
+ raise ActiveRecord::UnknownAttributeError.new(klass, field)
90
118
  end
91
119
  end
92
120
  end
@@ -135,11 +163,9 @@ module ScopedSearch
135
163
  end
136
164
  end
137
165
 
138
- def default_order(options)
139
- return nil if options[:default_order].nil?
140
- field_name = options[:rename].nil? ? options[:on] : options[:rename]
141
- order = (options[:default_order].to_s.downcase.include?('desc')) ? "DESC" : "ASC"
142
- return "#{field_name} #{order}"
166
+ def generate_default_order(default_order, field)
167
+ order = (default_order.to_s.downcase.include?('desc')) ? "DESC" : "ASC"
168
+ return "#{field} #{order}"
143
169
  end
144
170
 
145
171
  # Return 'table'.'column' with the correct database quotes
@@ -234,8 +260,8 @@ module ScopedSearch
234
260
  end
235
261
 
236
262
  # Defines a new search field for this search definition.
237
- def define(options)
238
- Field.new(self, options)
263
+ def define(*args)
264
+ Field.new(self, *args)
239
265
  end
240
266
 
241
267
  # Returns a reflection for a given klass and name
@@ -252,24 +278,13 @@ module ScopedSearch
252
278
  @klass.scope(:search_for, proc { |query, options|
253
279
  klass = definition.klass
254
280
 
255
- search_scope = case ActiveRecord::VERSION::MAJOR
256
- when 3
257
- klass.scoped
258
- when 4
259
- (ActiveRecord::VERSION::MINOR < 1) ? klass.where(nil) : klass.all
260
- when 5
261
- klass.all
262
- else
263
- raise ScopedSearch::DefinitionError, 'version ' \
264
- "#{ActiveRecord::VERSION::MAJOR} of activerecord is not supported"
265
- end
266
-
281
+ search_scope = klass.all
267
282
  find_options = ScopedSearch::QueryBuilder.build_query(definition, query || '', options || {})
268
283
  search_scope = search_scope.where(find_options[:conditions]) if find_options[:conditions]
269
284
  search_scope = search_scope.includes(find_options[:include]) if find_options[:include]
270
285
  search_scope = search_scope.joins(find_options[:joins]) if find_options[:joins]
271
286
  search_scope = search_scope.reorder(find_options[:order]) if find_options[:order]
272
- search_scope = search_scope.references(find_options[:include]) if find_options[:include] && ActiveRecord::VERSION::MAJOR >= 4
287
+ search_scope = search_scope.references(find_options[:include]) if find_options[:include]
273
288
 
274
289
  search_scope
275
290
  })
@@ -251,9 +251,9 @@ module ScopedSearch
251
251
 
252
252
  def find_has_many_through_association(field, through)
253
253
  middle_table_association = nil
254
- field.klass.reflect_on_all_associations(:has_many).each do |reflection|
254
+ field.klass.reflect_on_all_associations(:has_many).each do |reflection|
255
255
  class_name = reflection.options[:class_name].constantize.table_name if reflection.options[:class_name]
256
- middle_table_association = reflection.name if class_name == through.to_s
256
+ middle_table_association = reflection.name if class_name == through.to_s
257
257
  middle_table_association = reflection.plural_name if reflection.plural_name == through.to_s
258
258
  end
259
259
  middle_table_association
@@ -271,7 +271,7 @@ module ScopedSearch
271
271
 
272
272
  # primary and foreign keys + optional condition for the many to middle join
273
273
  pk1, fk1 = field.reflection_keys(definition.reflection_by_name(many_class, through))
274
- condition1 = field.reflection_conditions(definition.reflection_by_name(field.klass, many_table_name))
274
+ condition1 = field.reflection_conditions(definition.reflection_by_name(field.klass, middle_table_name))
275
275
 
276
276
  # primary and foreign keys + optional condition for the endpoint to middle join
277
277
  middle_table_association = find_has_many_through_association(field, through) || middle_table_name
@@ -468,6 +468,10 @@ module ScopedSearch
468
468
  # Search only on the given field.
469
469
  field = definition.field_by_name(lhs.value)
470
470
  raise ScopedSearch::QueryNotSupported, "Field '#{lhs.value}' not recognized for searching!" unless field
471
+
472
+ # see if the value passes user defined validation
473
+ validate_value(field, rhs.value)
474
+
471
475
  builder.sql_test(field, operator, rhs.value,lhs.value, &block)
472
476
  end
473
477
 
@@ -485,6 +489,16 @@ module ScopedSearch
485
489
  raise ScopedSearch::QueryNotSupported, "Don't know how to handle this operator node: #{operator.inspect} with #{children.inspect}!"
486
490
  end
487
491
  end
492
+
493
+ private
494
+
495
+ def validate_value(field, value)
496
+ validator = field.validator
497
+ if validator
498
+ valid = validator.call(value)
499
+ raise ScopedSearch::QueryNotSupported, "Value '#{value}' is not valid for field '#{field.field}'" unless valid
500
+ end
501
+ end
488
502
  end
489
503
 
490
504
  # Defines the to_sql method for AST AND/OR operators
@@ -4,20 +4,31 @@ module ScopedSearch
4
4
  #
5
5
  # Examples:
6
6
  #
7
- # sort @search, :by => :username
8
- # sort @search, :by => :created_at, :as => "Created"
9
- # sort @search, :by => :created_at, :default => "DESC"
7
+ # sort :username
8
+ # sort :created_at, as: "Created"
9
+ # sort :created_at, default: "DESC"
10
+ #
11
+ # * <tt>field</tt> - the name of the named scope. This helper will prepend this value with "ascend_by_" and "descend_by_"
10
12
  #
11
13
  # This helper accepts the following options:
12
14
  #
13
- # * <tt>:by</tt> - the name of the named scope. This helper will prepend this value with "ascend_by_" and "descend_by_"
14
- # * <tt>:as</tt> - the text used in the link, defaults to whatever is passed to :by
15
+ # * <tt>:as</tt> - the text used in the link, defaults to whatever is passed to `field`
15
16
  # * <tt>:default</tt> - default sorting order, DESC or ASC
16
- def sort(field, options = {}, html_options = {})
17
+ # * <tt>:html_options</tt> - is a hash of HTML options for the anchor tag
18
+ # * <tt>:url_options</tt> - is a hash of URL parameters, defaulting to `params`, to preserve the current URL
19
+ # parameters.
20
+ #
21
+ # On Rails 5 or higher, parameter whitelisting prevents any parameter being used in a link by
22
+ # default, so `params.permit(..)` should be passed for `url_options` for all known and
23
+ # permitted URL parameters, e.g.
24
+ #
25
+ # sort :username, url_options: params.permit(:search)
26
+ #
27
+ def sort(field, as: nil, default: "ASC", html_options: {}, url_options: params)
17
28
 
18
- unless options[:as]
19
- id = field.to_s.downcase == "id"
20
- options[:as] = id ? field.to_s.upcase : field.to_s.humanize
29
+ unless as
30
+ id = field.to_s.downcase == "id"
31
+ as = id ? field.to_s.upcase : field.to_s.humanize
21
32
  end
22
33
 
23
34
  ascend = "#{field} ASC"
@@ -30,151 +41,27 @@ module ScopedSearch
30
41
  when descend
31
42
  new_sort = ascend
32
43
  else
33
- new_sort = ["ASC", "DESC"].include?(options[:default]) ? "#{field} #{options[:default]}" : ascend
44
+ new_sort = ["ASC", "DESC"].include?(default) ? "#{field} #{default}" : ascend
34
45
  end
35
46
 
36
47
  unless selected_sort.nil?
37
48
  css_classes = html_options[:class] ? html_options[:class].split(" ") : []
38
49
  if selected_sort == ascend
39
- options[:as] = "&#9650;&nbsp;#{options[:as]}"
50
+ as = "&#9650;&nbsp;#{as}"
40
51
  css_classes << "ascending"
41
52
  else
42
- options[:as] = "&#9660;&nbsp;#{options[:as]}"
53
+ as = "&#9660;&nbsp;#{as}"
43
54
  css_classes << "descending"
44
55
  end
45
56
  html_options[:class] = css_classes.join(" ")
46
57
  end
47
58
 
48
- url_options = params.merge(:order => new_sort)
49
-
50
- options[:as] = raw(options[:as]) if defined?(RailsXss)
51
-
52
- a_link(options[:as], html_escape(url_for(url_options)),html_options)
53
- end
54
-
55
- # Adds AJAX auto complete functionality to the text input field with the
56
- # DOM ID specified by +field_id+.
57
- #
58
- # Required +options+ is:
59
- # <tt>:url</tt>:: URL to call for auto completion results
60
- # in url_for format.
61
- #
62
- # Additional +options+ are:
63
- # <tt>:update</tt>:: Specifies the DOM ID of the element whose
64
- # innerHTML should be updated with the auto complete
65
- # entries returned by the AJAX request.
66
- # Defaults to <tt>field_id</tt> + '_auto_complete'
67
- # <tt>:with</tt>:: A JavaScript expression specifying the
68
- # parameters for the XMLHttpRequest. This defaults
69
- # to 'fieldname=value'.
70
- # <tt>:frequency</tt>:: Determines the time to wait after the last keystroke
71
- # for the AJAX request to be initiated.
72
- # <tt>:indicator</tt>:: Specifies the DOM ID of an element which will be
73
- # displayed while auto complete is running.
74
- # <tt>:tokens</tt>:: A string or an array of strings containing
75
- # separator tokens for tokenized incremental
76
- # auto completion. Example: <tt>:tokens => ','</tt> would
77
- # allow multiple auto completion entries, separated
78
- # by commas.
79
- # <tt>:min_chars</tt>:: The minimum number of characters that should be
80
- # in the input field before an Ajax call is made
81
- # to the server.
82
- # <tt>:on_hide</tt>:: A Javascript expression that is called when the
83
- # auto completion div is hidden. The expression
84
- # should take two variables: element and update.
85
- # Element is a DOM element for the field, update
86
- # is a DOM element for the div from which the
87
- # innerHTML is replaced.
88
- # <tt>:on_show</tt>:: Like on_hide, only now the expression is called
89
- # then the div is shown.
90
- # <tt>:after_update_element</tt>:: A Javascript expression that is called when the
91
- # user has selected one of the proposed values.
92
- # The expression should take two variables: element and value.
93
- # Element is a DOM element for the field, value
94
- # is the value selected by the user.
95
- # <tt>:select</tt>:: Pick the class of the element from which the value for
96
- # insertion should be extracted. If this is not specified,
97
- # the entire element is used.
98
- # <tt>:method</tt>:: Specifies the HTTP verb to use when the auto completion
99
- # request is made. Defaults to POST.
100
- def auto_complete_field(field_id, options = {})
101
- function = "var #{field_id}_auto_completer = new Ajax.Autocompleter("
102
- function << "'#{field_id}', "
103
- function << "'" + (options[:update] || "#{field_id}_auto_complete") + "', "
104
- function << "'#{url_for(options[:url])}'"
105
-
106
- js_options = {}
107
- js_options[:tokens] = array_or_string_for_javascript(options[:tokens]) if options[:tokens]
108
- js_options[:callback] = "function(element, value) { return #{options[:with]} }" if options[:with]
109
- js_options[:indicator] = "'#{options[:indicator]}'" if options[:indicator]
110
- js_options[:select] = "'#{options[:select]}'" if options[:select]
111
- js_options[:paramName] = "'#{options[:param_name]}'" if options[:param_name]
112
- js_options[:frequency] = "#{options[:frequency]}" if options[:frequency]
113
- js_options[:method] = "'#{options[:method].to_s}'" if options[:method]
114
-
115
- { :after_update_element => :afterUpdateElement,
116
- :on_show => :onShow, :on_hide => :onHide, :min_chars => :minChars }.each do |k,v|
117
- js_options[v] = options[k] if options[k]
118
- end
59
+ url_options = url_options.to_h if url_options.respond_to?(:permit) # convert ActionController::Parameters if given
60
+ url_options = url_options.merge(:order => new_sort)
119
61
 
120
- function << (', ' + options_for_javascript(js_options) + ')')
62
+ as = raw(as) if defined?(RailsXss)
121
63
 
122
- javascript_tag(function)
123
- end
124
-
125
- def auto_complete_field_jquery(method, url, options = {})
126
- function = <<-JAVASCRIPT
127
- $.widget( "custom.catcomplete", $.ui.autocomplete, {
128
- _renderMenu: function( ul, items ) {
129
- var self = this,
130
- currentCategory = "";
131
- $.each( items, function( index, item ) {
132
- if ( item.category != undefined && item.category != currentCategory ) {
133
- ul.append( "<li class='ui-autocomplete-category'>" + item.category + "</li>" );
134
- currentCategory = item.category;
135
- }
136
- if ( item.error != undefined ) {
137
- ul.append( "<li class='ui-autocomplete-error'>" + item.error + "</li>" );
138
- }
139
- if( item.completed != undefined ) {
140
- $( "<li></li>" ).data( "item.autocomplete", item )
141
- .append( "<a>" + "<strong class='ui-autocomplete-completed'>" + item.completed + "</strong>" + item.part + "</a>" )
142
- .appendTo( ul );
143
- } else {
144
- if(typeof(self._renderItemData) === "function") {
145
- self._renderItemData( ul, item );
146
- } else {
147
- self._renderItem( ul, item );
148
- }
149
- }
150
- });
151
- }
152
- });
153
-
154
- $("##{method}")
155
- .catcomplete({
156
- source: function( request, response ) { $.getJSON( "#{url}", { #{method}: request.term }, response ); },
157
- minLength: #{options[:min_length] || 0},
158
- delay: #{options[:delay] || 200},
159
- select: function(event, ui) { $( this ).catcomplete( "search" , ui.item.value); },
160
- search: function(event, ui) { $(".auto_complete_clear").hide(); },
161
- open: function(event, ui) { $(".auto_complete_clear").show(); }
162
- });
163
-
164
- $("##{method}").bind( "focus", function( event ) {
165
- if( $( this )[0].value == "" ) {
166
- $( this ).catcomplete( "search" );
167
- }
168
- });
169
-
170
- JAVASCRIPT
171
-
172
- javascript_tag(function)
173
- end
174
-
175
- def auto_complete_clear_value_button(field_id)
176
- html_options = {:tabindex => '-1',:class=>"auto_complete_clear",:title =>'Clear Search', :onclick=>"document.getElementById('#{field_id}').value = '';"}
177
- a_link("", "#", html_options)
64
+ a_link(as, html_escape(url_for(url_options)),html_options)
178
65
  end
179
66
 
180
67
  def a_link(name, href, html_options)
@@ -182,41 +69,5 @@ module ScopedSearch
182
69
  link = "<a href=\"#{href}\"#{tag_options}>#{name}</a>"
183
70
  return link.respond_to?(:html_safe) ? link.html_safe : link
184
71
  end
185
-
186
- # Use this method in your view to generate a return for the AJAX auto complete requests.
187
- #
188
- # The auto_complete_result can of course also be called from a view belonging to the
189
- # auto_complete action if you need to decorate it further.
190
- def auto_complete_result(entries, phrase = nil)
191
- return unless entries
192
- items = entries.map { |entry| content_tag("li", phrase ? highlight(entry, phrase) : h(entry)) }
193
- content_tag("ul", items)
194
- end
195
-
196
- # Wrapper for text_field with added AJAX auto completion functionality.
197
- #
198
- # In your controller, you'll need to define an action called
199
- # auto_complete_method to respond the AJAX calls,
200
- def auto_complete_field_tag(method, val,tag_options = {}, completion_options = {})
201
- auto_completer_options = { :url => { :action => "auto_complete_#{method}" } }.update(completion_options)
202
- options = tag_options.merge(:class => "auto_complete_input " << tag_options[:class].to_s)
203
- text_field_tag(method, val,options) +
204
- auto_complete_clear_value_button(method) +
205
- content_tag("div", "", :id => "#{method}_auto_complete", :class => "auto_complete") +
206
- auto_complete_field(method, auto_completer_options)
207
- end
208
-
209
- # Wrapper for text_field with added JQuery auto completion functionality.
210
- #
211
- # In your controller, you'll need to define an action called
212
- # auto_complete_method to respond the JQuery calls,
213
- def auto_complete_field_tag_jquery(method, val,tag_options = {}, completion_options = {})
214
- url = url_for(:action => "auto_complete_#{method}", :filter => completion_options[:filter])
215
- options = tag_options.merge(:class => "auto_complete_input " << tag_options[:class].to_s)
216
- text_field_tag(method, val, options) + auto_complete_clear_value_button(method) +
217
- auto_complete_field_jquery(method, url, completion_options)
218
- end
219
- deprecate :auto_complete_field_tag_jquery, :auto_complete_field_tag, :auto_complete_result
220
-
221
72
  end
222
73
  end
@@ -0,0 +1,7 @@
1
+ module ScopedSearch
2
+ # This class will be used to store standard validators.
3
+ class Validators
4
+ NUMERIC = ->(value) { !!(value =~ ScopedSearch::Definition::NUMERICAL_REGXP) }
5
+ INTEGER = ->(value) { !!(value =~ ScopedSearch::Definition::INTEGER_REGXP) }
6
+ end
7
+ end
@@ -1,3 +1,3 @@
1
1
  module ScopedSearch
2
- VERSION = "3.3.0"
2
+ VERSION = "4.0.0"
3
3
  end
@@ -29,8 +29,8 @@ Gem::Specification.new do |gem|
29
29
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
30
30
  gem.require_paths = ["lib"]
31
31
 
32
- gem.required_ruby_version = '>= 1.9.3'
33
- gem.add_runtime_dependency('activerecord', '>= 3.2.0')
32
+ gem.required_ruby_version = '>= 2.0.0'
33
+ gem.add_runtime_dependency('activerecord', '>= 4.2.0')
34
34
  gem.add_development_dependency('rspec', '~> 3.0')
35
35
  gem.add_development_dependency('rake')
36
36
 
@@ -37,20 +37,20 @@ ScopedSearch::RSpec::Database.test_databases.each do |db|
37
37
 
38
38
  scoped_search :on => [:string, :date]
39
39
  scoped_search :on => [:int], :complete_value => true
40
- scoped_search :on => :another, :default_operator => :eq, :alias => :alias
40
+ scoped_search :on => :another, :default_operator => :eq, :aliases => [:alias], :complete_value => true
41
41
  scoped_search :on => :explicit, :only_explicit => true, :complete_value => true
42
42
  scoped_search :on => :deprecated, :complete_enabled => false
43
- scoped_search :on => :related, :in => :bars, :rename => 'bars.related'.to_sym
44
- scoped_search :on => :other_a, :in => :bars, :rename => 'bars.other_a'.to_sym
45
- scoped_search :on => :other_b, :in => :bars, :rename => 'bars.other_b'.to_sym
46
- scoped_search :on => :other_c, :in => :bars, :rename => 'bars.other_c'.to_sym
43
+ scoped_search :on => :related, :relation => :bars, :rename => 'bars.related'.to_sym
44
+ scoped_search :on => :other_a, :relation => :bars, :rename => 'bars.other_a'.to_sym
45
+ scoped_search :on => :other_b, :relation => :bars, :rename => 'bars.other_b'.to_sym
46
+ scoped_search :on => :other_c, :relation => :bars, :rename => 'bars.other_c'.to_sym
47
47
  end
48
48
 
49
49
  class ::Infoo < ::Foo
50
50
  end
51
51
 
52
52
  @foo_1 = Foo.create!(:string => 'foo', :another => 'temp 1', :explicit => 'baz', :int => 9 , :date => 'February 8, 2011' , :unindexed => 10)
53
- Foo.create!(:string => 'bar', :another => 'temp 2', :explicit => 'baz', :int => 22 , :date => 'February 10, 2011', :unindexed => 10)
53
+ Foo.create!(:string => 'bar', :another => 'temp "2"', :explicit => 'baz', :int => 22 , :date => 'February 10, 2011', :unindexed => 10)
54
54
  Foo.create!(:string => 'baz', :another => nil, :explicit => nil , :int => nil, :date => nil , :unindexed => nil)
55
55
  20.times { Foo.create!(:explicit => "aaa") }
56
56
 
@@ -143,6 +143,10 @@ ScopedSearch::RSpec::Database.test_databases.each do |db|
143
143
  it "should complete values should contain baz" do
144
144
  Foo.complete_for('explicit = ').should contain('explicit = baz')
145
145
  end
146
+
147
+ it "should complete values with quotes where required" do
148
+ Foo.complete_for('alias = ').should contain('alias = "temp \"2\""')
149
+ end
146
150
  end
147
151
 
148
152
  context 'auto complete relations' do
@@ -32,7 +32,7 @@ require "spec_helper"
32
32
  has_many :facts
33
33
  has_many :keys, :through => :facts
34
34
 
35
- scoped_search :in => :facts, :on => :value, :rename => :facts, :in_key => :keys, :on_key => :name, :complete_value => true
35
+ scoped_search :relation => :facts, :on => :value, :rename => :facts, :in_key => :keys, :on_key => :name, :complete_value => true
36
36
  end
37
37
  class ::MyItem < ::Item
38
38
  end
@@ -114,16 +114,6 @@ ScopedSearch::RSpec::Database.test_databases.each do |db|
114
114
  @class.search_for('date = 09-01-02').length.should == 1
115
115
  end
116
116
 
117
- if RUBY_VERSION.to_f == 1.8
118
- it "should accept MM/DD/YY as date format" do
119
- @class.search_for('date = 01/02/09').length.should == 1
120
- end
121
-
122
- it "should accept MM/DD/YYYY as date format" do
123
- @class.search_for('date = 01/02/2009').length.should == 1
124
- end
125
- end
126
-
127
117
  it "should accept YYYY/MM/DD as date format" do
128
118
  @class.search_for('date = 2009/01/02').length.should == 1
129
119
  end
@@ -46,7 +46,7 @@ ScopedSearch::RSpec::Database.test_databases.each do |db|
46
46
  ActiveRecord::Migration.create_table(:loos) { |t| t.string :foo; t.integer :har_id }
47
47
  class Loo < ActiveRecord::Base
48
48
  belongs_to :har
49
- scoped_search :in => :har, :on => :related
49
+ scoped_search :relation => :har, :on => :related
50
50
  end
51
51
 
52
52
  @har_record = Har.create!(:related => 'bar')
@@ -93,7 +93,7 @@ ScopedSearch::RSpec::Database.test_databases.each do |db|
93
93
  class Goo < ActiveRecord::Base
94
94
  has_many :jars
95
95
  scoped_search :on => :foo
96
- scoped_search :in => :jars, :on => :related
96
+ scoped_search :relation => :jars, :on => :related
97
97
  end
98
98
 
99
99
  @foo_1 = Goo.create!(:foo => 'foo')
@@ -158,7 +158,7 @@ ScopedSearch::RSpec::Database.test_databases.each do |db|
158
158
  class Hoo < ActiveRecord::Base
159
159
  has_one :car
160
160
  scoped_search :on => :foo
161
- scoped_search :in => :car, :on => :related
161
+ scoped_search :relation => :car, :on => :related
162
162
  end
163
163
 
164
164
  @hoo_1 = Hoo.create!(:foo => 'foo')
@@ -206,7 +206,7 @@ ScopedSearch::RSpec::Database.test_databases.each do |db|
206
206
  # The class on which to call search_for
207
207
  class Joo < ActiveRecord::Base
208
208
  has_and_belongs_to_many :dars
209
- scoped_search :in => :dars, :on => :related
209
+ scoped_search :relation => :dars, :on => :related
210
210
  end
211
211
 
212
212
  @joo_1 = Joo.create!(:foo => 'foo')
@@ -265,7 +265,7 @@ ScopedSearch::RSpec::Database.test_databases.each do |db|
265
265
  # as an indication for a polymorphic relation.
266
266
  has_many :bazs, :through => :mars, :source => :baz
267
267
 
268
- scoped_search :in => :bazs, :on => :related
268
+ scoped_search :relation => :bazs, :on => :related
269
269
  end
270
270
 
271
271
  @koo_1 = Koo.create!(:foo => 'foo')
@@ -316,7 +316,7 @@ ScopedSearch::RSpec::Database.test_databases.each do |db|
316
316
  belongs_to :zar
317
317
  has_many :bazs, :through => :zar
318
318
 
319
- scoped_search :in => :bazs, :on => :related
319
+ scoped_search :relation => :bazs, :on => :related
320
320
  end
321
321
 
322
322
  baz_1 = Baz.create(:related => 'baz')
@@ -362,7 +362,7 @@ ScopedSearch::RSpec::Database.test_databases.each do |db|
362
362
  has_many :taggables
363
363
  has_many :dogs, :through => :taggables, :source => :taggable, :source_type => 'Dog'
364
364
 
365
- scoped_search :in => :dogs, :on => :related, :rename => :dog
365
+ scoped_search :relation => :dogs, :on => :related, :rename => :dog
366
366
  end
367
367
 
368
368
  # The class on which to call search_for
@@ -370,7 +370,7 @@ ScopedSearch::RSpec::Database.test_databases.each do |db|
370
370
  has_many :taggables, :as => :taggable
371
371
  has_many :tags, :through => :taggables
372
372
 
373
- scoped_search :in => :tags, :on => :foo
373
+ scoped_search :relation => :tags, :on => :foo
374
374
  end
375
375
 
376
376
  class Cat < ActiveRecord::Base
@@ -438,7 +438,7 @@ ScopedSearch::RSpec::Database.test_databases.each do |db|
438
438
  has_many :zaps
439
439
  has_many :pazs, :through => :zaps
440
440
 
441
- scoped_search :in => :pazs, :on => :related
441
+ scoped_search :relation => :pazs, :on => :related
442
442
  end
443
443
 
444
444
  @moo_1 = Moo.create!(:foo => 'foo')
@@ -471,6 +471,59 @@ ScopedSearch::RSpec::Database.test_databases.each do |db|
471
471
  end
472
472
  end
473
473
 
474
+ context 'querying a :has_many => :through relation with same name on target class with custom condition' do
475
+
476
+ before do
477
+
478
+ # Create some tables
479
+ ActiveRecord::Migration.create_table(:user_groups) { |t| t.integer :user_id; t.integer :group_id }
480
+ ActiveRecord::Migration.create_table(:conflicts) { |t| t.integer :group_id; t.integer :user_id }
481
+ ActiveRecord::Migration.create_table(:groups) { |t| t.string :related; t.integer :user_id }
482
+ ActiveRecord::Migration.create_table(:users) { |t| t.string :foo }
483
+
484
+ # The related classes
485
+ class UserGroup < ActiveRecord::Base; belongs_to :user; belongs_to :group; end
486
+ class Conflict < ActiveRecord::Base; belongs_to :user; belongs_to :group; end
487
+ class Group < ActiveRecord::Base
488
+ has_many :user_groups
489
+ has_many :users, :through => :conflicts, :source_type => 'User', :source => :user
490
+ end
491
+
492
+ # The class on which to call search_for
493
+ class User < ActiveRecord::Base
494
+ has_many :user_groups
495
+ has_many :groups, :through => :user_groups
496
+
497
+ scoped_search :relation => :groups, :on => :related
498
+ end
499
+
500
+ @user_1 = User.create!(:foo => 'foo')
501
+ @user_2 = User.create!(:foo => 'foo too')
502
+ @user_3 = User.create!(:foo => 'foo three')
503
+
504
+ @group_1 = Group.create(:related => 'value')
505
+ @group_2 = Group.create(:related => 'value too!')
506
+
507
+ @bar_1 = UserGroup.create!(:user => @user_1, :group => @group_1)
508
+ @bar_2 = UserGroup.create!(:user => @user_1)
509
+ @bar_3 = UserGroup.create!(:user => @user_2, :group => @group_1)
510
+ @bar_3 = UserGroup.create!(:user => @user_2, :group => @group_2)
511
+ @bar_3 = UserGroup.create!(:user => @user_2, :group => @group_2)
512
+ @bar_4 = UserGroup.create!(:user => @user_3)
513
+ end
514
+
515
+ after do
516
+ ActiveRecord::Migration.drop_table(:user_groups)
517
+ ActiveRecord::Migration.drop_table(:users)
518
+ ActiveRecord::Migration.drop_table(:groups)
519
+ ActiveRecord::Migration.drop_table(:conflicts)
520
+ end
521
+
522
+ it "should find the one record that is related based on forward groups relation" do
523
+ User.search_for('related=value AND related="value too!"').length.should == 1
524
+ end
525
+ end
526
+
474
527
 
475
528
  context 'querying a :has_many => :through relation with modules' do
476
529
 
@@ -492,7 +545,7 @@ ScopedSearch::RSpec::Database.test_databases.each do |db|
492
545
  has_many :bazs, :through => :mars
493
546
  self.table_name = "zan_koos"
494
547
 
495
- scoped_search :in => :bazs, :on => :related
548
+ scoped_search :relation => :bazs, :on => :related
496
549
  end
497
550
  end
498
551
 
@@ -16,7 +16,7 @@ ScopedSearch::RSpec::Database.test_databases.each do |db|
16
16
  :description => :string
17
17
  ) do |klass|
18
18
  klass.scoped_search :on => :string
19
- klass.scoped_search :on => :another, :default_operator => :eq, :alias => :alias, :default_order => :desc
19
+ klass.scoped_search :on => :another, :default_operator => :eq, :aliases => [:alias], :default_order => :desc
20
20
  klass.scoped_search :on => :explicit, :only_explicit => true
21
21
  klass.scoped_search :on => :description
22
22
  end
@@ -150,7 +150,7 @@ describe ScopedSearch::QueryLanguage::AST::OperatorNode do
150
150
  end
151
151
 
152
152
  it "should raise an error of the LHS is requested" do
153
- lambda { @node.lhs }.should raise_error
153
+ lambda { @node.lhs }.should raise_error(ScopedSearch::Exception, "Operator does not have a LHS")
154
154
  end
155
155
  end
156
156
 
@@ -187,11 +187,11 @@ describe ScopedSearch::QueryLanguage::AST::OperatorNode do
187
187
  end
188
188
 
189
189
  it "should raise an error of the LHS is requested" do
190
- lambda { @node.lhs }.should raise_error
190
+ lambda { @node.lhs }.should raise_error(ScopedSearch::Exception, "Operators with more than 2 children do not have LHS/RHS")
191
191
  end
192
192
 
193
193
  it "should raise an error of the RHS is requested" do
194
- lambda { @node.rhs }.should raise_error
194
+ lambda { @node.rhs }.should raise_error(ScopedSearch::Exception, "Operators with more than 2 children do not have LHS/RHS")
195
195
  end
196
196
  end
197
197
  end
@@ -9,6 +9,42 @@ describe ScopedSearch::Definition do
9
9
  end
10
10
 
11
11
  describe ScopedSearch::Definition::Field do
12
+ describe '#initialize' do
13
+ it "should raise an exception with missing field or 'on' keyword" do
14
+ lambda {
15
+ @definition.define
16
+ }.should raise_error(ArgumentError, "Missing field or 'on' keyword argument")
17
+ end
18
+
19
+ it "should raise an exception with unknown keyword arguments" do
20
+ lambda {
21
+ @definition.define(:field, :nonexisting => 'foo')
22
+ }.should raise_error(ArgumentError, "Unknown arguments to scoped_search: nonexisting")
23
+ end
24
+
25
+ it "should alias :in to :relation" do
26
+ ActiveSupport::Deprecation.should_receive(:warn).with("'in' argument deprecated, prefer 'relation' since scoped_search 4.0.0", anything)
27
+ @definition.define(:field, :in => 'foo').relation.should eq('foo')
28
+ end
29
+
30
+ it "should accept :relation" do
31
+ ActiveSupport::Deprecation.should_not_receive(:warn)
32
+ @definition.define(:field, :relation => 'foo').relation.should eq('foo')
33
+ end
34
+
35
+ it "should alias :alias to :aliases" do
36
+ ActiveSupport::Deprecation.should_receive(:warn).with("'alias' argument deprecated, prefer aliases: [..] since scoped_search 4.0.0", anything)
37
+ @definition.define(:field, :alias => 'foo')
38
+ @definition.fields.keys.should eq([:field, :foo])
39
+ end
40
+
41
+ it "should accept :relation" do
42
+ ActiveSupport::Deprecation.should_not_receive(:warn)
43
+ @definition.define(:field, :aliases => ['foo'])
44
+ @definition.fields.keys.should eq([:field, :foo])
45
+ end
46
+ end
47
+
12
48
  describe '#column' do
13
49
  it "should raise an exception when using an unknown field" do
14
50
  lambda {
@@ -33,4 +33,26 @@ describe ScopedSearch::QueryBuilder do
33
33
  @definition.klass.connection.stub("class").and_return(connection)
34
34
  ScopedSearch::QueryBuilder.class_for(@definition).should == ScopedSearch::QueryBuilder::PostgreSQLAdapter
35
35
  end
36
+
37
+ it "should validate value if validator selected" do
38
+ field = double('field')
39
+ field.stub(:only_explicit).and_return(true)
40
+ field.stub(:field).and_return(:test_field)
41
+ field.stub(:validator).and_return(->(_value) { false })
42
+
43
+ @definition.stub(:field_by_name).and_return(field)
44
+
45
+ lambda { ScopedSearch::QueryBuilder.build_query(@definition, 'test_field = test_val') }.should raise_error(ScopedSearch::QueryNotSupported)
46
+ end
47
+
48
+ it "should display custom error from validator" do
49
+ field = double('field')
50
+ field.stub(:only_explicit).and_return(true)
51
+ field.stub(:field).and_return(:test_field)
52
+ field.stub(:validator).and_return(->(_value) { raise ScopedSearch::QueryNotSupported, 'my custom message' })
53
+
54
+ @definition.stub(:field_by_name).and_return(field)
55
+
56
+ lambda { ScopedSearch::QueryBuilder.build_query(@definition, 'test_field = test_val') }.should raise_error('my custom message')
57
+ end
36
58
  end
@@ -92,4 +92,24 @@ describe ScopedSearch::RailsHelper do
92
92
  params[:order] = "field DESC"
93
93
  sort("field")
94
94
  end
95
+
96
+ context 'with ActionController::Parameters' do
97
+ let(:ac_params) { double('ActionController::Parameters') }
98
+
99
+ it "should call to_h on passed params object" do
100
+ should_receive(:url_for).with(
101
+ "controller" => "resources",
102
+ "action" => "search",
103
+ "walrus" => "unicorns",
104
+ "order" => "field ASC"
105
+ ).and_return("/example")
106
+
107
+ params[:walrus] = "unicorns"
108
+
109
+ ac_params.should_receive(:respond_to?).with(:permit).and_return(true)
110
+ ac_params.should_receive(:to_h).and_return(params)
111
+
112
+ sort("field", url_options: ac_params)
113
+ end
114
+ end
95
115
  end
@@ -0,0 +1,27 @@
1
+ require "spec_helper"
2
+
3
+ describe ScopedSearch::Validators do
4
+ describe 'NUMERIC' do
5
+ it 'should accept integer value' do
6
+ ScopedSearch::Validators::NUMERIC.call('123').should eq(true)
7
+ end
8
+
9
+ it 'should accept float value' do
10
+ ScopedSearch::Validators::NUMERIC.call('123.5').should eq(true)
11
+ end
12
+
13
+ it 'should reject string value' do
14
+ ScopedSearch::Validators::NUMERIC.call('abc').should eq(false)
15
+ end
16
+ end
17
+
18
+ describe 'INTEGER' do
19
+ it 'should accept numeric value' do
20
+ ScopedSearch::Validators::INTEGER.call('123').should eq(true)
21
+ end
22
+
23
+ it 'should reject string value' do
24
+ ScopedSearch::Validators::INTEGER.call('abc').should eq(false)
25
+ end
26
+ end
27
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: scoped_search
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.3.0
4
+ version: 4.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Amos Benari
@@ -10,48 +10,48 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2016-08-09 00:00:00.000000000 Z
13
+ date: 2016-12-05 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activerecord
17
17
  requirement: !ruby/object:Gem::Requirement
18
18
  requirements:
19
- - - '>='
19
+ - - ">="
20
20
  - !ruby/object:Gem::Version
21
- version: 3.2.0
21
+ version: 4.2.0
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  requirements:
26
- - - '>='
26
+ - - ">="
27
27
  - !ruby/object:Gem::Version
28
- version: 3.2.0
28
+ version: 4.2.0
29
29
  - !ruby/object:Gem::Dependency
30
30
  name: rspec
31
31
  requirement: !ruby/object:Gem::Requirement
32
32
  requirements:
33
- - - ~>
33
+ - - "~>"
34
34
  - !ruby/object:Gem::Version
35
35
  version: '3.0'
36
36
  type: :development
37
37
  prerelease: false
38
38
  version_requirements: !ruby/object:Gem::Requirement
39
39
  requirements:
40
- - - ~>
40
+ - - "~>"
41
41
  - !ruby/object:Gem::Version
42
42
  version: '3.0'
43
43
  - !ruby/object:Gem::Dependency
44
44
  name: rake
45
45
  requirement: !ruby/object:Gem::Requirement
46
46
  requirements:
47
- - - '>='
47
+ - - ">="
48
48
  - !ruby/object:Gem::Version
49
49
  version: '0'
50
50
  type: :development
51
51
  prerelease: false
52
52
  version_requirements: !ruby/object:Gem::Requirement
53
53
  requirements:
54
- - - '>='
54
+ - - ">="
55
55
  - !ruby/object:Gem::Version
56
56
  version: '0'
57
57
  description: |2
@@ -77,14 +77,11 @@ extra_rdoc_files:
77
77
  - CONTRIBUTING.rdoc
78
78
  - LICENSE
79
79
  files:
80
- - .gitignore
81
- - .travis.yml
80
+ - ".gitignore"
81
+ - ".travis.yml"
82
82
  - CHANGELOG.rdoc
83
83
  - CONTRIBUTING.rdoc
84
84
  - Gemfile
85
- - Gemfile.activerecord32
86
- - Gemfile.activerecord40
87
- - Gemfile.activerecord41
88
85
  - Gemfile.activerecord42
89
86
  - Gemfile.activerecord50
90
87
  - LICENSE
@@ -105,6 +102,7 @@ files:
105
102
  - lib/scoped_search/query_language/tokenizer.rb
106
103
  - lib/scoped_search/rails_helper.rb
107
104
  - lib/scoped_search/railtie.rb
105
+ - lib/scoped_search/validators.rb
108
106
  - lib/scoped_search/version.rb
109
107
  - scoped_search.gemspec
110
108
  - spec/database.jruby.yml
@@ -128,33 +126,34 @@ files:
128
126
  - spec/unit/query_builder_spec.rb
129
127
  - spec/unit/rails_helper_spec.rb
130
128
  - spec/unit/tokenizer_spec.rb
129
+ - spec/unit/validators_spec.rb
131
130
  homepage: https://github.com/wvanbergen/scoped_search/wiki
132
131
  licenses:
133
132
  - MIT
134
133
  metadata: {}
135
134
  post_install_message:
136
135
  rdoc_options:
137
- - --title
136
+ - "--title"
138
137
  - scoped_search
139
- - --main
138
+ - "--main"
140
139
  - README.rdoc
141
- - --line-numbers
142
- - --inline-source
140
+ - "--line-numbers"
141
+ - "--inline-source"
143
142
  require_paths:
144
143
  - lib
145
144
  required_ruby_version: !ruby/object:Gem::Requirement
146
145
  requirements:
147
- - - '>='
146
+ - - ">="
148
147
  - !ruby/object:Gem::Version
149
- version: 1.9.3
148
+ version: 2.0.0
150
149
  required_rubygems_version: !ruby/object:Gem::Requirement
151
150
  requirements:
152
- - - '>='
151
+ - - ">="
153
152
  - !ruby/object:Gem::Version
154
153
  version: '0'
155
154
  requirements: []
156
155
  rubyforge_project:
157
- rubygems_version: 2.0.14.1
156
+ rubygems_version: 2.6.8
158
157
  signing_key:
159
158
  specification_version: 4
160
159
  summary: Easily search you ActiveRecord models with a simple query language using
@@ -181,3 +180,4 @@ test_files:
181
180
  - spec/unit/query_builder_spec.rb
182
181
  - spec/unit/rails_helper_spec.rb
183
182
  - spec/unit/tokenizer_spec.rb
183
+ - spec/unit/validators_spec.rb
@@ -1,16 +0,0 @@
1
- source 'https://rubygems.org'
2
- gemspec
3
-
4
- gem 'activerecord', '~> 3.2.0'
5
-
6
- platforms :jruby do
7
- gem 'activerecord-jdbcsqlite3-adapter'
8
- gem 'activerecord-jdbcmysql-adapter'
9
- gem 'activerecord-jdbcpostgresql-adapter'
10
- end
11
-
12
- platforms :ruby do
13
- gem 'sqlite3'
14
- gem 'mysql2', '~> 0.3.11'
15
- gem 'pg'
16
- end
@@ -1,16 +0,0 @@
1
- source 'https://rubygems.org'
2
- gemspec
3
-
4
- gem 'activerecord', '~> 4.0.0'
5
-
6
- platforms :jruby do
7
- gem 'activerecord-jdbcsqlite3-adapter'
8
- gem 'activerecord-jdbcmysql-adapter'
9
- gem 'activerecord-jdbcpostgresql-adapter'
10
- end
11
-
12
- platforms :ruby do
13
- gem 'sqlite3'
14
- gem 'mysql2', '~> 0.3.11'
15
- gem 'pg'
16
- end
@@ -1,16 +0,0 @@
1
- source 'https://rubygems.org'
2
- gemspec
3
-
4
- gem 'activerecord', '~> 4.1.0'
5
-
6
- platforms :jruby do
7
- gem 'activerecord-jdbcsqlite3-adapter'
8
- gem 'activerecord-jdbcmysql-adapter'
9
- gem 'activerecord-jdbcpostgresql-adapter'
10
- end
11
-
12
- platforms :ruby do
13
- gem 'sqlite3'
14
- gem 'mysql2', '~> 0.3.11'
15
- gem 'pg'
16
- end