functional-ruby 0.7.7 → 1.0.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.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +92 -152
  3. data/doc/memo.txt +192 -0
  4. data/doc/pattern_matching.txt +485 -0
  5. data/doc/protocol.txt +221 -0
  6. data/doc/record.txt +144 -0
  7. data/doc/thread_safety.txt +8 -0
  8. data/lib/functional.rb +48 -18
  9. data/lib/functional/abstract_struct.rb +161 -0
  10. data/lib/functional/delay.rb +117 -0
  11. data/lib/functional/either.rb +222 -0
  12. data/lib/functional/memo.rb +93 -0
  13. data/lib/functional/method_signature.rb +72 -0
  14. data/lib/functional/option.rb +209 -0
  15. data/lib/functional/pattern_matching.rb +117 -100
  16. data/lib/functional/protocol.rb +157 -0
  17. data/lib/functional/protocol_info.rb +193 -0
  18. data/lib/functional/record.rb +155 -0
  19. data/lib/functional/type_check.rb +112 -0
  20. data/lib/functional/union.rb +152 -0
  21. data/lib/functional/version.rb +3 -1
  22. data/spec/functional/abstract_struct_shared.rb +154 -0
  23. data/spec/functional/complex_pattern_matching_spec.rb +205 -0
  24. data/spec/functional/configuration_spec.rb +17 -0
  25. data/spec/functional/delay_spec.rb +147 -0
  26. data/spec/functional/either_spec.rb +237 -0
  27. data/spec/functional/memo_spec.rb +207 -0
  28. data/spec/functional/option_spec.rb +292 -0
  29. data/spec/functional/pattern_matching_spec.rb +279 -276
  30. data/spec/functional/protocol_info_spec.rb +444 -0
  31. data/spec/functional/protocol_spec.rb +274 -0
  32. data/spec/functional/record_spec.rb +175 -0
  33. data/spec/functional/type_check_spec.rb +103 -0
  34. data/spec/functional/union_spec.rb +110 -0
  35. data/spec/spec_helper.rb +6 -4
  36. metadata +55 -45
  37. data/lib/functional/behavior.rb +0 -138
  38. data/lib/functional/behaviour.rb +0 -2
  39. data/lib/functional/catalog.rb +0 -487
  40. data/lib/functional/collection.rb +0 -403
  41. data/lib/functional/inflect.rb +0 -127
  42. data/lib/functional/platform.rb +0 -120
  43. data/lib/functional/search.rb +0 -132
  44. data/lib/functional/sort.rb +0 -41
  45. data/lib/functional/utilities.rb +0 -189
  46. data/md/behavior.md +0 -188
  47. data/md/catalog.md +0 -32
  48. data/md/collection.md +0 -32
  49. data/md/inflect.md +0 -32
  50. data/md/pattern_matching.md +0 -512
  51. data/md/platform.md +0 -32
  52. data/md/search.md +0 -32
  53. data/md/sort.md +0 -32
  54. data/md/utilities.md +0 -55
  55. data/spec/functional/behavior_spec.rb +0 -528
  56. data/spec/functional/catalog_spec.rb +0 -1206
  57. data/spec/functional/collection_spec.rb +0 -752
  58. data/spec/functional/inflect_spec.rb +0 -85
  59. data/spec/functional/integration_spec.rb +0 -205
  60. data/spec/functional/platform_spec.rb +0 -501
  61. data/spec/functional/search_spec.rb +0 -187
  62. data/spec/functional/sort_spec.rb +0 -61
  63. data/spec/functional/utilities_spec.rb +0 -277
@@ -1,188 +0,0 @@
1
- # For good -behavior(:timeoff).
2
-
3
- One of Ruby's greatest strengths is [duck typing](http://rubylearning.com/satishtalim/duck_typing.html).
4
- Usually this is awesome and I'm happy to not have to deal with static typing and the compiler. Usually.
5
- The problem with duck typing is that is is impossible in Ruby to enforce an interface definition.
6
- I would never advocate turning Ruby into the cesspool complex object creation that Java has
7
- unfortunately become, but occasionally it would be nice to make sure a class implements a set of
8
- required methods. Enter Erlang's [-behavior](http://metajack.im/2008/10/29/custom-behaviors-in-erlang/)
9
- keyword. Basically, you define a `behavior_info` then drop a `behavior` call within a class.
10
- Forget to implement a required method and Ruby will let you know. See the examples below for details.
11
-
12
- ## Usage
13
-
14
- Require the gem
15
-
16
- ```ruby
17
- require 'functional'
18
- ```
19
-
20
- ### behavior_info
21
-
22
- Next, declare a behavior using the `behavior_info` function (this function should sit outside
23
- of any module/class definition, but will probably work regardless). The first parameter to
24
- `behavior_info` (or `behaviour_info`) is a symbol name for the behavior. The remaining parameter
25
- is a hash of function names and their arity:
26
-
27
- ```ruby
28
- behaviour_info(:gen_foo, foo: 0, bar: 1, baz: 2)
29
-
30
- # -or (for the Java/C# crowd)
31
-
32
- interface(:gen_foo, foo: 0, bar: 1, baz: 2)
33
- ```
34
-
35
- Each function name can be listed only once and the arity must follow the rules of the
36
- [Method#arity](http://ruby-doc.org/core-1.9.3/Method.html#method-i-arity) function.
37
- Though not explicitly documented, block arguments do not count toward a method's arity.
38
- methods defined using this gem's `defn` function will always have an arity of -1,
39
- regardless of how many overloads are defined.
40
-
41
- To specify class/module methods prepend the methid name with 'self_'
42
-
43
- ```ruby
44
- behaviour_info(:gen_foo, self_foo: 0, self_bar: 1, baz: 2)
45
- ```
46
-
47
- ### behavior
48
-
49
- To enforce a behavior on a class simply call the `behavior` function within the class,
50
- passing the name of the desired behavior:
51
-
52
- ```ruby
53
- class Foo
54
- behavior(:gen_foo)
55
- ...
56
- end
57
-
58
- # or use the idiomatic Erlang spelling
59
- class Bar
60
- behaviour(:gen_foo)
61
- ...
62
- end
63
-
64
- # or use the idiomatic Rails syntax
65
- class Baz
66
- behaves_as :gen_foo
67
- ...
68
- end
69
- ```
70
-
71
- Make sure you the implement the required methods in your class. If you don't, Ruby will
72
- raise an exception when you try to create an object from the class:
73
-
74
- ```ruby
75
- Baz.new #=> ArgumentError: undefined callback functions in Baz (behavior 'gen_foo')
76
- ```
77
-
78
- A class may support multiple behaviors:
79
-
80
- ```ruby
81
- behavior_info(:gen_foo, foo: 0)
82
- behavior_info(:gen_bar, bar: 1)
83
-
84
- class FooBar
85
- behavior(:gen_foo)
86
- behavior(:gen_bar)
87
- ...
88
- end
89
- ```
90
-
91
- Inheritance and module inclusion are supported as well:
92
-
93
- ```ruby
94
- behavior_info(:gen_foo, foo: 0)
95
- behavior_info(:gen_bar, bar: 0)
96
-
97
- class Foo
98
- behavior(:gen_foo)
99
- def foo() nil; end
100
- end
101
-
102
- module Bar
103
- behavior(:gen_bar)
104
- def bar() nil; end
105
- end
106
-
107
- class FooBar < Foo
108
- include Bar
109
- end
110
-
111
- foobar = FooBar.new
112
-
113
- foobar.behaves_as?(:gen_foo) #=> true
114
- foobar.behaves_as?(:gen_bar) #=> true
115
- ```
116
-
117
- ### behaves_as?
118
-
119
- As an added bonus, Ruby [Object](http://ruby-doc.org/core-1.9.3/Object.html) will be
120
- monkey-patched with a `behaves_as?` predicate method.
121
-
122
- ## Example
123
-
124
- A complete example:
125
-
126
- ```ruby
127
- behaviour_info(:gen_foo, self_foo: 0, bar: 1, baz: 2, boom: -1, bam: :any)
128
-
129
- class Foo
130
- behavior(:gen_foo)
131
-
132
- def self.foo
133
- return 'foo/0'
134
- end
135
-
136
- def bar(one, &block)
137
- return 'bar/1'
138
- end
139
-
140
- def baz(one, two)
141
- return 'baz/2'
142
- end
143
-
144
- def boom(*args)
145
- return 'boom/-1'
146
- end
147
-
148
- def bam
149
- return 'bam!'
150
- end
151
- end
152
-
153
- foo = Foo.new
154
-
155
- Foo.behaves_as? :gen_foo #=> true
156
- foo.behaves_as? :gen_foo #=> true
157
- foo.behaves_as?(:bogus) #=> false
158
- 'foo'.behaves_as? :gen_foo #=> false
159
- ```
160
-
161
- ## Copyright
162
-
163
- *Functional Ruby* is Copyright &copy; 2013 [Jerry D'Antonio](https://twitter.com/jerrydantonio).
164
- It is free software and may be redistributed under the terms specified in the LICENSE file.
165
-
166
- ## License
167
-
168
- Released under the MIT license.
169
-
170
- http://www.opensource.org/licenses/mit-license.php
171
-
172
- > Permission is hereby granted, free of charge, to any person obtaining a copy
173
- > of this software and associated documentation files (the "Software"), to deal
174
- > in the Software without restriction, including without limitation the rights
175
- > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
176
- > copies of the Software, and to permit persons to whom the Software is
177
- > furnished to do so, subject to the following conditions:
178
- >
179
- > The above copyright notice and this permission notice shall be included in
180
- > all copies or substantial portions of the Software.
181
- >
182
- > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
183
- > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
184
- > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
185
- > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
186
- > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
187
- > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
188
- > THE SOFTWARE.
@@ -1,32 +0,0 @@
1
- # Catalog
2
-
3
- TBD...
4
-
5
- ## Copyright
6
-
7
- *Functional Ruby* is Copyright &copy; 2013 [Jerry D'Antonio](https://twitter.com/jerrydantonio).
8
- It is free software and may be redistributed under the terms specified in the LICENSE file.
9
-
10
- ## License
11
-
12
- Released under the MIT license.
13
-
14
- http://www.opensource.org/licenses/mit-license.php
15
-
16
- > Permission is hereby granted, free of charge, to any person obtaining a copy
17
- > of this software and associated documentation files (the "Software"), to deal
18
- > in the Software without restriction, including without limitation the rights
19
- > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
20
- > copies of the Software, and to permit persons to whom the Software is
21
- > furnished to do so, subject to the following conditions:
22
- >
23
- > The above copyright notice and this permission notice shall be included in
24
- > all copies or substantial portions of the Software.
25
- >
26
- > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27
- > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28
- > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
29
- > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30
- > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
31
- > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
32
- > THE SOFTWARE.
@@ -1,32 +0,0 @@
1
- # Collection
2
-
3
- TBD...
4
-
5
- ## Copyright
6
-
7
- *Functional Ruby* is Copyright &copy; 2013 [Jerry D'Antonio](https://twitter.com/jerrydantonio).
8
- It is free software and may be redistributed under the terms specified in the LICENSE file.
9
-
10
- ## License
11
-
12
- Released under the MIT license.
13
-
14
- http://www.opensource.org/licenses/mit-license.php
15
-
16
- > Permission is hereby granted, free of charge, to any person obtaining a copy
17
- > of this software and associated documentation files (the "Software"), to deal
18
- > in the Software without restriction, including without limitation the rights
19
- > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
20
- > copies of the Software, and to permit persons to whom the Software is
21
- > furnished to do so, subject to the following conditions:
22
- >
23
- > The above copyright notice and this permission notice shall be included in
24
- > all copies or substantial portions of the Software.
25
- >
26
- > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27
- > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28
- > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
29
- > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30
- > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
31
- > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
32
- > THE SOFTWARE.
@@ -1,32 +0,0 @@
1
- # Inflect
2
-
3
- TBD...
4
-
5
- ## Copyright
6
-
7
- *Functional Ruby* is Copyright &copy; 2013 [Jerry D'Antonio](https://twitter.com/jerrydantonio).
8
- It is free software and may be redistributed under the terms specified in the LICENSE file.
9
-
10
- ## License
11
-
12
- Released under the MIT license.
13
-
14
- http://www.opensource.org/licenses/mit-license.php
15
-
16
- > Permission is hereby granted, free of charge, to any person obtaining a copy
17
- > of this software and associated documentation files (the "Software"), to deal
18
- > in the Software without restriction, including without limitation the rights
19
- > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
20
- > copies of the Software, and to permit persons to whom the Software is
21
- > furnished to do so, subject to the following conditions:
22
- >
23
- > The above copyright notice and this permission notice shall be included in
24
- > all copies or substantial portions of the Software.
25
- >
26
- > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27
- > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28
- > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
29
- > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30
- > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
31
- > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
32
- > THE SOFTWARE.
@@ -1,512 +0,0 @@
1
- # Erlang-style Pattern Matching
2
-
3
- As much as I love Ruby I've always been a little disappointed that Ruby doesn't
4
- support function overloading. Function overloading tends to reduce branching
5
- and keep function signatures simpler. No sweat, I learned to do without. Then
6
- I started programming in Erlang. My favorite Erlang feature is, without
7
- question, pattern matching. Pattern matching is like function overloading
8
- cranked to 11. So one day I was musing on Twitter that I'd like to see
9
- Erlang-stype pattern matching in Ruby and one of my friends responded
10
- "Build it!" So I did. And here it is.
11
-
12
-
13
- ## Features
14
-
15
- * Pattern matching for instance methods.
16
- * Pattern matching for object constructors.
17
- * Parameter count matching
18
- * Matching against primitive values
19
- * Matching by class/datatype
20
- * Matching against specific key/vaue pairs in hashes
21
- * Matching against the presence of keys within hashes
22
- * Implicit hash for last parameter
23
- * Variable-length parameter lists
24
- * Guard clauses
25
- * Recursive calls to other pattern matches
26
- * Recursive calls to superclass pattern matches
27
- * Recursive calls to superclass methods
28
- * Dispatching to superclass methods when no match is found
29
- * Reasonable error messages when no match is found
30
-
31
- ## Usage
32
-
33
- First, familiarize yourself with Erlang [pattern matching](http://learnyousomeerlang.com/syntax-in-functions#pattern-matching).
34
- This gem may not make much sense if you don't understand how Erlang dispatches functions.
35
-
36
- In the Ruby class file where you want to use pattern matching, require the *functional-ruby* gem:
37
-
38
- ```ruby
39
- require 'functional'
40
- ```
41
-
42
- Then include `PatternMatching` in your class:
43
-
44
- ```ruby
45
- require 'functional'
46
-
47
- class Foo
48
- include PatternMatching
49
-
50
- ...
51
-
52
- end
53
- ```
54
-
55
- You can then define functions with `defn` instead of the normal *def* statement.
56
- The syntax for `defn` is:
57
-
58
- ```ruby
59
- defn(:symbol_name_of_function, zero, or, more, parameters) { |block, arguments|
60
- # code to execute
61
- }
62
- ```
63
- You can then call your new function just like any other:
64
-
65
- ```ruby
66
- require 'functional/pattern_matching'
67
-
68
- class Foo
69
- include PatternMatching
70
-
71
- defn(:hello) {
72
- puts "Hello, World!"
73
- }
74
- end
75
-
76
- foo = Foo.new
77
- foo.hello #=> "Hello, World!"
78
- ```
79
-
80
- Patterns to match against are included in the parameter list:
81
-
82
- ```ruby
83
- defn(:greet, :male) {
84
- puts "Hello, sir!"
85
- }
86
-
87
- defn(:greet, :female) {
88
- puts "Hello, ma'am!"
89
- }
90
-
91
- ...
92
-
93
- foo.greet(:male) #=> "Hello, sir!"
94
- foo.greet(:female) #=> "Hello, ma'am!"
95
- ```
96
-
97
- If a particular method call can not be matched a *NoMethodError* is thrown with
98
- a reasonably helpful error message:
99
-
100
- ```ruby
101
- foo.greet(:unknown) #=> NoMethodError: no method `greet` matching [:unknown] found for class Foo
102
- foo.greet #=> NoMethodError: no method `greet` matching [] found for class Foo
103
- ```
104
-
105
- Parameters that are expected to exist but that can take any value are considered
106
- *unbound* parameters. Unbound parameters are specified by the `_` underscore
107
- character or `UNBOUND`:
108
-
109
- ```ruby
110
- defn(:greet, _) do |name|
111
- "Hello, #{name}!"
112
- end
113
-
114
- defn(:greet, UNBOUND, UNBOUND) do |first, last|
115
- "Hello, #{first} #{last}!"
116
- end
117
-
118
- ...
119
-
120
- foo.greet('Jerry') #=> "Hello, Jerry!"
121
- ```
122
-
123
- All unbound parameters will be passed to the block in the order they are specified in the definition:
124
-
125
- ```ruby
126
- defn(:greet, _, _) do |first, last|
127
- "Hello, #{first} #{last}!"
128
- end
129
-
130
- ...
131
-
132
- foo.greet('Jerry', "D'Antonio") #=> "Hello, Jerry D'Antonio!"
133
- ```
134
-
135
- If for some reason you don't care about one or more unbound parameters within
136
- the block you can use the `_` underscore character in the block parameters list
137
- as well:
138
-
139
- ```ruby
140
- defn(:greet, _, _, _) do |first, _, last|
141
- "Hello, #{first} #{last}!"
142
- end
143
-
144
- ...
145
-
146
- foo.greet('Jerry', "I'm not going to tell you my middle name!", "D'Antonio") #=> "Hello, Jerry D'Antonio!"
147
- ```
148
-
149
- Hash parameters can match against specific keys and either bound or unbound parameters. This allows for
150
- function dispatch by hash parameters without having to dig through the hash:
151
-
152
- ```ruby
153
- defn(:hashable, {foo: :bar}) { |opts|
154
- :foo_bar
155
- }
156
- defn(:hashable, {foo: _}) { |f|
157
- f
158
- }
159
-
160
- ...
161
-
162
- foo.hashable({foo: :bar}) #=> :foo_bar
163
- foo.hashable({foo: :baz}) #=> :baz
164
- ```
165
-
166
- The Ruby idiom of the final parameter being a hash is also supported:
167
-
168
- ```ruby
169
- defn(:options, _) { |opts|
170
- opts
171
- }
172
-
173
- ...
174
-
175
- foo.options(bar: :baz, one: 1, many: 2)
176
- ```
177
-
178
- As is the Ruby idiom of variable-length argument lists. The constant `ALL` as the last parameter
179
- will match one or more arguments and pass them to the block as an array:
180
-
181
- ```ruby
182
- defn(:baz, Integer, ALL) { |int, args|
183
- [int, args]
184
- }
185
- defn(:baz, ALL) { |args|
186
- args
187
- }
188
- ```
189
-
190
- Superclass polymorphism is supported as well. If an object cannot match a method
191
- signature it will defer to the parent class:
192
-
193
- ```ruby
194
- class Bar
195
- def greet
196
- return 'Hello, World!'
197
- end
198
- end
199
-
200
- class Foo < Bar
201
- include PatternMatching
202
-
203
- defn(:greet, _) do |name|
204
- "Hello, #{name}!"
205
- end
206
- end
207
-
208
- ...
209
-
210
- foo.greet('Jerry') #=> "Hello, Jerry!"
211
- foo.greet #=> "Hello, World!"
212
- ```
213
-
214
- Guard clauses in Erlang are defined with `when` clauses between the parameter list and the function body.
215
- In Ruby, guard clauses are defined by chaining a call to `when` onto the the `defn` call and passing
216
- a block. If the guard clause evaluates to true then the function will match. If the guard evaluates
217
- to false the function will not match and pattern matching will continue:
218
-
219
- Erlang:
220
-
221
- ```erlang
222
- old_enough(X) when X >= 16 -> true;
223
- old_enough(_) -> false.
224
- ```
225
-
226
- Ruby:
227
-
228
- ```ruby
229
- defn(:old_enough, _){ true }.when{|x| x >= 16 }
230
- defn(:old_enough, _){ false }
231
- ```
232
-
233
- ### Order Matters
234
-
235
- As with Erlang, the order of pattern matches is significant. Patterns will be matched
236
- *in the order declared* and the first match will be used. If a particular function call
237
- can be matched by more than one pattern, the *first matched pattern* will be used. It
238
- is the programmer's responsibility to ensure patterns are declared in the correct order.
239
-
240
- ### Blocks and Procs and Lambdas, oh my!
241
-
242
- When using this gem it is critical to remember that `defn` takes a block and
243
- that blocks in Ruby have special rules. There are [plenty](https://www.google.com/search?q=ruby+block+proc+lambda)
244
- of good tutorials on the web explaining [blocks](http://www.robertsosinski.com/2008/12/21/understanding-ruby-blocks-procs-and-lambdas/)
245
- and [Procs](https://coderwall.com/p/_-_mha) and [lambdas](http://railsguru.org/2010/03/learn-ruby-procs-blocks-lambda/)
246
- in Ruby. Please read them. Please don't submit a bug report if you use a
247
- `return` statement within your `defn` and your code blows up with a
248
- [LocalJumpError](http://ruby-doc.org/core-2.0/LocalJumpError.html).
249
-
250
- ### Examples
251
-
252
- For more examples see the integration tests in *spec/integration_spec.rb*.
253
-
254
- #### Simple Functions
255
-
256
- 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/).
257
-
258
- Erlang:
259
-
260
- ```erlang
261
- greet(male, Name) ->
262
- io:format("Hello, Mr. ~s!", [Name]);
263
- greet(female, Name) ->
264
- io:format("Hello, Mrs. ~s!", [Name]);
265
- greet(_, Name) ->
266
- io:format("Hello, ~s!", [Name]).
267
- ```
268
-
269
- Ruby:
270
-
271
- ```ruby
272
- require 'functional/pattern_matching'
273
-
274
- class Foo
275
- include PatternMatching
276
-
277
- defn(:greet, _) do |name|
278
- "Hello, #{name}!"
279
- end
280
-
281
- defn(:greet, :male, _) { |name|
282
- "Hello, Mr. #{name}!"
283
- }
284
- defn(:greet, :female, _) { |name|
285
- "Hello, Ms. #{name}!"
286
- }
287
- defn(:greet, _, _) { |_, name|
288
- "Hello, #{name}!"
289
- }
290
- end
291
- ```
292
-
293
- #### Simple Functions with Overloading
294
-
295
- 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/).
296
-
297
- Erlang:
298
-
299
- ```erlang
300
- greet(Name) ->
301
- io:format("Hello, ~s!", [Name]).
302
-
303
- greet(male, Name) ->
304
- io:format("Hello, Mr. ~s!", [Name]);
305
- greet(female, Name) ->
306
- io:format("Hello, Mrs. ~s!", [Name]);
307
- greet(_, Name) ->
308
- io:format("Hello, ~s!", [Name]).
309
- ```
310
-
311
- Ruby:
312
-
313
- ```ruby
314
- require 'functional/pattern_matching'
315
-
316
- class Foo
317
- include PatternMatching
318
-
319
- defn(:greet, _) do |name|
320
- "Hello, #{name}!"
321
- end
322
-
323
- defn(:greet, :male, _) { |name|
324
- "Hello, Mr. #{name}!"
325
- }
326
- defn(:greet, :female, _) { |name|
327
- "Hello, Ms. #{name}!"
328
- }
329
- defn(:greet, nil, _) { |name|
330
- "Goodbye, #{name}!"
331
- }
332
- defn(:greet, _, _) { |_, name|
333
- "Hello, #{name}!"
334
- }
335
- end
336
- ```
337
-
338
- #### Constructor Overloading
339
-
340
- ```ruby
341
- require 'functional/pattern_matching'
342
-
343
- class Foo
344
- include PatternMatching
345
-
346
- defn(:initialize) { @name = 'baz' }
347
- defn(:initialize, _) {|name| @name = name.to_s }
348
- end
349
- ```
350
-
351
- #### Matching by Class/Datatype
352
-
353
- ```ruby
354
- require 'functional/pattern_matching'
355
-
356
- class Foo
357
- include PatternMatching
358
-
359
- defn(:concat, Integer, Integer) { |first, second|
360
- first + second
361
- }
362
- defn(:concat, Integer, String) { |first, second|
363
- "#{first} #{second}"
364
- }
365
- defn(:concat, String, String) { |first, second|
366
- first + second
367
- }
368
- defn(:concat, Integer, _) { |first, second|
369
- first + second.to_i
370
- }
371
- end
372
- ```
373
-
374
- #### Matching a Hash Parameter
375
-
376
- ```ruby
377
- require 'functional/pattern_matching'
378
-
379
- class Foo
380
- include PatternMatching
381
-
382
- defn(:hashable, {foo: :bar}) { |opts|
383
- # matches any hash with key :foo and value :bar
384
- :foo_bar
385
- }
386
- defn(:hashable, {foo: _, bar: _}) { |f, b|
387
- # matches any hash with keys :foo and :bar
388
- # passes the values associated with those keys to the block
389
- [f, b]
390
- }
391
- defn(:hashable, {foo: _}) { |f|
392
- # matches any hash with key :foo
393
- # passes the value associated with that key to the block
394
- # must appear AFTER the prior match or it will override that one
395
- f
396
- }
397
- defn(:hashable, {}) { ||
398
- # matches an empty hash
399
- :empty
400
- }
401
- defn(:hashable, _) { |opts|
402
- # matches any hash (or any other value)
403
- opts
404
- }
405
- end
406
-
407
- ...
408
-
409
- foo.hashable({foo: :bar}) #=> :foo_bar
410
- foo.hashable({foo: :baz}) #=> :baz
411
- foo.hashable({foo: 1, bar: 2}) #=> [1, 2]
412
- foo.hashable({foo: 1, baz: 2}) #=> 1
413
- foo.hashable({bar: :baz}) #=> {bar: :baz}
414
- foo.hashable({}) #=> :empty
415
- ```
416
-
417
- #### Variable Length Argument Lists with ALL
418
-
419
- ```ruby
420
- defn(:all, :one, ALL) { |args|
421
- args
422
- }
423
- defn(:all, :one, Integer, ALL) { |int, args|
424
- [int, args]
425
- }
426
- defn(:all, 1, _, ALL) { |var, args|
427
- [var, args]
428
- }
429
- defn(:all, ALL) { | args|
430
- args
431
- }
432
-
433
- ...
434
-
435
- foo.all(:one, 'a', 'bee', :see) #=> ['a', 'bee', :see]
436
- foo.all(:one, 1, 'bee', :see) #=> [1, 'bee', :see]
437
- foo.all(1, 'a', 'bee', :see) #=> ['a', ['bee', :see]]
438
- foo.all('a', 'bee', :see) #=> ['a', 'bee', :see]
439
- foo.all() #=> NoMethodError: no method `all` matching [] found for class Foo
440
- ```
441
-
442
- #### Guard Clauses
443
-
444
- These examples are based on [Syntax in defnctions: Pattern Matching](http://learnyousomeerlang.com/syntax-in-defnctions)
445
- in [Learn You Some Erlang for Great Good!](http://learnyousomeerlang.com/).
446
-
447
- Erlang:
448
-
449
- ```erlang
450
- old_enough(X) when X >= 16 -> true;
451
- old_enough(_) -> false.
452
-
453
- right_age(X) when X >= 16, X =< 104 ->
454
- true;
455
- right_age(_) ->
456
- false.
457
-
458
- wrong_age(X) when X < 16; X > 104 ->
459
- true;
460
- wrong_age(_) ->
461
- false.
462
- ```
463
-
464
- ```ruby
465
- defn(:old_enough, _){ true }.when{|x| x >= 16 }
466
- defn(:old_enough, _){ false }
467
-
468
- defn(:right_age, _) {
469
- true
470
- }.when{|x| x >= 16 && x <= 104 }
471
-
472
- defn(:right_age, _) {
473
- false
474
- }
475
-
476
- defn(:wrong_age, _) {
477
- false
478
- }.when{|x| x < 16 || x > 104 }
479
-
480
- defn(:wrong_age, _) {
481
- true
482
- }
483
- ```
484
-
485
- ## Copyright
486
-
487
- *Functional Ruby* is Copyright &copy; 2013 [Jerry D'Antonio](https://twitter.com/jerrydantonio).
488
- It is free software and may be redistributed under the terms specified in the LICENSE file.
489
-
490
- ## License
491
-
492
- Released under the MIT license.
493
-
494
- http://www.opensource.org/licenses/mit-license.php
495
-
496
- > Permission is hereby granted, free of charge, to any person obtaining a copy
497
- > of this software and associated documentation files (the "Software"), to deal
498
- > in the Software without restriction, including without limitation the rights
499
- > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
500
- > copies of the Software, and to permit persons to whom the Software is
501
- > furnished to do so, subject to the following conditions:
502
- >
503
- > The above copyright notice and this permission notice shall be included in
504
- > all copies or substantial portions of the Software.
505
- >
506
- > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
507
- > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
508
- > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
509
- > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
510
- > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
511
- > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
512
- > THE SOFTWARE.