GitHub Sale: sign up for any paid plan this week and pay nothing until January 1, 2009!  [ hide ]

public
Rubygem
Description: Implements pattern-based method dispatch for Ruby, inspired by Topher Cyll's multi.
Clone URL: git://github.com/dyoder/functor.git
Major overhaul for Functor. LIFO, faster, better inheritance support.
dyoder (author)
Thu Sep 18 02:23:42 -0700 2008
commit  dfd0d7eb1d1b2dc7a040f75d6e3d6379957c9928
tree    039239b6985b646dc26951e61a7c4d4b5016ecc4
parent  8523c87d74c91f0ac26d9983a56bf5e3ed983473
...
1
 
2
3
4
5
 
 
 
 
 
 
6
7
 
 
 
 
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 
 
 
26
27
28
29
30
31
 
 
 
 
 
 
 
 
 
 
 
 
 
32
33
34
35
36
37
38
...
49
50
51
52
53
54
 
55
56
57
58
 
 
59
60
 
 
61
62
63
...
67
68
69
70
 
71
72
73
74
...
1
2
3
4
5
6
7
8
9
10
11
12
13
 
14
15
16
17
18
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
20
21
22
23
24
25
 
 
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
 
42
43
44
...
55
56
57
 
 
 
58
59
60
 
 
61
62
63
64
65
66
67
68
69
...
73
74
75
 
76
77
78
79
80
0
@@ -1,38 +1,44 @@
0
 require "#{File.dirname(__FILE__)}/object"
0
+ require 'ruby-debug'
0
 
0
 class Functor
0
   
0
   module Method
0
+ def self.copy_functors( functors )
0
+ r = {} ; functors.each do | name, functor |
0
+ r[ name ] = functor.clone
0
+ end
0
+ return r
0
+ end
0
     def self.included( k )
0
- def k.functors ; @__functors ||= {} ; end
0
+ def k.functors
0
+ @__functors ||= superclass.respond_to?( :functors ) ?
0
+ Functor::Method.copy_functors( superclass.functors ) : {}
0
+ end
0
       def k.functor( name, *args, &block )
0
- unless functors[ name ]
0
- functors[ name ] = Functor.new
0
- klass = self.name ; module_eval <<-CODE
0
- def #{name}( *args, &block )
0
- begin
0
- #{klass}.functors[ :#{name} ].apply( self, *args, &block )
0
- rescue ArgumentError => e
0
- begin
0
- super
0
- rescue NoMethodError => f
0
- raise e
0
- end
0
- end
0
- end
0
- CODE
0
- end
0
- functors[ name ].given( *args, &block )
0
+ name = name.to_sym
0
+ ( f = ( functors[ name ] or ( functors[ name ] = Functor.new ) ) ).given( *args, &block )
0
+ define_method( name ) { | *args | f.apply( self, *args ) }
0
       end
0
     end
0
   end
0
   
0
- def initialize( &block )
0
- @rules = [] ; instance_eval( &block ) if block_given?
0
+
0
+ def initialize( &block )
0
+ @rules = [] ; yield( self ) if block_given?
0
+ end
0
+
0
+ def initialize_copy( from )
0
+ @rules = from.instance_eval { @rules.clone }
0
+ # @rules = from.instance_eval do
0
+ # @rules.inject( [] ) do | rules, rule |
0
+ # pattern, action = rule
0
+ # rules << [ pattern.clone, rule ]
0
+ # end
0
+ # end
0
   end
0
   
0
   def given( *pattern, &action )
0
- @rules.delete_if { |p,a| p == pattern }
0
     @rules << [ pattern, action ]
0
   end
0
   
0
@@ -49,15 +55,15 @@ class Functor
0
   end
0
   
0
   def to_proc ; lambda { |*args| self.call( *args ) } ; end
0
-
0
- private
0
-
0
+
0
   def match( args, &block )
0
     args << block if block_given?
0
- pattern, action = @rules.find { | p, a | match?( args, p ) }
0
- action or raise argument_error( args )
0
+ pattern, action = @rules.reverse.find { | p, a | match?( args, p ) }
0
+ action or argument_error( args )
0
   end
0
   
0
+ private
0
+
0
   def match?( args, pattern )
0
     args.zip( pattern ).all? { | arg, rule | pair?( arg, rule ) } if args.length == pattern.length
0
   end
0
@@ -67,7 +73,7 @@ class Functor
0
   end
0
   
0
   def argument_error( args )
0
- ArgumentError.new( "argument mismatch for argument(s): #{ args.map{ |arg| arg.inspect }.join(', ') }." )
0
+ raise ArgumentError.new( "Argument error: no functor matches the given arguments." )
0
   end
0
   
0
 end
0
\ No newline at end of file
...
1
2
3
4
5
6
 
 
 
 
7
8
9
...
1
2
 
 
 
 
3
4
5
6
7
8
9
0
@@ -1,9 +1,9 @@
0
 require "#{File.dirname(__FILE__)}/helpers"
0
 
0
-fib ||= Functor.new do
0
- given( 0 ) { 0 }
0
- given( 1 ) { 1 }
0
- given( Integer ) { | n | self.call( n - 1 ) + self.call( n - 2 ) }
0
+fib ||= Functor.new do |f|
0
+ f.given( Integer ) { | n | f.call( n - 1 ) + f.call( n - 2 ) }
0
+ f.given( 0 ) { 0 }
0
+ f.given( 1 ) { 1 }
0
 end
0
 
0
 describe "Dispatch on a functor object should" do
...
3
4
5
6
7
8
 
 
 
9
10
11
12
13
 
 
 
14
15
16
...
3
4
5
 
 
 
6
7
8
9
10
 
 
 
11
12
13
14
15
16
0
@@ -3,14 +3,14 @@ require "#{File.dirname(__FILE__)}/helpers"
0
 describe "Dispatch should support guards" do
0
   
0
   before do
0
- @stripe = Functor.new do
0
- given( lambda { |x| x % 2 == 0 } ) { 'white' }
0
- given( lambda { |x| x % 2 == 1 } ) { 'silver' }
0
+ @stripe = Functor.new do |f|
0
+ f.given( lambda { |x| x % 2 == 1 } ) { 'silver' }
0
+ f.given( lambda { |x| x % 2 == 0 } ) { 'white' }
0
     end
0
 
0
- @safe_divide = Functor.new do
0
- given( lambda { |x| x == 0 }, Integer ) { |x,y| false }
0
- given( Integer, Integer ) { |x,y| ( y / ( x * 1.0 )) }
0
+ @safe_divide = Functor.new do |f|
0
+ f.given( Integer, Integer ) { |x,y| ( y / ( x * 1.0 )) }
0
+ f.given( lambda { |x| x == 0 }, Integer ) { |x,y| false }
0
     end
0
   end
0
   
...
2
3
4
5
6
 
7
8
9
...
2
3
4
 
5
6
7
8
9
0
@@ -2,8 +2,8 @@ require "#{File.dirname(__FILE__)}/helpers"
0
 
0
 class C
0
   include Functor::Method
0
- functor( :foo, 1 ) { |a| "==" }
0
   functor( :foo, Integer ) { |a| "===" }
0
+ functor( :foo, 1 ) { |a| "==" }
0
   functor( :foo, lambda { |a| a == "boo" } ) { |v| "Lambda: #{v}" }
0
 end
0
 

Comments

    No one has commented yet.