pattern-matching 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- NTczMjQ3ODhmZmM1ZTFjYWI0NDc3Mjk4ZDg0ZWNiZTI2MTEyMWUzNg==
5
- data.tar.gz: !binary |-
6
- YzQwN2I4N2VhNDhlOGJjZjM0MmZjNGI1OTFkZDE1NWNhMjA3ODU5ZQ==
7
- !binary "U0hBNTEy":
8
- metadata.gz: !binary |-
9
- YTFiNzcwMzg0NmQ2OGI5MmI2MTA1Njg1YzE2NjIzMDJiNjg5NDk4OGZmMDUw
10
- YzlmMGI3NzJlMWNmNGViYTcwN2MxODY4MzA4OGRhNzZjOTJlOTg1ODUzZTcy
11
- NzYyZjgzZjIzZmE2ZjFjMjEzZTIxZDE2OGJlNDEzMDE0MDNkOTU=
12
- data.tar.gz: !binary |-
13
- MjIxM2ViMmYzY2UyNDhhMWViNzI0NTgxODNmODRmZGEyODY4MGY0YWM0Mjcw
14
- NWVmZjg1NDhjMjZjNDZjNzI2NTRmNjY3YzBlZjQwYjM4MmZkZmE2NzUwZjYx
15
- OWMwMTRkOGJiMzBkNDA4OTY1NmU2NmY3NmQ1M2Q3YzdmOWE2NDc=
2
+ SHA1:
3
+ metadata.gz: 16f7fd19a880e5d513cc2c48abb1ee42b580daf4
4
+ data.tar.gz: aabdb877f6c81402fcd459da73b60df396ad2577
5
+ SHA512:
6
+ metadata.gz: 660d6aad1d0f2eafa481e5d43b9ee581b4551b9845968b3f229d7ef2b9bd444e0f690791dfde39a8f0ec11014cf334386120b2a2ee7303d786bfb3942846c47f
7
+ data.tar.gz: bafa502a02e91ee80ae206700913dc9c208f93fbca85865967fe6242ee21ce8ba15f40dd814f9e2ca9b58d3f37944392d953b6e9ba59b3186a7fbd70f4bf040f
data/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- Copyright (c) Jerry D'Antonio -- released under the MIT license.
2
-
3
- http://www.opensource.org/licenses/mit-license.php
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in
13
- all copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
- THE SOFTWARE.
1
+ Copyright (c) Jerry D'Antonio -- released under the MIT license.
2
+
3
+ http://www.opensource.org/licenses/mit-license.php
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md CHANGED
@@ -1,562 +1,671 @@
1
- # PatternMatching [![Build Status](https://secure.travis-ci.org/jdantonio/pattern_matching.png)](http://travis-ci.org/jdantonio/pattern_matching?branch=master) [![Dependency Status](https://gemnasium.com/jdantonio/pattern_matching.png)](https://gemnasium.com/jdantonio/pattern_matching)
2
-
3
- A gem for adding Erlang-style function/method overloading through pattern matching to Ruby classes.
4
-
5
- *NOTE: This is a work in progress. Expect changes.*
6
-
7
- The project is hosted on the following sites:
8
-
9
- * [RubyGems project page](https://rubygems.org/gems/pattern-matching)
10
- * [Source code on GitHub](https://github.com/jdantonio/pattern_matching)
11
- * [Continuous integration on Travis-CI](https://travis-ci.org/jdantonio/pattern_matching)
12
- * [Dependency tracking on Gemnasium](https://gemnasium.com/jdantonio/pattern_matching)
13
- * [Follow me on Twitter](https://twitter.com/jerrydantonio)
14
-
15
- ## Introduction
16
-
17
- [Ruby](http://www.ruby-lang.org/en/) is my favorite programming by far. As much as I love
18
- Ruby I've always been a little disappointed that Ruby doesn't support function overloading.
19
- Function overloading tends to reduce branching and keep function signatures simpler.
20
- No sweat, I learned to do without. Then I started programming in [Erlang](http://www.erlang.org/)...
21
-
22
- I've really started to enjoy working in Erlang. Erlang is good at all the things Ruby is bad
23
- at and vice versa. Together, Ruby and Erlang make me happy. My favorite Erlang feature is,
24
- without question, [pattern matching](http://learnyousomeerlang.com/syntax-in-functions#pattern-matching).
25
- Pattern matching is like function overloading cranked to 11. So one day I was musing on Twitter
26
- that I'd like to see Erlang-stype pattern matching in Ruby and one of my friends responded "Build it!"
27
- So I did. And here it is.
28
-
29
- ### Goals
30
-
31
- * Stay true to the spirit of Erlang pattern matching, if not the semantics
32
- * Keep the semantics as idiomatic Ruby as possible
33
- * Support features that make sense in Ruby
34
- * Exclude features that only make sense in Erlang
35
- * Avoid using *method_missing*
36
- * Keep it small (currently arround 100 LOC)
37
- * Be as fast as reasonably possible
38
-
39
- ### Features
40
-
41
- * Pattern matching for instance methods.
42
- * Pattern matching for object constructors.
43
- * Parameter count matching
44
- * Matching against primitive values
45
- * Matching by class/datatype
46
- * Matching against specific key/vaue pairs in hashes
47
- * Matching against the presence of keys within hashes
48
- * Implicit hash for last parameter
49
- * Variable-length parameter lists
50
- * Guard clauses
51
- * Recursive calls to other pattern matches
52
- * Recursive calls to superclass pattern matches
53
- * Recursive calls to superclass methods
54
- * Dispatching to superclass methods when no match is found
55
- * Reasonable error messages when no match is found
56
-
57
- ### To-do
58
-
59
- * Support class methods
60
- * Support module instance methods
61
- * Support module methods
62
-
63
- ## Supported Ruby versions
64
-
65
- MRI 1.9.x and above. Anything else and your mileage may vary.
66
-
67
- ## Install
68
-
69
- ```shell
70
- gem install pattern-matching
71
- ```
72
-
73
- or add the following line to Gemfile:
74
-
75
- ```ruby
76
- gem 'pattern-matching'
77
- ```
78
-
79
- and run `bundle install` from your shell.
80
-
81
- ## Usage
82
-
83
- First, familiarize yourself with Erlang [pattern matching](http://learnyousomeerlang.com/syntax-in-functions#pattern-matching).
84
- This gem may not make much sense if you don't understand how Erlang dispatches
85
- functions.
86
-
87
- In the Ruby class file where you want to use pattern matching, require the
88
- *pattern_matching* gem:
89
-
90
- ```ruby
91
- require 'pattern_matching'
92
- ```
93
-
94
- Then include `PatternMatching` in your class:
95
-
96
- ```ruby
97
- require 'pattern_matching'
98
-
99
- class Foo
100
- include PatternMatching
101
-
102
- ...
103
-
104
- end
105
- ```
106
-
107
- You can then define functions with `defn` instead of the normal *def* statement.
108
- The syntax for `defn` is:
109
-
110
- ```ruby
111
- defn(:symbol_name_of_function, zero, or, more, parameters) { |block, arguments|
112
- # code to execute
113
- }
114
- ```
115
- You can then call your new function just like any other:
116
-
117
- ```ruby
118
- require 'pattern_matching'
119
-
120
- class Foo
121
- include PatternMatching
122
-
123
- defn(:hello) {
124
- puts "Hello, World!"
125
- }
126
- end
127
-
128
- foo = Foo.new
129
- foo.hello #=> "Hello, World!"
130
- ```
131
-
132
- Patterns to match against are included in the parameter list:
133
-
134
- ```ruby
135
- defn(:greet, :male) {
136
- puts "Hello, sir!"
137
- }
138
-
139
- defn(:greet, :female) {
140
- puts "Hello, ma'am!"
141
- }
142
-
143
- ...
144
-
145
- foo.hello(:male) #=> "Hello, sir!"
146
- foo.hello(:female) #=> "Hello, ma'am!"
147
- ```
148
-
149
- If a particular method call can not be matched a *NoMethodError* is thrown with
150
- a reasonably helpful error message:
151
-
152
- ```ruby
153
- foo.greet(:unknown) #=> NoMethodError: no method `greet` matching [:unknown] found for class Foo
154
- foo.greet #=> NoMethodError: no method `greet` matching [] found for class Foo
155
- ```
156
-
157
- Parameters that are expected to exist but that can take any value are considered
158
- *unbound* parameters. Unbound parameters are specified by the `_` underscore
159
- character or `UNBOUND`:
160
-
161
- ```ruby
162
- defn(:greet, _) do |name|
163
- "Hello, #{name}!"
164
- end
165
-
166
- defn(:greet, UNBOUND, UNBOUND) do |first, last|
167
- "Hello, #{first} #{last}!"
168
- end
169
-
170
- ...
171
-
172
- foo.greet('Jerry') #=> "Hello, Jerry!"
173
- ```
174
-
175
- All unbound parameters will be passed to the block in the order they are specified in the definition:
176
-
177
- ```ruby
178
- defn(:greet, _, _) do |first, last|
179
- "Hello, #{first} #{last}!"
180
- end
181
-
182
- ...
183
-
184
- foo.greet('Jerry', "D'Antonio") #=> "Hello, Jerry D'Antonio!"
185
- ```
186
-
187
- If for some reason you don't care about one or more unbound parameters within
188
- the block you can use the `_` underscore character in the block parameters list
189
- as well:
190
-
191
- ```ruby
192
- defn(:greet, _, _, _) do |first, _, last|
193
- "Hello, #{first} #{last}!"
194
- end
195
-
196
- ...
197
-
198
- foo.greet('Jerry', "I'm not going to tell you my middle name!", "D'Antonio") #=> "Hello, Jerry D'Antonio!"
199
- ```
200
-
201
- Hash parameters can match against specific keys and either bound or unbound parameters. This allows for function dispatch by hash parameters without having to dig through the hash:
202
-
203
- ```ruby
204
- defn(:hashable, {foo: :bar}) { |opts|
205
- :foo_bar
206
- }
207
- defn(:hashable, {foo: _}) { |f|
208
- f
209
- }
210
-
211
- ...
212
-
213
- foo.hashable({foo: :bar}) #=> :foo_bar
214
- foo.hashable({foo: :baz}) #=> :baz
215
- ```
216
-
217
- The Ruby idiom of the final parameter being a hash is also supported:
218
-
219
- ```ruby
220
- defn(:options, _) { |opts|
221
- opts
222
- }
223
-
224
- ...
225
-
226
- foo.options(bar: :baz, one: 1, many: 2)
227
- ```
228
-
229
- As is the Ruby idiom of variable-length argument lists. The constant `ALL` as the last parameter
230
- will match one or more arguments and pass them to the block as an array:
231
-
232
- ```ruby
233
- defn(:baz, Integer, ALL) { |int, args|
234
- [int, args]
235
- }
236
- defn(:baz, ALL) { |args|
237
- args
238
- }
239
- ```
240
-
241
- Superclass polymorphism is supported as well. If an object cannot match a method
242
- signature it will defer to the parent class:
243
-
244
- ```ruby
245
- class Bar
246
- def greet
247
- return 'Hello, World!'
248
- end
249
- end
250
-
251
- class Foo < Bar
252
- include PatternMatching
253
-
254
- defn(:greet, _) do |name|
255
- "Hello, #{name}!"
256
- end
257
- end
258
-
259
- ...
260
-
261
- foo.greet('Jerry') #=> "Hello, Jerry!"
262
- foo.greet #=> "Hello, World!"
263
- ```
264
-
265
- Guard clauses in Erlang are defined with `when` clauses between the parameter list and the function body.
266
- In Ruby, guard clauses are defined by chaining a call to `when` onto the the `defn` call and passing
267
- a block. If the guard clause evaluates to true then the function will match. If the guard evaluates
268
- to false the function will not match and pattern matching will continue:
269
-
270
- Erlang:
271
-
272
- ```erlang
273
- old_enough(X) when X >= 16 -> true;
274
- old_enough(_) -> false.
275
- ```
276
-
277
- Ruby:
278
-
279
- ```ruby
280
- defn(:old_enough, _){ true }.when{|x| x >= 16 }
281
- defn(:old_enough, _){ false }
282
- ```
283
-
284
- ### Order Matters
285
-
286
- As with Erlang, the order of pattern matches is significant. Patterns will be matched
287
- *in the order declared* and the first match will be used. If a particular function call
288
- can be matched by more than one pattern, the *first matched pattern* will be used. It
289
- is the programmer's responsibility to ensure patterns are declared in the correct order.
290
-
291
- ### Blocks and Procs and Lambdas, oh my!
292
-
293
- When using this gem it is critical to remember that `defn` takes a block and
294
- that blocks in Ruby have special rules. There are [plenty](https://www.google.com/search?q=ruby+block+proc+lambda)
295
- of good tutorials on the web explaining [blocks](http://www.robertsosinski.com/2008/12/21/understanding-ruby-blocks-procs-and-lambdas/)
296
- and [Procs](https://coderwall.com/p/_-_mha) and [lambdas](http://railsguru.org/2010/03/learn-ruby-procs-blocks-lambda/)
297
- in Ruby. Please read them. Please don't submit a bug report if you use a
298
- `return` statement within your `defn` and your code blows up with a
299
- [LocalJumpError](http://ruby-doc.org/core-2.0/LocalJumpError.html).
300
-
301
- ## Examples
302
-
303
- For more examples see the integration tests in *spec/integration_spec.rb*.
304
-
305
- ### Simple Functions
306
-
307
- This example is based on [Syntax in defnctions: Pattern Matching](http://learnyousomeerlang.com/syntax-in-defnctions) in [Learn You Some Erlang for Great Good!](http://learnyousomeerlang.com/).
308
-
309
- Erlang:
310
-
311
- ```erlang
312
- greet(male, Name) ->
313
- io:format("Hello, Mr. ~s!", [Name]);
314
- greet(female, Name) ->
315
- io:format("Hello, Mrs. ~s!", [Name]);
316
- greet(_, Name) ->
317
- io:format("Hello, ~s!", [Name]).
318
- ```
319
-
320
- Ruby:
321
-
322
- ```ruby
323
- require 'pattern_matching'
324
-
325
- class Foo
326
- include PatternMatching
327
-
328
- defn(:greet, _) do |name|
329
- "Hello, #{name}!"
330
- end
331
-
332
- defn(:greet, :male, _) { |name|
333
- "Hello, Mr. #{name}!"
334
- }
335
- defn(:greet, :female, _) { |name|
336
- "Hello, Ms. #{name}!"
337
- }
338
- defn(:greet, _, _) { |_, name|
339
- "Hello, #{name}!"
340
- }
341
- end
342
- ```
343
-
344
- ### Simple Functions with Overloading
345
-
346
- This example is based on [Syntax in defnctions: Pattern Matching](http://learnyousomeerlang.com/syntax-in-defnctions) in [Learn You Some Erlang for Great Good!](http://learnyousomeerlang.com/).
347
-
348
- Erlang:
349
-
350
- ```erlang
351
- greet(Name) ->
352
- io:format("Hello, ~s!", [Name]).
353
-
354
- greet(male, Name) ->
355
- io:format("Hello, Mr. ~s!", [Name]);
356
- greet(female, Name) ->
357
- io:format("Hello, Mrs. ~s!", [Name]);
358
- greet(_, Name) ->
359
- io:format("Hello, ~s!", [Name]).
360
- ```
361
-
362
- Ruby:
363
-
364
- ```ruby
365
- require 'pattern_matching'
366
-
367
- class Foo
368
- include PatternMatching
369
-
370
- defn(:greet, _) do |name|
371
- "Hello, #{name}!"
372
- end
373
-
374
- defn(:greet, :male, _) { |name|
375
- "Hello, Mr. #{name}!"
376
- }
377
- defn(:greet, :female, _) { |name|
378
- "Hello, Ms. #{name}!"
379
- }
380
- defn(:greet, nil, _) { |name|
381
- "Goodbye, #{name}!"
382
- }
383
- defn(:greet, _, _) { |_, name|
384
- "Hello, #{name}!"
385
- }
386
- end
387
- ```
388
-
389
- ### Constructor Overloading
390
-
391
- ```ruby
392
- require 'pattern_matching'
393
-
394
- class Foo
395
- include PatternMatching
396
-
397
- defn(:initialize) { @name = 'baz' }
398
- defn(:initialize, _) {|name| @name = name.to_s }
399
- end
400
- ```
401
-
402
- ### Matching by Class/Datatype
403
-
404
- ```ruby
405
- require 'pattern_matching'
406
-
407
- class Foo
408
- include PatternMatching
409
-
410
- defn(:concat, Integer, Integer) { |first, second|
411
- first + second
412
- }
413
- defn(:concat, Integer, String) { |first, second|
414
- "#{first} #{second}"
415
- }
416
- defn(:concat, String, String) { |first, second|
417
- first + second
418
- }
419
- defn(:concat, Integer, _) { |first, second|
420
- first + second.to_i
421
- }
422
- end
423
- ```
424
-
425
- ### Matching a Hash Parameter
426
-
427
- ```ruby
428
- require 'pattern_matching'
429
-
430
- class Foo
431
- include PatternMatching
432
-
433
- defn(:hashable, {foo: :bar}) { |opts|
434
- # matches any hash with key :foo and value :bar
435
- :foo_bar
436
- }
437
- defn(:hashable, {foo: _, bar: _}) { |f, b|
438
- # matches any hash with keys :foo and :bar
439
- # passes the values associated with those keys to the block
440
- [f, b]
441
- }
442
- defn(:hashable, {foo: _}) { |f|
443
- # matches any hash with key :foo
444
- # passes the value associated with that key to the block
445
- # must appear AFTER the prior match or it will override that one
446
- f
447
- }
448
- defn(:hashable, {}) { ||
449
- # matches an empty hash
450
- :empty
451
- }
452
- defn(:hashable, _) { |opts|
453
- # matches any hash (or any other value)
454
- opts
455
- }
456
- end
457
-
458
- ...
459
-
460
- foo.hashable({foo: :bar}) #=> :foo_bar
461
- foo.hashable({foo: :baz}) #=> :baz
462
- foo.hashable({foo: 1, bar: 2}) #=> [1, 2]
463
- foo.hashable({foo: 1, baz: 2}) #=> 1
464
- foo.hashable({bar: :baz}) #=> {bar: :baz}
465
- foo.hashable({}) #=> :empty
466
- ```
467
-
468
- ### Variable Length Argument Lists with ALL
469
-
470
- ```ruby
471
- defn(:all, :one, ALL) { |args|
472
- args
473
- }
474
- defn(:all, :one, Integer, ALL) { |int, args|
475
- [int, args]
476
- }
477
- defn(:all, 1, _, ALL) { |var, args|
478
- [var, args]
479
- }
480
- defn(:all, ALL) { | args|
481
- args
482
- }
483
-
484
- ...
485
-
486
- foo.all(:one, 'a', 'bee', :see) #=> ['a', 'bee', :see]
487
- foo.all(:one, 1, 'bee', :see) #=> [1, 'bee', :see]
488
- foo.all(1, 'a', 'bee', :see) #=> ['a', ['bee', :see]]
489
- foo.all('a', 'bee', :see) #=> ['a', 'bee', :see]
490
- foo.all() #=> NoMethodError: no method `all` matching [] found for class Foo
491
- ```
492
-
493
- ### Guard Clauses
494
-
495
- These examples are based on [Syntax in defnctions: Pattern Matching](http://learnyousomeerlang.com/syntax-in-defnctions) in [Learn You Some Erlang for Great Good!](http://learnyousomeerlang.com/).
496
-
497
- Erlang:
498
-
499
- ```erlang
500
- old_enough(X) when X >= 16 -> true;
501
- old_enough(_) -> false.
502
-
503
- right_age(X) when X >= 16, X =< 104 ->
504
- true;
505
- right_age(_) ->
506
- false.
507
-
508
- wrong_age(X) when X < 16; X > 104 ->
509
- true;
510
- wrong_age(_) ->
511
- false.
512
- ```
513
-
514
- ```ruby
515
- defn(:old_enough, _){ true }.when{|x| x >= 16 }
516
- defn(:old_enough, _){ false }
517
-
518
- defn(:right_age, _) {
519
- true
520
- }.when{|x| x >= 16 && x <= 104 }
521
-
522
- defn(:right_age, _) {
523
- false
524
- }
525
-
526
- defn(:wrong_age, _) {
527
- false
528
- }.when{|x| x < 16 || x > 104 }
529
-
530
- defn(:wrong_age, _) {
531
- true
532
- }
533
- ```
534
-
535
- ## Copyright
536
-
537
- *PatternMatching* is Copyright &copy; 2013 [Jerry D'Antonio](https://twitter.com/jerrydantonio).
538
- It is free software and may be redistributed under the terms specified in the LICENSE file.
539
-
540
- ## License
541
-
542
- Released under the MIT license.
543
-
544
- http://www.opensource.org/licenses/mit-license.php
545
-
546
- > Permission is hereby granted, free of charge, to any person obtaining a copy
547
- > of this software and associated documentation files (the "Software"), to deal
548
- > in the Software without restriction, including without limitation the rights
549
- > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
550
- > copies of the Software, and to permit persons to whom the Software is
551
- > furnished to do so, subject to the following conditions:
552
- >
553
- > The above copyright notice and this permission notice shall be included in
554
- > all copies or substantial portions of the Software.
555
- >
556
- > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
557
- > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
558
- > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
559
- > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
560
- > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
561
- > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
562
- > THE SOFTWARE.
1
+ # PatternMatching [![Build Status](https://secure.travis-ci.org/jdantonio/pattern_matching.png)](http://travis-ci.org/jdantonio/pattern_matching?branch=master) [![Dependency Status](https://gemnasium.com/jdantonio/pattern_matching.png)](https://gemnasium.com/jdantonio/pattern_matching)
2
+
3
+ A gem for adding Erlang-style function/method overloading through pattern matching to Ruby classes.
4
+
5
+ *NOTE: This is a work in progress. Expect changes.*
6
+
7
+ The project is hosted on the following sites:
8
+
9
+ * [RubyGems project page](https://rubygems.org/gems/pattern-matching)
10
+ * [Source code on GitHub](https://github.com/jdantonio/pattern_matching)
11
+ * [Continuous integration on Travis-CI](https://travis-ci.org/jdantonio/pattern_matching)
12
+ * [Dependency tracking on Gemnasium](https://gemnasium.com/jdantonio/pattern_matching)
13
+ * [Follow me on Twitter](https://twitter.com/jerrydantonio)
14
+
15
+ ## Introduction
16
+
17
+ [Ruby](http://www.ruby-lang.org/en/) is my favorite programming by far. As much as I love
18
+ Ruby I've always been a little disappointed that Ruby doesn't support function overloading.
19
+ Function overloading tends to reduce branching and keep function signatures simpler.
20
+ No sweat, I learned to do without. Then I started programming in [Erlang](http://www.erlang.org/)...
21
+
22
+ I've really started to enjoy working in Erlang. Erlang is good at all the things Ruby is bad
23
+ at and vice versa. Together, Ruby and Erlang make me happy. My favorite Erlang feature is,
24
+ without question, [pattern matching](http://learnyousomeerlang.com/syntax-in-functions#pattern-matching).
25
+ Pattern matching is like function overloading cranked to 11. So one day I was musing on Twitter
26
+ that I'd like to see Erlang-stype pattern matching in Ruby and one of my friends responded "Build it!"
27
+ So I did. And here it is.
28
+
29
+ For fun I've also thrown in Erlang's sparsely documented [-behaviour](http://www.erlang.org/doc/design_principles/gen_server_concepts.html).
30
+
31
+ ### Goals
32
+
33
+ * Stay true to the spirit of Erlang pattern matching, if not the semantics
34
+ * Keep the semantics as idiomatic Ruby as possible
35
+ * Support features that make sense in Ruby
36
+ * Exclude features that only make sense in Erlang
37
+ * Avoid using *method_missing*
38
+ * Keep it small (currently arround 100 LOC)
39
+ * Be as fast as reasonably possible
40
+
41
+ ### Features
42
+
43
+ * Pattern matching for instance methods.
44
+ * Pattern matching for object constructors.
45
+ * Parameter count matching
46
+ * Matching against primitive values
47
+ * Matching by class/datatype
48
+ * Matching against specific key/vaue pairs in hashes
49
+ * Matching against the presence of keys within hashes
50
+ * Implicit hash for last parameter
51
+ * Variable-length parameter lists
52
+ * Guard clauses
53
+ * Recursive calls to other pattern matches
54
+ * Recursive calls to superclass pattern matches
55
+ * Recursive calls to superclass methods
56
+ * Dispatching to superclass methods when no match is found
57
+ * Reasonable error messages when no match is found
58
+
59
+ ### For good -behavior(timeoff).
60
+
61
+ One of Ruby's greatest strengths is [duck typing](http://rubylearning.com/satishtalim/duck_typing.html).
62
+ Usually this is awesome and I'm happy to not have to deal with static typing and the compiler. Usually.
63
+ The problem with duck typing is that is is impossible in Ruby to enforce an interface definition.
64
+ I would never advocate turning Ruby into the cesspool complex object creation that Java has
65
+ unfortunately become, but occasionally it would be nice to make sure a class implements a set of
66
+ required methods. Enter Erlang's [-behavior](http://metajack.im/2008/10/29/custom-behaviors-in-erlang/)
67
+ keyword. Basically, you define a `behavior_info` then drop a `behavior` call within a class.
68
+ Forget to implement a required method and Ruby will let you know. See the examples below for details.
69
+
70
+ ## Supported Ruby versions
71
+
72
+ MRI 1.9.x and above. Anything else and your mileage may vary.
73
+
74
+ ## Install
75
+
76
+ ```shell
77
+ gem install pattern-matching
78
+ ```
79
+
80
+ or add the following line to Gemfile:
81
+
82
+ ```ruby
83
+ gem 'pattern-matching'
84
+ ```
85
+
86
+ and run `bundle install` from your shell.
87
+
88
+ ## Usage
89
+
90
+ First, familiarize yourself with Erlang [pattern matching](http://learnyousomeerlang.com/syntax-in-functions#pattern-matching).
91
+ This gem may not make much sense if you don't understand how Erlang dispatches
92
+ functions.
93
+
94
+ In the Ruby class file where you want to use pattern matching, require the
95
+ *pattern_matching* gem:
96
+
97
+ ```ruby
98
+ require 'pattern_matching'
99
+ ```
100
+
101
+ Then include `PatternMatching` in your class:
102
+
103
+ ```ruby
104
+ require 'pattern_matching'
105
+
106
+ class Foo
107
+ include PatternMatching
108
+
109
+ ...
110
+
111
+ end
112
+ ```
113
+
114
+ You can then define functions with `defn` instead of the normal *def* statement.
115
+ The syntax for `defn` is:
116
+
117
+ ```ruby
118
+ defn(:symbol_name_of_function, zero, or, more, parameters) { |block, arguments|
119
+ # code to execute
120
+ }
121
+ ```
122
+ You can then call your new function just like any other:
123
+
124
+ ```ruby
125
+ require 'pattern_matching'
126
+
127
+ class Foo
128
+ include PatternMatching
129
+
130
+ defn(:hello) {
131
+ puts "Hello, World!"
132
+ }
133
+ end
134
+
135
+ foo = Foo.new
136
+ foo.hello #=> "Hello, World!"
137
+ ```
138
+
139
+ Patterns to match against are included in the parameter list:
140
+
141
+ ```ruby
142
+ defn(:greet, :male) {
143
+ puts "Hello, sir!"
144
+ }
145
+
146
+ defn(:greet, :female) {
147
+ puts "Hello, ma'am!"
148
+ }
149
+
150
+ ...
151
+
152
+ foo.hello(:male) #=> "Hello, sir!"
153
+ foo.hello(:female) #=> "Hello, ma'am!"
154
+ ```
155
+
156
+ If a particular method call can not be matched a *NoMethodError* is thrown with
157
+ a reasonably helpful error message:
158
+
159
+ ```ruby
160
+ foo.greet(:unknown) #=> NoMethodError: no method `greet` matching [:unknown] found for class Foo
161
+ foo.greet #=> NoMethodError: no method `greet` matching [] found for class Foo
162
+ ```
163
+
164
+ Parameters that are expected to exist but that can take any value are considered
165
+ *unbound* parameters. Unbound parameters are specified by the `_` underscore
166
+ character or `UNBOUND`:
167
+
168
+ ```ruby
169
+ defn(:greet, _) do |name|
170
+ "Hello, #{name}!"
171
+ end
172
+
173
+ defn(:greet, UNBOUND, UNBOUND) do |first, last|
174
+ "Hello, #{first} #{last}!"
175
+ end
176
+
177
+ ...
178
+
179
+ foo.greet('Jerry') #=> "Hello, Jerry!"
180
+ ```
181
+
182
+ All unbound parameters will be passed to the block in the order they are specified in the definition:
183
+
184
+ ```ruby
185
+ defn(:greet, _, _) do |first, last|
186
+ "Hello, #{first} #{last}!"
187
+ end
188
+
189
+ ...
190
+
191
+ foo.greet('Jerry', "D'Antonio") #=> "Hello, Jerry D'Antonio!"
192
+ ```
193
+
194
+ If for some reason you don't care about one or more unbound parameters within
195
+ the block you can use the `_` underscore character in the block parameters list
196
+ as well:
197
+
198
+ ```ruby
199
+ defn(:greet, _, _, _) do |first, _, last|
200
+ "Hello, #{first} #{last}!"
201
+ end
202
+
203
+ ...
204
+
205
+ foo.greet('Jerry', "I'm not going to tell you my middle name!", "D'Antonio") #=> "Hello, Jerry D'Antonio!"
206
+ ```
207
+
208
+ Hash parameters can match against specific keys and either bound or unbound parameters. This allows for
209
+ function dispatch by hash parameters without having to dig through the hash:
210
+
211
+ ```ruby
212
+ defn(:hashable, {foo: :bar}) { |opts|
213
+ :foo_bar
214
+ }
215
+ defn(:hashable, {foo: _}) { |f|
216
+ f
217
+ }
218
+
219
+ ...
220
+
221
+ foo.hashable({foo: :bar}) #=> :foo_bar
222
+ foo.hashable({foo: :baz}) #=> :baz
223
+ ```
224
+
225
+ The Ruby idiom of the final parameter being a hash is also supported:
226
+
227
+ ```ruby
228
+ defn(:options, _) { |opts|
229
+ opts
230
+ }
231
+
232
+ ...
233
+
234
+ foo.options(bar: :baz, one: 1, many: 2)
235
+ ```
236
+
237
+ As is the Ruby idiom of variable-length argument lists. The constant `ALL` as the last parameter
238
+ will match one or more arguments and pass them to the block as an array:
239
+
240
+ ```ruby
241
+ defn(:baz, Integer, ALL) { |int, args|
242
+ [int, args]
243
+ }
244
+ defn(:baz, ALL) { |args|
245
+ args
246
+ }
247
+ ```
248
+
249
+ Superclass polymorphism is supported as well. If an object cannot match a method
250
+ signature it will defer to the parent class:
251
+
252
+ ```ruby
253
+ class Bar
254
+ def greet
255
+ return 'Hello, World!'
256
+ end
257
+ end
258
+
259
+ class Foo < Bar
260
+ include PatternMatching
261
+
262
+ defn(:greet, _) do |name|
263
+ "Hello, #{name}!"
264
+ end
265
+ end
266
+
267
+ ...
268
+
269
+ foo.greet('Jerry') #=> "Hello, Jerry!"
270
+ foo.greet #=> "Hello, World!"
271
+ ```
272
+
273
+ Guard clauses in Erlang are defined with `when` clauses between the parameter list and the function body.
274
+ In Ruby, guard clauses are defined by chaining a call to `when` onto the the `defn` call and passing
275
+ a block. If the guard clause evaluates to true then the function will match. If the guard evaluates
276
+ to false the function will not match and pattern matching will continue:
277
+
278
+ Erlang:
279
+
280
+ ```erlang
281
+ old_enough(X) when X >= 16 -> true;
282
+ old_enough(_) -> false.
283
+ ```
284
+
285
+ Ruby:
286
+
287
+ ```ruby
288
+ defn(:old_enough, _){ true }.when{|x| x >= 16 }
289
+ defn(:old_enough, _){ false }
290
+ ```
291
+
292
+ ### Order Matters
293
+
294
+ As with Erlang, the order of pattern matches is significant. Patterns will be matched
295
+ *in the order declared* and the first match will be used. If a particular function call
296
+ can be matched by more than one pattern, the *first matched pattern* will be used. It
297
+ is the programmer's responsibility to ensure patterns are declared in the correct order.
298
+
299
+ ### Blocks and Procs and Lambdas, oh my!
300
+
301
+ When using this gem it is critical to remember that `defn` takes a block and
302
+ that blocks in Ruby have special rules. There are [plenty](https://www.google.com/search?q=ruby+block+proc+lambda)
303
+ of good tutorials on the web explaining [blocks](http://www.robertsosinski.com/2008/12/21/understanding-ruby-blocks-procs-and-lambdas/)
304
+ and [Procs](https://coderwall.com/p/_-_mha) and [lambdas](http://railsguru.org/2010/03/learn-ruby-procs-blocks-lambda/)
305
+ in Ruby. Please read them. Please don't submit a bug report if you use a
306
+ `return` statement within your `defn` and your code blows up with a
307
+ [LocalJumpError](http://ruby-doc.org/core-2.0/LocalJumpError.html).
308
+
309
+ ## Examples
310
+
311
+ For more examples see the integration tests in *spec/integration_spec.rb*.
312
+
313
+ ### Simple Functions
314
+
315
+ This example is based on [Syntax in defnctions: Pattern Matching](http://learnyousomeerlang.com/syntax-in-defnctions) in [Learn You Some Erlang for Great Good!](http://learnyousomeerlang.com/).
316
+
317
+ Erlang:
318
+
319
+ ```erlang
320
+ greet(male, Name) ->
321
+ io:format("Hello, Mr. ~s!", [Name]);
322
+ greet(female, Name) ->
323
+ io:format("Hello, Mrs. ~s!", [Name]);
324
+ greet(_, Name) ->
325
+ io:format("Hello, ~s!", [Name]).
326
+ ```
327
+
328
+ Ruby:
329
+
330
+ ```ruby
331
+ require 'pattern_matching'
332
+
333
+ class Foo
334
+ include PatternMatching
335
+
336
+ defn(:greet, _) do |name|
337
+ "Hello, #{name}!"
338
+ end
339
+
340
+ defn(:greet, :male, _) { |name|
341
+ "Hello, Mr. #{name}!"
342
+ }
343
+ defn(:greet, :female, _) { |name|
344
+ "Hello, Ms. #{name}!"
345
+ }
346
+ defn(:greet, _, _) { |_, name|
347
+ "Hello, #{name}!"
348
+ }
349
+ end
350
+ ```
351
+
352
+ ### Simple Functions with Overloading
353
+
354
+ This example is based on [Syntax in defnctions: Pattern Matching](http://learnyousomeerlang.com/syntax-in-defnctions) in [Learn You Some Erlang for Great Good!](http://learnyousomeerlang.com/).
355
+
356
+ Erlang:
357
+
358
+ ```erlang
359
+ greet(Name) ->
360
+ io:format("Hello, ~s!", [Name]).
361
+
362
+ greet(male, Name) ->
363
+ io:format("Hello, Mr. ~s!", [Name]);
364
+ greet(female, Name) ->
365
+ io:format("Hello, Mrs. ~s!", [Name]);
366
+ greet(_, Name) ->
367
+ io:format("Hello, ~s!", [Name]).
368
+ ```
369
+
370
+ Ruby:
371
+
372
+ ```ruby
373
+ require 'pattern_matching'
374
+
375
+ class Foo
376
+ include PatternMatching
377
+
378
+ defn(:greet, _) do |name|
379
+ "Hello, #{name}!"
380
+ end
381
+
382
+ defn(:greet, :male, _) { |name|
383
+ "Hello, Mr. #{name}!"
384
+ }
385
+ defn(:greet, :female, _) { |name|
386
+ "Hello, Ms. #{name}!"
387
+ }
388
+ defn(:greet, nil, _) { |name|
389
+ "Goodbye, #{name}!"
390
+ }
391
+ defn(:greet, _, _) { |_, name|
392
+ "Hello, #{name}!"
393
+ }
394
+ end
395
+ ```
396
+
397
+ ### Constructor Overloading
398
+
399
+ ```ruby
400
+ require 'pattern_matching'
401
+
402
+ class Foo
403
+ include PatternMatching
404
+
405
+ defn(:initialize) { @name = 'baz' }
406
+ defn(:initialize, _) {|name| @name = name.to_s }
407
+ end
408
+ ```
409
+
410
+ ### Matching by Class/Datatype
411
+
412
+ ```ruby
413
+ require 'pattern_matching'
414
+
415
+ class Foo
416
+ include PatternMatching
417
+
418
+ defn(:concat, Integer, Integer) { |first, second|
419
+ first + second
420
+ }
421
+ defn(:concat, Integer, String) { |first, second|
422
+ "#{first} #{second}"
423
+ }
424
+ defn(:concat, String, String) { |first, second|
425
+ first + second
426
+ }
427
+ defn(:concat, Integer, _) { |first, second|
428
+ first + second.to_i
429
+ }
430
+ end
431
+ ```
432
+
433
+ ### Matching a Hash Parameter
434
+
435
+ ```ruby
436
+ require 'pattern_matching'
437
+
438
+ class Foo
439
+ include PatternMatching
440
+
441
+ defn(:hashable, {foo: :bar}) { |opts|
442
+ # matches any hash with key :foo and value :bar
443
+ :foo_bar
444
+ }
445
+ defn(:hashable, {foo: _, bar: _}) { |f, b|
446
+ # matches any hash with keys :foo and :bar
447
+ # passes the values associated with those keys to the block
448
+ [f, b]
449
+ }
450
+ defn(:hashable, {foo: _}) { |f|
451
+ # matches any hash with key :foo
452
+ # passes the value associated with that key to the block
453
+ # must appear AFTER the prior match or it will override that one
454
+ f
455
+ }
456
+ defn(:hashable, {}) { ||
457
+ # matches an empty hash
458
+ :empty
459
+ }
460
+ defn(:hashable, _) { |opts|
461
+ # matches any hash (or any other value)
462
+ opts
463
+ }
464
+ end
465
+
466
+ ...
467
+
468
+ foo.hashable({foo: :bar}) #=> :foo_bar
469
+ foo.hashable({foo: :baz}) #=> :baz
470
+ foo.hashable({foo: 1, bar: 2}) #=> [1, 2]
471
+ foo.hashable({foo: 1, baz: 2}) #=> 1
472
+ foo.hashable({bar: :baz}) #=> {bar: :baz}
473
+ foo.hashable({}) #=> :empty
474
+ ```
475
+
476
+ ### Variable Length Argument Lists with ALL
477
+
478
+ ```ruby
479
+ defn(:all, :one, ALL) { |args|
480
+ args
481
+ }
482
+ defn(:all, :one, Integer, ALL) { |int, args|
483
+ [int, args]
484
+ }
485
+ defn(:all, 1, _, ALL) { |var, args|
486
+ [var, args]
487
+ }
488
+ defn(:all, ALL) { | args|
489
+ args
490
+ }
491
+
492
+ ...
493
+
494
+ foo.all(:one, 'a', 'bee', :see) #=> ['a', 'bee', :see]
495
+ foo.all(:one, 1, 'bee', :see) #=> [1, 'bee', :see]
496
+ foo.all(1, 'a', 'bee', :see) #=> ['a', ['bee', :see]]
497
+ foo.all('a', 'bee', :see) #=> ['a', 'bee', :see]
498
+ foo.all() #=> NoMethodError: no method `all` matching [] found for class Foo
499
+ ```
500
+
501
+ ### Guard Clauses
502
+
503
+ These examples are based on [Syntax in defnctions: Pattern Matching](http://learnyousomeerlang.com/syntax-in-defnctions)
504
+ in [Learn You Some Erlang for Great Good!](http://learnyousomeerlang.com/).
505
+
506
+ Erlang:
507
+
508
+ ```erlang
509
+ old_enough(X) when X >= 16 -> true;
510
+ old_enough(_) -> false.
511
+
512
+ right_age(X) when X >= 16, X =< 104 ->
513
+ true;
514
+ right_age(_) ->
515
+ false.
516
+
517
+ wrong_age(X) when X < 16; X > 104 ->
518
+ true;
519
+ wrong_age(_) ->
520
+ false.
521
+ ```
522
+
523
+ ```ruby
524
+ defn(:old_enough, _){ true }.when{|x| x >= 16 }
525
+ defn(:old_enough, _){ false }
526
+
527
+ defn(:right_age, _) {
528
+ true
529
+ }.when{|x| x >= 16 && x <= 104 }
530
+
531
+ defn(:right_age, _) {
532
+ false
533
+ }
534
+
535
+ defn(:wrong_age, _) {
536
+ false
537
+ }.when{|x| x < 16 || x > 104 }
538
+
539
+ defn(:wrong_age, _) {
540
+ true
541
+ }
542
+ ```
543
+
544
+ ### Behavior
545
+
546
+ The `behavior` functionality is not import by default. It requires a separate require statement:
547
+
548
+ ```ruby
549
+ require 'behavior'
550
+
551
+ # -or-
552
+
553
+ require 'behaviour'
554
+ ```
555
+
556
+ Next, declare a behavior using the `behavior_info` function (this function should sit outside
557
+ of any module/class definition, but will probably work regardless). The first parameter to
558
+ `behavior_info` (or `behaviour_info`) is a symbol name for the behavior. The remaining parameter
559
+ is a hash of function names and their arity:
560
+
561
+ ```ruby
562
+ behaviour_info(:gen_foo, foo: 0, bar: 1, baz: 2)
563
+
564
+ # -or (for the Java/C# crowd)
565
+
566
+ interface(:gen_foo, foo: 0, bar: 1, baz: 2)
567
+
568
+ ```
569
+
570
+ Each function name can be listed only once and the arity must follow the rules of the
571
+ [Method#arity](http://ruby-doc.org/core-1.9.3/Method.html#method-i-arity) function.
572
+ Though not explicitly documented, block arguments do not count toward a method's arity.
573
+ methods defined using this gem's `defn` function will always have an arity of -1,
574
+ regardless of how many overloads are defined.
575
+
576
+ To enforce a behavior on a class simply call the `behavior` function within the class,
577
+ passing the name of the desired behavior:
578
+
579
+ ```ruby
580
+ class Foo
581
+ behavior(:gen_foo)
582
+ ...
583
+ end
584
+
585
+ # or use the idiomatic Erlang spelling
586
+ class Bar
587
+ behaviour(:gen_foo)
588
+ ...
589
+ end
590
+
591
+ # or use the idiomatic Rails syntax
592
+ class Baz
593
+ behaves_as :gen_foo
594
+ ...
595
+ end
596
+ ```
597
+
598
+ Make sure you the implement the required methods in your class. If you don't, Ruby will
599
+ raise an exception when you try to create an object from the class:
600
+
601
+ ```ruby
602
+ Baz.new #=> ArgumentError: undefined callback functions in Baz (behavior 'gen_foo')
603
+ ```
604
+
605
+ As an added bonus, Ruby [Object](http://ruby-doc.org/core-1.9.3/Object.html) will be
606
+ monkey-patched with a `behaves_as?` predicate method.
607
+
608
+ A complete example:
609
+
610
+ ```ruby
611
+ behaviour_info(:gen_foo, foo: 0, bar: 1, baz: 2, boom: -1, bam: :any)
612
+
613
+ class Foo
614
+ behavior(:gen_foo)
615
+
616
+ def foo
617
+ return 'foo/0'
618
+ end
619
+
620
+ def bar(one, &block)
621
+ return 'bar/1'
622
+ end
623
+
624
+ def baz(one, two)
625
+ return 'baz/2'
626
+ end
627
+
628
+ def boom(*args)
629
+ return 'boom/-1'
630
+ end
631
+
632
+ def bam
633
+ return 'bam!'
634
+ end
635
+ end
636
+
637
+ foo = Foo.new
638
+
639
+ foo.behaves_as? :gen_foo #=> true
640
+ foo.behaves_as?(:bogus) #=> false
641
+ 'foo'.behaves_as? :gen_foo #=> false
642
+ ```
643
+
644
+ ## Copyright
645
+
646
+ *PatternMatching* is Copyright &copy; 2013 [Jerry D'Antonio](https://twitter.com/jerrydantonio).
647
+ It is free software and may be redistributed under the terms specified in the LICENSE file.
648
+
649
+ ## License
650
+
651
+ Released under the MIT license.
652
+
653
+ http://www.opensource.org/licenses/mit-license.php
654
+
655
+ > Permission is hereby granted, free of charge, to any person obtaining a copy
656
+ > of this software and associated documentation files (the "Software"), to deal
657
+ > in the Software without restriction, including without limitation the rights
658
+ > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
659
+ > copies of the Software, and to permit persons to whom the Software is
660
+ > furnished to do so, subject to the following conditions:
661
+ >
662
+ > The above copyright notice and this permission notice shall be included in
663
+ > all copies or substantial portions of the Software.
664
+ >
665
+ > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
666
+ > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
667
+ > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
668
+ > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
669
+ > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
670
+ > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
671
+ > THE SOFTWARE.