qo 0.2.0 → 0.2.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.
Files changed (44) hide show
  1. checksums.yaml +5 -5
  2. data/.yardopts +3 -0
  3. data/README.md +35 -2
  4. data/Rakefile +65 -13
  5. data/docs/Qo.html +165 -0
  6. data/docs/Qo/Exceptions.html +160 -0
  7. data/docs/Qo/Exceptions/MultipleMatchersProvided.html +257 -0
  8. data/docs/Qo/Exceptions/NoMatchersProvided.html +257 -0
  9. data/docs/Qo/Exceptions/NotAllGuardMatchersProvided.html +260 -0
  10. data/docs/Qo/Helpers.html +382 -0
  11. data/docs/Qo/Matchers.html +169 -0
  12. data/docs/Qo/Matchers/ArrayMatcher.html +459 -0
  13. data/docs/Qo/Matchers/BaseMatcher.html +493 -0
  14. data/docs/Qo/Matchers/GuardBlockMatcher.html +471 -0
  15. data/docs/Qo/Matchers/HashMatcher.html +445 -0
  16. data/docs/Qo/Matchers/PatternMatch.html +551 -0
  17. data/docs/Qo/PublicApi.html +867 -0
  18. data/docs/_index.html +258 -0
  19. data/docs/class_list.html +51 -0
  20. data/docs/css/common.css +1 -0
  21. data/docs/css/full_list.css +58 -0
  22. data/docs/css/style.css +499 -0
  23. data/docs/file.README.html +701 -0
  24. data/docs/file_list.html +56 -0
  25. data/docs/frames.html +17 -0
  26. data/docs/img/qo_logo.png +0 -0
  27. data/docs/index.html +701 -0
  28. data/docs/js/app.js +248 -0
  29. data/docs/js/full_list.js +216 -0
  30. data/docs/js/jquery.js +4 -0
  31. data/docs/method_list.html +227 -0
  32. data/docs/top-level-namespace.html +110 -0
  33. data/img/whoa_lemur.png +0 -0
  34. data/lib/qo/exceptions.rb +8 -4
  35. data/lib/qo/matchers/array_matcher.rb +34 -12
  36. data/lib/qo/matchers/base_matcher.rb +26 -11
  37. data/lib/qo/matchers/guard_block_matcher.rb +17 -3
  38. data/lib/qo/matchers/hash_matcher.rb +32 -23
  39. data/lib/qo/matchers/pattern_match.rb +2 -1
  40. data/lib/qo/public_api.rb +6 -5
  41. data/lib/qo/version.rb +1 -1
  42. data/performance_report.txt +73 -24
  43. data/qo.gemspec +2 -0
  44. metadata +61 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: dcbbe9e009a9ccf04769b8ccb7eca4343ea972a5
4
- data.tar.gz: 53dae10eca53508dacfb75ad940207f0f047d288
2
+ SHA256:
3
+ metadata.gz: 11b6629bbb972894e4d1ebc01916769e14a70ec4dbc0d197f990d2c6849d3ffa
4
+ data.tar.gz: d609ce71af4795164999b2219f3e70892c09c0eaca4174d73d79bc3e2d988231
5
5
  SHA512:
6
- metadata.gz: 62bceca4a54804a1e18c86a26802e3903693a61d213fa27b959e0e6a362b54470aeb22f45101ebd8b73cb5dfa90a7c1214c7d78574d3a366a679734744005007
7
- data.tar.gz: 40a0319fa994a9e82e1f55001deab434e95187819efc1ef5eaa6bdd9be015987c481b7b7097b00820974cdc43eeed815fc4b9f7d442f5388b1881549ad00eb62
6
+ metadata.gz: c44fe7b89ec3da320eca4007f0b207da6d2300999c23c167c494e281bbe96c7449f88419d1eec29dcc9f5bc987df3ecea9b1bb0b88afa7968c6e2f3d94b12237
7
+ data.tar.gz: c4e5e607debf592180547d4f7180251e38cc09958a5a2f4961ebbe91c4a52416fb2a2ceeb26c7ba0076e24999c7333716141649aace38d4152931040d8b1dc7d
@@ -0,0 +1,3 @@
1
+ --markup=markdown
2
+ --asset img:img
3
+ --output-dir docs
data/README.md CHANGED
@@ -4,10 +4,12 @@
4
4
  [![Maintainability](https://api.codeclimate.com/v1/badges/186e9cbb7003842acaf0/maintainability)](https://codeclimate.com/github/baweaver/qo/maintainability)
5
5
  [![Gem Version](https://badge.fury.io/rb/qo.svg)](https://badge.fury.io/rb/qo)
6
6
 
7
- Short for Query Object, my play at Ruby pattern matching and fluent querying
7
+ Short for Query Object, my play at Ruby pattern matching and fluent querying, [pronounced "Q-whoah"](img/whoa_lemur.png).
8
8
 
9
9
  ![Qo Lemur logo](img/qo_logo.png)
10
10
 
11
+ [Read the Docs for more detailed information](https://baweaver.github.io/qo/)
12
+
11
13
  ## How does it work?
12
14
 
13
15
  Mostly by using Ruby language features like `to_proc` and `===`.
@@ -537,7 +539,7 @@ Qo.count_by([1,2,3,2,2,2,1], &:even?)
537
539
 
538
540
  These examples will grow over the next few weeks as I think of more fun things to do with Qo. PRs welcome if you find fun uses!
539
541
 
540
- #### 5.1 - JSON
542
+ #### 5.1 - JSON and HTTP
541
543
 
542
544
  > Note that Qo does not support deep querying of hashes (yet)
543
545
 
@@ -581,6 +583,37 @@ users.select(&Qo.and(
581
583
 
582
584
  Nifty!
583
585
 
586
+ ##### Yield Self HTTP status matching
587
+
588
+ You can even use `#yield_self` to pipe values into a pattern matching block. In
589
+ this particular case it'll let you check against the type signatures of the
590
+ HTTP responses.
591
+
592
+ ```ruby
593
+ def get_url(url)
594
+ Net::HTTP.get_response(URI(url)).yield_self(&Qo.match(
595
+ Qo.m(Net::HTTPSuccess) { |response| response.body.size },
596
+ Qo.m(:*) { |response| raise response.message }
597
+ ))
598
+ end
599
+
600
+ get_url('https://github.com/baweaver/qo')
601
+ # => 142387
602
+ get_url('https://github.com/baweaver/qo/does_not_exist')
603
+ # => RuntimeError: Not Found
604
+ ```
605
+
606
+ The difference between this and case? Well, the first is you can pass this to
607
+ `yield_self` for a more inline solution. The second is that any Qo matcher can
608
+ be used in there, including predicate and content checks on the body:
609
+
610
+ ```ruby
611
+ Qo.m(Net::HTTPSuccess, body: /Qo/)
612
+ ```
613
+
614
+ You could put as many checks as you want in there, or use different Qo matchers
615
+ nested to get even further in.
616
+
584
617
  #### 5.2 - Opsy Stuff
585
618
 
586
619
  ##### 5.2.1 - NMap
data/Rakefile CHANGED
@@ -22,6 +22,13 @@ task :default => :spec
22
22
  def run_benchmark(title, **benchmarks)
23
23
  puts '', title, '=' * title.size, ''
24
24
 
25
+ # Validation
26
+ benchmarks.each do |benchmark_name, benchmark_fn|
27
+ puts "#{benchmark_name} result: #{benchmark_fn.call()}"
28
+ end
29
+
30
+ puts
31
+
25
32
  Benchmark.ips do |bm|
26
33
  benchmarks.each do |benchmark_name, benchmark_fn|
27
34
  bm.report(benchmark_name, &benchmark_fn)
@@ -31,10 +38,14 @@ def run_benchmark(title, **benchmarks)
31
38
  end
32
39
  end
33
40
 
41
+ def xrun_benchmark(title, **benchmarks) end
42
+
34
43
  # Note that the current development of Qo is NOT to be performance first, it's to
35
44
  # be readability first with performance coming later. That means that early iterations
36
45
  # may well be slower, but the net expressiveness we get is worth it in the short run.
37
46
  task :perf do
47
+ puts "Running on Qo v#{Qo::VERSION} at commit #{`git rev-parse HEAD`}"
48
+
38
49
  # Compare simple array equality. I almost think this isn't fair to Qo considering
39
50
  # no sane dev should use it for literal 1 to 1 matches like this.
40
51
 
@@ -45,7 +56,7 @@ task :perf do
45
56
  },
46
57
 
47
58
  'Qo.and': -> {
48
- Qo.and(*simple_array).call(simple_array)
59
+ Qo.and(1, 1).call(simple_array)
49
60
  }
50
61
  )
51
62
 
@@ -61,7 +72,7 @@ task :perf do
61
72
  },
62
73
 
63
74
  'Qo.and': -> {
64
- Qo.and(*range_match_set).call(range_match_target)
75
+ Qo.and(1..10, 1..10, 1..10, 1..10).call(range_match_target)
65
76
  }
66
77
  )
67
78
 
@@ -101,7 +112,37 @@ task :perf do
101
112
  },
102
113
 
103
114
  'Qo.and': -> {
104
- Qo.and(*people_array_query).call(people_array_target)
115
+ people_array_target.select(&Qo.and(/Rob/, 15..25))
116
+ }
117
+ )
118
+
119
+ people_hashes = people_array_target.map { |(name, age)| {name: name, age: age} }
120
+
121
+ run_benchmark('Hash * Hash - Hash intersection',
122
+ 'Vanilla': -> {
123
+ people_hashes.select { |person| (15..25).include?(person[:age]) && /Rob/ =~ person[:name] }
124
+ },
125
+
126
+ 'Qo.and': -> {
127
+ people_hashes.select(&Qo.and(name: /Rob/, age: 15..25))
128
+ }
129
+ )
130
+
131
+ Person = Struct.new(:name, :age)
132
+ people = [
133
+ Person.new('Robert', 22),
134
+ Person.new('Roberta', 22),
135
+ Person.new('Foo', 42),
136
+ Person.new('Bar', 17)
137
+ ]
138
+
139
+ run_benchmark('Hash * Object - Property match',
140
+ 'Vanilla': -> {
141
+ people.select { |person| (15..25).include?(person.age) && /Rob/ =~ person.name }
142
+ },
143
+
144
+ 'Qo.and': -> {
145
+ people.select(&Qo.and(name: /Rob/, age: 15..25))
105
146
  }
106
147
  )
107
148
  end
@@ -117,6 +158,17 @@ end
117
158
  # of the 2.4+ bug of lambdas not destructuring automatically, which will wreak
118
159
  # havoc on hash matchers.
119
160
 
161
+ task :kwargs_vs_positional do
162
+ def add_kw(a:, b:, c:, d:) a + b + c + d end
163
+
164
+ def add_pos(a,b,c,d) a + b + c + d end
165
+
166
+ run_benchmark('Positional vs KW Args',
167
+ 'keyword': -> { add_kw(a: 1, b: 2, c: 3, d: 4) },
168
+ 'positional': -> { add_pos(1,2,3,4) }
169
+ )
170
+ end
171
+
120
172
  task :perf_predicates do
121
173
  array = (1..1000).to_a
122
174
 
@@ -154,18 +206,18 @@ task :perf_predicates do
154
206
  end
155
207
 
156
208
  task :perf_random do
157
- # run_benchmark('Empty on blank array',
158
- # 'empty?': -> { [].empty? },
159
- # 'size == 0': -> { [].size == 0 },
160
- # 'size.zero?': -> { [].size.zero? },
161
- # )
209
+ run_benchmark('Empty on blank array',
210
+ 'empty?': -> { [].empty? },
211
+ 'size == 0': -> { [].size == 0 },
212
+ 'size.zero?': -> { [].size.zero? },
213
+ )
162
214
 
163
215
  array = (1..1000).to_a
164
- # run_benchmark('Empty on several elements array',
165
- # 'empty?': -> { array.empty? },
166
- # 'size == 0': -> { array.size == 0 },
167
- # 'size.zero?': -> { array.size.zero? },
168
- # )
216
+ run_benchmark('Empty on several elements array',
217
+ 'empty?': -> { array.empty? },
218
+ 'size == 0': -> { array.size == 0 },
219
+ 'size.zero?': -> { array.size.zero? },
220
+ )
169
221
 
170
222
  hash = array.map { |v| [v, v] }.to_h
171
223
 
@@ -0,0 +1,165 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>
7
+ Module: Qo
8
+
9
+ &mdash; Documentation by YARD 0.9.12
10
+
11
+ </title>
12
+
13
+ <link rel="stylesheet" href="css/style.css" type="text/css" charset="utf-8" />
14
+
15
+ <link rel="stylesheet" href="css/common.css" type="text/css" charset="utf-8" />
16
+
17
+ <script type="text/javascript" charset="utf-8">
18
+ pathId = "Qo";
19
+ relpath = '';
20
+ </script>
21
+
22
+
23
+ <script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
24
+
25
+ <script type="text/javascript" charset="utf-8" src="js/app.js"></script>
26
+
27
+
28
+ </head>
29
+ <body>
30
+ <div class="nav_wrap">
31
+ <iframe id="nav" src="class_list.html?1"></iframe>
32
+ <div id="resizer"></div>
33
+ </div>
34
+
35
+ <div id="main" tabindex="-1">
36
+ <div id="header">
37
+ <div id="menu">
38
+
39
+ <a href="_index.html">Index (Q)</a> &raquo;
40
+
41
+
42
+ <span class="title">Qo</span>
43
+
44
+ </div>
45
+
46
+ <div id="search">
47
+
48
+ <a class="full_list_link" id="class_list_link"
49
+ href="class_list.html">
50
+
51
+ <svg width="24" height="24">
52
+ <rect x="0" y="4" width="24" height="4" rx="1" ry="1"></rect>
53
+ <rect x="0" y="12" width="24" height="4" rx="1" ry="1"></rect>
54
+ <rect x="0" y="20" width="24" height="4" rx="1" ry="1"></rect>
55
+ </svg>
56
+ </a>
57
+
58
+ </div>
59
+ <div class="clear"></div>
60
+ </div>
61
+
62
+ <div id="content"><h1>Module: Qo
63
+
64
+
65
+
66
+ </h1>
67
+ <div class="box_info">
68
+
69
+
70
+
71
+
72
+ <dl>
73
+ <dt>Extended by:</dt>
74
+ <dd><span class='object_link'><a href="Qo/Exceptions.html" title="Qo::Exceptions (module)">Exceptions</a></span>, <span class='object_link'><a href="Qo/Helpers.html" title="Qo::Helpers (module)">Helpers</a></span>, <span class='object_link'><a href="Qo/PublicApi.html" title="Qo::PublicApi (module)">PublicApi</a></span></dd>
75
+ </dl>
76
+
77
+
78
+
79
+
80
+
81
+
82
+
83
+
84
+ <dl>
85
+ <dt>Defined in:</dt>
86
+ <dd>lib/qo.rb<span class="defines">,<br />
87
+ lib/qo/helpers.rb,<br /> lib/qo/version.rb,<br /> lib/qo/exceptions.rb,<br /> lib/qo/public_api.rb,<br /> lib/qo/matchers/base_matcher.rb,<br /> lib/qo/matchers/hash_matcher.rb,<br /> lib/qo/matchers/array_matcher.rb,<br /> lib/qo/matchers/pattern_match.rb,<br /> lib/qo/matchers/guard_block_matcher.rb</span>
88
+ </dd>
89
+ </dl>
90
+
91
+ </div>
92
+
93
+ <h2>Defined Under Namespace</h2>
94
+ <p class="children">
95
+
96
+
97
+ <strong class="modules">Modules:</strong> <span class='object_link'><a href="Qo/Exceptions.html" title="Qo::Exceptions (module)">Exceptions</a></span>, <span class='object_link'><a href="Qo/Helpers.html" title="Qo::Helpers (module)">Helpers</a></span>, <span class='object_link'><a href="Qo/Matchers.html" title="Qo::Matchers (module)">Matchers</a></span>, <span class='object_link'><a href="Qo/PublicApi.html" title="Qo::PublicApi (module)">PublicApi</a></span>
98
+
99
+
100
+
101
+
102
+ </p>
103
+
104
+ <h2>Constant Summary</h2>
105
+ <dl class="constants">
106
+
107
+ <dt id="WILDCARD_MATCH-constant" class="">WILDCARD_MATCH =
108
+
109
+ </dt>
110
+ <dd><pre class="code"><span class='symbol'>:*</span></pre></dd>
111
+
112
+ <dt id="VERSION-constant" class="">VERSION =
113
+
114
+ </dt>
115
+ <dd><pre class="code"><span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>0.2.0</span><span class='tstring_end'>&#39;</span></span></pre></dd>
116
+
117
+ </dl>
118
+
119
+
120
+
121
+
122
+
123
+
124
+
125
+
126
+
127
+
128
+
129
+
130
+
131
+
132
+ <h2>Method Summary</h2>
133
+
134
+ <h3 class="inherited">Methods included from <span class='object_link'><a href="Qo/PublicApi.html" title="Qo::PublicApi (module)">PublicApi</a></span></h3>
135
+ <p class="inherited"><span class='object_link'><a href="Qo/PublicApi.html#and-instance_method" title="Qo::PublicApi#and (method)">and</a></span>, <span class='object_link'><a href="Qo/PublicApi.html#match-instance_method" title="Qo::PublicApi#match (method)">match</a></span>, <span class='object_link'><a href="Qo/PublicApi.html#matcher-instance_method" title="Qo::PublicApi#matcher (method)">matcher</a></span>, <span class='object_link'><a href="Qo/PublicApi.html#not-instance_method" title="Qo::PublicApi#not (method)">not</a></span>, <span class='object_link'><a href="Qo/PublicApi.html#or-instance_method" title="Qo::PublicApi#or (method)">or</a></span></p>
136
+
137
+
138
+
139
+
140
+
141
+
142
+
143
+
144
+
145
+
146
+
147
+
148
+
149
+
150
+
151
+ <h3 class="inherited">Methods included from <span class='object_link'><a href="Qo/Helpers.html" title="Qo::Helpers (module)">Helpers</a></span></h3>
152
+ <p class="inherited"><span class='object_link'><a href="Qo/Helpers.html#count_by-instance_method" title="Qo::Helpers#count_by (method)">count_by</a></span>, <span class='object_link'><a href="Qo/Helpers.html#dig-instance_method" title="Qo::Helpers#dig (method)">dig</a></span></p>
153
+
154
+
155
+ </div>
156
+
157
+ <div id="footer">
158
+ Generated on Sun Apr 15 20:29:44 2018 by
159
+ <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
160
+ 0.9.12 (ruby-2.4.4).
161
+ </div>
162
+
163
+ </div>
164
+ </body>
165
+ </html>
@@ -0,0 +1,160 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>
7
+ Module: Qo::Exceptions
8
+
9
+ &mdash; Documentation by YARD 0.9.12
10
+
11
+ </title>
12
+
13
+ <link rel="stylesheet" href="../css/style.css" type="text/css" charset="utf-8" />
14
+
15
+ <link rel="stylesheet" href="../css/common.css" type="text/css" charset="utf-8" />
16
+
17
+ <script type="text/javascript" charset="utf-8">
18
+ pathId = "Qo::Exceptions";
19
+ relpath = '../';
20
+ </script>
21
+
22
+
23
+ <script type="text/javascript" charset="utf-8" src="../js/jquery.js"></script>
24
+
25
+ <script type="text/javascript" charset="utf-8" src="../js/app.js"></script>
26
+
27
+
28
+ </head>
29
+ <body>
30
+ <div class="nav_wrap">
31
+ <iframe id="nav" src="../class_list.html?1"></iframe>
32
+ <div id="resizer"></div>
33
+ </div>
34
+
35
+ <div id="main" tabindex="-1">
36
+ <div id="header">
37
+ <div id="menu">
38
+
39
+ <a href="../_index.html">Index (E)</a> &raquo;
40
+ <span class='title'><span class='object_link'><a href="../Qo.html" title="Qo (module)">Qo</a></span></span>
41
+ &raquo;
42
+ <span class="title">Exceptions</span>
43
+
44
+ </div>
45
+
46
+ <div id="search">
47
+
48
+ <a class="full_list_link" id="class_list_link"
49
+ href="../class_list.html">
50
+
51
+ <svg width="24" height="24">
52
+ <rect x="0" y="4" width="24" height="4" rx="1" ry="1"></rect>
53
+ <rect x="0" y="12" width="24" height="4" rx="1" ry="1"></rect>
54
+ <rect x="0" y="20" width="24" height="4" rx="1" ry="1"></rect>
55
+ </svg>
56
+ </a>
57
+
58
+ </div>
59
+ <div class="clear"></div>
60
+ </div>
61
+
62
+ <div id="content"><h1>Module: Qo::Exceptions
63
+
64
+
65
+
66
+ </h1>
67
+ <div class="box_info">
68
+
69
+
70
+
71
+
72
+
73
+
74
+
75
+
76
+
77
+ <dl>
78
+ <dt>Included in:</dt>
79
+ <dd><span class='object_link'><a href="../Qo.html" title="Qo (module)">Qo</a></span>, <span class='object_link'><a href="PublicApi.html" title="Qo::PublicApi (module)">PublicApi</a></span></dd>
80
+ </dl>
81
+
82
+
83
+
84
+ <dl>
85
+ <dt>Defined in:</dt>
86
+ <dd>lib/qo/exceptions.rb</dd>
87
+ </dl>
88
+
89
+ </div>
90
+
91
+ <h2>Overview</h2><div class="docstring">
92
+ <div class="discussion">
93
+ <p>Defines common exception classes for use throughout the library</p>
94
+
95
+
96
+ </div>
97
+ </div>
98
+ <div class="tags">
99
+
100
+ <p class="tag_title">Author:</p>
101
+ <ul class="author">
102
+
103
+ <li>
104
+
105
+
106
+
107
+
108
+
109
+ <div class='inline'><p>baweaver</p>
110
+ </div>
111
+
112
+ </li>
113
+
114
+ </ul>
115
+ <p class="tag_title">Since:</p>
116
+ <ul class="since">
117
+
118
+ <li>
119
+
120
+
121
+
122
+
123
+
124
+ <div class='inline'><p>0.2.0</p>
125
+ </div>
126
+
127
+ </li>
128
+
129
+ </ul>
130
+
131
+ </div><h2>Defined Under Namespace</h2>
132
+ <p class="children">
133
+
134
+
135
+
136
+
137
+ <strong class="classes">Classes:</strong> <span class='object_link'><a href="Exceptions/MultipleMatchersProvided.html" title="Qo::Exceptions::MultipleMatchersProvided (class)">MultipleMatchersProvided</a></span>, <span class='object_link'><a href="Exceptions/NoMatchersProvided.html" title="Qo::Exceptions::NoMatchersProvided (class)">NoMatchersProvided</a></span>, <span class='object_link'><a href="Exceptions/NotAllGuardMatchersProvided.html" title="Qo::Exceptions::NotAllGuardMatchersProvided (class)">NotAllGuardMatchersProvided</a></span>
138
+
139
+
140
+ </p>
141
+
142
+
143
+
144
+
145
+
146
+
147
+
148
+
149
+
150
+ </div>
151
+
152
+ <div id="footer">
153
+ Generated on Sun Apr 15 20:29:44 2018 by
154
+ <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
155
+ 0.9.12 (ruby-2.4.4).
156
+ </div>
157
+
158
+ </div>
159
+ </body>
160
+ </html>