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