mongory 0.4.0 → 0.6.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +51 -0
- data/README.md +37 -7
- data/examples/benchmark-rails.rb +52 -0
- data/examples/benchmark.rb +79 -18
- data/lib/generators/mongory/matcher/matcher_generator.rb +1 -1
- data/lib/mongory/converters/abstract_converter.rb +22 -32
- data/lib/mongory/converters/condition_converter.rb +9 -19
- data/lib/mongory/converters/converted.rb +81 -0
- data/lib/mongory/converters/data_converter.rb +18 -7
- data/lib/mongory/converters/key_converter.rb +43 -19
- data/lib/mongory/converters/value_converter.rb +24 -19
- data/lib/mongory/converters.rb +1 -0
- data/lib/mongory/matchers/abstract_matcher.rb +94 -32
- data/lib/mongory/matchers/abstract_multi_matcher.rb +16 -45
- data/lib/mongory/matchers/and_matcher.rb +38 -10
- data/lib/mongory/matchers/array_record_matcher.rb +54 -28
- data/lib/mongory/matchers/elem_match_matcher.rb +13 -9
- data/lib/mongory/matchers/eq_matcher.rb +12 -7
- data/lib/mongory/matchers/every_matcher.rb +20 -9
- data/lib/mongory/matchers/exists_matcher.rb +15 -14
- data/lib/mongory/matchers/field_matcher.rb +58 -38
- data/lib/mongory/matchers/gt_matcher.rb +15 -7
- data/lib/mongory/matchers/gte_matcher.rb +15 -7
- data/lib/mongory/matchers/hash_condition_matcher.rb +54 -26
- data/lib/mongory/matchers/in_matcher.rb +20 -13
- data/lib/mongory/matchers/literal_matcher.rb +42 -48
- data/lib/mongory/matchers/lt_matcher.rb +15 -7
- data/lib/mongory/matchers/lte_matcher.rb +15 -7
- data/lib/mongory/matchers/ne_matcher.rb +12 -7
- data/lib/mongory/matchers/nin_matcher.rb +20 -12
- data/lib/mongory/matchers/not_matcher.rb +9 -5
- data/lib/mongory/matchers/or_matcher.rb +42 -13
- data/lib/mongory/matchers/present_matcher.rb +14 -15
- data/lib/mongory/matchers/regex_matcher.rb +37 -22
- data/lib/mongory/matchers/size_matcher.rb +50 -0
- data/lib/mongory/matchers.rb +1 -1
- data/lib/mongory/query_builder.rb +89 -27
- data/lib/mongory/query_matcher.rb +40 -13
- data/lib/mongory/query_operator.rb +1 -1
- data/lib/mongory/utils/context.rb +41 -0
- data/lib/mongory/utils/debugger.rb +6 -4
- data/lib/mongory/utils.rb +1 -0
- data/lib/mongory/version.rb +1 -1
- data/lib/mongory.rb +3 -3
- data/mongory.gemspec +3 -3
- metadata +11 -9
- data/lib/mongory/matchers/README.md +0 -57
- data/lib/mongory/matchers/abstract_operator_matcher.rb +0 -46
@@ -18,16 +18,20 @@ module Mongory
|
|
18
18
|
#
|
19
19
|
# @see HashConditionMatcher
|
20
20
|
class ElemMatchMatcher < HashConditionMatcher
|
21
|
-
#
|
22
|
-
#
|
23
|
-
|
24
|
-
# @
|
25
|
-
|
26
|
-
|
27
|
-
|
21
|
+
# Creates a raw Proc that performs the element matching operation.
|
22
|
+
# The Proc checks if any element in the array matches the condition.
|
23
|
+
#
|
24
|
+
# @return [Proc] a Proc that performs the element matching operation
|
25
|
+
def raw_proc
|
26
|
+
super_proc = super
|
27
|
+
need_convert = @context.need_convert
|
28
|
+
data_converter = Mongory.data_converter
|
28
29
|
|
29
|
-
|
30
|
-
|
30
|
+
Proc.new do |collection|
|
31
|
+
collection.any? do |record|
|
32
|
+
record = data_converter.convert(record) if need_convert
|
33
|
+
super_proc.call(record)
|
34
|
+
end
|
31
35
|
end
|
32
36
|
end
|
33
37
|
|
@@ -4,7 +4,7 @@ module Mongory
|
|
4
4
|
module Matchers
|
5
5
|
# EqMatcher matches values using the equality operator `==`.
|
6
6
|
#
|
7
|
-
# It inherits from
|
7
|
+
# It inherits from AbstractMatcher and defines its operator as `:==`.
|
8
8
|
#
|
9
9
|
# Used for conditions like:
|
10
10
|
# - { age: { '$eq' => 30 } }
|
@@ -22,13 +22,18 @@ module Mongory
|
|
22
22
|
#
|
23
23
|
# @note Equality behavior depends on how `==` is implemented for the given objects.
|
24
24
|
#
|
25
|
-
# @see
|
26
|
-
class EqMatcher <
|
27
|
-
#
|
25
|
+
# @see AbstractMatcher
|
26
|
+
class EqMatcher < AbstractMatcher
|
27
|
+
# Creates a raw Proc that performs the equality check.
|
28
|
+
# The Proc uses the `==` operator to compare values.
|
28
29
|
#
|
29
|
-
# @return [
|
30
|
-
def
|
31
|
-
|
30
|
+
# @return [Proc] a Proc that performs the equality check
|
31
|
+
def raw_proc
|
32
|
+
condition = @condition
|
33
|
+
|
34
|
+
Proc.new do |record|
|
35
|
+
record == condition
|
36
|
+
end
|
32
37
|
end
|
33
38
|
end
|
34
39
|
|
@@ -15,20 +15,31 @@ module Mongory
|
|
15
15
|
#
|
16
16
|
# @see HashConditionMatcher
|
17
17
|
class EveryMatcher < HashConditionMatcher
|
18
|
-
#
|
19
|
-
#
|
18
|
+
# Creates a raw Proc that performs the element matching operation.
|
19
|
+
# The Proc checks if all elements in the array match the condition.
|
20
|
+
#
|
21
|
+
# @return [Proc] A proc that performs element matching with context awareness
|
22
|
+
# @note The proc includes error handling and context-based record conversion
|
23
|
+
def raw_proc
|
24
|
+
super_proc = super
|
25
|
+
need_convert = @context.need_convert
|
26
|
+
data_converter = Mongory.data_converter
|
20
27
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
return false unless collection.is_a?(Array)
|
25
|
-
return false if collection.empty?
|
28
|
+
Proc.new do |collection|
|
29
|
+
next false unless collection.is_a?(Array)
|
30
|
+
next false if collection.empty?
|
26
31
|
|
27
|
-
|
28
|
-
|
32
|
+
collection.all? do |record|
|
33
|
+
record = data_converter.convert(record) if need_convert
|
34
|
+
super_proc.call(record)
|
35
|
+
end
|
29
36
|
end
|
30
37
|
end
|
31
38
|
|
39
|
+
# Ensures the condition is a Hash.
|
40
|
+
#
|
41
|
+
# @raise [Mongory::TypeError] if the condition is not a Hash
|
42
|
+
# @return [void]
|
32
43
|
def check_validity!
|
33
44
|
raise TypeError, '$every needs a Hash.' unless @condition.is_a?(Hash)
|
34
45
|
|
@@ -17,21 +17,20 @@ module Mongory
|
|
17
17
|
# matcher = ExistsMatcher.build(false)
|
18
18
|
# matcher.match?(KEY_NOT_FOUND) #=> true
|
19
19
|
#
|
20
|
-
# @see
|
21
|
-
class ExistsMatcher <
|
22
|
-
#
|
20
|
+
# @see AbstractMatcher
|
21
|
+
class ExistsMatcher < AbstractMatcher
|
22
|
+
# Creates a raw Proc that performs the existence check.
|
23
|
+
# The Proc checks if the record exists and compares it to the condition.
|
23
24
|
#
|
24
|
-
# @
|
25
|
-
|
26
|
-
|
27
|
-
record != KEY_NOT_FOUND
|
28
|
-
end
|
25
|
+
# @return [Proc] A proc that performs existence check with error handling
|
26
|
+
def raw_proc
|
27
|
+
condition = @condition
|
29
28
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
29
|
+
Proc.new do |record|
|
30
|
+
# Check if the record is nil or KEY_NOT_FOUND
|
31
|
+
# and compare it to the condition.
|
32
|
+
(record != KEY_NOT_FOUND) == condition
|
33
|
+
end
|
35
34
|
end
|
36
35
|
|
37
36
|
# Ensures that the condition value is a valid boolean.
|
@@ -39,7 +38,9 @@ module Mongory
|
|
39
38
|
# @raise [TypeError] if condition is not true or false
|
40
39
|
# @return [void]
|
41
40
|
def check_validity!
|
42
|
-
|
41
|
+
return if [true, false].include?(@condition)
|
42
|
+
|
43
|
+
raise TypeError, "$exists needs a boolean, but got #{@condition.inspect}"
|
43
44
|
end
|
44
45
|
end
|
45
46
|
|
@@ -2,18 +2,22 @@
|
|
2
2
|
|
3
3
|
module Mongory
|
4
4
|
module Matchers
|
5
|
-
# FieldMatcher
|
6
|
-
# using a field (or index) and then delegating the match to LiteralMatcher logic.
|
5
|
+
# FieldMatcher handles field-level matching by extracting and comparing field values.
|
7
6
|
#
|
8
|
-
#
|
9
|
-
#
|
7
|
+
# This matcher is responsible for:
|
8
|
+
# 1. Extracting field values from records using dot notation
|
9
|
+
# 2. Converting extracted values if needed
|
10
|
+
# 3. Delegating the actual comparison to a submatcher
|
10
11
|
#
|
11
|
-
#
|
12
|
-
#
|
12
|
+
# It supports:
|
13
|
+
# - Hash records with string/symbol keys
|
14
|
+
# - Array records with numeric indices
|
15
|
+
# - Objects that respond to `[]`
|
13
16
|
#
|
14
|
-
# @example
|
15
|
-
# matcher = FieldMatcher.build(
|
16
|
-
# matcher.match?({ age
|
17
|
+
# @example Basic field matching
|
18
|
+
# matcher = FieldMatcher.build('age', 30)
|
19
|
+
# matcher.match?({ 'age' => 30 }) #=> true
|
20
|
+
# matcher.match?({ age: 30 }) #=> true
|
17
21
|
#
|
18
22
|
# @see LiteralMatcher
|
19
23
|
class FieldMatcher < LiteralMatcher
|
@@ -29,16 +33,18 @@ module Mongory
|
|
29
33
|
::Symbol
|
30
34
|
].freeze
|
31
35
|
|
32
|
-
# Initializes
|
36
|
+
# Initializes a new field matcher.
|
33
37
|
#
|
34
|
-
# @param field [
|
35
|
-
# @param condition [Object] the condition to match
|
36
|
-
|
38
|
+
# @param field [String, Symbol] the field to match against
|
39
|
+
# @param condition [Object] the condition to match with
|
40
|
+
# @param context [Context] the query context
|
41
|
+
def initialize(field, condition, context: Context.new)
|
37
42
|
@field = field
|
38
|
-
super(condition)
|
43
|
+
super(condition, context: context)
|
39
44
|
end
|
40
45
|
|
41
|
-
#
|
46
|
+
# Creates a raw Proc that performs the field matching operation.
|
47
|
+
# The Proc extracts the field value and delegates to the submatcher.
|
42
48
|
#
|
43
49
|
# This method first ensures the record is structurally eligible for field extraction—
|
44
50
|
# it must be a Hash, Array, or respond to `[]`. If the structure does not allow for
|
@@ -54,9 +60,6 @@ module Mongory
|
|
54
60
|
# Once the value is extracted, it is passed through the data converter
|
55
61
|
# and matched against the condition via the superclass.
|
56
62
|
#
|
57
|
-
# @param record [Object] the input data structure to be matched
|
58
|
-
# @return [Boolean] true if the extracted field value matches the condition; false otherwise
|
59
|
-
#
|
60
63
|
# @example Matching a Hash with a nil field value
|
61
64
|
# matcher = Mongory::QueryMatcher.new(a: nil)
|
62
65
|
# matcher.match?({ a: nil }) # => true
|
@@ -72,27 +75,44 @@ module Mongory
|
|
72
75
|
# @example Hash with symbol key, matcher uses string key
|
73
76
|
# matcher = Mongory::QueryMatcher.new('a' => 123)
|
74
77
|
# matcher.match?({ a: 123 }) # => true
|
75
|
-
def match(record)
|
76
|
-
sub_record =
|
77
|
-
case record
|
78
|
-
when Hash
|
79
|
-
record.fetch(@field) do
|
80
|
-
record.fetch(@field.to_sym, KEY_NOT_FOUND)
|
81
|
-
end
|
82
|
-
when Array
|
83
|
-
record.fetch(@field, KEY_NOT_FOUND)
|
84
|
-
when KEY_NOT_FOUND, *CLASSES_NOT_ALLOW_TO_DIG
|
85
|
-
return false
|
86
|
-
else
|
87
|
-
return false unless record.respond_to?(:[])
|
88
78
|
|
89
|
-
|
90
|
-
|
79
|
+
# Creates a raw Proc that performs the field-based matching operation.
|
80
|
+
# The Proc extracts the field value and delegates matching to the superclass.
|
81
|
+
#
|
82
|
+
# @return [Proc] A proc that performs field-based matching with context awareness
|
83
|
+
# @note The proc handles field extraction and delegates matching to the superclass
|
84
|
+
def raw_proc
|
85
|
+
super_proc = super
|
86
|
+
field = @field
|
87
|
+
need_convert = @context.need_convert
|
88
|
+
data_converter = Mongory.data_converter
|
89
|
+
|
90
|
+
Proc.new do |record|
|
91
|
+
sub_record =
|
92
|
+
case record
|
93
|
+
when Hash
|
94
|
+
record.fetch(field) do
|
95
|
+
record.fetch(field.to_sym, KEY_NOT_FOUND)
|
96
|
+
end
|
97
|
+
when Array
|
98
|
+
record.fetch(field, KEY_NOT_FOUND)
|
99
|
+
when KEY_NOT_FOUND, *CLASSES_NOT_ALLOW_TO_DIG
|
100
|
+
next false
|
101
|
+
else
|
102
|
+
next false unless record.respond_to?(:[])
|
91
103
|
|
92
|
-
|
104
|
+
record[field]
|
105
|
+
end
|
106
|
+
|
107
|
+
sub_record = data_converter.convert(sub_record) if need_convert
|
108
|
+
super_proc.call(sub_record)
|
109
|
+
end
|
93
110
|
end
|
94
111
|
|
95
|
-
#
|
112
|
+
# Returns a unique key for this matcher, including the field name.
|
113
|
+
# Used for deduplication in multi-matchers.
|
114
|
+
#
|
115
|
+
# @return [String] a unique key for this matcher
|
96
116
|
# @see AbstractMultiMatcher#matchers
|
97
117
|
def uniq_key
|
98
118
|
super + "field:#{@field}"
|
@@ -100,9 +120,9 @@ module Mongory
|
|
100
120
|
|
101
121
|
private
|
102
122
|
|
103
|
-
# Returns a single-line summary of the
|
123
|
+
# Returns a single-line summary of the field matcher including the field and condition.
|
104
124
|
#
|
105
|
-
# @return [String]
|
125
|
+
# @return [String] a formatted title for tree display
|
106
126
|
def tree_title
|
107
127
|
"Field: #{@field.inspect} to match: #{@condition.inspect}"
|
108
128
|
end
|
@@ -111,7 +131,7 @@ module Mongory
|
|
111
131
|
#
|
112
132
|
# @param record [Object] the input record
|
113
133
|
# @param result [Boolean] match result
|
114
|
-
# @return [String] formatted debug string
|
134
|
+
# @return [String] formatted debug string with highlighted field
|
115
135
|
def debug_display(record, result)
|
116
136
|
"#{self.class.name.split('::').last} #{colored_result(result)}, " \
|
117
137
|
"condition: #{@condition.inspect}, " \
|
@@ -6,7 +6,7 @@ module Mongory
|
|
6
6
|
#
|
7
7
|
# It returns true if the record is strictly greater than the condition.
|
8
8
|
#
|
9
|
-
# Inherits core logic from
|
9
|
+
# Inherits core logic from AbstractMatcher, including
|
10
10
|
# error handling and optional preprocessing.
|
11
11
|
#
|
12
12
|
# @example
|
@@ -14,13 +14,21 @@ module Mongory
|
|
14
14
|
# matcher.match?(15) #=> true
|
15
15
|
# matcher.match?(10) #=> false
|
16
16
|
#
|
17
|
-
# @see
|
18
|
-
class GtMatcher <
|
19
|
-
#
|
17
|
+
# @see AbstractMatcher
|
18
|
+
class GtMatcher < AbstractMatcher
|
19
|
+
# Creates a raw Proc that performs the greater-than comparison.
|
20
|
+
# The Proc uses the `>` operator to compare values.
|
20
21
|
#
|
21
|
-
# @return [
|
22
|
-
|
23
|
-
|
22
|
+
# @return [Proc] A proc that performs greater-than comparison with error handling
|
23
|
+
# @note The proc includes error handling for invalid comparisons
|
24
|
+
def raw_proc
|
25
|
+
condition = @condition
|
26
|
+
|
27
|
+
Proc.new do |record|
|
28
|
+
record > condition
|
29
|
+
rescue StandardError
|
30
|
+
false
|
31
|
+
end
|
24
32
|
end
|
25
33
|
end
|
26
34
|
|
@@ -6,7 +6,7 @@ module Mongory
|
|
6
6
|
#
|
7
7
|
# It returns true if the record is greater than or equal to the condition value.
|
8
8
|
#
|
9
|
-
# Inherits comparison logic and error safety from
|
9
|
+
# Inherits comparison logic and error safety from AbstractMatcher.
|
10
10
|
#
|
11
11
|
# @example
|
12
12
|
# matcher = GteMatcher.build(10)
|
@@ -14,13 +14,21 @@ module Mongory
|
|
14
14
|
# matcher.match?(11) #=> true
|
15
15
|
# matcher.match?(9) #=> false
|
16
16
|
#
|
17
|
-
# @see
|
18
|
-
class GteMatcher <
|
19
|
-
#
|
17
|
+
# @see AbstractMatcher
|
18
|
+
class GteMatcher < AbstractMatcher
|
19
|
+
# Creates a raw Proc that performs the greater-than-or-equal comparison.
|
20
|
+
# The Proc uses the `>=` operator to compare values.
|
20
21
|
#
|
21
|
-
# @return [
|
22
|
-
|
23
|
-
|
22
|
+
# @return [Proc] A proc that performs greater-than-or-equal comparison with error handling
|
23
|
+
# @note The proc includes error handling for invalid comparisons
|
24
|
+
def raw_proc
|
25
|
+
condition = @condition
|
26
|
+
|
27
|
+
Proc.new do |record|
|
28
|
+
record >= condition
|
29
|
+
rescue StandardError
|
30
|
+
false
|
31
|
+
end
|
24
32
|
end
|
25
33
|
end
|
26
34
|
|
@@ -9,46 +9,74 @@ module Mongory
|
|
9
9
|
#
|
10
10
|
# Each subcondition is matched independently using the `:all?` strategy, meaning
|
11
11
|
# all subconditions must match for the entire HashConditionMatcher to succeed.
|
12
|
+
# For empty conditions, it returns true (using TRUE_PROC).
|
12
13
|
#
|
13
14
|
# This matcher plays a central role in dispatching symbolic query conditions
|
14
15
|
# to the appropriate field or operator matcher.
|
15
16
|
#
|
16
|
-
# @example
|
17
|
+
# @example Basic field matching
|
17
18
|
# matcher = HashConditionMatcher.build({ age: { :$gt => 30 }, active: true })
|
18
19
|
# matcher.match?(record) #=> true only if all subconditions match
|
19
20
|
#
|
21
|
+
# @example Empty conditions
|
22
|
+
# matcher = HashConditionMatcher.build({})
|
23
|
+
# matcher.match?(record) #=> true (uses TRUE_PROC)
|
24
|
+
#
|
20
25
|
# @see AbstractMultiMatcher
|
21
26
|
class HashConditionMatcher < AbstractMultiMatcher
|
22
27
|
enable_unwrap!
|
23
|
-
|
24
|
-
#
|
25
|
-
#
|
26
|
-
|
27
|
-
#
|
28
|
-
# @
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
28
|
+
|
29
|
+
# Creates a raw Proc that performs the hash condition matching operation.
|
30
|
+
# The Proc combines all submatcher Procs and returns true only if all match.
|
31
|
+
# For empty conditions, returns TRUE_PROC.
|
32
|
+
#
|
33
|
+
# @return [Proc] a Proc that performs the hash condition matching operation
|
34
|
+
def raw_proc
|
35
|
+
return TRUE_PROC if matchers.empty?
|
36
|
+
|
37
|
+
combine_procs(*matchers.map(&:to_proc))
|
38
|
+
end
|
39
|
+
|
40
|
+
# Recursively combines multiple matcher procs with AND logic.
|
41
|
+
# This method optimizes the combination of multiple matchers by building
|
42
|
+
# a balanced tree of AND operations.
|
43
|
+
#
|
44
|
+
# @param left [Proc] The left matcher proc to combine
|
45
|
+
# @param rest [Array<Proc>] The remaining matcher procs to combine
|
46
|
+
# @return [Proc] A new proc that combines all matchers with AND logic
|
47
|
+
# @example
|
48
|
+
# combine_procs(proc1, proc2, proc3)
|
49
|
+
# #=> proc { |record| proc1.call(record) && proc2.call(record) && proc3.call(record) }
|
50
|
+
def combine_procs(left, *rest)
|
51
|
+
return left if rest.empty?
|
52
|
+
|
53
|
+
right = combine_procs(*rest)
|
54
|
+
Proc.new do |record|
|
55
|
+
left.call(record) && right.call(record)
|
43
56
|
end
|
44
57
|
end
|
45
58
|
|
46
|
-
#
|
47
|
-
#
|
59
|
+
# Returns the list of matchers for each key-value pair in the condition.
|
60
|
+
#
|
61
|
+
# For each pair:
|
62
|
+
# - If the key is a registered operator, uses the corresponding matcher
|
63
|
+
# - Otherwise, wraps the value in a FieldMatcher for field path matching
|
48
64
|
#
|
49
|
-
# @return [
|
50
|
-
|
51
|
-
|
65
|
+
# @return [Array<AbstractMatcher>] List of matchers for each condition
|
66
|
+
define_instance_cache_method(:matchers) do
|
67
|
+
@condition.map do |key, value|
|
68
|
+
if (matcher_class = Matchers.lookup(key))
|
69
|
+
matcher_class.build(value, context: @context)
|
70
|
+
else
|
71
|
+
FieldMatcher.build(key, value, context: @context)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def check_validity!
|
77
|
+
return super if @condition.is_a?(Hash)
|
78
|
+
|
79
|
+
raise TypeError, 'condition needs a Hash.'
|
52
80
|
end
|
53
81
|
end
|
54
82
|
end
|
@@ -24,26 +24,33 @@ module Mongory
|
|
24
24
|
#
|
25
25
|
# @see AbstractMatcher
|
26
26
|
class InMatcher < AbstractMatcher
|
27
|
-
#
|
28
|
-
#
|
27
|
+
# Creates a raw Proc that performs the in-matching operation.
|
28
|
+
# The Proc checks if any element of the record is in the condition array.
|
29
29
|
#
|
30
|
-
# @
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
30
|
+
# @return [Proc] a Proc that performs the in-matching operation
|
31
|
+
def raw_proc
|
32
|
+
condition = @condition
|
33
|
+
|
34
|
+
Proc.new do |record|
|
35
|
+
if record.is_a?(Array)
|
36
|
+
return false if condition.is_a?(Range)
|
37
|
+
|
38
|
+
is_present?(condition & record)
|
39
|
+
else
|
40
|
+
condition.include?(record)
|
41
|
+
end
|
38
42
|
end
|
39
43
|
end
|
40
44
|
|
41
|
-
# Ensures the condition is an array.
|
45
|
+
# Ensures the condition is an array or range.
|
42
46
|
#
|
43
|
-
# @raise [TypeError] if condition is not an array
|
47
|
+
# @raise [TypeError] if condition is not an array nor a range
|
44
48
|
# @return [void]
|
45
49
|
def check_validity!
|
46
|
-
|
50
|
+
return if @condition.is_a?(Array)
|
51
|
+
return if @condition.is_a?(Range)
|
52
|
+
|
53
|
+
raise TypeError, '$in needs an array or range'
|
47
54
|
end
|
48
55
|
end
|
49
56
|
|