qo 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,56 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
5
+ <meta charset="utf-8" />
6
+
7
+ <link rel="stylesheet" href="css/full_list.css" type="text/css" media="screen" charset="utf-8" />
8
+
9
+ <link rel="stylesheet" href="css/common.css" type="text/css" media="screen" charset="utf-8" />
10
+
11
+
12
+
13
+ <script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
14
+
15
+ <script type="text/javascript" charset="utf-8" src="js/full_list.js"></script>
16
+
17
+
18
+ <title>File List</title>
19
+ <base id="base_target" target="_parent" />
20
+ </head>
21
+ <body>
22
+ <div id="content">
23
+ <div class="fixed_header">
24
+ <h1 id="full_list_header">File List</h1>
25
+ <div id="full_list_nav">
26
+
27
+ <span><a target="_self" href="class_list.html">
28
+ Classes
29
+ </a></span>
30
+
31
+ <span><a target="_self" href="method_list.html">
32
+ Methods
33
+ </a></span>
34
+
35
+ <span><a target="_self" href="file_list.html">
36
+ Files
37
+ </a></span>
38
+
39
+ </div>
40
+
41
+ <div id="search">Search: <input type="text" /></div>
42
+ </div>
43
+
44
+ <ul id="full_list" class="file">
45
+
46
+
47
+ <li id="object_README" class="odd">
48
+ <div class="item"><span class="object_link"><a href="index.html" title="README">README</a></span></div>
49
+ </li>
50
+
51
+
52
+
53
+ </ul>
54
+ </div>
55
+ </body>
56
+ </html>
@@ -0,0 +1,17 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>Documentation by YARD 0.9.12</title>
6
+ </head>
7
+ <script type="text/javascript" charset="utf-8">
8
+ var match = unescape(window.location.hash).match(/^#!(.+)/);
9
+ var name = match ? match[1] : 'index.html';
10
+ name = name.replace(/^(\w+):\/\//, '').replace(/^\/\//, '');
11
+ window.top.location = name;
12
+ </script>
13
+ <noscript>
14
+ <h1>Oops!</h1>
15
+ <h2>YARD requires JavaScript!</h2>
16
+ </noscript>
17
+ </html>
Binary file
@@ -0,0 +1,701 @@
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
+ File: README
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 = "README";
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</a> &raquo;
40
+ <span class="title">File: README</span>
41
+
42
+ </div>
43
+
44
+ <div id="search">
45
+
46
+ <a class="full_list_link" id="class_list_link"
47
+ href="class_list.html">
48
+
49
+ <svg width="24" height="24">
50
+ <rect x="0" y="4" width="24" height="4" rx="1" ry="1"></rect>
51
+ <rect x="0" y="12" width="24" height="4" rx="1" ry="1"></rect>
52
+ <rect x="0" y="20" width="24" height="4" rx="1" ry="1"></rect>
53
+ </svg>
54
+ </a>
55
+
56
+ </div>
57
+ <div class="clear"></div>
58
+ </div>
59
+
60
+ <div id="content"><div id='filecontents'><h1>Qo</h1>
61
+
62
+ <p><a href="https://travis-ci.org/baweaver/qo"><img src="https://travis-ci.org/baweaver/qo.svg?branch=master" alt="Build Status"></a>
63
+ <a href="https://codeclimate.com/github/baweaver/qo/maintainability"><img src="https://api.codeclimate.com/v1/badges/186e9cbb7003842acaf0/maintainability" alt="Maintainability"></a>
64
+ <a href="https://badge.fury.io/rb/qo"><img src="https://badge.fury.io/rb/qo.svg" alt="Gem Version"></a></p>
65
+
66
+ <p>Short for Query Object, my play at Ruby pattern matching and fluent querying</p>
67
+
68
+ <p><img src="img/qo_logo.png" alt="Qo Lemur logo"></p>
69
+
70
+ <h2>How does it work?</h2>
71
+
72
+ <p>Mostly by using Ruby language features like <code>to_proc</code> and <code>===</code>.</p>
73
+
74
+ <p>There&#39;s an article explaining most of the base mechanics behind Qo:</p>
75
+
76
+ <p><a href="https://medium.com/@baweaver/for-want-of-pattern-matching-in-ruby-the-creation-of-qo-c3b267109b25">For Want of Pattern Matching in Ruby - The Creation of Qo</a></p>
77
+
78
+ <p>Most of it, though, utilizes Triple Equals. If you&#39;re not familiar with what all you can do with it in Ruby, I would encourage you to read this article as well:</p>
79
+
80
+ <p><a href="https://medium.com/rubyinside/triple-equals-black-magic-d934936a6379">Triple Equals Black Magic</a></p>
81
+
82
+ <p>The original inspiration was from a chat I&#39;d had with a few other Rubyists about pattern matching, which led to this experiment:</p>
83
+
84
+ <p><a href="https://gist.github.com/baweaver/611389c41c9005d025fb8e55448bf5f5">Having fun with M and Q</a></p>
85
+
86
+ <p>Fast forward a few months and I kind of wanted to make it real, so here it is. Introducing Qo!</p>
87
+
88
+ <h2>Usage</h2>
89
+
90
+ <h3>Quick Start</h3>
91
+
92
+ <p>Qo is used for pattern matching in Ruby. All Qo matchers respond to <code>===</code> and <code>to_proc</code> meaning they can be used with <code>case</code> and Enumerable functions alike:</p>
93
+
94
+ <pre class="code ruby"><code class="ruby"><span class='kw'>case</span> <span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Foo</span><span class='tstring_end'>&#39;</span></span><span class='comma'>,</span> <span class='int'>42</span><span class='rbracket'>]</span>
95
+ <span class='kw'>when</span> <span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='lbracket'>[</span><span class='symbol'>:*</span><span class='comma'>,</span> <span class='int'>42</span><span class='rbracket'>]</span> <span class='kw'>then</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Truly the one answer</span><span class='tstring_end'>&#39;</span></span>
96
+ <span class='kw'>else</span> <span class='kw'>nil</span>
97
+ <span class='kw'>end</span>
98
+
99
+ <span class='comment'># Run a select like an AR query, getting the age attribute against a range
100
+ </span><span class='id identifier rubyid_people'>people</span><span class='period'>.</span><span class='id identifier rubyid_select'>select</span><span class='lparen'>(</span><span class='op'>&amp;</span><span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='lbracket'>[</span><span class='label'>age:</span> <span class='int'>18</span><span class='op'>..</span><span class='int'>30</span><span class='rbracket'>]</span><span class='rparen'>)</span>
101
+
102
+ <span class='comment'># How about some &quot;right-hand assignment&quot; pattern matching
103
+ </span><span class='id identifier rubyid_name_longer_than_three'>name_longer_than_three</span> <span class='op'>=</span> <span class='tlambda'>-&gt;</span> <span class='id identifier rubyid_person'>person</span> <span class='tlambeg'>{</span> <span class='id identifier rubyid_person'>person</span><span class='period'>.</span><span class='id identifier rubyid_name'>name</span><span class='period'>.</span><span class='id identifier rubyid_size'>size</span> <span class='op'>&gt;</span> <span class='int'>3</span> <span class='rbrace'>}</span>
104
+ <span class='id identifier rubyid_people_with_truncated_names'>people_with_truncated_names</span> <span class='op'>=</span> <span class='id identifier rubyid_people'>people</span><span class='period'>.</span><span class='id identifier rubyid_map'>map</span><span class='lparen'>(</span><span class='op'>&amp;</span><span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='period'>.</span><span class='id identifier rubyid_match'><span class='object_link'><a href="Qo/PublicApi.html#match-instance_method" title="Qo::PublicApi#match (method)">match</a></span></span><span class='lparen'>(</span>
105
+ <span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='period'>.</span><span class='id identifier rubyid_m'>m</span><span class='lparen'>(</span><span class='id identifier rubyid_name_longer_than_three'>name_longer_than_three</span><span class='rparen'>)</span> <span class='lbrace'>{</span> <span class='op'>|</span><span class='id identifier rubyid_person'>person</span><span class='op'>|</span> <span class='const'>Person</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span><span class='lparen'>(</span><span class='id identifier rubyid_person'>person</span><span class='period'>.</span><span class='id identifier rubyid_name'>name</span><span class='lbracket'>[</span><span class='int'>0</span><span class='op'>..</span><span class='int'>2</span><span class='rbracket'>]</span><span class='comma'>,</span> <span class='id identifier rubyid_person'>person</span><span class='period'>.</span><span class='id identifier rubyid_age'>age</span><span class='rparen'>)</span> <span class='rbrace'>}</span><span class='comma'>,</span>
106
+ <span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='period'>.</span><span class='id identifier rubyid_m'>m</span><span class='lparen'>(</span><span class='symbol'>:*</span><span class='rparen'>)</span> <span class='comment'># Identity function, catch-all
107
+ </span><span class='rparen'>)</span><span class='rparen'>)</span>
108
+
109
+ <span class='comment'># And standalone like a case:
110
+ </span><span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='period'>.</span><span class='id identifier rubyid_match'><span class='object_link'><a href="Qo/PublicApi.html#match-instance_method" title="Qo::PublicApi#match (method)">match</a></span></span><span class='lparen'>(</span><span class='id identifier rubyid_people'>people</span><span class='period'>.</span><span class='id identifier rubyid_first'>first</span><span class='comma'>,</span>
111
+ <span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='period'>.</span><span class='id identifier rubyid_m'>m</span><span class='lparen'>(</span><span class='label'>age:</span> <span class='int'>10</span><span class='op'>..</span><span class='int'>19</span><span class='rparen'>)</span> <span class='lbrace'>{</span> <span class='op'>|</span><span class='id identifier rubyid_person'>person</span><span class='op'>|</span> <span class='tstring'><span class='tstring_beg'>&quot;</span><span class='embexpr_beg'>#{</span><span class='id identifier rubyid_person'>person</span><span class='period'>.</span><span class='id identifier rubyid_name'>name</span><span class='embexpr_end'>}</span><span class='tstring_content'> is a teen that&#39;s </span><span class='embexpr_beg'>#{</span><span class='id identifier rubyid_person'>person</span><span class='period'>.</span><span class='id identifier rubyid_age'>age</span><span class='embexpr_end'>}</span><span class='tstring_content'> years old</span><span class='tstring_end'>&quot;</span></span> <span class='rbrace'>}</span><span class='comma'>,</span>
112
+ <span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='period'>.</span><span class='id identifier rubyid_m'>m</span><span class='lparen'>(</span><span class='symbol'>:*</span><span class='rparen'>)</span> <span class='lbrace'>{</span> <span class='op'>|</span><span class='id identifier rubyid_person'>person</span><span class='op'>|</span> <span class='tstring'><span class='tstring_beg'>&quot;</span><span class='embexpr_beg'>#{</span><span class='id identifier rubyid_person'>person</span><span class='period'>.</span><span class='id identifier rubyid_name'>name</span><span class='embexpr_end'>}</span><span class='tstring_content'> is </span><span class='embexpr_beg'>#{</span><span class='id identifier rubyid_person'>person</span><span class='period'>.</span><span class='id identifier rubyid_age'>age</span><span class='embexpr_end'>}</span><span class='tstring_content'> years old</span><span class='tstring_end'>&quot;</span></span> <span class='rbrace'>}</span>
113
+ <span class='rparen'>)</span>
114
+ </code></pre>
115
+
116
+ <p>Get a lot more expressiveness in your queries and transformations. Read on for the full details.</p>
117
+
118
+ <h3>Qo&#39;isms</h3>
119
+
120
+ <p>Qo supports three main types of queries: <code>and</code>, <code>or</code>, and <code>not</code>.</p>
121
+
122
+ <p>Most examples are written in terms of <code>and</code> and its alias <code>[]</code>. <code>[]</code> is mostly used for portable syntax:</p>
123
+
124
+ <pre class="code ruby"><code class="ruby"><span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='lbracket'>[</span><span class='tstring'><span class='regexp_beg'>/</span><span class='tstring_content'>Rob</span><span class='regexp_end'>/</span></span><span class='comma'>,</span> <span class='int'>22</span><span class='rbracket'>]</span>
125
+
126
+ <span class='comment'># ...is functionally the same as an and query, which uses `all?` to match
127
+ </span><span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='period'>.</span><span class='id identifier rubyid_and'><span class='object_link'><a href="Qo/PublicApi.html#and-instance_method" title="Qo::PublicApi#and (method)">and</a></span></span><span class='lparen'>(</span><span class='tstring'><span class='regexp_beg'>/</span><span class='tstring_content'>Rob</span><span class='regexp_end'>/</span></span><span class='comma'>,</span> <span class='int'>22</span><span class='rparen'>)</span>
128
+
129
+ <span class='comment'># This is shorthand for
130
+ </span><span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='op'>::</span><span class='const'><span class='object_link'><a href="Qo/Matchers.html" title="Qo::Matchers (module)">Matchers</a></span></span><span class='op'>::</span><span class='const'><span class='object_link'><a href="Qo/Matchers/BaseMatcher.html" title="Qo::Matchers::BaseMatcher (class)">BaseMatcher</a></span></span><span class='period'>.</span><span class='id identifier rubyid_new'><span class='object_link'><a href="Qo/Matchers/BaseMatcher.html#initialize-instance_method" title="Qo::Matchers::BaseMatcher#initialize (method)">new</a></span></span><span class='lparen'>(</span><span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>and</span><span class='tstring_end'>&#39;</span></span><span class='comma'>,</span> <span class='tstring'><span class='regexp_beg'>/</span><span class='tstring_content'>Rob</span><span class='regexp_end'>/</span></span><span class='comma'>,</span> <span class='int'>22</span><span class='rparen'>)</span>
131
+
132
+ <span class='comment'># An `or` matcher uses the same shorthand as `and` but uses `any?` behind the scenes instead:
133
+ </span><span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='period'>.</span><span class='id identifier rubyid_or'><span class='object_link'><a href="Qo/PublicApi.html#or-instance_method" title="Qo::PublicApi#or (method)">or</a></span></span><span class='lparen'>(</span><span class='tstring'><span class='regexp_beg'>/</span><span class='tstring_content'>Rob</span><span class='regexp_end'>/</span></span><span class='comma'>,</span> <span class='int'>22</span><span class='rparen'>)</span>
134
+
135
+ <span class='comment'># Same with not, except it uses `none?`
136
+ </span><span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='period'>.</span><span class='id identifier rubyid_not'><span class='object_link'><a href="Qo/PublicApi.html#not-instance_method" title="Qo::PublicApi#not (method)">not</a></span></span><span class='lparen'>(</span><span class='tstring'><span class='regexp_beg'>/</span><span class='tstring_content'>Rob</span><span class='regexp_end'>/</span></span><span class='comma'>,</span> <span class='int'>22</span><span class='rparen'>)</span>
137
+ </code></pre>
138
+
139
+ <p>Qo has a few Qo&#39;isms, mainly based around triple equals in Ruby. See the above articles for tutorials on that count.</p>
140
+
141
+ <p>We will assume the following data:</p>
142
+
143
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_people_arrays'>people_arrays</span> <span class='op'>=</span> <span class='lbracket'>[</span>
144
+ <span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Robert</span><span class='tstring_end'>&#39;</span></span><span class='comma'>,</span> <span class='int'>22</span><span class='rbracket'>]</span><span class='comma'>,</span>
145
+ <span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Roberta</span><span class='tstring_end'>&#39;</span></span><span class='comma'>,</span> <span class='int'>22</span><span class='rbracket'>]</span><span class='comma'>,</span>
146
+ <span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Foo</span><span class='tstring_end'>&#39;</span></span><span class='comma'>,</span> <span class='int'>42</span><span class='rbracket'>]</span><span class='comma'>,</span>
147
+ <span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Bar</span><span class='tstring_end'>&#39;</span></span><span class='comma'>,</span> <span class='int'>18</span><span class='rbracket'>]</span>
148
+ <span class='rbracket'>]</span>
149
+
150
+ <span class='id identifier rubyid_people_objects'>people_objects</span> <span class='op'>=</span> <span class='lbracket'>[</span>
151
+ <span class='const'>Person</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span><span class='lparen'>(</span><span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Robert</span><span class='tstring_end'>&#39;</span></span><span class='comma'>,</span> <span class='int'>22</span><span class='rparen'>)</span><span class='comma'>,</span>
152
+ <span class='const'>Person</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span><span class='lparen'>(</span><span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Roberta</span><span class='tstring_end'>&#39;</span></span><span class='comma'>,</span> <span class='int'>22</span><span class='rparen'>)</span><span class='comma'>,</span>
153
+ <span class='const'>Person</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span><span class='lparen'>(</span><span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Foo</span><span class='tstring_end'>&#39;</span></span><span class='comma'>,</span> <span class='int'>42</span><span class='rparen'>)</span><span class='comma'>,</span>
154
+ <span class='const'>Person</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span><span class='lparen'>(</span><span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Bar</span><span class='tstring_end'>&#39;</span></span><span class='comma'>,</span> <span class='int'>17</span><span class='rparen'>)</span><span class='comma'>,</span>
155
+ <span class='rbracket'>]</span>
156
+ </code></pre>
157
+
158
+ <h3>1 - Wildcard Matching</h3>
159
+
160
+ <p>Qo has a concept of a Wildcard, <code>:*</code>, which will match against any value</p>
161
+
162
+ <pre class="code ruby"><code class="ruby"><span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='lbracket'>[</span><span class='symbol'>:*</span><span class='comma'>,</span> <span class='symbol'>:*</span><span class='rbracket'>]</span> <span class='op'>===</span> <span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Robert</span><span class='tstring_end'>&#39;</span></span><span class='comma'>,</span> <span class='int'>22</span><span class='rbracket'>]</span> <span class='comment'># true
163
+ </span></code></pre>
164
+
165
+ <p>A single wildcard will match anything, and can frequently be used as an always true:</p>
166
+
167
+ <pre class="code ruby"><code class="ruby"><span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='lbracket'>[</span><span class='symbol'>:*</span><span class='rbracket'>]</span> <span class='op'>===</span> <span class='symbol'>:literally_anything_here</span>
168
+ </code></pre>
169
+
170
+ <h3>2 - Array Matching</h3>
171
+
172
+ <p>The first way a Qo matcher can be defined is by using <code>*varargs</code>:</p>
173
+
174
+ <pre class="code ruby"><code class="ruby"><span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='op'>::</span><span class='const'><span class='object_link'><a href="Qo/Matchers.html" title="Qo::Matchers (module)">Matchers</a></span></span><span class='op'>::</span><span class='const'><span class='object_link'><a href="Qo/Matchers/BaseMatcher.html" title="Qo::Matchers::BaseMatcher (class)">BaseMatcher</a></span></span><span class='lparen'>(</span><span class='id identifier rubyid_type'>type</span><span class='comma'>,</span> <span class='op'>*</span><span class='id identifier rubyid_varargs'>varargs</span><span class='comma'>,</span> <span class='op'>**</span><span class='id identifier rubyid_kwargs'>kwargs</span><span class='rparen'>)</span>
175
+ </code></pre>
176
+
177
+ <p>This gives us the <code>and</code> matcher shorthand for array matchers.</p>
178
+
179
+ <h4>2.1 - Array matched against an Array</h4>
180
+
181
+ <p>When an Array matcher is run against an Array, it will compare elements by index in the following priority:</p>
182
+
183
+ <ol>
184
+ <li>Was a wildcard provided?</li>
185
+ <li>Does it case match (<code>===</code>)?</li>
186
+ <li>Does it have a predicate method by that name that matches?</li>
187
+ </ol>
188
+
189
+ <p>This functionality is left biased and permissive, meaning that if the right side of the argument is longer it will ignore those items in the match. If it&#39;s shorter? Not so much.</p>
190
+
191
+ <h5>2.1.1 - Wildcard provided</h5>
192
+
193
+ <pre class="code ruby"><code class="ruby"><span class='comment'># Standalone
194
+ </span>
195
+ <span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='lbracket'>[</span><span class='symbol'>:*</span><span class='comma'>,</span> <span class='symbol'>:*</span><span class='rbracket'>]</span> <span class='op'>===</span> <span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Robert</span><span class='tstring_end'>&#39;</span></span><span class='comma'>,</span> <span class='int'>22</span><span class='rbracket'>]</span>
196
+ <span class='comment'># =&gt; true
197
+ </span>
198
+ <span class='comment'># Case statement
199
+ </span>
200
+ <span class='kw'>case</span> <span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Roberta</span><span class='tstring_end'>&#39;</span></span><span class='comma'>,</span> <span class='int'>22</span><span class='rbracket'>]</span>
201
+ <span class='kw'>when</span> <span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='lbracket'>[</span><span class='symbol'>:*</span><span class='comma'>,</span> <span class='symbol'>:*</span><span class='rbracket'>]</span> <span class='kw'>then</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>it matched</span><span class='tstring_end'>&#39;</span></span>
202
+ <span class='kw'>else</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>will not ever be reached</span><span class='tstring_end'>&#39;</span></span>
203
+ <span class='kw'>end</span>
204
+ <span class='comment'># =&gt; &#39;it matched&#39;
205
+ </span>
206
+ <span class='comment'># Select
207
+ </span>
208
+ <span class='id identifier rubyid_people_arrays'>people_arrays</span><span class='period'>.</span><span class='id identifier rubyid_select'>select</span><span class='lparen'>(</span><span class='op'>&amp;</span><span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='lbracket'>[</span><span class='symbol'>:*</span><span class='comma'>,</span> <span class='symbol'>:*</span><span class='rbracket'>]</span><span class='rparen'>)</span>
209
+ <span class='comment'># =&gt; [[&#39;Robert&#39;, 22], [&#39;Roberta&#39;, 22], [&#39;Foo&#39;, 42], [&#39;Bar&#39;, 18]]
210
+ </span></code></pre>
211
+
212
+ <h5>2.1.2 - Case Match present</h5>
213
+
214
+ <p>We&#39;ve seen some case matching so far with <code>Range</code> and <code>Regex</code>:</p>
215
+
216
+ <pre class="code ruby"><code class="ruby"><span class='comment'># Standalone
217
+ </span>
218
+ <span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='lbracket'>[</span><span class='tstring'><span class='regexp_beg'>/</span><span class='tstring_content'>Rob</span><span class='regexp_end'>/</span></span><span class='comma'>,</span> <span class='symbol'>:*</span><span class='rbracket'>]</span> <span class='op'>===</span> <span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Robert</span><span class='tstring_end'>&#39;</span></span><span class='comma'>,</span> <span class='int'>22</span><span class='rbracket'>]</span>
219
+ <span class='comment'># =&gt; true
220
+ </span>
221
+ <span class='comment'># Case statement
222
+ </span>
223
+ <span class='kw'>case</span> <span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Roberta</span><span class='tstring_end'>&#39;</span></span><span class='comma'>,</span> <span class='int'>22</span><span class='rbracket'>]</span>
224
+ <span class='kw'>when</span> <span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='lbracket'>[</span><span class='symbol'>:*</span><span class='comma'>,</span> <span class='int'>0</span><span class='op'>..</span><span class='int'>9</span><span class='rbracket'>]</span> <span class='kw'>then</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>child</span><span class='tstring_end'>&#39;</span></span>
225
+ <span class='kw'>when</span> <span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='lbracket'>[</span><span class='symbol'>:*</span><span class='comma'>,</span> <span class='int'>10</span><span class='op'>..</span><span class='int'>19</span><span class='rbracket'>]</span> <span class='kw'>then</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>teen</span><span class='tstring_end'>&#39;</span></span>
226
+ <span class='kw'>when</span> <span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='lbracket'>[</span><span class='symbol'>:*</span><span class='comma'>,</span> <span class='int'>20</span><span class='op'>..</span><span class='int'>99</span><span class='rbracket'>]</span> <span class='kw'>then</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>adult</span><span class='tstring_end'>&#39;</span></span>
227
+ <span class='kw'>else</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>not sure</span><span class='tstring_end'>&#39;</span></span>
228
+ <span class='kw'>end</span>
229
+ <span class='comment'># =&gt; &#39;adult&#39;
230
+ </span>
231
+ <span class='comment'># Select
232
+ </span>
233
+ <span class='id identifier rubyid_people_arrays'>people_arrays</span><span class='period'>.</span><span class='id identifier rubyid_select'>select</span><span class='lparen'>(</span><span class='op'>&amp;</span><span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='lbracket'>[</span><span class='symbol'>:*</span><span class='comma'>,</span> <span class='int'>10</span><span class='op'>..</span><span class='int'>19</span><span class='rbracket'>]</span><span class='rparen'>)</span>
234
+ <span class='comment'># =&gt; [[&#39;Bar&#39;, 18]]
235
+ </span></code></pre>
236
+
237
+ <h5>2.1.3 - Predicate Method matched</h5>
238
+
239
+ <p>If no wildcard or case match is found, it will attempt to see if a predicate method by the same name exists, call it, and check the result:</p>
240
+
241
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_dirty_values'>dirty_values</span> <span class='op'>=</span> <span class='lbracket'>[</span><span class='kw'>nil</span><span class='comma'>,</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_end'>&#39;</span></span><span class='comma'>,</span> <span class='kw'>true</span><span class='rbracket'>]</span>
242
+
243
+ <span class='comment'># Standalone
244
+ </span>
245
+ <span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='lbracket'>[</span><span class='symbol'>:nil?</span><span class='rbracket'>]</span> <span class='op'>===</span> <span class='lbracket'>[</span><span class='kw'>nil</span><span class='rbracket'>]</span>
246
+ <span class='comment'># =&gt; true, though you could also just use Qo[nil]
247
+ </span>
248
+ <span class='comment'># Case statement
249
+ </span>
250
+ <span class='kw'>case</span> <span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Roberta</span><span class='tstring_end'>&#39;</span></span><span class='comma'>,</span> <span class='kw'>nil</span><span class='rbracket'>]</span>
251
+ <span class='kw'>when</span> <span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='lbracket'>[</span><span class='symbol'>:*</span><span class='comma'>,</span> <span class='symbol'>:nil?</span><span class='rbracket'>]</span> <span class='kw'>then</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>no age</span><span class='tstring_end'>&#39;</span></span>
252
+ <span class='kw'>else</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>not sure</span><span class='tstring_end'>&#39;</span></span>
253
+ <span class='kw'>end</span>
254
+ <span class='comment'># =&gt; &#39;no age&#39;
255
+ </span>
256
+ <span class='comment'># Select
257
+ </span>
258
+ <span class='id identifier rubyid_people_arrays'>people_arrays</span><span class='period'>.</span><span class='id identifier rubyid_select'>select</span><span class='lparen'>(</span><span class='op'>&amp;</span><span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='lbracket'>[</span><span class='symbol'>:*</span><span class='comma'>,</span> <span class='symbol'>:even?</span><span class='rbracket'>]</span><span class='rparen'>)</span>
259
+ <span class='comment'># =&gt; [[&quot;Robert&quot;, 22], [&quot;Roberta&quot;, 22], [&quot;Foo&quot;, 42], [&quot;Bar&quot;, 18]]
260
+ </span></code></pre>
261
+
262
+ <h4>2.2 - Array matched against an Object</h4>
263
+
264
+ <p>When an Array matcher is matched against anything other than an Array it will follow the priority:</p>
265
+
266
+ <ol>
267
+ <li>Was a wildcard provided?</li>
268
+ <li>Does it case match (<code>===</code>)?</li>
269
+ <li>Does it have a predicate method by that name that matches?</li>
270
+ </ol>
271
+
272
+ <p>Every argument provided will be run against the target object.</p>
273
+
274
+ <h5>2.2.1 - Wildcard provided</h5>
275
+
276
+ <p>A wildcard in an Array to Object match is functionally an always true, but can be used as such:</p>
277
+
278
+ <pre class="code ruby"><code class="ruby"><span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='lbracket'>[</span><span class='symbol'>:*</span><span class='rbracket'>]</span> <span class='op'>===</span> <span class='symbol'>:literally_anything_here</span>
279
+ </code></pre>
280
+
281
+ <h5>2.2.2 - Case Match present</h5>
282
+
283
+ <pre class="code ruby"><code class="ruby"><span class='comment'># Standalone
284
+ </span>
285
+ <span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='lbracket'>[</span><span class='const'>Integer</span><span class='comma'>,</span> <span class='int'>15</span><span class='op'>..</span><span class='int'>25</span><span class='rbracket'>]</span> <span class='op'>===</span> <span class='int'>20</span>
286
+ <span class='comment'># =&gt; true
287
+ </span>
288
+ <span class='comment'># Case statement - functionally indistinguishable from a regular case statement
289
+ </span>
290
+ <span class='comment'># Select
291
+ </span>
292
+ <span class='lbracket'>[</span><span class='kw'>nil</span><span class='comma'>,</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_end'>&#39;</span></span><span class='comma'>,</span> <span class='int'>10</span><span class='comma'>,</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>string</span><span class='tstring_end'>&#39;</span></span><span class='rbracket'>]</span><span class='period'>.</span><span class='id identifier rubyid_select'>select</span><span class='lparen'>(</span><span class='op'>&amp;</span><span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='period'>.</span><span class='id identifier rubyid_or'><span class='object_link'><a href="Qo/PublicApi.html#or-instance_method" title="Qo::PublicApi#or (method)">or</a></span></span><span class='lparen'>(</span><span class='tstring'><span class='regexp_beg'>/</span><span class='tstring_content'>str</span><span class='regexp_end'>/</span></span><span class='comma'>,</span> <span class='int'>10</span><span class='op'>..</span><span class='int'>20</span><span class='rparen'>)</span><span class='rparen'>)</span>
293
+ <span class='comment'># =&gt; [10, &quot;string&quot;]
294
+ </span></code></pre>
295
+
296
+ <h5>2.2.3 - Predicate Method matched</h5>
297
+
298
+ <p>Now this is where some of the fun starts in</p>
299
+
300
+ <pre class="code ruby"><code class="ruby"><span class='comment'># Standalone
301
+ </span>
302
+ <span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='period'>.</span><span class='id identifier rubyid_or'><span class='object_link'><a href="Qo/PublicApi.html#or-instance_method" title="Qo::PublicApi#or (method)">or</a></span></span><span class='lparen'>(</span><span class='symbol'>:nil?</span><span class='comma'>,</span> <span class='symbol'>:empty?</span><span class='rparen'>)</span> <span class='op'>===</span> <span class='kw'>nil</span>
303
+ <span class='comment'># =&gt; true
304
+ </span><span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='period'>.</span><span class='id identifier rubyid_not'><span class='object_link'><a href="Qo/PublicApi.html#not-instance_method" title="Qo::PublicApi#not (method)">not</a></span></span><span class='lparen'>(</span><span class='symbol'>:nil?</span><span class='comma'>,</span> <span class='symbol'>:empty?</span><span class='rparen'>)</span> <span class='op'>===</span> <span class='kw'>nil</span>
305
+ <span class='comment'># =&gt; false
306
+ </span>
307
+ <span class='comment'># Case statement
308
+ </span>
309
+ <span class='kw'>case</span> <span class='int'>42</span>
310
+ <span class='kw'>when</span> <span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='lbracket'>[</span><span class='const'>Integer</span><span class='comma'>,</span> <span class='symbol'>:even?</span><span class='comma'>,</span> <span class='int'>40</span><span class='op'>..</span><span class='int'>50</span><span class='rbracket'>]</span> <span class='kw'>then</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>oddly specific number criteria</span><span class='tstring_end'>&#39;</span></span>
311
+ <span class='kw'>else</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>nope</span><span class='tstring_end'>&#39;</span></span>
312
+ <span class='kw'>end</span>
313
+ <span class='comment'># =&gt; &quot;oddly specific number criteria&quot;
314
+ </span>
315
+ <span class='comment'># Reject
316
+ </span>
317
+ <span class='lbracket'>[</span><span class='kw'>nil</span><span class='comma'>,</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_end'>&#39;</span></span><span class='comma'>,</span> <span class='int'>10</span><span class='comma'>,</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>string</span><span class='tstring_end'>&#39;</span></span><span class='rbracket'>]</span><span class='period'>.</span><span class='id identifier rubyid_reject'>reject</span><span class='lparen'>(</span><span class='op'>&amp;</span><span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='period'>.</span><span class='id identifier rubyid_or'><span class='object_link'><a href="Qo/PublicApi.html#or-instance_method" title="Qo::PublicApi#or (method)">or</a></span></span><span class='lparen'>(</span><span class='symbol'>:nil?</span><span class='comma'>,</span> <span class='symbol'>:empty?</span><span class='rparen'>)</span><span class='rparen'>)</span>
318
+ <span class='comment'># =&gt; [10, &quot;string&quot;]
319
+ </span></code></pre>
320
+
321
+ <h3>3 - Hash Matching</h3>
322
+
323
+ <h4>3.1 - Hash matched against a Hash</h4>
324
+
325
+ <ol>
326
+ <li>Does the key exist on the other hash?</li>
327
+ <li>Are the match value and match target hashes?</li>
328
+ <li>Was a wildcard value provided?</li>
329
+ <li>Does the target object&#39;s value case match against the match value?</li>
330
+ <li>Does the target object&#39;s value predicate match against the match value?</li>
331
+ <li>What about the String version of the match key? Abort if it can&#39;t coerce.</li>
332
+ </ol>
333
+
334
+ <h5>3.1.1 - Key present</h5>
335
+
336
+ <p>Checks to see if the key is even present on the other object, false if not.</p>
337
+
338
+ <h5>3.1.2 - Match value and target are hashes</h5>
339
+
340
+ <p>If both the match value (<code>match_key: matcher</code>) and the match target are hashes, Qo will begin a recursive descent starting at the match key until it finds a matcher to try out:</p>
341
+
342
+ <pre class="code ruby"><code class="ruby"><span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='lbracket'>[</span><span class='label'>a:</span> <span class='lbrace'>{</span><span class='label'>b:</span> <span class='lbrace'>{</span><span class='label'>c:</span> <span class='int'>5</span><span class='op'>..</span><span class='int'>15</span><span class='rbrace'>}</span><span class='rbrace'>}</span><span class='rbracket'>]</span> <span class='op'>===</span> <span class='lbrace'>{</span><span class='label'>a:</span> <span class='lbrace'>{</span><span class='label'>b:</span> <span class='lbrace'>{</span><span class='label'>c:</span> <span class='int'>10</span><span class='rbrace'>}</span><span class='rbrace'>}</span><span class='rbrace'>}</span>
343
+ <span class='comment'># =&gt; true
344
+ </span>
345
+ <span class='comment'># Na, no fun. Deeper!
346
+ </span><span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='period'>.</span><span class='id identifier rubyid_and'><span class='object_link'><a href="Qo/PublicApi.html#and-instance_method" title="Qo::PublicApi#and (method)">and</a></span></span><span class='lparen'>(</span><span class='label'>a:</span> <span class='lbrace'>{</span>
347
+ <span class='label'>f:</span> <span class='int'>5</span><span class='op'>..</span><span class='int'>15</span><span class='comma'>,</span>
348
+ <span class='label'>b:</span> <span class='lbrace'>{</span>
349
+ <span class='label'>c:</span> <span class='tstring'><span class='regexp_beg'>/</span><span class='tstring_content'>foo</span><span class='regexp_end'>/</span></span><span class='comma'>,</span>
350
+ <span class='label'>d:</span> <span class='int'>10</span><span class='op'>..</span><span class='int'>30</span>
351
+ <span class='rbrace'>}</span>
352
+ <span class='rbrace'>}</span><span class='rparen'>)</span><span class='period'>.</span><span class='id identifier rubyid_call'>call</span><span class='lparen'>(</span><span class='label'>a:</span> <span class='lbrace'>{</span>
353
+ <span class='label'>f:</span> <span class='int'>10</span><span class='comma'>,</span>
354
+ <span class='label'>b:</span> <span class='lbrace'>{</span>
355
+ <span class='label'>c:</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>foobar</span><span class='tstring_end'>&#39;</span></span><span class='comma'>,</span>
356
+ <span class='label'>d:</span> <span class='int'>20</span>
357
+ <span class='rbrace'>}</span>
358
+ <span class='rbrace'>}</span><span class='rparen'>)</span>
359
+ <span class='comment'># =&gt; true
360
+ </span>
361
+ <span class='comment'># It can get chaotic with `or` though. Anything anywhere in there matches and
362
+ </span><span class='comment'># it&#39;ll pass.
363
+ </span><span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='period'>.</span><span class='id identifier rubyid_or'><span class='object_link'><a href="Qo/PublicApi.html#or-instance_method" title="Qo::PublicApi#or (method)">or</a></span></span><span class='lparen'>(</span><span class='label'>a:</span> <span class='lbrace'>{</span>
364
+ <span class='label'>f:</span> <span class='kw'>false</span><span class='comma'>,</span>
365
+ <span class='label'>b:</span> <span class='lbrace'>{</span>
366
+ <span class='label'>c:</span> <span class='tstring'><span class='regexp_beg'>/</span><span class='tstring_content'>nope</span><span class='regexp_end'>/</span></span><span class='comma'>,</span>
367
+ <span class='label'>d:</span> <span class='int'>10</span><span class='op'>..</span><span class='int'>30</span>
368
+ <span class='rbrace'>}</span>
369
+ <span class='rbrace'>}</span><span class='rparen'>)</span><span class='period'>.</span><span class='id identifier rubyid_call'>call</span><span class='lparen'>(</span><span class='label'>a:</span> <span class='lbrace'>{</span>
370
+ <span class='label'>f:</span> <span class='int'>10</span><span class='comma'>,</span>
371
+ <span class='label'>b:</span> <span class='lbrace'>{</span>
372
+ <span class='label'>c:</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>foobar</span><span class='tstring_end'>&#39;</span></span><span class='comma'>,</span>
373
+ <span class='label'>d:</span> <span class='int'>20</span>
374
+ <span class='rbrace'>}</span>
375
+ <span class='rbrace'>}</span><span class='rparen'>)</span>
376
+ </code></pre>
377
+
378
+ <h5>3.1.3 - Wildcard provided</h5>
379
+
380
+ <p>As with other wildcards, if the value matched against is a wildcard it&#39;ll always get through:</p>
381
+
382
+ <pre class="code ruby"><code class="ruby"><span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='lbracket'>[</span><span class='label'>name:</span> <span class='symbol'>:*</span><span class='rbracket'>]</span> <span class='op'>===</span> <span class='lbrace'>{</span><span class='label'>name:</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Foo</span><span class='tstring_end'>&#39;</span></span><span class='rbrace'>}</span>
383
+ <span class='comment'># =&gt; true
384
+ </span></code></pre>
385
+
386
+ <h5>3.1.4 - Case match present</h5>
387
+
388
+ <p>If a case match is present for the key, it&#39;ll try and compare:</p>
389
+
390
+ <pre class="code ruby"><code class="ruby"><span class='comment'># Standalone
391
+ </span>
392
+ <span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='lbracket'>[</span><span class='label'>name:</span> <span class='tstring'><span class='regexp_beg'>/</span><span class='tstring_content'>Foo</span><span class='regexp_end'>/</span></span><span class='rbracket'>]</span> <span class='op'>===</span> <span class='lbrace'>{</span><span class='label'>name:</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Foo</span><span class='tstring_end'>&#39;</span></span><span class='rbrace'>}</span>
393
+ <span class='comment'># =&gt; true
394
+ </span>
395
+ <span class='comment'># Case statement
396
+ </span>
397
+ <span class='kw'>case</span> <span class='lbrace'>{</span><span class='label'>name:</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Foo</span><span class='tstring_end'>&#39;</span></span><span class='comma'>,</span> <span class='label'>age:</span> <span class='int'>42</span><span class='rbrace'>}</span>
398
+ <span class='kw'>when</span> <span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='lbracket'>[</span><span class='label'>age:</span> <span class='int'>40</span><span class='op'>..</span><span class='int'>50</span><span class='rbracket'>]</span> <span class='kw'>then</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Gotcha!</span><span class='tstring_end'>&#39;</span></span>
399
+ <span class='kw'>else</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>nope</span><span class='tstring_end'>&#39;</span></span>
400
+ <span class='kw'>end</span>
401
+ <span class='comment'># =&gt; &quot;Gotcha!&quot;
402
+ </span>
403
+ <span class='comment'># Select
404
+ </span>
405
+ <span class='id identifier rubyid_people_hashes'>people_hashes</span> <span class='op'>=</span> <span class='id identifier rubyid_people_arrays'>people_arrays</span><span class='period'>.</span><span class='id identifier rubyid_map'>map</span> <span class='lbrace'>{</span> <span class='op'>|</span><span class='id identifier rubyid_n'>n</span><span class='comma'>,</span> <span class='id identifier rubyid_a'>a</span><span class='op'>|</span> <span class='lbrace'>{</span><span class='label'>name:</span> <span class='id identifier rubyid_n'>n</span><span class='comma'>,</span> <span class='label'>age:</span> <span class='id identifier rubyid_a'>a</span><span class='rbrace'>}</span> <span class='rbrace'>}</span>
406
+ <span class='id identifier rubyid_people_hashes'>people_hashes</span><span class='period'>.</span><span class='id identifier rubyid_select'>select</span><span class='lparen'>(</span><span class='op'>&amp;</span><span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='lbracket'>[</span><span class='label'>age:</span> <span class='int'>15</span><span class='op'>..</span><span class='int'>25</span><span class='rbracket'>]</span><span class='rparen'>)</span>
407
+ <span class='comment'># =&gt; [{:name=&gt;&quot;Robert&quot;, :age=&gt;22}, {:name=&gt;&quot;Roberta&quot;, :age=&gt;22}, {:name=&gt;&quot;Bar&quot;, :age=&gt;18}]
408
+ </span></code></pre>
409
+
410
+ <h5>3.1.5 - Predicate match present</h5>
411
+
412
+ <p>Much like our array friend above, if a predicate style method is present see if it&#39;ll work</p>
413
+
414
+ <pre class="code ruby"><code class="ruby"><span class='comment'># Standalone
415
+ </span>
416
+ <span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='lbracket'>[</span><span class='label'>name:</span> <span class='symbol'>:empty?</span><span class='rbracket'>]</span> <span class='op'>===</span> <span class='lbrace'>{</span><span class='label'>name:</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_end'>&#39;</span></span><span class='rbrace'>}</span>
417
+ <span class='comment'># =&gt; true
418
+ </span>
419
+ <span class='comment'># Case statement
420
+ </span>
421
+ <span class='kw'>case</span> <span class='lbrace'>{</span><span class='label'>name:</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Foo</span><span class='tstring_end'>&#39;</span></span><span class='comma'>,</span> <span class='label'>age:</span> <span class='kw'>nil</span><span class='rbrace'>}</span>
422
+ <span class='kw'>when</span> <span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='lbracket'>[</span><span class='label'>age:</span> <span class='symbol'>:nil?</span><span class='rbracket'>]</span> <span class='kw'>then</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>No age provided!</span><span class='tstring_end'>&#39;</span></span>
423
+ <span class='kw'>else</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>nope</span><span class='tstring_end'>&#39;</span></span>
424
+ <span class='kw'>end</span>
425
+ <span class='comment'># =&gt; &quot;No age provided!&quot;
426
+ </span>
427
+ <span class='comment'># Reject
428
+ </span>
429
+ <span class='id identifier rubyid_people_hashes'>people_hashes</span> <span class='op'>=</span> <span class='id identifier rubyid_people_arrays'>people_arrays</span><span class='period'>.</span><span class='id identifier rubyid_map'>map</span> <span class='lbrace'>{</span> <span class='op'>|</span><span class='lparen'>(</span><span class='id identifier rubyid_n'>n</span><span class='comma'>,</span><span class='id identifier rubyid_a'>a</span><span class='rparen'>)</span><span class='op'>|</span> <span class='lbrace'>{</span><span class='label'>name:</span> <span class='id identifier rubyid_n'>n</span><span class='comma'>,</span> <span class='label'>age:</span> <span class='id identifier rubyid_a'>a</span><span class='rbrace'>}</span> <span class='rbrace'>}</span> <span class='op'>&lt;&lt;</span> <span class='lbrace'>{</span><span class='label'>name:</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Ghost</span><span class='tstring_end'>&#39;</span></span><span class='comma'>,</span> <span class='label'>age:</span> <span class='kw'>nil</span><span class='rbrace'>}</span>
430
+ <span class='id identifier rubyid_people_hashes'>people_hashes</span><span class='period'>.</span><span class='id identifier rubyid_reject'>reject</span><span class='lparen'>(</span><span class='op'>&amp;</span><span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='lbracket'>[</span><span class='label'>age:</span> <span class='symbol'>:nil?</span><span class='rbracket'>]</span><span class='rparen'>)</span>
431
+ <span class='comment'># =&gt; [{:name=&gt;&quot;Robert&quot;, :age=&gt;22}, {:name=&gt;&quot;Roberta&quot;, :age=&gt;22}, {:name=&gt;&quot;Bar&quot;, :age=&gt;18}]
432
+ </span></code></pre>
433
+
434
+ <p>Careful though, if the key doesn&#39;t exist that won&#39;t match. I&#39;ll have to consider this one later.</p>
435
+
436
+ <h5>3.1.6 - String variant present</h5>
437
+
438
+ <p>Coerces the key into a string if possible, and sees if that can provide a valid case match</p>
439
+
440
+ <h4>3.2 - Hash matched against an Object</h4>
441
+
442
+ <ol>
443
+ <li>Does the object respond to the match key?</li>
444
+ <li>Was a wildcard value provided?</li>
445
+ <li>Does the result of sending the match key as a method case match the provided value?</li>
446
+ <li>Does a predicate method exist for it?</li>
447
+ </ol>
448
+
449
+ <h5>3.2.1 - Responds to match key</h5>
450
+
451
+ <p>If it doesn&#39;t know how to deal with it, false out.</p>
452
+
453
+ <h5>3.2.2 - Wildcard provided</h5>
454
+
455
+ <p>Same as other wildcards, but if the object doesn&#39;t respond to the method you specify it&#39;ll have false&#39;d out before it reaches here.</p>
456
+
457
+ <h5>3.2.3 - Case match present</h5>
458
+
459
+ <p>This is where we can get into some interesting code, much like the hash selections above</p>
460
+
461
+ <pre class="code ruby"><code class="ruby"><span class='comment'># Standalone
462
+ </span>
463
+ <span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='lbracket'>[</span><span class='label'>name:</span> <span class='tstring'><span class='regexp_beg'>/</span><span class='tstring_content'>Rob</span><span class='regexp_end'>/</span></span><span class='rbracket'>]</span> <span class='op'>===</span> <span class='id identifier rubyid_people_objects'>people_objects</span><span class='period'>.</span><span class='id identifier rubyid_first'>first</span>
464
+ <span class='comment'># =&gt; true
465
+ </span>
466
+ <span class='comment'># Case statement
467
+ </span>
468
+ <span class='kw'>case</span> <span class='id identifier rubyid_people_objects'>people_objects</span><span class='period'>.</span><span class='id identifier rubyid_first'>first</span>
469
+ <span class='kw'>when</span> <span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='lbracket'>[</span><span class='label'>name:</span> <span class='tstring'><span class='regexp_beg'>/</span><span class='tstring_content'>Rob</span><span class='regexp_end'>/</span></span><span class='rbracket'>]</span> <span class='kw'>then</span> <span class='tstring'><span class='tstring_beg'>&quot;</span><span class='tstring_content'>It&#39;s Rob!</span><span class='tstring_end'>&quot;</span></span>
470
+ <span class='kw'>else</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Na, not them</span><span class='tstring_end'>&#39;</span></span>
471
+ <span class='kw'>end</span>
472
+ <span class='comment'># =&gt; &quot;It&#39;s Rob!&quot;
473
+ </span>
474
+ <span class='comment'># Select
475
+ </span>
476
+ <span class='id identifier rubyid_people_objects'>people_objects</span><span class='period'>.</span><span class='id identifier rubyid_select'>select</span><span class='lparen'>(</span><span class='op'>&amp;</span><span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='lbracket'>[</span><span class='label'>name:</span> <span class='tstring'><span class='regexp_beg'>/</span><span class='tstring_content'>Rob</span><span class='regexp_end'>/</span></span><span class='rbracket'>]</span><span class='rparen'>)</span>
477
+ <span class='comment'># =&gt; [Person(Robert, 22), Person(Roberta, 22)]
478
+ </span></code></pre>
479
+
480
+ <h5>3.2.4 - Predicate match present</h5>
481
+
482
+ <pre class="code ruby"><code class="ruby"><span class='comment'># Standalone
483
+ </span>
484
+ <span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='lbracket'>[</span><span class='label'>name:</span> <span class='symbol'>:empty?</span><span class='rbracket'>]</span> <span class='op'>===</span> <span class='const'>Person</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span><span class='lparen'>(</span><span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_end'>&#39;</span></span><span class='comma'>,</span> <span class='int'>22</span><span class='rparen'>)</span>
485
+ <span class='comment'># =&gt; true
486
+ </span>
487
+ <span class='comment'># Case statement
488
+ </span>
489
+ <span class='kw'>case</span> <span class='const'>Person</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span><span class='lparen'>(</span><span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_end'>&#39;</span></span><span class='comma'>,</span> <span class='kw'>nil</span><span class='rparen'>)</span>
490
+ <span class='kw'>when</span> <span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='lbracket'>[</span><span class='label'>age:</span> <span class='symbol'>:nil?</span><span class='rbracket'>]</span> <span class='kw'>then</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>No age provided!</span><span class='tstring_end'>&#39;</span></span>
491
+ <span class='kw'>else</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>nope</span><span class='tstring_end'>&#39;</span></span>
492
+ <span class='kw'>end</span>
493
+ <span class='comment'># =&gt; &quot;No age provided!&quot;
494
+ </span>
495
+ <span class='comment'># Select
496
+ </span>
497
+ <span class='id identifier rubyid_people_hashes'>people_hashes</span><span class='period'>.</span><span class='id identifier rubyid_select'>select</span><span class='lparen'>(</span><span class='op'>&amp;</span><span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='lbracket'>[</span><span class='label'>age:</span> <span class='symbol'>:nil?</span><span class='rbracket'>]</span><span class='rparen'>)</span>
498
+ <span class='comment'># =&gt; []
499
+ </span></code></pre>
500
+
501
+ <h3>4 - Right Hand Pattern Matching</h3>
502
+
503
+ <p>This is where I start going a bit off into the weeds. We&#39;re going to try and get RHA style pattern matching in Ruby.</p>
504
+
505
+ <pre class="code ruby"><code class="ruby"><span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='period'>.</span><span class='id identifier rubyid_match'><span class='object_link'><a href="Qo/PublicApi.html#match-instance_method" title="Qo::PublicApi#match (method)">match</a></span></span><span class='lparen'>(</span><span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Robert</span><span class='tstring_end'>&#39;</span></span><span class='comma'>,</span> <span class='int'>22</span><span class='rbracket'>]</span><span class='comma'>,</span>
506
+ <span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='period'>.</span><span class='id identifier rubyid_m'>m</span><span class='lparen'>(</span><span class='symbol'>:*</span><span class='comma'>,</span> <span class='int'>20</span><span class='op'>..</span><span class='int'>99</span><span class='rparen'>)</span> <span class='lbrace'>{</span> <span class='op'>|</span><span class='id identifier rubyid_n'>n</span><span class='comma'>,</span> <span class='id identifier rubyid_a'>a</span><span class='op'>|</span> <span class='tstring'><span class='tstring_beg'>&quot;</span><span class='embexpr_beg'>#{</span><span class='id identifier rubyid_n'>n</span><span class='embexpr_end'>}</span><span class='tstring_content'> is an adult that is </span><span class='embexpr_beg'>#{</span><span class='id identifier rubyid_a'>a</span><span class='embexpr_end'>}</span><span class='tstring_content'> years old</span><span class='tstring_end'>&quot;</span></span> <span class='rbrace'>}</span><span class='comma'>,</span>
507
+ <span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='period'>.</span><span class='id identifier rubyid_m'>m</span><span class='lparen'>(</span><span class='symbol'>:*</span><span class='rparen'>)</span>
508
+ <span class='rparen'>)</span>
509
+ <span class='comment'># =&gt; &quot;Robert is an adult that is 22 years old&quot;
510
+ </span></code></pre>
511
+
512
+ <pre class="code ruby"><code class="ruby"><span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='period'>.</span><span class='id identifier rubyid_match'><span class='object_link'><a href="Qo/PublicApi.html#match-instance_method" title="Qo::PublicApi#match (method)">match</a></span></span><span class='lparen'>(</span><span class='id identifier rubyid_people_objects'>people_objects</span><span class='period'>.</span><span class='id identifier rubyid_first'>first</span><span class='comma'>,</span>
513
+ <span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='period'>.</span><span class='id identifier rubyid_m'>m</span><span class='lparen'>(</span><span class='label'>name:</span> <span class='symbol'>:*</span><span class='comma'>,</span> <span class='label'>age:</span> <span class='int'>20</span><span class='op'>..</span><span class='int'>99</span><span class='rparen'>)</span> <span class='lbrace'>{</span> <span class='op'>|</span><span class='id identifier rubyid_person'>person</span><span class='op'>|</span> <span class='tstring'><span class='tstring_beg'>&quot;</span><span class='embexpr_beg'>#{</span><span class='id identifier rubyid_person'>person</span><span class='period'>.</span><span class='id identifier rubyid_name'>name</span><span class='embexpr_end'>}</span><span class='tstring_content'> is an adult that is </span><span class='embexpr_beg'>#{</span><span class='id identifier rubyid_person'>person</span><span class='period'>.</span><span class='id identifier rubyid_age'>age</span><span class='embexpr_end'>}</span><span class='tstring_content'> years old</span><span class='tstring_end'>&quot;</span></span> <span class='rbrace'>}</span><span class='comma'>,</span>
514
+ <span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='period'>.</span><span class='id identifier rubyid_m'>m</span><span class='lparen'>(</span><span class='symbol'>:*</span><span class='rparen'>)</span>
515
+ <span class='rparen'>)</span>
516
+ </code></pre>
517
+
518
+ <p>In this case it&#39;s trying to do a few things:</p>
519
+
520
+ <ol>
521
+ <li>Iterate over every matcher until it finds a match</li>
522
+ <li>Execute its block function</li>
523
+ </ol>
524
+
525
+ <p>If no block function is provided, it assumes an identity function (<code>-&gt; v { v }</code>) instead. If no match is found, <code>nil</code> will be returned.</p>
526
+
527
+ <p>If an initial target is not furnished, the matcher will become a curried proc awaiting a target. In more simple terms it just wants a target to run against, so let&#39;s give it a few with map:</p>
528
+
529
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_name_longer_than_three'>name_longer_than_three</span> <span class='op'>=</span> <span class='tlambda'>-&gt;</span> <span class='id identifier rubyid_person'>person</span> <span class='tlambeg'>{</span> <span class='id identifier rubyid_person'>person</span><span class='period'>.</span><span class='id identifier rubyid_name'>name</span><span class='period'>.</span><span class='id identifier rubyid_size'>size</span> <span class='op'>&gt;</span> <span class='int'>3</span> <span class='rbrace'>}</span>
530
+
531
+ <span class='id identifier rubyid_people_objects'>people_objects</span><span class='period'>.</span><span class='id identifier rubyid_map'>map</span><span class='lparen'>(</span><span class='op'>&amp;</span><span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='period'>.</span><span class='id identifier rubyid_match'><span class='object_link'><a href="Qo/PublicApi.html#match-instance_method" title="Qo::PublicApi#match (method)">match</a></span></span><span class='lparen'>(</span>
532
+ <span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='period'>.</span><span class='id identifier rubyid_m'>m</span><span class='lparen'>(</span><span class='id identifier rubyid_name_longer_than_three'>name_longer_than_three</span><span class='rparen'>)</span> <span class='lbrace'>{</span> <span class='op'>|</span><span class='id identifier rubyid_person'>person</span><span class='op'>|</span>
533
+ <span class='id identifier rubyid_person'>person</span><span class='period'>.</span><span class='id identifier rubyid_name'>name</span> <span class='op'>=</span> <span class='id identifier rubyid_person'>person</span><span class='period'>.</span><span class='id identifier rubyid_name'>name</span><span class='lbracket'>[</span><span class='int'>0</span><span class='op'>..</span><span class='int'>2</span><span class='rbracket'>]</span>
534
+ <span class='id identifier rubyid_person'>person</span>
535
+ <span class='rbrace'>}</span><span class='comma'>,</span>
536
+ <span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='period'>.</span><span class='id identifier rubyid_m'>m</span><span class='lparen'>(</span><span class='symbol'>:*</span><span class='rparen'>)</span>
537
+ <span class='rparen'>)</span><span class='rparen'>)</span>
538
+
539
+ <span class='comment'># =&gt; [Person(age: 22, name: &quot;Rob&quot;), Person(age: 22, name: &quot;Rob&quot;), Person(age: 42, name: &quot;Foo&quot;), Person(age: 17, name: &quot;Bar&quot;)]
540
+ </span></code></pre>
541
+
542
+ <p>So we just truncated everyone&#39;s name that was longer than three characters.</p>
543
+
544
+ <h3>6 - Helper functions</h3>
545
+
546
+ <p>There are a few functions added for convenience, and it should be noted that because all Qo matchers respond to <code>===</code> that they can be used as helpers as well.</p>
547
+
548
+ <h4>6.1 - Dig</h4>
549
+
550
+ <p>Dig is used to get in deep at a nested hash value. It takes a dot-path and a <code>===</code> respondent matcher:</p>
551
+
552
+ <pre class="code ruby"><code class="ruby"><span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='period'>.</span><span class='id identifier rubyid_dig'><span class='object_link'><a href="Qo/Helpers.html#dig-instance_method" title="Qo::Helpers#dig (method)">dig</a></span></span><span class='lparen'>(</span><span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>a.b.c</span><span class='tstring_end'>&#39;</span></span><span class='comma'>,</span> <span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='period'>.</span><span class='id identifier rubyid_or'><span class='object_link'><a href="Qo/PublicApi.html#or-instance_method" title="Qo::PublicApi#or (method)">or</a></span></span><span class='lparen'>(</span><span class='int'>1</span><span class='op'>..</span><span class='int'>5</span><span class='comma'>,</span> <span class='int'>15</span><span class='op'>..</span><span class='int'>25</span><span class='rparen'>)</span><span class='rparen'>)</span> <span class='op'>===</span> <span class='lbrace'>{</span><span class='label'>a:</span> <span class='lbrace'>{</span><span class='label'>b:</span> <span class='lbrace'>{</span><span class='label'>c:</span> <span class='int'>1</span><span class='rbrace'>}</span><span class='rbrace'>}</span><span class='rbrace'>}</span>
553
+ <span class='comment'># =&gt; true
554
+ </span>
555
+ <span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='period'>.</span><span class='id identifier rubyid_dig'><span class='object_link'><a href="Qo/Helpers.html#dig-instance_method" title="Qo::Helpers#dig (method)">dig</a></span></span><span class='lparen'>(</span><span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>a.b.c</span><span class='tstring_end'>&#39;</span></span><span class='comma'>,</span> <span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='period'>.</span><span class='id identifier rubyid_or'><span class='object_link'><a href="Qo/PublicApi.html#or-instance_method" title="Qo::PublicApi#or (method)">or</a></span></span><span class='lparen'>(</span><span class='int'>1</span><span class='op'>..</span><span class='int'>5</span><span class='comma'>,</span> <span class='int'>15</span><span class='op'>..</span><span class='int'>25</span><span class='rparen'>)</span><span class='rparen'>)</span> <span class='op'>===</span> <span class='lbrace'>{</span><span class='label'>a:</span> <span class='lbrace'>{</span><span class='label'>b:</span> <span class='lbrace'>{</span><span class='label'>c:</span> <span class='int'>20</span><span class='rbrace'>}</span><span class='rbrace'>}</span><span class='rbrace'>}</span>
556
+ <span class='comment'># =&gt; true
557
+ </span></code></pre>
558
+
559
+ <p>To be fair that means anything that can respond to <code>===</code>, including classes and other such things.</p>
560
+
561
+ <h4>6.2 - Count By</h4>
562
+
563
+ <p>This ends up coming up a lot, especially around querying, so let&#39;s get a way to count by!</p>
564
+
565
+ <pre class="code ruby"><code class="ruby"><span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='period'>.</span><span class='id identifier rubyid_count_by'><span class='object_link'><a href="Qo/Helpers.html#count_by-instance_method" title="Qo::Helpers#count_by (method)">count_by</a></span></span><span class='lparen'>(</span><span class='lbracket'>[</span><span class='int'>1</span><span class='comma'>,</span><span class='int'>2</span><span class='comma'>,</span><span class='int'>3</span><span class='comma'>,</span><span class='int'>2</span><span class='comma'>,</span><span class='int'>2</span><span class='comma'>,</span><span class='int'>2</span><span class='comma'>,</span><span class='int'>1</span><span class='rbracket'>]</span><span class='rparen'>)</span>
566
+
567
+ <span class='comment'># =&gt; {
568
+ </span><span class='comment'># 1 =&gt; 2,
569
+ </span><span class='comment'># 2 =&gt; 4,
570
+ </span><span class='comment'># 3 =&gt; 1
571
+ </span><span class='comment'># }
572
+ </span>
573
+ <span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='period'>.</span><span class='id identifier rubyid_count_by'><span class='object_link'><a href="Qo/Helpers.html#count_by-instance_method" title="Qo::Helpers#count_by (method)">count_by</a></span></span><span class='lparen'>(</span><span class='lbracket'>[</span><span class='int'>1</span><span class='comma'>,</span><span class='int'>2</span><span class='comma'>,</span><span class='int'>3</span><span class='comma'>,</span><span class='int'>2</span><span class='comma'>,</span><span class='int'>2</span><span class='comma'>,</span><span class='int'>2</span><span class='comma'>,</span><span class='int'>1</span><span class='rbracket'>]</span><span class='comma'>,</span> <span class='op'>&amp;</span><span class='symbol'>:even?</span><span class='rparen'>)</span>
574
+
575
+ <span class='comment'># =&gt; {
576
+ </span><span class='comment'># false =&gt; 3,
577
+ </span><span class='comment'># true =&gt; 4
578
+ </span><span class='comment'># }
579
+ </span></code></pre>
580
+
581
+ <h3>5 - Hacky Fun Time</h3>
582
+
583
+ <p>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!</p>
584
+
585
+ <h4>5.1 - JSON</h4>
586
+
587
+ <blockquote>
588
+ <p>Note that Qo does not support deep querying of hashes (yet)</p>
589
+ </blockquote>
590
+
591
+ <h5>5.1.1 - JSON Placeholder</h5>
592
+
593
+ <p>Qo tries to be clever though, it assumes Symbol keys first and then String keys, so how about some JSON?:</p>
594
+
595
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_require'>require</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>json</span><span class='tstring_end'>&#39;</span></span>
596
+ <span class='id identifier rubyid_require'>require</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>net/http</span><span class='tstring_end'>&#39;</span></span>
597
+
598
+ <span class='id identifier rubyid_posts'>posts</span> <span class='op'>=</span> <span class='const'>JSON</span><span class='period'>.</span><span class='id identifier rubyid_parse'>parse</span><span class='lparen'>(</span>
599
+ <span class='const'>Net</span><span class='op'>::</span><span class='const'>HTTP</span><span class='period'>.</span><span class='id identifier rubyid_get'>get</span><span class='lparen'>(</span><span class='const'>URI</span><span class='lparen'>(</span><span class='tstring'><span class='tstring_beg'>&quot;</span><span class='tstring_content'>https://jsonplaceholder.typicode.com/posts</span><span class='tstring_end'>&quot;</span></span><span class='rparen'>)</span><span class='rparen'>)</span><span class='comma'>,</span> <span class='label'>symbolize_names:</span> <span class='kw'>true</span>
600
+ <span class='rparen'>)</span>
601
+
602
+ <span class='id identifier rubyid_users'>users</span> <span class='op'>=</span> <span class='const'>JSON</span><span class='period'>.</span><span class='id identifier rubyid_parse'>parse</span><span class='lparen'>(</span>
603
+ <span class='const'>Net</span><span class='op'>::</span><span class='const'>HTTP</span><span class='period'>.</span><span class='id identifier rubyid_get'>get</span><span class='lparen'>(</span><span class='const'>URI</span><span class='lparen'>(</span><span class='tstring'><span class='tstring_beg'>&quot;</span><span class='tstring_content'>https://jsonplaceholder.typicode.com/users</span><span class='tstring_end'>&quot;</span></span><span class='rparen'>)</span><span class='rparen'>)</span><span class='comma'>,</span> <span class='label'>symbolize_names:</span> <span class='kw'>true</span>
604
+ <span class='rparen'>)</span>
605
+
606
+ <span class='comment'># Get all posts where the userId is 1.
607
+ </span><span class='id identifier rubyid_posts'>posts</span><span class='period'>.</span><span class='id identifier rubyid_select'>select</span><span class='lparen'>(</span><span class='op'>&amp;</span><span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='lbracket'>[</span><span class='label'>userId:</span> <span class='int'>1</span><span class='rbracket'>]</span><span class='rparen'>)</span>
608
+
609
+ <span class='comment'># Get users named Nicholas or have two names and an address somewhere with a zipcode
610
+ </span><span class='comment'># that starts with 9 or 4.
611
+ </span><span class='comment'>#
612
+ </span><span class='comment'># Qo matchers return a `===` respondant object, remember, so we can totally nest them.
613
+ </span><span class='id identifier rubyid_users'>users</span><span class='period'>.</span><span class='id identifier rubyid_select'>select</span><span class='lparen'>(</span><span class='op'>&amp;</span><span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='period'>.</span><span class='id identifier rubyid_and'><span class='object_link'><a href="Qo/PublicApi.html#and-instance_method" title="Qo::PublicApi#and (method)">and</a></span></span><span class='lparen'>(</span>
614
+ <span class='label'>name:</span> <span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='period'>.</span><span class='id identifier rubyid_or'><span class='object_link'><a href="Qo/PublicApi.html#or-instance_method" title="Qo::PublicApi#or (method)">or</a></span></span><span class='lparen'>(</span><span class='tstring'><span class='regexp_beg'>/</span><span class='tstring_content'>^Nicholas</span><span class='regexp_end'>/</span></span><span class='comma'>,</span> <span class='tstring'><span class='regexp_beg'>/</span><span class='tstring_content'>^\w+ \w+$</span><span class='regexp_end'>/</span></span><span class='rparen'>)</span><span class='comma'>,</span>
615
+ <span class='label'>address:</span> <span class='lbrace'>{</span>
616
+ <span class='label'>zipcode:</span> <span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='period'>.</span><span class='id identifier rubyid_or'><span class='object_link'><a href="Qo/PublicApi.html#or-instance_method" title="Qo::PublicApi#or (method)">or</a></span></span><span class='lparen'>(</span><span class='tstring'><span class='regexp_beg'>/</span><span class='tstring_content'>^9</span><span class='regexp_end'>/</span></span><span class='comma'>,</span> <span class='tstring'><span class='regexp_beg'>/</span><span class='tstring_content'>^4</span><span class='regexp_end'>/</span></span><span class='rparen'>)</span>
617
+ <span class='rbrace'>}</span>
618
+ <span class='rparen'>)</span><span class='rparen'>)</span>
619
+
620
+ <span class='comment'># We could even use dig to get at some of the same information. This and the above will
621
+ </span><span class='comment'># return the same results even.
622
+ </span><span class='id identifier rubyid_users'>users</span><span class='period'>.</span><span class='id identifier rubyid_select'>select</span><span class='lparen'>(</span><span class='op'>&amp;</span><span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='period'>.</span><span class='id identifier rubyid_and'><span class='object_link'><a href="Qo/PublicApi.html#and-instance_method" title="Qo::PublicApi#and (method)">and</a></span></span><span class='lparen'>(</span>
623
+ <span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='period'>.</span><span class='id identifier rubyid_dig'><span class='object_link'><a href="Qo/Helpers.html#dig-instance_method" title="Qo::Helpers#dig (method)">dig</a></span></span><span class='lparen'>(</span><span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>address.zipcode</span><span class='tstring_end'>&#39;</span></span><span class='comma'>,</span> <span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='period'>.</span><span class='id identifier rubyid_or'><span class='object_link'><a href="Qo/PublicApi.html#or-instance_method" title="Qo::PublicApi#or (method)">or</a></span></span><span class='lparen'>(</span><span class='tstring'><span class='regexp_beg'>/</span><span class='tstring_content'>^9</span><span class='regexp_end'>/</span></span><span class='comma'>,</span> <span class='tstring'><span class='regexp_beg'>/</span><span class='tstring_content'>^4</span><span class='regexp_end'>/</span></span><span class='rparen'>)</span><span class='rparen'>)</span><span class='comma'>,</span>
624
+ <span class='label'>name:</span> <span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='period'>.</span><span class='id identifier rubyid_or'><span class='object_link'><a href="Qo/PublicApi.html#or-instance_method" title="Qo::PublicApi#or (method)">or</a></span></span><span class='lparen'>(</span><span class='tstring'><span class='regexp_beg'>/</span><span class='tstring_content'>^Nicholas</span><span class='regexp_end'>/</span></span><span class='comma'>,</span> <span class='tstring'><span class='regexp_beg'>/</span><span class='tstring_content'>^\w+ \w+$</span><span class='regexp_end'>/</span></span><span class='rparen'>)</span>
625
+ <span class='rparen'>)</span><span class='rparen'>)</span>
626
+ </code></pre>
627
+
628
+ <p>Nifty!</p>
629
+
630
+ <h4>5.2 - Opsy Stuff</h4>
631
+
632
+ <h5>5.2.1 - NMap</h5>
633
+
634
+ <p>What about NMap for our Opsy friends? Well, simulated, but still fun.</p>
635
+
636
+ <pre class="code ruby"><code class="ruby">hosts = (`nmap -oG - -sP 192.168.1.* 10.0.0.* | grep Host`).lines.map { |v| v.split[1..2] }
637
+ =&gt; [[&quot;192.168.1.1&quot;, &quot;(Router)&quot;], [&quot;192.168.1.2&quot;, &quot;(My Computer)&quot;], [&quot;10.0.0.1&quot;, &quot;(Gateway)&quot;]]
638
+
639
+ hosts.select(&amp;Qo[IPAddr.new(&#39;192.168.1.1/8&#39;)])
640
+ =&gt; [[&quot;192.168.1.1&quot;, &quot;(Router)&quot;], [&quot;192.168.1.2&quot;, &quot;(My Computer)&quot;]]
641
+ </code></pre>
642
+
643
+ <h5>5.2.2 - <code>df</code></h5>
644
+
645
+ <p>The nice thing about Unix style commands is that they use headers, which means CSV can get a hold of them for some good formatting. It&#39;s also smart enough to deal with space separators that may vary in length:</p>
646
+
647
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_rows'>rows</span> <span class='op'>=</span> <span class='const'>CSV</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span><span class='lparen'>(</span><span class='backtick'>`</span><span class='tstring_content'>df -h</span><span class='tstring_end'>`</span></span><span class='comma'>,</span> <span class='label'>col_sep:</span> <span class='tstring'><span class='tstring_beg'>&quot;</span><span class='tstring_content'> </span><span class='tstring_end'>&quot;</span></span><span class='comma'>,</span> <span class='label'>headers:</span> <span class='kw'>true</span><span class='rparen'>)</span><span class='period'>.</span><span class='id identifier rubyid_read'>read</span><span class='period'>.</span><span class='id identifier rubyid_map'>map</span><span class='lparen'>(</span><span class='op'>&amp;</span><span class='symbol'>:to_h</span><span class='rparen'>)</span>
648
+
649
+ <span class='id identifier rubyid_rows'>rows</span><span class='period'>.</span><span class='id identifier rubyid_map'>map</span><span class='lparen'>(</span><span class='op'>&amp;</span><span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='period'>.</span><span class='id identifier rubyid_match'><span class='object_link'><a href="Qo/PublicApi.html#match-instance_method" title="Qo::PublicApi#match (method)">match</a></span></span><span class='lparen'>(</span>
650
+ <span class='const'><span class='object_link'><a href="Qo.html" title="Qo (module)">Qo</a></span></span><span class='period'>.</span><span class='id identifier rubyid_m'>m</span><span class='lparen'>(</span><span class='label'>Avail:</span> <span class='tstring'><span class='regexp_beg'>/</span><span class='tstring_content'>Gi$</span><span class='regexp_end'>/</span></span><span class='rparen'>)</span> <span class='lbrace'>{</span> <span class='op'>|</span><span class='id identifier rubyid_row'>row</span><span class='op'>|</span>
651
+ <span class='tstring'><span class='tstring_beg'>&quot;</span><span class='embexpr_beg'>#{</span><span class='id identifier rubyid_row'>row</span><span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Filesystem</span><span class='tstring_end'>&#39;</span></span><span class='rbracket'>]</span><span class='embexpr_end'>}</span><span class='tstring_content'> mounted on </span><span class='embexpr_beg'>#{</span><span class='id identifier rubyid_row'>row</span><span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Mounted</span><span class='tstring_end'>&#39;</span></span><span class='rbracket'>]</span><span class='embexpr_end'>}</span><span class='tstring_content'> [</span><span class='embexpr_beg'>#{</span><span class='id identifier rubyid_row'>row</span><span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Avail</span><span class='tstring_end'>&#39;</span></span><span class='rbracket'>]</span><span class='embexpr_end'>}</span><span class='tstring_content'> / </span><span class='embexpr_beg'>#{</span><span class='id identifier rubyid_row'>row</span><span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Size</span><span class='tstring_end'>&#39;</span></span><span class='rbracket'>]</span><span class='embexpr_end'>}</span><span class='tstring_content'>]</span><span class='tstring_end'>&quot;</span></span>
652
+ <span class='rbrace'>}</span>
653
+ <span class='rparen'>)</span><span class='rparen'>)</span><span class='period'>.</span><span class='id identifier rubyid_compact'>compact</span>
654
+ <span class='comment'># =&gt; [&quot;/dev/***** mounted on / [186Gi / 466Gi]&quot;]
655
+ </span></code></pre>
656
+
657
+ <h2>Installation</h2>
658
+
659
+ <p>Add this line to your application&#39;s Gemfile:</p>
660
+
661
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_gem'>gem</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>qo</span><span class='tstring_end'>&#39;</span></span>
662
+ </code></pre>
663
+
664
+ <p>And then execute:</p>
665
+
666
+ <pre class="code ruby"><code class="ruby">$ bundle
667
+ </code></pre>
668
+
669
+ <p>Or install it yourself as:</p>
670
+
671
+ <pre class="code ruby"><code class="ruby">$ gem install qo
672
+ </code></pre>
673
+
674
+ <h2>Development</h2>
675
+
676
+ <p>After checking out the repo, run <code>bin/setup</code> to install dependencies. Then, run <code>rake spec</code> to run the tests. You can also run <code>bin/console</code> for an interactive prompt that will allow you to experiment.</p>
677
+
678
+ <p>To install this gem onto your local machine, run <code>bundle exec rake install</code>. To release a new version, update the version number in <code>version.rb</code>, and then run <code>bundle exec rake release</code>, which will create a git tag for the version, push git commits and tags, and push the <code>.gem</code> file to <a href="https://rubygems.org">rubygems.org</a>.</p>
679
+
680
+ <h2>Contributing</h2>
681
+
682
+ <p>Bug reports and pull requests are welcome on GitHub at <a href="https://github.com/baweaver/qo">https://github.com/baweaver/qo</a>. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the <a href="http://contributor-covenant.org">Contributor Covenant</a> code of conduct.</p>
683
+
684
+ <h2>License</h2>
685
+
686
+ <p>The gem is available as open source under the terms of the <a href="http://opensource.org/licenses/MIT">MIT License</a>.</p>
687
+
688
+ <h2>Code of Conduct</h2>
689
+
690
+ <p>Everyone interacting in the Qo project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the <a href="https://github.com/baweaver/qo/blob/master/CODE_OF_CONDUCT.md">code of conduct</a>.</p>
691
+ </div></div>
692
+
693
+ <div id="footer">
694
+ Generated on Sun Apr 15 20:29:44 2018 by
695
+ <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
696
+ 0.9.12 (ruby-2.4.4).
697
+ </div>
698
+
699
+ </div>
700
+ </body>
701
+ </html>