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 +40 -37
- data/test/fib.rb +4 -4
- data/test/guards.rb +7 -7
- data/test/inheritance.rb +0 -4
- data/test/matchers.rb +1 -1
- data/test/with_self.rb +21 -0
- metadata +4 -3
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
|
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
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
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
|
-
|
31
|
-
|
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
|
40
|
-
|
45
|
+
def call( *args, &block )
|
46
|
+
match( *args, &block ).call( *args )
|
41
47
|
end
|
42
48
|
|
43
|
-
def
|
44
|
-
|
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
|
-
|
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
|
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.
|
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(
|
5
|
-
given(
|
6
|
-
given(
|
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
|
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 ==
|
8
|
-
given( lambda { |x| x % 2 ==
|
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(
|
13
|
-
given(
|
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
|
+
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-
|
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
|
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.
|