qo 0.1.7 → 0.1.8

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: c98fa2c3b82ac4167eba17b183fe1cea46a0e36f
4
- data.tar.gz: ab2527c365781b54fac1290ac64e8a17acdcd07c
3
+ metadata.gz: 594012163edefd5fedd3266382aca2efddd10432
4
+ data.tar.gz: aa376733835f2fa1ce1abbe16018e2b2344f96ad
5
5
  SHA512:
6
- metadata.gz: f1e9b886e694b8c08f212209db40bc8ca1276b738d1d30c81040e0b651f264bcfc9c83a21d82d96f2ff418d05def3e5abae82a29394f184266fab424f5dad4a6
7
- data.tar.gz: ab226ea4d673ea462b2e41084d25c8a61b2c04e37e8aac9354745b1b17c4ae54b5efa6184ae28e0201fa453b525938f4d8f260912300a0f145cc0992607424e1
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
+ ![Qo Lemur logo](img/qo_logo.png)
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
Binary file
@@ -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))
@@ -1,3 +1,3 @@
1
1
  module Qo
2
- VERSION = '0.1.7'
2
+ VERSION = '0.1.8'
3
3
  end
@@ -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
@@ -25,4 +25,5 @@ Gem::Specification.new do |spec|
25
25
  spec.add_development_dependency "rspec", "~> 3.0"
26
26
  spec.add_development_dependency "guard"
27
27
  spec.add_development_dependency "guard-rspec"
28
+ spec.add_development_dependency "benchmark-ips"
28
29
  end
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.7
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-13 00:00:00.000000000 Z
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: