qo 0.1.7 → 0.1.8
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/README.md +3 -1
- data/Rakefile +101 -0
- data/img/qo_logo.png +0 -0
- data/lib/qo/matcher.rb +4 -0
- data/lib/qo/version.rb +1 -1
- data/performance_report.txt +60 -0
- data/qo.gemspec +1 -0
- metadata +18 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 594012163edefd5fedd3266382aca2efddd10432
|
4
|
+
data.tar.gz: aa376733835f2fa1ce1abbe16018e2b2344f96ad
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6db60b6de5c5ab900e6b144ddc3c9ed4eee275781017cc3f36580f1f904b2287ce734378d9d3dc6e0412ac4f62f37166c001c07235ae519373efbb99282c75f6
|
7
|
+
data.tar.gz: 93404e15e4db2dee338f64769e035d2c33f5945e6f1a2c2d53240d5019c2f11b9eceb08af13dcfdb9a540fbe39aa935fb201f08ef8638c7c5f447ea722456923
|
data/README.md
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
Short for Query Object, my play at Ruby pattern matching and fluent querying
|
4
4
|
|
5
|
+

|
6
|
+
|
5
7
|
## How does it work?
|
6
8
|
|
7
9
|
Triple equals black magic, mostly.
|
@@ -505,7 +507,7 @@ To be fair that means anything that can respond to `===`, including classes and
|
|
505
507
|
This ends up coming up a lot, especially around querying, so let's get a way to count by!
|
506
508
|
|
507
509
|
```ruby
|
508
|
-
Qo.count_by([1,2,3,2,2,2,1]
|
510
|
+
Qo.count_by([1,2,3,2,2,2,1])
|
509
511
|
|
510
512
|
# => {
|
511
513
|
# 1 => 2,
|
data/Rakefile
CHANGED
@@ -1,6 +1,107 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
2
|
require "rspec/core/rake_task"
|
3
|
+
require 'benchmark/ips'
|
4
|
+
require 'qo'
|
3
5
|
|
4
6
|
RSpec::Core::RakeTask.new(:spec)
|
5
7
|
|
6
8
|
task :default => :spec
|
9
|
+
|
10
|
+
# Run a benchmark given a title and a set of benchmarks. Admittedly this
|
11
|
+
# is done because the Benchmark.ips code can get a tinge repetitive and this
|
12
|
+
# is easier to write out.
|
13
|
+
#
|
14
|
+
# @param title [String] Title of the benchmark
|
15
|
+
# @param **benchmarks [Hash[Symbol, Proc]] Name to Proc to run to benchmark it
|
16
|
+
#
|
17
|
+
# @note Notice I'm using `'String': -> {}` instead of hashrockets? Kwargs doesn't
|
18
|
+
# take string / hashrocket arguments, probably to prevent abuse of the
|
19
|
+
# "anything can be a key" bit of Ruby.
|
20
|
+
#
|
21
|
+
# @return [Unit] StdOut
|
22
|
+
def run_benchmark(title, **benchmarks)
|
23
|
+
puts '', title, '=' * title.size, ''
|
24
|
+
|
25
|
+
Benchmark.ips do |bm|
|
26
|
+
benchmarks.each do |benchmark_name, benchmark_fn|
|
27
|
+
bm.report(benchmark_name, &benchmark_fn)
|
28
|
+
end
|
29
|
+
|
30
|
+
bm.compare!
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Note that the current development of Qo is NOT to be performance first, it's to
|
35
|
+
# be readability first with performance coming later. That means that early iterations
|
36
|
+
# may well be slower, but the net expressiveness we get is worth it in the short run.
|
37
|
+
task :perf do
|
38
|
+
# Compare simple array equality. I almost think this isn't fair to Qo considering
|
39
|
+
# no sane dev should use it for literal 1 to 1 matches like this.
|
40
|
+
|
41
|
+
simple_array = [1, 1]
|
42
|
+
run_benchmark('Array * Array - Literal',
|
43
|
+
'Vanilla': -> {
|
44
|
+
simple_array == simple_array
|
45
|
+
},
|
46
|
+
|
47
|
+
'Qo.and': -> {
|
48
|
+
Qo.and(*simple_array).call(simple_array)
|
49
|
+
}
|
50
|
+
)
|
51
|
+
|
52
|
+
# Compare testing indexed array matches. This gets a bit more into what Qo does,
|
53
|
+
# though I feel like there are optimizations that could be had here as well.
|
54
|
+
|
55
|
+
range_match_set = [1..10, 1..10, 1..10, 1..10]
|
56
|
+
range_match_target = [1, 2, 3, 4]
|
57
|
+
|
58
|
+
run_benchmark('Array * Array - Index pattern match',
|
59
|
+
'Vanilla': -> {
|
60
|
+
range_match_target.each_with_index.all? { |x, i| range_match_set[i] === x }
|
61
|
+
},
|
62
|
+
|
63
|
+
'Qo.and': -> {
|
64
|
+
Qo.and(*range_match_set).call(range_match_target)
|
65
|
+
}
|
66
|
+
)
|
67
|
+
|
68
|
+
# Now we're getting into things Qo makes sense for. Comparing an entire list
|
69
|
+
# against a stream of predicates to check
|
70
|
+
|
71
|
+
numbers_array = [1, 2.0, 3, 4]
|
72
|
+
|
73
|
+
run_benchmark('Array * Object - Predicate match',
|
74
|
+
'Vanilla': -> {
|
75
|
+
numbers_array.all? { |i| i.is_a?(Integer) && i.even? && (20..30).include?(i) }
|
76
|
+
},
|
77
|
+
|
78
|
+
'Qo.and': -> {
|
79
|
+
numbers_array.all?(&Qo.and(Integer, :even?, 20..30))
|
80
|
+
}
|
81
|
+
)
|
82
|
+
|
83
|
+
# This one is a bit interesting. The vanilla version is written to reflect that
|
84
|
+
# it has NO idea what the length of either set is, which is exactly what Qo
|
85
|
+
# has to deal with as well.
|
86
|
+
|
87
|
+
people_array_target = [
|
88
|
+
['Robert', 22],
|
89
|
+
['Roberta', 22],
|
90
|
+
['Foo', 42],
|
91
|
+
['Bar', 18]
|
92
|
+
]
|
93
|
+
|
94
|
+
people_array_query = [/Rob/, 15..25]
|
95
|
+
|
96
|
+
run_benchmark('Array * Array - Select index pattern match',
|
97
|
+
'Vanilla': -> {
|
98
|
+
people_array_target.select { |person|
|
99
|
+
person.each_with_index.all? { |a, i| people_array_query[i] === a }
|
100
|
+
}
|
101
|
+
},
|
102
|
+
|
103
|
+
'Qo.and': -> {
|
104
|
+
Qo.and(*people_array_query).call(people_array_target)
|
105
|
+
}
|
106
|
+
)
|
107
|
+
end
|
data/img/qo_logo.png
ADDED
Binary file
|
data/lib/qo/matcher.rb
CHANGED
@@ -43,6 +43,8 @@ module Qo
|
|
43
43
|
# Object -> Bool # Boolean public send
|
44
44
|
private def match_against_array(matchers)
|
45
45
|
-> match_target {
|
46
|
+
return true if matchers == match_target
|
47
|
+
|
46
48
|
match_target.is_a?(::Array) ?
|
47
49
|
match_with(matchers.each_with_index, array_against_array_matcher(match_target)) :
|
48
50
|
match_with(matchers, array_against_object_matcher(match_target))
|
@@ -60,6 +62,8 @@ module Qo
|
|
60
62
|
# Object -> Bool # Uses keys as methods with public send to `===` match against the value
|
61
63
|
private def match_against_hash(matchers)
|
62
64
|
-> match_target {
|
65
|
+
return true if matchers == match_target
|
66
|
+
|
63
67
|
match_target.is_a?(::Hash) ?
|
64
68
|
match_with(matchers, hash_against_hash_matcher(match_target)) :
|
65
69
|
match_with(matchers, hash_against_object_matcher(match_target))
|
data/lib/qo/version.rb
CHANGED
@@ -0,0 +1,60 @@
|
|
1
|
+
|
2
|
+
Array * Array - Literal
|
3
|
+
=======================
|
4
|
+
|
5
|
+
Warming up --------------------------------------
|
6
|
+
Vanilla 289.298k i/100ms
|
7
|
+
Qo.and 39.896k i/100ms
|
8
|
+
Calculating -------------------------------------
|
9
|
+
Vanilla 9.620M (± 2.4%) i/s - 48.313M in 5.025188s
|
10
|
+
Qo.and 456.077k (± 2.3%) i/s - 2.314M in 5.076462s
|
11
|
+
|
12
|
+
Comparison:
|
13
|
+
Vanilla: 9620049.8 i/s
|
14
|
+
Qo.and: 456077.4 i/s - 21.09x slower
|
15
|
+
|
16
|
+
|
17
|
+
Array * Array - Index pattern match
|
18
|
+
===================================
|
19
|
+
|
20
|
+
Warming up --------------------------------------
|
21
|
+
Vanilla 46.056k i/100ms
|
22
|
+
Qo.and 14.514k i/100ms
|
23
|
+
Calculating -------------------------------------
|
24
|
+
Vanilla 528.961k (± 3.0%) i/s - 2.671M in 5.054671s
|
25
|
+
Qo.and 154.299k (± 1.9%) i/s - 783.756k in 5.081304s
|
26
|
+
|
27
|
+
Comparison:
|
28
|
+
Vanilla: 528961.3 i/s
|
29
|
+
Qo.and: 154299.4 i/s - 3.43x slower
|
30
|
+
|
31
|
+
|
32
|
+
Array * Object - Predicate match
|
33
|
+
================================
|
34
|
+
|
35
|
+
Warming up --------------------------------------
|
36
|
+
Vanilla 148.876k i/100ms
|
37
|
+
Qo.and 19.598k i/100ms
|
38
|
+
Calculating -------------------------------------
|
39
|
+
Vanilla 2.385M (± 1.7%) i/s - 12.059M in 5.058028s
|
40
|
+
Qo.and 211.780k (± 1.4%) i/s - 1.078M in 5.090600s
|
41
|
+
|
42
|
+
Comparison:
|
43
|
+
Vanilla: 2384846.4 i/s
|
44
|
+
Qo.and: 211780.0 i/s - 11.26x slower
|
45
|
+
|
46
|
+
|
47
|
+
Array * Array - Select index pattern match
|
48
|
+
==========================================
|
49
|
+
|
50
|
+
Warming up --------------------------------------
|
51
|
+
Vanilla 12.366k i/100ms
|
52
|
+
Qo.and 20.112k i/100ms
|
53
|
+
Calculating -------------------------------------
|
54
|
+
Vanilla 128.645k (± 2.1%) i/s - 643.032k in 5.000638s
|
55
|
+
Qo.and 207.792k (± 7.2%) i/s - 1.046M in 5.061963s
|
56
|
+
|
57
|
+
Comparison:
|
58
|
+
Qo.and: 207792.4 i/s
|
59
|
+
Vanilla: 128645.0 i/s - 1.62x slower
|
60
|
+
|
data/qo.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
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.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brandon Weaver
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-04-
|
11
|
+
date: 2018-04-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -80,6 +80,20 @@ dependencies:
|
|
80
80
|
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: benchmark-ips
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
83
97
|
description:
|
84
98
|
email:
|
85
99
|
- keystonelemur@gmail.com
|
@@ -101,10 +115,12 @@ files:
|
|
101
115
|
- bin/setup
|
102
116
|
- docs/.gitkeep
|
103
117
|
- docs/_config.yml
|
118
|
+
- img/qo_logo.png
|
104
119
|
- lib/qo.rb
|
105
120
|
- lib/qo/guard_block_matcher.rb
|
106
121
|
- lib/qo/matcher.rb
|
107
122
|
- lib/qo/version.rb
|
123
|
+
- performance_report.txt
|
108
124
|
- qo.gemspec
|
109
125
|
homepage: https://www.github.com/baweaver/q
|
110
126
|
licenses:
|