mongoid 7.0.4 → 7.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/LICENSE +1 -0
  5. data/README.md +3 -2
  6. data/Rakefile +26 -0
  7. data/lib/mongoid.rb +2 -1
  8. data/lib/mongoid/association/embedded/embeds_many.rb +2 -1
  9. data/lib/mongoid/association/embedded/embeds_one.rb +2 -1
  10. data/lib/mongoid/association/proxy.rb +1 -1
  11. data/lib/mongoid/atomic.rb +13 -3
  12. data/lib/mongoid/atomic/paths/embedded.rb +1 -1
  13. data/lib/mongoid/attributes.rb +28 -20
  14. data/lib/mongoid/attributes/dynamic.rb +15 -14
  15. data/lib/mongoid/clients/sessions.rb +20 -4
  16. data/lib/mongoid/config/environment.rb +21 -8
  17. data/lib/mongoid/criteria.rb +7 -1
  18. data/lib/mongoid/criteria/modifiable.rb +13 -2
  19. data/lib/mongoid/criteria/queryable/extensions/numeric.rb +1 -1
  20. data/lib/mongoid/criteria/queryable/extensions/regexp.rb +3 -3
  21. data/lib/mongoid/criteria/queryable/extensions/time.rb +1 -1
  22. data/lib/mongoid/criteria/queryable/extensions/time_with_zone.rb +12 -0
  23. data/lib/mongoid/criteria/queryable/key.rb +67 -8
  24. data/lib/mongoid/criteria/queryable/mergeable.rb +5 -4
  25. data/lib/mongoid/criteria/queryable/selectable.rb +3 -4
  26. data/lib/mongoid/criteria/queryable/selector.rb +9 -31
  27. data/lib/mongoid/extensions/hash.rb +4 -2
  28. data/lib/mongoid/extensions/regexp.rb +1 -1
  29. data/lib/mongoid/extensions/string.rb +2 -2
  30. data/lib/mongoid/fields.rb +2 -1
  31. data/lib/mongoid/matchable.rb +14 -15
  32. data/lib/mongoid/matchable/all.rb +4 -3
  33. data/lib/mongoid/matchable/default.rb +71 -24
  34. data/lib/mongoid/matchable/regexp.rb +2 -2
  35. data/lib/mongoid/persistable/pushable.rb +11 -2
  36. data/lib/mongoid/persistence_context.rb +6 -6
  37. data/lib/mongoid/positional.rb +1 -1
  38. data/lib/mongoid/query_cache.rb +24 -11
  39. data/lib/mongoid/validatable/macros.rb +1 -1
  40. data/lib/mongoid/validatable/uniqueness.rb +1 -1
  41. data/lib/mongoid/version.rb +2 -1
  42. data/lib/rails/generators/mongoid/model/templates/model.rb.tt +1 -1
  43. data/spec/README.md +18 -0
  44. data/spec/app/models/delegating_patient.rb +16 -0
  45. data/spec/integration/app_spec.rb +192 -0
  46. data/spec/integration/associations/embedded_spec.rb +62 -0
  47. data/spec/integration/criteria/date_field_spec.rb +41 -0
  48. data/spec/integration/criteria/time_with_zone_spec.rb +32 -0
  49. data/spec/integration/document_spec.rb +22 -0
  50. data/spec/integration/matchable_spec.rb +680 -0
  51. data/spec/lite_spec_helper.rb +15 -5
  52. data/spec/mongoid/association/embedded/embeds_many_models.rb +53 -0
  53. data/spec/mongoid/association/embedded/embeds_many_spec.rb +10 -0
  54. data/spec/mongoid/association/embedded/embeds_one_spec.rb +0 -2
  55. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +140 -1
  56. data/spec/mongoid/association/referenced/has_many/enumerable_spec.rb +105 -0
  57. data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +2 -1
  58. data/spec/mongoid/attributes/dynamic_spec.rb +153 -0
  59. data/spec/mongoid/attributes_spec.rb +19 -7
  60. data/spec/mongoid/clients/factory_spec.rb +2 -2
  61. data/spec/mongoid/clients/options_spec.rb +4 -4
  62. data/spec/mongoid/clients/sessions_spec.rb +20 -7
  63. data/spec/mongoid/clients/transactions_spec.rb +36 -15
  64. data/spec/mongoid/clients_spec.rb +2 -2
  65. data/spec/mongoid/contextual/atomic_spec.rb +20 -10
  66. data/spec/mongoid/contextual/geo_near_spec.rb +12 -2
  67. data/spec/mongoid/contextual/map_reduce_spec.rb +20 -5
  68. data/spec/mongoid/contextual/mongo_spec.rb +76 -53
  69. data/spec/mongoid/criteria/modifiable_spec.rb +59 -10
  70. data/spec/mongoid/criteria/queryable/extensions/numeric_spec.rb +54 -0
  71. data/spec/mongoid/criteria/queryable/extensions/regexp_spec.rb +7 -7
  72. data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +1 -1
  73. data/spec/mongoid/criteria/queryable/extensions/time_spec.rb +19 -7
  74. data/spec/mongoid/criteria/queryable/extensions/time_with_zone_spec.rb +28 -1
  75. data/spec/mongoid/criteria/queryable/key_spec.rb +48 -6
  76. data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +762 -0
  77. data/spec/mongoid/criteria/queryable/selectable_spec.rb +5 -224
  78. data/spec/mongoid/criteria/queryable/selector_spec.rb +37 -0
  79. data/spec/mongoid/criteria_spec.rb +7 -2
  80. data/spec/mongoid/document_fields_spec.rb +88 -0
  81. data/spec/mongoid/document_persistence_context_spec.rb +33 -0
  82. data/spec/mongoid/indexable_spec.rb +6 -4
  83. data/spec/mongoid/matchable/default_spec.rb +10 -3
  84. data/spec/mongoid/matchable/regexp_spec.rb +2 -2
  85. data/spec/mongoid/matchable_spec.rb +2 -2
  86. data/spec/mongoid/persistable/pushable_spec.rb +55 -1
  87. data/spec/mongoid/query_cache_spec.rb +62 -8
  88. data/spec/mongoid/relations/proxy_spec.rb +1 -1
  89. data/spec/mongoid/scopable_spec.rb +2 -1
  90. data/spec/mongoid/tasks/database_rake_spec.rb +13 -13
  91. data/spec/mongoid/tasks/database_spec.rb +1 -1
  92. data/spec/mongoid/validatable/uniqueness_spec.rb +33 -6
  93. data/spec/spec_helper.rb +4 -37
  94. data/spec/support/child_process_helper.rb +76 -0
  95. data/spec/support/cluster_config.rb +158 -0
  96. data/spec/support/constraints.rb +201 -30
  97. data/spec/support/expectations.rb +17 -3
  98. data/spec/support/spec_config.rb +12 -4
  99. metadata +490 -454
  100. metadata.gz.sig +0 -0
@@ -58,7 +58,7 @@ module Mongoid
58
58
  #
59
59
  # @since 1.0.0
60
60
  def __numeric__(object)
61
- object.to_s =~ /(^[-+]?[0-9]+$)|(\.0+$)|(\.$)/ ? object.to_i : Float(object)
61
+ object.to_s =~ /(\A[-+]?[0-9]+\z)|(\.0+\z)|(\.\z)/ ? object.to_i : Float(object)
62
62
  end
63
63
 
64
64
  # Evolve the object to an integer.
@@ -10,7 +10,7 @@ module Mongoid
10
10
  # Is the object a regexp?
11
11
  #
12
12
  # @example Is the object a regex?
13
- # /^[123]/.regexp?
13
+ # /\A[123]/.regexp?
14
14
  #
15
15
  # @return [ true ] Always true.
16
16
  #
@@ -22,7 +22,7 @@ module Mongoid
22
22
  # Evolve the object into a regex.
23
23
  #
24
24
  # @example Evolve the object to a regex.
25
- # Regexp.evolve("^[123]")
25
+ # Regexp.evolve("\A[123]")
26
26
  #
27
27
  # @param [ Regexp, String ] object The object to evolve.
28
28
  #
@@ -53,7 +53,7 @@ module Mongoid
53
53
  # Evolve the object into a raw bson regex.
54
54
  #
55
55
  # @example Evolve the object to a regex.
56
- # BSON::Regexp::Raw.evolve("^[123]")
56
+ # BSON::Regexp::Raw.evolve("\\A[123]")
57
57
  #
58
58
  # @param [ BSON::Regexp::Raw, String ] object The object to evolve.
59
59
  #
@@ -28,7 +28,7 @@ module Mongoid
28
28
  #
29
29
  # @since 1.0.0
30
30
  def __evolve_time__
31
- utc
31
+ getutc
32
32
  end
33
33
 
34
34
  module ClassMethods
@@ -7,6 +7,18 @@ module Mongoid
7
7
  # This module contains additional time with zone behaviour.
8
8
  module TimeWithZone
9
9
 
10
+ # Evolve the time as a date, UTC midnight.
11
+ #
12
+ # @example Evolve the time to a date query format.
13
+ # time.__evolve_date__
14
+ #
15
+ # @return [ Time ] The date at midnight UTC.
16
+ #
17
+ # @since 1.0.0
18
+ def __evolve_date__
19
+ ::Time.utc(year, month, day, 0, 0, 0, 0)
20
+ end
21
+
10
22
  # Evolve the time into a utc time.
11
23
  #
12
24
  # @example Evolve the time.
@@ -3,16 +3,75 @@ module Mongoid
3
3
  class Criteria
4
4
  module Queryable
5
5
 
6
- # The key is a representation of a field in a queryable, that can be
7
- # expanded to special MongoDB selectors.
6
+ # Key objects represent specifications for building query expressions
7
+ # utilizing MongoDB selectors.
8
+ #
9
+ # Simple key-value conditions are translated directly into expression
10
+ # hashes by Mongoid without utilizing Key objects. For example, the
11
+ # following condition:
12
+ #
13
+ # Foo.where(price: 1)
14
+ #
15
+ # ... is translated to the following simple expression:
16
+ #
17
+ # {price: 1}
18
+ #
19
+ # More complex conditions would start involving Key objects. For example:
20
+ #
21
+ # Foo.where(:price.gt => 1)
22
+ #
23
+ # ... causes a Key instance to be created thusly:
24
+ #
25
+ # Key.new(:price, :__override__, '$gt')
26
+ #
27
+ # This Key instance utilizes +operator+ but not +expanded+ nor +block+.
28
+ # The corresponding MongoDB query expression is:
29
+ #
30
+ # {price: {'$gt' => 1}}
31
+ #
32
+ # A yet more more complex example is the following condition:
33
+ #
34
+ # Foo.geo_spacial(:boundary.intersects_point => [1, 10])
35
+ #
36
+ # Processing this condition will cause a Key instance to be created as
37
+ # follows:
38
+ #
39
+ # Key.new(:location, :__override__, '$geoIntersects', '$geometry') do |value|
40
+ # { "type" => POINT, "coordinates" => value }
41
+ # end
42
+ #
43
+ # ... eventually producing the following MongoDB query expression:
44
+ #
45
+ # {
46
+ # boundary: {
47
+ # '$geoIntersects' => {
48
+ # '$geometry' => {
49
+ # type: "Point" ,
50
+ # coordinates: [ 1, 10 ]
51
+ # }
52
+ # }
53
+ # }
54
+ # }
55
+ #
56
+ # Key instances can be thought of as procs that map a value to the
57
+ # MongoDB query expression required to obtain the key's condition,
58
+ # given the value.
8
59
  class Key
9
60
 
10
- # @attribute [r] name The name of the field.
11
- # @attribute [r] block The optional block to transform values.
12
- # @attribute [r] operator The MongoDB query operator.
13
- # @attribute [r] expanded The MongoDB expanded query operator.
14
- # @attribute [r] strategy The name of the merge strategy.
15
- attr_reader :block, :name, :operator, :expanded, :strategy
61
+ # @return [ String | Symbol ] The name of the field.
62
+ attr_reader :name
63
+
64
+ # @return [ String ] The MongoDB query operator.
65
+ attr_reader :operator
66
+
67
+ # @return [ String ] The MongoDB expanded query operator.
68
+ attr_reader :expanded
69
+
70
+ # @return [ Symbol ] The name of the merge strategy.
71
+ attr_reader :strategy
72
+
73
+ # @return [ Proc ] The optional block to transform values.
74
+ attr_reader :block
16
75
 
17
76
  # Does the key equal another object?
18
77
  #
@@ -45,7 +45,7 @@ module Mongoid
45
45
  use(:__union__)
46
46
  end
47
47
 
48
- # Reset the stratgies to nil, used after cloning.
48
+ # Clear the current strategy and negating flag, used after cloning.
49
49
  #
50
50
  # @example Reset the strategies.
51
51
  # mergeable.reset_strategies!
@@ -54,7 +54,8 @@ module Mongoid
54
54
  #
55
55
  # @since 1.0.0
56
56
  def reset_strategies!
57
- self.strategy, self.negating = nil, nil
57
+ self.strategy = nil
58
+ self.negating = nil
58
59
  end
59
60
 
60
61
  private
@@ -167,7 +168,7 @@ module Mongoid
167
168
  # @example Add the criterion.
168
169
  # mergeable.__override__([ 1, 2 ], "$in")
169
170
  #
170
- # @param [ Hash ] criterion The criteria.
171
+ # @param [ Hash | Criteria ] criterion The criteria.
171
172
  # @param [ String ] operator The MongoDB operator.
172
173
  #
173
174
  # @return [ Mergeable ] The new mergeable.
@@ -225,7 +226,7 @@ module Mongoid
225
226
  # @api private
226
227
  #
227
228
  # @example Add criterion with a strategy.
228
- # mergeable.with_strategy(:__union__, [ 1, 2, 3 ], "$in")
229
+ # mergeable.with_strategy(:__union__, {field_name: [ 1, 2, 3 ]}, "$in")
229
230
  #
230
231
  # @param [ Symbol ] strategy The name of the strategy method.
231
232
  # @param [ Object ] criterion The criterion to add.
@@ -24,7 +24,7 @@ module Mongoid
24
24
  # @since 2.0.0
25
25
  POLYGON = "Polygon"
26
26
 
27
- # @attribute [rw] negating If the next spression is negated.
27
+ # @attribute [rw] negating If the next expression is negated.
28
28
  # @attribute [rw] selector The query selector.
29
29
  attr_accessor :negating, :selector
30
30
 
@@ -434,7 +434,7 @@ module Mongoid
434
434
  # @since 1.0.0
435
435
  def not(*criterion)
436
436
  if criterion.empty?
437
- tap { |query| query.negating = true }
437
+ dup.tap { |query| query.negating = true }
438
438
  else
439
439
  __override__(criterion.first, "$not")
440
440
  end
@@ -630,8 +630,6 @@ module Mongoid
630
630
  # Take the provided criterion and store it as a selection in the query
631
631
  # selector.
632
632
  #
633
- # @api private
634
- #
635
633
  # @example Store the selection.
636
634
  # selectable.selection({ field: "value" })
637
635
  #
@@ -640,6 +638,7 @@ module Mongoid
640
638
  # @return [ Selectable ] The cloned selectable.
641
639
  #
642
640
  # @since 1.0.0
641
+ # @api private
643
642
  def selection(criterion = nil)
644
643
  clone.tap do |query|
645
644
  if criterion
@@ -21,9 +21,10 @@ module Mongoid
21
21
  other.each_pair do |key, value|
22
22
  if value.is_a?(Hash) && self[key.to_s].is_a?(Hash)
23
23
  value = self[key.to_s].merge(value) do |_key, old_val, new_val|
24
- if in?(_key)
24
+ case _key
25
+ when '$in'
25
26
  new_val & old_val
26
- elsif nin?(_key)
27
+ when '$nin'
27
28
  (old_val + new_val).uniq
28
29
  else
29
30
  new_val
@@ -52,10 +53,13 @@ module Mongoid
52
53
  def store(key, value)
53
54
  name, serializer = storage_pair(key)
54
55
  if multi_selection?(name)
55
- super(name, evolve_multi(value))
56
+ store_name = name
57
+ store_value = evolve_multi(value)
56
58
  else
57
- super(localized_key(name, serializer), evolve(serializer, value))
59
+ store_name = localized_key(name, serializer)
60
+ store_value = evolve(serializer, value)
58
61
  end
62
+ super(store_name, store_value)
59
63
  end
60
64
  alias :[]= :store
61
65
 
@@ -178,33 +182,7 @@ module Mongoid
178
182
  #
179
183
  # @since 1.0.0
180
184
  def multi_selection?(key)
181
- key =~ /\$and|\$or|\$nor/
182
- end
183
-
184
- # Determines if the selection operator takes a list. Returns true for $in and $nin.
185
- #
186
- # @api private
187
- #
188
- # @example Does the selection operator take multiple values?
189
- # selector.multi_value?("$nin")
190
- #
191
- # @param [ String ] key The key to check.
192
- #
193
- # @return [ true, false ] If the key is $in or $nin.
194
- #
195
- # @since 2.1.1
196
- def multi_value?(key)
197
- key =~ /\$nin|\$in/
198
- end
199
-
200
- private
201
-
202
- def in?(key)
203
- key =~ /\$in/
204
- end
205
-
206
- def nin?(key)
207
- key =~ /\$nin/
185
+ %w($and $or $nor).include?(key)
208
186
  end
209
187
  end
210
188
  end
@@ -46,9 +46,11 @@ module Mongoid
46
46
  value.each_pair do |_key, _value|
47
47
  value[_key] = (key == "$rename") ? _value.to_s : mongoize_for(key, klass, _key, _value)
48
48
  end
49
- (consolidated[key] ||= {}).merge!(value)
49
+ consolidated[key] ||= {}
50
+ consolidated[key].update(value)
50
51
  else
51
- (consolidated["$set"] ||= {}).merge!(key => mongoize_for(key, klass, key, value))
52
+ consolidated["$set"] ||= {}
53
+ consolidated["$set"].update(key => mongoize_for(key, klass, key, value))
52
54
  end
53
55
  end
54
56
  consolidated
@@ -9,7 +9,7 @@ module Mongoid
9
9
  # type.
10
10
  #
11
11
  # @example Mongoize the object.
12
- # Regexp.mongoize(/^[abc]/)
12
+ # Regexp.mongoize(/\A[abc]/)
13
13
  #
14
14
  # @param [ Regexp, String ] object The object to mongoize.
15
15
  #
@@ -69,7 +69,7 @@ module Mongoid
69
69
  #
70
70
  # @since 2.3.1
71
71
  def mongoid_id?
72
- self =~ /\A(|_)id$/
72
+ self =~ /\A(|_)id\z/
73
73
  end
74
74
 
75
75
  # Is the string a number? The literals "NaN", "Infinity", and "-Infinity"
@@ -96,7 +96,7 @@ module Mongoid
96
96
  #
97
97
  # @since 1.0.0
98
98
  def reader
99
- delete("=").sub(/\_before\_type\_cast$/, '')
99
+ delete("=").sub(/\_before\_type\_cast\z/, '')
100
100
  end
101
101
 
102
102
  # Is this string a writer?
@@ -498,7 +498,8 @@ module Mongoid
498
498
  def create_translations_getter(name, meth)
499
499
  generated_methods.module_eval do
500
500
  re_define_method("#{meth}_translations") do
501
- (attributes[name] ||= {}).with_indifferent_access
501
+ attributes[name] ||= {}
502
+ attributes[name].with_indifferent_access
502
503
  end
503
504
  alias_method :"#{meth}_t", :"#{meth}_translations"
504
505
  end
@@ -2,6 +2,7 @@
2
2
  require "mongoid/matchable/default"
3
3
  require "mongoid/matchable/all"
4
4
  require "mongoid/matchable/and"
5
+ require "mongoid/matchable/elem_match"
5
6
  require "mongoid/matchable/eq"
6
7
  require "mongoid/matchable/exists"
7
8
  require "mongoid/matchable/gt"
@@ -11,15 +12,14 @@ require "mongoid/matchable/lt"
11
12
  require "mongoid/matchable/lte"
12
13
  require "mongoid/matchable/ne"
13
14
  require "mongoid/matchable/nin"
14
- require "mongoid/matchable/or"
15
15
  require "mongoid/matchable/nor"
16
- require "mongoid/matchable/size"
17
- require "mongoid/matchable/elem_match"
16
+ require "mongoid/matchable/or"
18
17
  require "mongoid/matchable/regexp"
18
+ require "mongoid/matchable/size"
19
19
 
20
20
  module Mongoid
21
21
 
22
- # This module contains all the behavior for ruby implementations of MongoDB
22
+ # This module contains all the behavior for Ruby implementations of MongoDB
23
23
  # selectors.
24
24
  #
25
25
  # @since 4.0.0
@@ -31,8 +31,8 @@ module Mongoid
31
31
  # @since 1.0.0
32
32
  MATCHERS = {
33
33
  "$all" => All,
34
- "$elemMatch" => ElemMatch,
35
34
  "$and" => And,
35
+ "$elemMatch" => ElemMatch,
36
36
  "$eq" => Eq,
37
37
  "$exists" => Exists,
38
38
  "$gt" => Gt,
@@ -42,8 +42,8 @@ module Mongoid
42
42
  "$lte" => Lte,
43
43
  "$ne" => Ne,
44
44
  "$nin" => Nin,
45
- "$or" => Or,
46
45
  "$nor" => Nor,
46
+ "$or" => Or,
47
47
  "$size" => Size,
48
48
  }.with_indifferent_access.freeze
49
49
 
@@ -64,13 +64,13 @@ module Mongoid
64
64
  value.each do |item|
65
65
  if item[0].to_s == "$not".freeze
66
66
  item = item[1]
67
- return false if matcher(self, key, item)._matches?(item)
67
+ return false if matcher(key, item)._matches?(item)
68
68
  else
69
- return false unless matcher(self, key, Hash[*item])._matches?(Hash[*item])
69
+ return false unless matcher(key, Hash[*item])._matches?(Hash[*item])
70
70
  end
71
71
  end
72
72
  else
73
- return false unless matcher(self, key, value)._matches?(value)
73
+ return false unless matcher(key, value)._matches?(value)
74
74
  end
75
75
  end
76
76
  true
@@ -81,20 +81,18 @@ module Mongoid
81
81
  # Get the matcher for the supplied key and value. Will determine the class
82
82
  # name from the key.
83
83
  #
84
- # @api private
85
- #
86
84
  # @example Get the matcher.
87
85
  # document.matcher(:title, { "$in" => [ "test" ] })
88
86
  #
89
- # @param [ Document ] document The document to check.
90
87
  # @param [ Symbol, String ] key The field name.
91
88
  # @param [ Object, Hash ] value The value or selector.
92
89
  #
93
90
  # @return [ Matcher ] The matcher.
94
91
  #
95
92
  # @since 2.0.0.rc.7
96
- def matcher(document, key, value)
97
- Matchable.matcher(document, key, value)
93
+ # @api private
94
+ def matcher(key, value)
95
+ Matchable.matcher(self, key, value)
98
96
  end
99
97
 
100
98
  class << self
@@ -105,7 +103,7 @@ module Mongoid
105
103
  # @api private
106
104
  #
107
105
  # @example Get the matcher.
108
- # document.matcher(:title, { "$in" => [ "test" ] })
106
+ # Matchable.matcher(document, :title, { "$in" => [ "test" ] })
109
107
  #
110
108
  # @param [ Document ] document The document to check.
111
109
  # @param [ Symbol, String ] key The field name.
@@ -149,6 +147,7 @@ module Mongoid
149
147
  # @return [ Object ] The value of the attribute.
150
148
  #
151
149
  # @since 2.2.1
150
+ # @api private
152
151
  def extract_attribute(document, key)
153
152
  if (key_string = key.to_s) =~ /.+\..+/
154
153
  key_string.split('.').inject(document.send(:as_attributes)) do |_attribs, _key|
@@ -10,11 +10,12 @@ module Mongoid
10
10
  # @example Do the values match?
11
11
  # matcher._matches?({ :key => 10 })
12
12
  #
13
- # @param [ Hash ] value The values to check.
13
+ # @param [ Hash ] condition The condition to evaluate. This must be
14
+ # a one-element hash like {'$gt' => 1}.
14
15
  #
15
16
  # @return [ true, false ] If the values match.
16
- def _matches?(value)
17
- first = first(value)
17
+ def _matches?(condition)
18
+ first = condition_value(condition)
18
19
  return false if first.is_a?(Array) && first.empty?
19
20
 
20
21
  attribute_array = Array.wrap(@attribute)