functional-ruby 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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.