This repository is private.
All pages are served over SSL and all pushing and pulling is done over SSH.
No one may fork, clone, or view it unless they are added as a member.
Every repository with this icon (
) is private.
Every repository with this icon (
This repository is public.
Anyone may fork, clone, or view it.
Every repository with this icon (
) is public.
Every repository with this icon (
Run the following if you haven't already:
gem sources -a http://gems.github.com
Install the gem(s):
sudo gem install dyoder-functor
functor / doc
| name | age | message | |
|---|---|---|---|
| .. | |||
| |
HISTORY | Sun Jun 15 18:16:12 -0700 2008 | [dyoder] |
| |
README | Mon Jun 16 10:20:58 -0700 2008 | [dyoder] |
README
Functor provides pattern-based function and method dispatch for Ruby, originally inspired by Topher Cyll's multi gem.
= Method Functors
To use it in a class:
class Repeater
attr_accessor :times
include Functor::Method
functor( :repeat, Integer ) { |x| x * @times }
functor( :repeat, String ) { |s| [].fill( s, 0..@times ).join(' ') }
end
r = Repeater.new
r.times = 5
r.repeat( 5 ) # => 25
r.repeat( "-" ) # => "- - - - -"
r.repeat( 7.3 ) # => ArgumentError!
Warning: This defines a class instance variable <tt>@__functors</tt> behind the scenes as a side-effect. Also, although
inheritance works within a functor method, super does not. To call the parent method, you need to call it explicitly
using the <tt>#functors</tt> class method, like this:
A.functors[ :foo ].apply( self, 'bar' )
= Stand-Alone Functors
You can also define Functor objects directly:
fib = Functor.new do
given( 0 ) { 0 }
given( 1 ) { 1 }
given( Integer ) { |n| self.call( n - 1 ) + self.call( n - 2 ) }
end
You can use functors directly with functions taking a block like this:
[ *0..10 ].map( &fib ) # => [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
You can call a functor as a method using #apply:
fun.apply( obj, 7 )
which is actually how the method functors are implemented.
= Pattern Matching
Arguments are matched first using === and then ==, so anything that supports these methods can be matched against. In
addition, you may pass "guards," any object that responds to #call and which take and object (the argument) and return
true or false. This allows you to do things like this:
stripe ||= Functor.new do
given( lambda { |x| x % 2 == 0 } ) { 'white' }
given( lambda { |x| x % 2 == 1 } ) { 'silver' }
end
which will return "white" and "silver" alternately for a sequence of numbers.
= Precedence
Precedence is defined in order of declaration: first-come, first-serve, aka FIFO. Thus, you need to be careful in how
you define your functor. The Fibonacci example above would not work properly if the Integer pattern was given first.
That said, it is possible to redefine earlier cases, which, in effect, "demotes" it, as if it had not been declared
before. So the following will work properly:
fib = Functor.new do
given( Integer ) { |n| raise "this would start an infinite loop ..." }
given( 0 ) { 0 }
given( 1 ) { 1 }
# but this will "demote" the Integer pattern and now it will work ...
given( Integer ) { |n| self.call( n - 1 ) + self.call( n - 2 ) }
end
This isn't perfect, but it is very easy to predict, simple to implement, and reasonably fast, which other approaches
(such as implementing a precedence scheme) are not.
= Credits And Support
Functor was written by Dan Yoder, Matthew King, and Lawrence Pit. Send email to dan at zeraweb.com for support or
questions.




