functor 0.4.2 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
data/lib/functor.rb CHANGED
@@ -3,67 +3,70 @@ require "#{File.dirname(__FILE__)}/object"
3
3
  class Functor
4
4
 
5
5
  module Method
6
+ def self.copy_functors( functors )
7
+ r = {} ; functors.each do | name, functor |
8
+ r[ name ] = functor.clone
9
+ end
10
+ return r
11
+ end
6
12
  def self.included( k )
7
- def k.functors ; @__functors ||= {} ; end
13
+ def k.functors
14
+ @__functors ||= superclass.respond_to?( :functors ) ?
15
+ Functor::Method.copy_functors( superclass.functors ) : {}
16
+ end
8
17
  def k.functor( name, *args, &block )
9
- unless functors[ name ]
10
- functors[ name ] = Functor.new
11
- klass = self.name ; module_eval <<-CODE
12
- def #{name}( *args, &block )
13
- begin
14
- #{klass}.functors[ :#{name} ].apply( self, *args, &block )
15
- rescue ArgumentError => e
16
- begin
17
- super
18
- rescue NoMethodError => f
19
- raise e
20
- end
21
- end
22
- end
23
- CODE
24
- end
25
- functors[ name ].given( *args, &block )
18
+ name = name.to_sym
19
+ ( f = ( functors[ name ] or
20
+ ( functors[ name ] = Functor.new ) ) ).given( *args, &block )
21
+ define_method( name ) { | *args | instance_exec( *args, &f.match( *args ) ) }
22
+ end
23
+ def k.functor_with_self( name, *args, &block )
24
+ name = name.to_sym
25
+ ( f = ( functors[ name ] or
26
+ ( functors[ name ] = Functor.new ) ) ).given( *args, &block )
27
+ define_method( name ) { | *args | instance_exec( *args, &f.match( self, *args ) ) }
26
28
  end
27
29
  end
28
30
  end
29
31
 
30
- def initialize( &block )
31
- @rules = [] ; instance_eval( &block ) if block_given?
32
+
33
+ def initialize( &block )
34
+ @rules = [] ; yield( self ) if block_given?
35
+ end
36
+
37
+ def initialize_copy( from )
38
+ @rules = from.instance_eval { @rules.clone }
32
39
  end
33
40
 
34
41
  def given( *pattern, &action )
35
- @rules.delete_if { |p,a| p == pattern }
36
42
  @rules << [ pattern, action ]
37
43
  end
38
44
 
39
- def apply( object, *args, &block )
40
- object.instance_exec( *args, &match( args, &block ) )
45
+ def call( *args, &block )
46
+ match( *args, &block ).call( *args )
41
47
  end
42
48
 
43
- def call( *args, &block )
44
- match( args, &block ).call( *args )
49
+ def []( *args, &block )
50
+ call( *args, &block )
45
51
  end
46
52
 
47
53
  def to_proc ; lambda { |*args| self.call( *args ) } ; end
48
-
49
- private
50
-
51
- def match( args, &block )
54
+
55
+ def match( *args, &block )
52
56
  args << block if block_given?
53
- pattern, action = @rules.find { | p, a | match?( args, p ) }
54
- action or raise argument_error( args )
57
+ pattern, action = @rules.reverse.find { | p, a | match?( args, p ) }
58
+ action or
59
+ raise ArgumentError.new( "Argument error: no functor matches the given arguments." )
55
60
  end
56
61
 
62
+ private
63
+
57
64
  def match?( args, pattern )
58
65
  args.zip( pattern ).all? { | arg, rule | pair?( arg, rule ) } if args.length == pattern.length
59
66
  end
60
67
 
61
68
  def pair?( arg, rule )
62
- ( rule.is_a?( Proc ) and rule.call( arg ) ) or rule === arg or rule == arg
63
- end
64
-
65
- def argument_error( args )
66
- ArgumentError.new( "argument mismatch for argument(s): #{ args.map{ |arg| arg.inspect }.join(', ') }." )
69
+ ( rule.respond_to? :call and rule.call( arg ) ) or rule === arg
67
70
  end
68
-
71
+
69
72
  end
data/test/fib.rb CHANGED
@@ -1,9 +1,9 @@
1
1
  require "#{File.dirname(__FILE__)}/helpers"
2
2
 
3
- fib ||= Functor.new do
4
- given( 0 ) { 0 }
5
- given( 1 ) { 1 }
6
- given( Integer ) { | n | self.call( n - 1 ) + self.call( n - 2 ) }
3
+ fib ||= Functor.new do |f|
4
+ f.given( Integer ) { | n | f.call( n - 1 ) + f.call( n - 2 ) }
5
+ f.given( 0 ) { 0 }
6
+ f.given( 1 ) { 1 }
7
7
  end
8
8
 
9
9
  describe "Dispatch on a functor object should" do
data/test/guards.rb CHANGED
@@ -1,16 +1,16 @@
1
- require 'test/helpers'
1
+ require "#{File.dirname(__FILE__)}/helpers"
2
2
 
3
3
  describe "Dispatch should support guards" do
4
4
 
5
5
  before do
6
- @stripe = Functor.new do
7
- given( lambda { |x| x % 2 == 0 } ) { 'white' }
8
- given( lambda { |x| x % 2 == 1 } ) { 'silver' }
6
+ @stripe = Functor.new do |f|
7
+ f.given( lambda { |x| x % 2 == 1 } ) { 'silver' }
8
+ f.given( lambda { |x| x % 2 == 0 } ) { 'white' }
9
9
  end
10
10
 
11
- @safe_divide = Functor.new do
12
- given( lambda { |x| x == 0 }, Integer ) { |x,y| false }
13
- given( Integer, Integer ) { |x,y| ( y / ( x * 1.0 )) }
11
+ @safe_divide = Functor.new do |f|
12
+ f.given( Integer, Integer ) { |x,y| ( y / ( x * 1.0 )) }
13
+ f.given( lambda { |x| x == 0 }, Integer ) { |x,y| false }
14
14
  end
15
15
  end
16
16
 
data/test/inheritance.rb CHANGED
@@ -9,7 +9,6 @@ end
9
9
 
10
10
  class B < A
11
11
  functor( :foo, String ) { |s| [ B, String ] }
12
- functor( :foo, Float ) { |f| [ B, *A.functors[:foo].apply( self, f ) ] }
13
12
  end
14
13
 
15
14
  describe "Functor methods should support inheritance" do
@@ -22,7 +21,4 @@ describe "Functor methods should support inheritance" do
22
21
  B.new.foo( "bar" ).should == [ B, String ]
23
22
  end
24
23
 
25
- specify "by allowing you to call base class functors using #functors" do
26
- B.new.foo( 1.0 ).should == [ B, A, Float ]
27
- end
28
24
  end
data/test/matchers.rb CHANGED
@@ -2,8 +2,8 @@ require "#{File.dirname(__FILE__)}/helpers"
2
2
 
3
3
  class C
4
4
  include Functor::Method
5
- functor( :foo, 1 ) { |a| "==" }
6
5
  functor( :foo, Integer ) { |a| "===" }
6
+ functor( :foo, 1 ) { |a| "==" }
7
7
  functor( :foo, lambda { |a| a == "boo" } ) { |v| "Lambda: #{v}" }
8
8
  end
9
9
 
data/test/with_self.rb ADDED
@@ -0,0 +1,21 @@
1
+ require "#{File.dirname(__FILE__)}/helpers"
2
+
3
+ class A
4
+ attr_accessor :bar
5
+ include Functor::Method
6
+ def initialize( x ) ; @bar = x ; end
7
+ functor_with_self( :foo, self, Integer ) { |x| x }
8
+ functor_with_self( :foo, lambda{ |x| x.bar == true }, Integer ) { |s| 'bar' }
9
+ end
10
+
11
+ describe "Functor methods should support allow matching on self" do
12
+
13
+ specify "by allowing functor_with_self to provide a guard on self" do
14
+ A.new( true ).foo( 5 ).should == 'bar'
15
+ end
16
+
17
+ specify "or by simply providing self as an argument" do
18
+ A.new( false ).foo( 5 ).should == 5
19
+ end
20
+
21
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: functor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dan Yoder
@@ -11,7 +11,7 @@ autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
13
 
14
- date: 2008-07-11 00:00:00 -07:00
14
+ date: 2008-10-08 00:00:00 -07:00
15
15
  default_executable:
16
16
  dependencies: []
17
17
 
@@ -64,6 +64,7 @@ files:
64
64
  - test/inheritance.rb
65
65
  - test/matchers.rb
66
66
  - test/reopening.rb
67
+ - test/with_self.rb
67
68
  has_rdoc: true
68
69
  homepage: http://dev.zeraweb.com/
69
70
  post_install_message:
@@ -86,7 +87,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
86
87
  requirements: []
87
88
 
88
89
  rubyforge_project: functor
89
- rubygems_version: 1.0.1
90
+ rubygems_version: 1.2.0
90
91
  signing_key:
91
92
  specification_version: 2
92
93
  summary: Pattern-based dispatch for Ruby, inspired by Topher Cyll's multi.