qo 0.1.9 → 0.1.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.
- checksums.yaml +5 -5
- data/.travis.yml +3 -1
- data/README.md +4 -0
- data/lib/qo/guard_block_matcher.rb +2 -2
- data/lib/qo/matcher.rb +104 -34
- data/lib/qo/version.rb +1 -1
- data/performance_report.txt +24 -24
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1af9159c107b7761e1b30c7062b108e692403067
|
4
|
+
data.tar.gz: 483b4e35c8c9bba6a7e84c7516ea3e8a1de6e5b2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3db647525ff5685025108dacbe62b7945f135399d56c8a68eb9f39eb63dda3704614da143608a97d66251754c7d57c97d69d5e1a0d73f0c56e5d256cf813acdf
|
7
|
+
data.tar.gz: 72582ba2f1d0f81d149e2f0b9e3d35d10dcb929418c2cde4f88d3773a734f93c7e78594dc59689058f8de0d2cf3edfbc9dc7bb448ec7cfe9bda237fe101a07d0
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
# Qo
|
2
2
|
|
3
|
+
[](https://travis-ci.org/baweaver/qo)
|
4
|
+
[](https://codeclimate.com/github/baweaver/qo/maintainability)
|
5
|
+
[](https://badge.fury.io/rb/qo)
|
6
|
+
|
3
7
|
Short for Query Object, my play at Ruby pattern matching and fluent querying
|
4
8
|
|
5
9
|

|
data/lib/qo/matcher.rb
CHANGED
@@ -45,9 +45,15 @@ module Qo
|
|
45
45
|
Proc.new { |match_target|
|
46
46
|
next true if matchers == match_target
|
47
47
|
|
48
|
-
match_target.is_a?(::Array)
|
49
|
-
|
50
|
-
|
48
|
+
if match_target.is_a?(::Array)
|
49
|
+
match_collection = matchers.each_with_index
|
50
|
+
match_fn = array_against_array_matcher(match_target)
|
51
|
+
else
|
52
|
+
match_collection = matchers
|
53
|
+
match_fn = array_against_object_matcher(match_target)
|
54
|
+
end
|
55
|
+
|
56
|
+
match_with(match_collection, match_fn)
|
51
57
|
}
|
52
58
|
end
|
53
59
|
|
@@ -64,9 +70,11 @@ module Qo
|
|
64
70
|
Proc.new { |match_target|
|
65
71
|
next true if matchers == match_target
|
66
72
|
|
67
|
-
match_target.is_a?(::Hash) ?
|
68
|
-
|
69
|
-
|
73
|
+
match_fn = match_target.is_a?(::Hash) ?
|
74
|
+
hash_against_hash_matcher(match_target) :
|
75
|
+
hash_against_object_matcher(match_target)
|
76
|
+
|
77
|
+
match_with(matchers, match_fn)
|
70
78
|
}
|
71
79
|
end
|
72
80
|
|
@@ -92,8 +100,8 @@ module Qo
|
|
92
100
|
# Any -> Int -> Bool # Match against wildcard or same position in target array
|
93
101
|
private def array_against_array_matcher(match_target)
|
94
102
|
Proc.new { |matcher, i|
|
95
|
-
wildcard_match(matcher) ||
|
96
|
-
case_match(match_target[i], matcher) ||
|
103
|
+
wildcard_match?(matcher) ||
|
104
|
+
case_match?(match_target[i], matcher) ||
|
97
105
|
method_matches?(match_target[i], matcher)
|
98
106
|
}
|
99
107
|
end
|
@@ -106,8 +114,8 @@ module Qo
|
|
106
114
|
# String | Symbol -> Bool # Match against wildcard or boolean return of a predicate method
|
107
115
|
private def array_against_object_matcher(match_target)
|
108
116
|
Proc.new { |matcher|
|
109
|
-
wildcard_match(matcher) ||
|
110
|
-
case_match(match_target, matcher) ||
|
117
|
+
wildcard_match?(matcher) ||
|
118
|
+
case_match?(match_target, matcher) ||
|
111
119
|
method_matches?(match_target, matcher)
|
112
120
|
}
|
113
121
|
end
|
@@ -120,22 +128,12 @@ module Qo
|
|
120
128
|
# Any -> Any -> Bool # Matches against wildcard or a key and value. Coerces key to_s if no matches for JSON.
|
121
129
|
private def hash_against_hash_matcher(match_target)
|
122
130
|
Proc.new { |(match_key, match_value)|
|
123
|
-
next
|
131
|
+
next true if hash_wildcard_match?(match_target, match_key, match_value)
|
124
132
|
|
125
|
-
|
126
|
-
if match_value.is_a?(Hash) && match_target.is_a?(Hash)
|
127
|
-
next match_against_hash(match_value)[match_target[match_key]]
|
128
|
-
end
|
133
|
+
next hash_recurse(match_target[match_key], match_value) if hash_should_recurse?(match_target, match_value)
|
129
134
|
|
130
|
-
|
131
|
-
|
132
|
-
method_matches?(match_target[match_key], match_value) || (
|
133
|
-
# This is done for JSON responses, but as key can be `Any` we don't want to assume it knows how
|
134
|
-
# to coerce `to_s` either. It's more of a nicety function.
|
135
|
-
match_key.respond_to?(:to_s) &&
|
136
|
-
match_target.key?(match_key.to_s) &&
|
137
|
-
case_match(match_target[match_key.to_s], match_value)
|
138
|
-
)
|
135
|
+
hash_case_match?(match_target, match_key, match_value) ||
|
136
|
+
hash_method_case_match?(match_target, match_key, match_value)
|
139
137
|
}
|
140
138
|
end
|
141
139
|
|
@@ -147,11 +145,8 @@ module Qo
|
|
147
145
|
# Any -> Any -> Bool # Matches against wildcard or match value versus the public send return of the target
|
148
146
|
private def hash_against_object_matcher(match_target)
|
149
147
|
Proc.new { |(match_key, match_value)|
|
150
|
-
|
151
|
-
|
152
|
-
wildcard_match(match_value) ||
|
153
|
-
case_match(method_send(match_target, match_key), match_value) ||
|
154
|
-
method_matches?(method_send(match_target, match_key), match_value)
|
148
|
+
object_wildcard_match?(match_target, match_key, match_value) ||
|
149
|
+
hash_method_case_match?(match_target, match_key, match_value)
|
155
150
|
}
|
156
151
|
end
|
157
152
|
|
@@ -196,21 +191,96 @@ module Qo
|
|
196
191
|
# like IPAddr, and I kinda want to use that.
|
197
192
|
#
|
198
193
|
# @return [Boolean]
|
199
|
-
private def wildcard_match(value)
|
194
|
+
private def wildcard_match?(value)
|
200
195
|
value == WILDCARD_MATCH rescue false
|
201
196
|
end
|
202
197
|
|
198
|
+
# Wraps strict checks on keys with a wildcard match
|
199
|
+
#
|
200
|
+
# @param match_target [Hash]
|
201
|
+
# @param match_key [Symbol]
|
202
|
+
# @param match_value [Any]
|
203
|
+
#
|
204
|
+
# @return [Boolean]
|
205
|
+
private def hash_wildcard_match?(match_target, match_key, match_value)
|
206
|
+
return false unless match_target.key?(match_key)
|
207
|
+
|
208
|
+
wildcard_match?(match_value)
|
209
|
+
end
|
210
|
+
|
211
|
+
# Wraps strict checks for methods existing on objects with a wildcard match
|
212
|
+
#
|
213
|
+
# @param match_target [Hash]
|
214
|
+
# @param match_key [Symbol]
|
215
|
+
# @param match_value [Any]
|
216
|
+
#
|
217
|
+
# @return [Boolean]
|
218
|
+
private def object_wildcard_match?(match_target, match_key, match_value)
|
219
|
+
return false unless match_target.respond_to?(match_key)
|
220
|
+
|
221
|
+
wildcard_match?(match_value)
|
222
|
+
end
|
223
|
+
|
203
224
|
# Wraps a case equality statement to make it a bit easier to read. The
|
204
225
|
# typical left bias of `===` can be confusing reading down a page, so
|
205
226
|
# more of a clarity thing than anything. Also makes for nicer stack traces.
|
206
227
|
#
|
207
|
-
# @param
|
208
|
-
# @param
|
228
|
+
# @param match_target [Any] Target to match against
|
229
|
+
# @param match_value [respond_to?(:===)]
|
209
230
|
# Anything that responds to ===, preferably in a unique and entertaining way.
|
210
231
|
#
|
211
232
|
# @return [Boolean]
|
212
|
-
private def case_match(
|
213
|
-
|
233
|
+
private def case_match?(match_target, match_value)
|
234
|
+
match_value === match_target
|
235
|
+
end
|
236
|
+
|
237
|
+
# Double wraps case match in order to ensure that we try against both Symbol
|
238
|
+
# and String variants of the keys, as this is a very common mixup in Ruby.
|
239
|
+
#
|
240
|
+
# @param match_target [Hash] Target of the match
|
241
|
+
# @param match_key [Symbol] Key to match against
|
242
|
+
# @param match_value [respond_to?(:===)] Matcher
|
243
|
+
#
|
244
|
+
# @return [Boolean]
|
245
|
+
private def hash_case_match?(match_target, match_key, match_value)
|
246
|
+
return true if case_match?(match_target[match_key], match_value)
|
247
|
+
|
248
|
+
match_key.respond_to?(:to_s) &&
|
249
|
+
match_target.key?(match_key.to_s) &&
|
250
|
+
case_match?(match_target[match_key.to_s], match_value)
|
251
|
+
end
|
252
|
+
|
253
|
+
# Attempts to run a case match against a method call derived from a hash
|
254
|
+
# key, and checks the result.
|
255
|
+
#
|
256
|
+
# @param match_target [Hash] Target of the match
|
257
|
+
# @param match_key [Symbol] Method to call
|
258
|
+
# @param match_value [respond_to?(:===)] Matcher
|
259
|
+
#
|
260
|
+
# @return [Boolean]
|
261
|
+
private def hash_method_case_match?(match_target, match_key, match_value)
|
262
|
+
case_match?(method_send(match_target, match_key), match_value)
|
263
|
+
end
|
264
|
+
|
265
|
+
# Defines preconditions for Hash recursion in matching. Currently it's
|
266
|
+
# only Hash and Hash, but may expand later to Arrays and other Enums.
|
267
|
+
#
|
268
|
+
# @param match_target [Any]
|
269
|
+
# @param match_value [Any]
|
270
|
+
#
|
271
|
+
# @return [Boolean]
|
272
|
+
private def hash_should_recurse?(match_target, match_value)
|
273
|
+
match_target.is_a?(Hash) && match_value.is_a?(Hash)
|
274
|
+
end
|
275
|
+
|
276
|
+
# Recurses on nested hashes.
|
277
|
+
#
|
278
|
+
# @param match_target [Hash]
|
279
|
+
# @param match_value [Hash]
|
280
|
+
#
|
281
|
+
# @return [Boolean]
|
282
|
+
private def hash_recurse(match_target, match_value)
|
283
|
+
match_against_hash(match_value).call(match_target)
|
214
284
|
end
|
215
285
|
end
|
216
286
|
end
|
data/lib/qo/version.rb
CHANGED
data/performance_report.txt
CHANGED
@@ -3,58 +3,58 @@ Array * Array - Literal
|
|
3
3
|
=======================
|
4
4
|
|
5
5
|
Warming up --------------------------------------
|
6
|
-
Vanilla
|
7
|
-
Qo.and
|
6
|
+
Vanilla 290.029k i/100ms
|
7
|
+
Qo.and 37.778k i/100ms
|
8
8
|
Calculating -------------------------------------
|
9
|
-
Vanilla
|
10
|
-
Qo.and
|
9
|
+
Vanilla 9.559M (± 2.3%) i/s - 47.855M in 5.009272s
|
10
|
+
Qo.and 468.514k (± 2.5%) i/s - 2.342M in 5.002419s
|
11
11
|
|
12
12
|
Comparison:
|
13
|
-
Vanilla:
|
14
|
-
Qo.and:
|
13
|
+
Vanilla: 9558516.6 i/s
|
14
|
+
Qo.and: 468514.2 i/s - 20.40x slower
|
15
15
|
|
16
16
|
|
17
17
|
Array * Array - Index pattern match
|
18
18
|
===================================
|
19
19
|
|
20
20
|
Warming up --------------------------------------
|
21
|
-
Vanilla
|
22
|
-
Qo.and
|
21
|
+
Vanilla 47.088k i/100ms
|
22
|
+
Qo.and 14.227k i/100ms
|
23
23
|
Calculating -------------------------------------
|
24
|
-
Vanilla
|
25
|
-
Qo.and
|
24
|
+
Vanilla 540.415k (± 3.3%) i/s - 2.731M in 5.059509s
|
25
|
+
Qo.and 149.040k (± 4.2%) i/s - 754.031k in 5.068772s
|
26
26
|
|
27
27
|
Comparison:
|
28
|
-
Vanilla:
|
29
|
-
Qo.and:
|
28
|
+
Vanilla: 540414.9 i/s
|
29
|
+
Qo.and: 149040.0 i/s - 3.63x slower
|
30
30
|
|
31
31
|
|
32
32
|
Array * Object - Predicate match
|
33
33
|
================================
|
34
34
|
|
35
35
|
Warming up --------------------------------------
|
36
|
-
Vanilla
|
37
|
-
Qo.and
|
36
|
+
Vanilla 139.244k i/100ms
|
37
|
+
Qo.and 20.096k i/100ms
|
38
38
|
Calculating -------------------------------------
|
39
|
-
Vanilla 2.
|
40
|
-
Qo.and
|
39
|
+
Vanilla 2.356M (± 3.4%) i/s - 11.836M in 5.030228s
|
40
|
+
Qo.and 218.039k (± 2.9%) i/s - 1.105M in 5.073725s
|
41
41
|
|
42
42
|
Comparison:
|
43
|
-
Vanilla:
|
44
|
-
Qo.and:
|
43
|
+
Vanilla: 2355717.5 i/s
|
44
|
+
Qo.and: 218038.9 i/s - 10.80x slower
|
45
45
|
|
46
46
|
|
47
47
|
Array * Array - Select index pattern match
|
48
48
|
==========================================
|
49
49
|
|
50
50
|
Warming up --------------------------------------
|
51
|
-
Vanilla
|
52
|
-
Qo.and 20.
|
51
|
+
Vanilla 14.015k i/100ms
|
52
|
+
Qo.and 20.325k i/100ms
|
53
53
|
Calculating -------------------------------------
|
54
|
-
Vanilla 140.
|
55
|
-
Qo.and
|
54
|
+
Vanilla 140.673k (± 3.6%) i/s - 714.765k in 5.087715s
|
55
|
+
Qo.and 219.533k (± 3.8%) i/s - 1.098M in 5.006844s
|
56
56
|
|
57
57
|
Comparison:
|
58
|
-
Qo.and:
|
59
|
-
Vanilla:
|
58
|
+
Qo.and: 219533.2 i/s
|
59
|
+
Vanilla: 140672.7 i/s - 1.56x slower
|
60
60
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: qo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brandon Weaver
|
@@ -142,7 +142,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
142
142
|
version: '0'
|
143
143
|
requirements: []
|
144
144
|
rubyforge_project:
|
145
|
-
rubygems_version: 2.
|
145
|
+
rubygems_version: 2.6.14.1
|
146
146
|
signing_key:
|
147
147
|
specification_version: 4
|
148
148
|
summary: Qo is a querying library for Ruby pattern matching
|