lambda_driver 1.2.2 → 1.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +15 -0
- data/lib/lambda_driver/context.rb +59 -0
- data/lib/lambda_driver/liftable.rb +39 -18
- data/lib/lambda_driver/version.rb +1 -1
- data/spec/context_spec.rb +93 -0
- data/spec/shared/liftable.rb +4 -4
- metadata +7 -4
data/README.md
CHANGED
@@ -96,6 +96,21 @@ The context-funciton should recieve 2 arguments.
|
|
96
96
|
- second arg is a result of g(x)
|
97
97
|
- g is a function passed to `compose_with_lifting`
|
98
98
|
|
99
|
+
If given arguments is Symbol, find context-function from
|
100
|
+
default context-functions.
|
101
|
+
|
102
|
+
- :identify
|
103
|
+
- this context nothing to do
|
104
|
+
- :maybe
|
105
|
+
- computations which may not return a result
|
106
|
+
- :list
|
107
|
+
- computations which can return multiple possible results
|
108
|
+
- :reader
|
109
|
+
- computations which read from a shared environment
|
110
|
+
- :writer
|
111
|
+
- computations which write data in addition to computing values
|
112
|
+
|
113
|
+
see -> LambdaDriver::Context
|
99
114
|
|
100
115
|
#### Proc#compose_with_lifting
|
101
116
|
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
module LambdaDriver::Context
|
3
|
+
|
4
|
+
Identify = lambda{|f, x| f.call(x) }
|
5
|
+
|
6
|
+
Maybe = lambda{|f, x|
|
7
|
+
mzero_method = x.respond_to?(:mzero?) ? :mzero? : :nil?
|
8
|
+
x.send(mzero_method) ? x : f.call(x)
|
9
|
+
}
|
10
|
+
|
11
|
+
List = lambda{|f, x| x.map(&f) }
|
12
|
+
|
13
|
+
Reader = lambda{|f, (r, x)|
|
14
|
+
# set reader env to thread local
|
15
|
+
Thread.current[:lambda_driver_reader_ctx_ask] = r
|
16
|
+
# define ask method to access context of reader
|
17
|
+
f.binding.eval(<<-CODE)
|
18
|
+
def ask
|
19
|
+
Thread.current[:lambda_driver_reader_ctx_ask]
|
20
|
+
end
|
21
|
+
CODE
|
22
|
+
|
23
|
+
begin
|
24
|
+
[r, f.call(x)]
|
25
|
+
ensure
|
26
|
+
# tear down reader context
|
27
|
+
Thread.current[:lambda_driver_reader_ctx_ask] = nil
|
28
|
+
f.binding.eval("undef ask")
|
29
|
+
end
|
30
|
+
}
|
31
|
+
|
32
|
+
Writer = lambda{|f, (x, w)|
|
33
|
+
pool = w || []
|
34
|
+
|
35
|
+
# set writer pool to thread local
|
36
|
+
Thread.current[:lambda_driver_writer_ctx_pool] = pool
|
37
|
+
# define tell method to write log to context
|
38
|
+
f.binding.eval(<<-CODE)
|
39
|
+
def tell(s)
|
40
|
+
pool = Thread.current[:lambda_driver_writer_ctx_pool]
|
41
|
+
pool << s
|
42
|
+
end
|
43
|
+
CODE
|
44
|
+
|
45
|
+
begin
|
46
|
+
[f.call(x), pool]
|
47
|
+
ensure
|
48
|
+
# tear down reader context
|
49
|
+
Thread.current[:lambda_driver_writer_ctx_pool] = nil
|
50
|
+
f.binding.eval("undef tell")
|
51
|
+
end
|
52
|
+
}
|
53
|
+
|
54
|
+
def self.[](name)
|
55
|
+
name = name.to_s.capitalize
|
56
|
+
const_defined?(name) && const_get(name)
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
@@ -6,7 +6,7 @@ module LambdaDriver::Liftable
|
|
6
6
|
#
|
7
7
|
# This method returns composed funciton like bellow.
|
8
8
|
#
|
9
|
-
# lambda{|args| context(self, g
|
9
|
+
# lambda{|args| context.call(self, context.call(g,*args) }
|
10
10
|
#
|
11
11
|
# For example, set context-function that logging the result.
|
12
12
|
#
|
@@ -15,18 +15,17 @@ module LambdaDriver::Liftable
|
|
15
15
|
# g = lambda{|y| hash[y]}
|
16
16
|
#
|
17
17
|
# ctx = lambda{|f,x|
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
# y
|
18
|
+
# res = f.call(x)
|
19
|
+
# puts "result -> #{res}"
|
20
|
+
# res
|
22
21
|
# }
|
23
22
|
#
|
24
23
|
# lifted = f.lift(ctx)
|
25
24
|
# h = lifted.compose_with_lifting g
|
26
25
|
#
|
27
26
|
# h.(:a)
|
28
|
-
# #=>
|
29
|
-
# #=>
|
27
|
+
# #=> result -> foo
|
28
|
+
# #=> result -> 3
|
30
29
|
# #=> 3
|
31
30
|
#
|
32
31
|
# if context-function does not given,
|
@@ -49,9 +48,17 @@ module LambdaDriver::Liftable
|
|
49
48
|
# f <= g # => f.compose_with_lifting(g)
|
50
49
|
#
|
51
50
|
def compose_with_lifting(g)
|
52
|
-
|
53
|
-
|
54
|
-
|
51
|
+
if @lambda_driver_lifted
|
52
|
+
ctx = @lambda_driver_liftable_context
|
53
|
+
self.compose(g).tap{|f|
|
54
|
+
f.instance_eval do
|
55
|
+
@lambda_driver_lifted = true
|
56
|
+
@lambda_driver_liftable_context = ctx
|
57
|
+
end
|
58
|
+
}
|
59
|
+
else
|
60
|
+
self.lift(DEFAULT_CONTEXT).compose_with_lifting(g)
|
61
|
+
end
|
55
62
|
end
|
56
63
|
|
57
64
|
# This is a default context-function.
|
@@ -69,10 +76,7 @@ module LambdaDriver::Liftable
|
|
69
76
|
# h.(:a) # => 3
|
70
77
|
# h.(:b) # => nil (it does not called f)
|
71
78
|
#
|
72
|
-
DEFAULT_CONTEXT =
|
73
|
-
mzero_method = x.respond_to?(:mzero?) ? :mzero? : :nil?
|
74
|
-
x.send(mzero_method) ? x : f.call(x)
|
75
|
-
}
|
79
|
+
DEFAULT_CONTEXT = LambdaDriver::Context[:maybe]
|
76
80
|
|
77
81
|
# Lift this function to the given context-function.
|
78
82
|
# The lifted fucntion can compose other function with context-fucntion.
|
@@ -85,9 +89,26 @@ module LambdaDriver::Liftable
|
|
85
89
|
# - second arg is a result of g(x)
|
86
90
|
# -- g is a function passed to `compose_with_lifting`
|
87
91
|
#
|
88
|
-
def lift(
|
89
|
-
|
90
|
-
|
92
|
+
def lift(ctx = DEFAULT_CONTEXT, &block)
|
93
|
+
ctx = block_given? ? block : ctx
|
94
|
+
ctx = case ctx
|
95
|
+
when String, Symbol then LambdaDriver::Context[ctx]
|
96
|
+
else ctx
|
97
|
+
end
|
98
|
+
|
99
|
+
# do not lift same context again
|
100
|
+
return self if lambda_driver_lifted? && (ctx == lambda_driver_liftable_context)
|
101
|
+
|
102
|
+
lambda{|*args| ctx.call(self, *args) }.tap{|f|
|
103
|
+
f.instance_eval do
|
104
|
+
@lambda_driver_lifted = true
|
105
|
+
@lambda_driver_liftable_context = ctx
|
106
|
+
end
|
107
|
+
}
|
108
|
+
end
|
109
|
+
|
110
|
+
def lambda_driver_lifted?
|
111
|
+
@lambda_driver_lifted
|
91
112
|
end
|
92
113
|
|
93
114
|
def lambda_driver_liftable_context
|
@@ -95,7 +116,7 @@ module LambdaDriver::Liftable
|
|
95
116
|
end
|
96
117
|
|
97
118
|
def >=(g)
|
98
|
-
g.to_proc.lift(lambda_driver_liftable_context)
|
119
|
+
g.to_proc.lift(lambda_driver_liftable_context).compose_with_lifting(self)
|
99
120
|
end
|
100
121
|
|
101
122
|
def self.included(klass)
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe LambdaDriver::Context do
|
5
|
+
|
6
|
+
let(:f){ lambda{|x| x.to_s} }
|
7
|
+
let(:g){ lambda{|x| x * 2} }
|
8
|
+
|
9
|
+
describe LambdaDriver::Context::Identify do
|
10
|
+
let(:ctx) { :identify }
|
11
|
+
let(:x){ :foo }
|
12
|
+
it("f.lift(:identify).call(x).should == f(x)"){
|
13
|
+
f.lift(:identify).call(x).should == f.call(x)
|
14
|
+
}
|
15
|
+
|
16
|
+
it("(f.lift(:identify) >= g).call(x).should == g(f(x))"){
|
17
|
+
(f.lift(:identify) >= g).call(x).should == g.call(f.call(x))
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
describe LambdaDriver::Context::Maybe do
|
22
|
+
let(:x){ :foo }
|
23
|
+
|
24
|
+
it("f.lift(:maybe).call(nil).should be_nil"){
|
25
|
+
f.lift(:maybe).call(nil).should be_nil
|
26
|
+
}
|
27
|
+
|
28
|
+
it("f.lift(:maybe).call(x).should f(x)"){
|
29
|
+
f.lift(:maybe).call(x).should == f.call(x)
|
30
|
+
}
|
31
|
+
|
32
|
+
it("(f.lift(:maybe) >= g).call(nil).should be_nil "){
|
33
|
+
(f.lift(:maybe) >= g).call(nil).should be_nil
|
34
|
+
}
|
35
|
+
|
36
|
+
it("(f.lift(:maybe) >= g).call(x).should == g(f(x))"){
|
37
|
+
(f.lift(:maybe) >= g).call(x).should == g.call(f.call(x))
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
describe LambdaDriver::Context::List do
|
42
|
+
let(:x){ [:foo, :bar] }
|
43
|
+
|
44
|
+
it("f.lift(:list).call([]).should == []"){
|
45
|
+
f.lift(:list).call([]).should == []
|
46
|
+
}
|
47
|
+
|
48
|
+
it("f.lift(:list).call(x).should == x.map(&f)"){
|
49
|
+
f.lift(:list).call(x).should == x.map(&f)
|
50
|
+
}
|
51
|
+
|
52
|
+
it("(f.lift(:list) >= g).call([]).should == (x.map(&f)).map(&g)"){
|
53
|
+
(f.lift(:list) >= g).call([]).should == []
|
54
|
+
}
|
55
|
+
|
56
|
+
it("(f.lift(:list) >= g).call(x).should == (x.map(&f)).map(&g)"){
|
57
|
+
(f.lift(:list) >= g).call(x).should == (x.map(&f)).map(&g)
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
describe LambdaDriver::Context::Reader do
|
62
|
+
let(:x){ 2 }
|
63
|
+
let(:r){ 3 }
|
64
|
+
|
65
|
+
let(:f){ lambda{|x| (ask + x).to_s} }
|
66
|
+
let(:g){ lambda{|x| x * (ask)} }
|
67
|
+
|
68
|
+
it("f.lift(:reader).call([r, x]).should == [r, f(x)]"){
|
69
|
+
f.lift(:reader).call([r, x]).should == [r, (r + x).to_s]
|
70
|
+
}
|
71
|
+
|
72
|
+
it("(f.lift(:reader) >= g).call([r, x]).should == [r, g(f(x))]"){
|
73
|
+
(f.lift(:reader) >= g).call([r, x]).should == [r, ((r + x).to_s) * r]
|
74
|
+
}
|
75
|
+
end
|
76
|
+
|
77
|
+
describe LambdaDriver::Context::Writer do
|
78
|
+
let(:w) { [:hoge] }
|
79
|
+
let(:x) { :foo }
|
80
|
+
let(:f){ lambda{|x| tell("bar_" + x.to_s); x.to_s } }
|
81
|
+
let(:g){ lambda{|x| tell("baz_" + x); x * 2 } }
|
82
|
+
|
83
|
+
it("f.lift(:writer).call([x, w]).should == [f(x), w]"){
|
84
|
+
f.lift(:writer).call([x, w]).should == [x.to_s, w]
|
85
|
+
w.should == [:hoge, "bar_foo"]
|
86
|
+
}
|
87
|
+
|
88
|
+
it("(f.lift(:writer) >= g).call([r, x]).should == [r, g(f(x))]"){
|
89
|
+
(f.lift(:writer) >= g).call([x, w]).should == [(x.to_s) * 2, w]
|
90
|
+
w.should == [:hoge, "bar_foo", "baz_foo"]
|
91
|
+
}
|
92
|
+
end
|
93
|
+
end
|
data/spec/shared/liftable.rb
CHANGED
@@ -50,11 +50,11 @@ shared_examples_for 'liftable' do
|
|
50
50
|
it(" f.lift(ctx) >= g returns funciton that compose with ctx"){
|
51
51
|
(subject.lift(ctx) >= g).should be_a_kind_of Proc
|
52
52
|
}
|
53
|
-
it('"(f.
|
54
|
-
(subject.lift(ctx) >= g).call(x).should == ctx.call(g, subject.to_proc
|
53
|
+
it('"(f.lift(ctx) >= g).call(x) should be ctx(g, ctx(f, x))'){
|
54
|
+
(subject.lift(ctx) >= g).call(x).should == ctx.call(g, ctx.call(subject.to_proc,x))
|
55
55
|
}
|
56
|
-
it('"(f.
|
57
|
-
(subject.lift(ctx) >= g >= h).call(x).should == ctx.call(h, ctx.call(g, subject.to_proc
|
56
|
+
it('"(f.lift(ctx) >= g >= h).call(x) should be ctx(h, ctx(g, f(x)))'){
|
57
|
+
(subject.lift(ctx) >= g >= h).call(x).should == ctx.call(h, ctx.call(g, ctx.call(subject.to_proc, x)))
|
58
58
|
}
|
59
59
|
end
|
60
60
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lambda_driver
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-
|
12
|
+
date: 2014-02-06 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
@@ -45,6 +45,7 @@ files:
|
|
45
45
|
- lib/lambda_driver.rb
|
46
46
|
- lib/lambda_driver/callable.rb
|
47
47
|
- lib/lambda_driver/composable.rb
|
48
|
+
- lib/lambda_driver/context.rb
|
48
49
|
- lib/lambda_driver/core_ext.rb
|
49
50
|
- lib/lambda_driver/core_ext/class.rb
|
50
51
|
- lib/lambda_driver/core_ext/method.rb
|
@@ -64,6 +65,7 @@ files:
|
|
64
65
|
- lib/lambda_driver/version.rb
|
65
66
|
- lib/lambda_driver/with_args.rb
|
66
67
|
- spec/class_spec.rb
|
68
|
+
- spec/context_spec.rb
|
67
69
|
- spec/disjunction_spec.rb
|
68
70
|
- spec/lambda_spec.rb
|
69
71
|
- spec/method_spec.rb
|
@@ -89,7 +91,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
89
91
|
version: '0'
|
90
92
|
segments:
|
91
93
|
- 0
|
92
|
-
hash: -
|
94
|
+
hash: -2789820637790150552
|
93
95
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
96
|
none: false
|
95
97
|
requirements:
|
@@ -98,7 +100,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
98
100
|
version: '0'
|
99
101
|
segments:
|
100
102
|
- 0
|
101
|
-
hash: -
|
103
|
+
hash: -2789820637790150552
|
102
104
|
requirements: []
|
103
105
|
rubyforge_project:
|
104
106
|
rubygems_version: 1.8.23
|
@@ -107,6 +109,7 @@ specification_version: 3
|
|
107
109
|
summary: Drives your code more functioal!
|
108
110
|
test_files:
|
109
111
|
- spec/class_spec.rb
|
112
|
+
- spec/context_spec.rb
|
110
113
|
- spec/disjunction_spec.rb
|
111
114
|
- spec/lambda_spec.rb
|
112
115
|
- spec/method_spec.rb
|