ruff 1.0.1 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +18 -1
- data/Gemfile.lock +1 -1
- data/README.md +3 -14
- data/docs/Ruff.html +3 -3
- data/docs/Ruff/Effect.html +2 -2
- data/docs/Ruff/Handler.html +73 -113
- data/docs/Ruff/Standard.html +33 -3
- data/docs/Ruff/Standard/CurrentTime.html +150 -14
- data/docs/Ruff/Standard/CurrentTime/Instance.html +183 -25
- data/docs/Ruff/Standard/Defer.html +152 -15
- data/docs/Ruff/Standard/Defer/Instance.html +213 -37
- data/docs/Ruff/Standard/State.html +215 -30
- data/docs/Ruff/Standard/State/Instance.html +389 -72
- data/docs/Ruff/Throws.html +2 -2
- data/docs/Ruff/Throws/Eff.html +6 -4
- data/docs/Ruff/Throws/Resend.html +14 -12
- data/docs/_index.html +3 -3
- data/docs/file.README.html +7 -23
- data/docs/frames.html +1 -1
- data/docs/index.html +7 -23
- data/docs/method_list.html +84 -28
- data/docs/top-level-namespace.html +2 -2
- data/lib/ruff/handler.rb +50 -49
- data/lib/ruff/objects.rb +4 -2
- data/lib/ruff/standard.rb +16 -0
- data/lib/ruff/standard/current_time.rb +29 -2
- data/lib/ruff/standard/defer.rb +33 -3
- data/lib/ruff/standard/state.rb +69 -14
- data/lib/ruff/version.rb +1 -1
- data/version +1 -1
- metadata +2 -3
- data/.rubocop_todo.yml +0 -366
@@ -6,7 +6,7 @@
|
|
6
6
|
<title>
|
7
7
|
Top Level Namespace
|
8
8
|
|
9
|
-
— Ruff 1.0.
|
9
|
+
— Ruff 1.0.1 Documentation
|
10
10
|
|
11
11
|
</title>
|
12
12
|
|
@@ -100,7 +100,7 @@
|
|
100
100
|
</div>
|
101
101
|
|
102
102
|
<div id="footer">
|
103
|
-
Generated on
|
103
|
+
Generated on Fri Oct 4 13:57:07 2019 by
|
104
104
|
<a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
105
105
|
0.9.20 (ruby-2.6.4).
|
106
106
|
</div>
|
data/lib/ruff/handler.rb
CHANGED
@@ -13,7 +13,6 @@ class Ruff::Handler
|
|
13
13
|
#
|
14
14
|
# @example
|
15
15
|
# handler = Handler.new
|
16
|
-
|
17
16
|
def initialize
|
18
17
|
@handlers = {}
|
19
18
|
@valh = ->(x) { x }
|
@@ -24,7 +23,8 @@ class Ruff::Handler
|
|
24
23
|
# Value handler is the handler for *the result value of the computation*.
|
25
24
|
# For example, `Handler.new.to{|_x| 0}.run { value }` results in `0` .
|
26
25
|
#
|
27
|
-
# The value handler modifies the result of the call of continuation
|
26
|
+
# The value handler modifies the result of the call of continuation
|
27
|
+
# in effect handlers of the handler.
|
28
28
|
#
|
29
29
|
# @param [Proc<A, B>] fun
|
30
30
|
# value handler
|
@@ -52,7 +52,6 @@ class Ruff::Handler
|
|
52
52
|
# # msg>> hello
|
53
53
|
# # msg>> world
|
54
54
|
# # returns !
|
55
|
-
|
56
55
|
def to(&fun)
|
57
56
|
@valh = fun
|
58
57
|
|
@@ -67,14 +66,14 @@ class Ruff::Handler
|
|
67
66
|
# a handler to handle `eff`;
|
68
67
|
# First argument of `&fun` is *continuation*, proc object
|
69
68
|
# to go back to the handled computation.
|
70
|
-
# @return [Handler<A!{Effect<Arg, Ret>, e}, B!{e}>]
|
69
|
+
# @return [Handler<A!{Effect<Arg, Ret>, e}, B!{e}>]
|
70
|
+
# itself updated with handling `Effect<Arg, Ret>`
|
71
71
|
#
|
72
72
|
# @example
|
73
73
|
# handler.on(Log) {|k, msg|
|
74
74
|
# puts "Logger: #{msg}"
|
75
75
|
# k[]
|
76
76
|
# }
|
77
|
-
|
78
77
|
def on(eff, &fun)
|
79
78
|
@handlers[eff.id] = fun
|
80
79
|
|
@@ -86,7 +85,8 @@ class Ruff::Handler
|
|
86
85
|
# @param [Proc<(), A>] prc
|
87
86
|
# a thunk to be handled and returns `A`
|
88
87
|
# @return [B]
|
89
|
-
# a value modified by value handler `Proc<A, B>` ,
|
88
|
+
# a value modified by value handler `Proc<A, B>` ,
|
89
|
+
# or returned from the effect handler throwing continuation away
|
90
90
|
#
|
91
91
|
# @example
|
92
92
|
# handler.run {
|
@@ -103,57 +103,58 @@ class Ruff::Handler
|
|
103
103
|
# Log.perform 3
|
104
104
|
# }
|
105
105
|
# }
|
106
|
-
|
107
106
|
def run(&prc)
|
108
|
-
co = Fiber.new
|
109
|
-
continue = nil
|
110
|
-
rehandles = nil
|
111
|
-
|
112
|
-
handle = lambda { |r|
|
113
|
-
case r
|
114
|
-
when Eff
|
115
|
-
if effh = @handlers[r.id]
|
116
|
-
effh[continue, *r.args]
|
117
|
-
else
|
118
|
-
Fiber.yield Resend.new(r, continue)
|
119
|
-
end
|
120
|
-
when Resend then
|
121
|
-
eff = r.eff
|
122
|
-
next_k = rehandles.call(r.k)
|
123
|
-
|
124
|
-
if effh = @handlers[eff.id]
|
125
|
-
effh.call(next_k, *eff.args)
|
126
|
-
else
|
127
|
-
Fiber.yield Resend.new(eff, next_k)
|
128
|
-
end
|
129
|
-
else
|
130
|
-
@valh.call(r)
|
131
|
-
end
|
132
|
-
}
|
107
|
+
co = Fiber.new(&prc)
|
133
108
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
109
|
+
continue(co).call(nil)
|
110
|
+
end
|
111
|
+
|
112
|
+
# is also private method.
|
113
|
+
def handlers=(handlers)
|
114
|
+
@handlers = handlers.dup
|
115
|
+
end
|
139
116
|
|
140
|
-
|
141
|
-
|
117
|
+
private
|
118
|
+
|
119
|
+
def continue(co)
|
120
|
+
->(*arg) { handle(co, co.resume(*arg)) }
|
121
|
+
end
|
122
|
+
|
123
|
+
# rubocop:disable Metrics/AbcSize
|
124
|
+
def handle(co, r)
|
125
|
+
case r
|
126
|
+
when Eff
|
127
|
+
if (effh = @handlers[r.id])
|
128
|
+
effh[continue(co), *r.args]
|
129
|
+
else
|
130
|
+
Fiber.yield Resend.new(r, continue(co))
|
142
131
|
end
|
132
|
+
when Resend then
|
133
|
+
eff = r.eff
|
134
|
+
next_k = rehandles(co, r.k)
|
143
135
|
|
144
|
-
|
145
|
-
|
136
|
+
if (effh = @handlers[eff.id])
|
137
|
+
effh.call(next_k, *eff.args)
|
138
|
+
else
|
139
|
+
Fiber.yield Resend.new(eff, next_k)
|
146
140
|
end
|
141
|
+
else
|
142
|
+
@valh.call(r)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
# rubocop:enable Metrics/AbcSize
|
147
146
|
|
148
|
-
|
149
|
-
|
150
|
-
}
|
151
|
-
}
|
147
|
+
def rehandles(co, k)
|
148
|
+
newh = self.class.new
|
152
149
|
|
153
|
-
|
154
|
-
handle.call(co.resume(*arg))
|
155
|
-
}
|
150
|
+
newh.handlers = @handlers
|
156
151
|
|
157
|
-
|
152
|
+
lambda { |*args|
|
153
|
+
newh
|
154
|
+
.to { |v| continue(co).call(v) }
|
155
|
+
.run { k.call(*args) }
|
156
|
+
}
|
158
157
|
end
|
158
|
+
|
159
|
+
private_methods :handlers=
|
159
160
|
end
|
data/lib/ruff/objects.rb
CHANGED
@@ -14,7 +14,8 @@ class Ruff::Throws::Eff
|
|
14
14
|
|
15
15
|
# creates a new object with `id` and `args`.
|
16
16
|
def initialize(id, args)
|
17
|
-
@id = id
|
17
|
+
@id = id
|
18
|
+
@args = args
|
18
19
|
end
|
19
20
|
end
|
20
21
|
|
@@ -30,6 +31,7 @@ class Ruff::Throws::Resend
|
|
30
31
|
|
31
32
|
# creates a new object with `eff` and `k`.
|
32
33
|
def initialize(eff, k)
|
33
|
-
@eff = eff
|
34
|
+
@eff = eff
|
35
|
+
@k = k
|
34
36
|
end
|
35
37
|
end
|
data/lib/ruff/standard.rb
CHANGED
@@ -1,5 +1,21 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# `Ruff::Standard` provides several pre-defined effect handlers modules.
|
4
|
+
# Each module provides `Instance` class to instantiate and handle the indivisual effect instances.
|
5
|
+
# @example
|
6
|
+
# include Ruff::Standard
|
7
|
+
#
|
8
|
+
# state1 = State::Instance.new
|
9
|
+
# state2 = State::Instance.new
|
10
|
+
#
|
11
|
+
# state1.with_init(3) {
|
12
|
+
# state2.with_init(4) {
|
13
|
+
# state2.modify {|s| s + state1.get }
|
14
|
+
#
|
15
|
+
# puts state1.get #==> 3
|
16
|
+
# puts state2.get #==> 7
|
17
|
+
# }}
|
18
|
+
#
|
3
19
|
module Ruff::Standard end
|
4
20
|
|
5
21
|
require 'ruff/standard/current_time'
|
@@ -1,30 +1,57 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# `CurrentTime` provides an effect `CurrentTime.eff` and the implementation returning `Time.now` .
|
4
|
+
#
|
5
|
+
# The module has an instance of `Instance` and provides its methods as module method.
|
6
|
+
# @see Standard::CurrentTime::Instance
|
3
7
|
module Ruff::Standard::CurrentTime
|
4
8
|
class Instance
|
9
|
+
# makes a new instance.
|
5
10
|
def initialize
|
6
11
|
@eff = Ruff.instance
|
7
12
|
end
|
8
13
|
|
14
|
+
# is a smart method to invoke the effect operation.
|
15
|
+
# @return [Time]
|
16
|
+
# with `with` , returns `Time.now`
|
9
17
|
def get
|
10
18
|
@eff.perform
|
11
19
|
end
|
12
20
|
|
21
|
+
# is a handler to interpret the effect invokation as requesting the current time.
|
22
|
+
# This handler receives the *request* and returns current time.
|
23
|
+
#
|
24
|
+
# @param [Proc<(), A>!{CurrentTime.eff, e}] th
|
25
|
+
# is a thunk returning `A` with the possibility to invoke effects,
|
26
|
+
# including `CurrentTime.eff` .
|
27
|
+
#
|
28
|
+
# @return [A!{e}]
|
29
|
+
# returns `A` , without modification by value handler.
|
30
|
+
# But it still has the possibility to invoke effects(`e`).
|
13
31
|
def with(&th)
|
14
|
-
Ruff.handler.on(@eff) { |k| k[Time.now] }.run
|
32
|
+
Ruff.handler.on(@eff) { |k| k[Time.now] }.run(&th)
|
15
33
|
end
|
34
|
+
|
35
|
+
# You can reimplement the handler using this effect instance.
|
36
|
+
attr_reader :eff
|
16
37
|
end
|
17
38
|
|
18
39
|
# ---
|
19
40
|
@inst = Instance.new
|
41
|
+
@eff = @inst.eff
|
20
42
|
|
43
|
+
# @see Ruff::Standard::CurrentTime::Instance#get
|
21
44
|
def get
|
22
45
|
@inst.get
|
23
46
|
end
|
24
47
|
|
48
|
+
# @see Ruff::Standard::CurrentTime::Instance#with
|
25
49
|
def with(&th)
|
26
|
-
@inst.with
|
50
|
+
@inst.with(&th)
|
27
51
|
end
|
28
52
|
|
29
53
|
module_function :get, :with
|
54
|
+
|
55
|
+
# @see Ruff::Standard::CurrentTime::Instance#eff
|
56
|
+
attr_reader :eff
|
30
57
|
end
|
data/lib/ruff/standard/defer.rb
CHANGED
@@ -1,16 +1,36 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# `Defer` provides effects `Defer.eff` ,
|
4
|
+
# and the implementation to defer procedures .
|
5
|
+
#
|
6
|
+
# The module has an instance of `Instance` and provides its methods as module method.
|
7
|
+
# @see Standard::Defer::Instance
|
3
8
|
module Ruff::Standard::Defer
|
4
9
|
class Instance
|
10
|
+
# makes a new instance.
|
5
11
|
def initialize
|
6
12
|
@eff = Ruff.instance
|
7
13
|
end
|
8
14
|
|
15
|
+
# is a smart method to invoke the effect operation.
|
16
|
+
# @param [Proc<(), ()>] prc
|
17
|
+
# is deferred, or "registerred", and called on the end of computation.
|
18
|
+
# @return [()]
|
9
19
|
def register(&prc)
|
10
20
|
@eff.perform prc
|
11
21
|
end
|
12
22
|
|
23
|
+
# is a handler to interpret the effect invocation as registering a procedure.
|
24
|
+
# Registerred procedures are run on the end of computation, by value handler.
|
25
|
+
#
|
26
|
+
# @param [Proc<(), A>!{Defer.eff, e}] th
|
27
|
+
# is a thunk returning `A` with the possibility to invoke effects, including `Defer.eff` .
|
28
|
+
#
|
29
|
+
# @return [A!{e}]
|
30
|
+
# returns `A` , without modification by value handler.
|
31
|
+
# But it still has the possibility to invoke effects(`e`).
|
13
32
|
def with(&th)
|
33
|
+
# This is a stack to store deferred procedures.
|
14
34
|
procs = []
|
15
35
|
|
16
36
|
Ruff.handler
|
@@ -19,22 +39,32 @@ module Ruff::Standard::Defer
|
|
19
39
|
k[]
|
20
40
|
end
|
21
41
|
.to do |_|
|
42
|
+
# Like Go's defer functions, it crashes the thunk by reversed order.
|
22
43
|
procs.reverse_each(&:[])
|
23
44
|
end
|
24
|
-
.run
|
45
|
+
.run(&th)
|
25
46
|
end
|
47
|
+
|
48
|
+
# You can reimplement the handler using this effect instance.
|
49
|
+
attr_reader :eff
|
26
50
|
end
|
27
51
|
|
28
52
|
# ---
|
29
53
|
@inst = Instance.new
|
54
|
+
@eff = @inst.eff
|
30
55
|
|
56
|
+
# @see Ruff::Standard::Defer::Instance#register
|
31
57
|
def register(&prc)
|
32
|
-
@inst.register
|
58
|
+
@inst.register(&prc)
|
33
59
|
end
|
34
60
|
|
61
|
+
# @see Ruff::Standard::Defer::Instance#with
|
35
62
|
def with(&th)
|
36
|
-
@inst.with
|
63
|
+
@inst.with(&th)
|
37
64
|
end
|
38
65
|
|
39
66
|
module_function :register, :with
|
67
|
+
|
68
|
+
# @see Ruff::Standard::Defer::Instance#eff
|
69
|
+
attr_reader :eff
|
40
70
|
end
|
data/lib/ruff/standard/state.rb
CHANGED
@@ -1,65 +1,120 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'ostruct'
|
4
|
+
|
5
|
+
# `State` provides effects `State.get` and `State.modify` ,
|
6
|
+
# and the implementation of the mutable cell or so-called *state* .
|
7
|
+
#
|
8
|
+
# The module has an instance of `Instance` and provides its methods as module method.
|
9
|
+
# @see Standard::State::Instance
|
3
10
|
module Ruff::Standard::State
|
4
11
|
class Instance
|
12
|
+
# makes new instances.
|
5
13
|
def initialize
|
6
|
-
|
7
|
-
|
14
|
+
get = Ruff.instance
|
15
|
+
modify = Ruff.instance
|
16
|
+
|
17
|
+
# delegates effect instances
|
18
|
+
@eff = OpenStruct.new(get: get, modify: modify)
|
8
19
|
end
|
9
20
|
|
21
|
+
# is a smart method to invoke the effect operation `State.get` .
|
22
|
+
# @return [S]
|
23
|
+
# with `with` , returns `S` , the current state.
|
10
24
|
def get
|
11
|
-
@get.perform
|
25
|
+
@eff.get.perform
|
12
26
|
end
|
13
27
|
|
28
|
+
# is a smart hetmod to invoke the effect operation `State.modify` .
|
29
|
+
# @param [Proc<S, U>] fn
|
30
|
+
# is the function to modify the state `S` to `U` .
|
31
|
+
# This function has an argument receiving the state.
|
32
|
+
# @return [()]
|
14
33
|
def modify(&fn)
|
15
|
-
@modify.perform fn
|
34
|
+
@eff.modify.perform fn
|
16
35
|
end
|
17
36
|
|
37
|
+
# is a short hand for `modify {|_| s }`
|
38
|
+
# @param [S] s
|
39
|
+
# is the new state.
|
40
|
+
# @return [()]
|
18
41
|
def put(s)
|
19
|
-
@modify.perform ->(_) { s }
|
42
|
+
@eff.modify.perform ->(_) { s }
|
20
43
|
end
|
21
44
|
|
22
|
-
|
45
|
+
# is a handler to interpret the effect invocations like *state monad* .
|
46
|
+
#
|
47
|
+
# @param [S] init
|
48
|
+
# is the initial state.
|
49
|
+
# @param [Proc<(), A!{State.get, State.modify,, e}>] th
|
50
|
+
# is a thunk returning `A` with the possibility to invoke effects,
|
51
|
+
# including `State.get` and `State.modify` .
|
52
|
+
# @return [A!{e}]
|
53
|
+
# returns `A` , without modification by value handler.
|
54
|
+
# But it still has the possibility to invoke effects(`e`).
|
55
|
+
def with_init(init, &th)
|
56
|
+
# not a parameter passing style, or so-called *pure* implementation,
|
57
|
+
# just using mutable assignment
|
23
58
|
state = init
|
24
59
|
|
25
60
|
Ruff.handler
|
26
|
-
.on(@modify) do |k, fn|
|
61
|
+
.on(@eff.modify) do |k, fn|
|
27
62
|
state = fn[state]
|
28
63
|
k[nil]
|
29
|
-
end
|
30
|
-
.on(@get) do |k|
|
64
|
+
end.on(@eff.get) do |k|
|
31
65
|
k[state]
|
32
66
|
end
|
33
|
-
.run
|
67
|
+
.run(&th)
|
34
68
|
end
|
35
69
|
|
36
|
-
|
37
|
-
|
70
|
+
# is a short hand for `with_init(nil, th)` .
|
71
|
+
#
|
72
|
+
# @param [Proc<(), A!{State.get, State.modify,, e}>] th
|
73
|
+
# is a thunk returning `A` with the possibility to invoke effects,
|
74
|
+
# including `State.get` and `State.modify` .
|
75
|
+
# @return [A!{e}]
|
76
|
+
# returns `A` , without modification by value handler.
|
77
|
+
# But it still has the possibility to invoke effects(`e`).
|
78
|
+
def with(&th)
|
79
|
+
with_init(nil, &th)
|
38
80
|
end
|
81
|
+
|
82
|
+
# You can reimplement the handler using these effect instances
|
83
|
+
# with accessing `#eff.get` and `#eff.modify` .
|
84
|
+
attr_reader :eff
|
39
85
|
end
|
40
86
|
|
41
87
|
# ---
|
42
88
|
@inst = Instance.new
|
89
|
+
@eff = @inst.eff
|
43
90
|
|
91
|
+
# @see Ruff::Standard::State::Instance#get
|
44
92
|
def get
|
45
93
|
@inst.get
|
46
94
|
end
|
47
95
|
|
96
|
+
# @see Ruff::Standard::State::Instance#modify
|
48
97
|
def modify(&fn)
|
49
|
-
@inst.modify
|
98
|
+
@inst.modify(&fn)
|
50
99
|
end
|
51
100
|
|
101
|
+
# @see Ruff::Standard::State::Instance#put
|
52
102
|
def put(s)
|
53
103
|
@inst.put s
|
54
104
|
end
|
55
105
|
|
106
|
+
# @see Ruff::Standard::State::Instance#with_init
|
56
107
|
def with_init(init, &task)
|
57
108
|
@inst.with_init init, &task
|
58
109
|
end
|
59
110
|
|
111
|
+
# @see Ruff::Standard::State::Instance#with
|
60
112
|
def with(&task)
|
61
|
-
@inst.with
|
113
|
+
@inst.with(&task)
|
62
114
|
end
|
63
115
|
|
64
116
|
module_function :get, :put, :modify, :with, :with_init
|
117
|
+
|
118
|
+
# @see Ruff::Standard::Instance#eff
|
119
|
+
attr_reader :eff
|
65
120
|
end
|