ruff 1.3.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -1
  3. data/.rubocop.yml +1 -1
  4. data/Gemfile +3 -0
  5. data/README.md +35 -58
  6. data/Rakefile +2 -1
  7. data/docs/.nojekyll +0 -0
  8. data/docs/Ruff.html +7 -7
  9. data/docs/Ruff/Effect.html +165 -23
  10. data/docs/Ruff/Handler.html +46 -114
  11. data/docs/Ruff/Standard.html +7 -7
  12. data/docs/Ruff/Standard/Async.html +28 -27
  13. data/docs/Ruff/Standard/Async/Instance.html +63 -27
  14. data/docs/Ruff/Standard/Call1cc.html +297 -0
  15. data/docs/Ruff/Standard/CurrentTime.html +6 -6
  16. data/docs/Ruff/Standard/CurrentTime/Instance.html +7 -7
  17. data/docs/Ruff/Standard/Defer.html +6 -6
  18. data/docs/Ruff/Standard/Defer/Instance.html +6 -6
  19. data/docs/Ruff/Standard/DelimCtrl.html +340 -0
  20. data/docs/Ruff/Standard/MeasureTime.html +6 -6
  21. data/docs/Ruff/Standard/MeasureTime/Instance.html +8 -8
  22. data/docs/Ruff/Standard/State.html +6 -6
  23. data/docs/Ruff/Standard/State/Instance.html +6 -6
  24. data/docs/Ruff/Throws.html +6 -11
  25. data/docs/Ruff/Throws/Eff.html +6 -6
  26. data/docs/Ruff/Throws/Resend.html +6 -6
  27. data/docs/_index.html +14 -7
  28. data/docs/class_list.html +3 -3
  29. data/docs/css/style.css +2 -2
  30. data/docs/file.README.html +41 -58
  31. data/docs/file_list.html +2 -2
  32. data/docs/frames.html +2 -2
  33. data/docs/index.html +41 -58
  34. data/docs/js/app.js +14 -3
  35. data/docs/method_list.html +46 -30
  36. data/docs/top-level-namespace.html +6 -6
  37. data/lib/ruff/effect.rb +32 -3
  38. data/lib/ruff/handler.rb +43 -18
  39. data/lib/ruff/standard.rb +1 -0
  40. data/lib/ruff/standard/async.rb +27 -22
  41. data/lib/ruff/standard/current_time.rb +1 -1
  42. data/lib/ruff/standard/delim_ctrl.rb +49 -0
  43. data/lib/ruff/standard/measure_time.rb +2 -2
  44. data/lib/ruff/version.rb +1 -1
  45. data/ruff.gemspec +1 -1
  46. data/version +1 -1
  47. metadata +12 -9
  48. data/Gemfile.lock +0 -62
@@ -6,15 +6,15 @@
6
6
  <title>
7
7
  Top Level Namespace
8
8
 
9
- &mdash; Ruff 1.3.0 Documentation
9
+ &mdash; Ruff 2.1.0 Documentation
10
10
 
11
11
  </title>
12
12
 
13
- <link rel="stylesheet" href="css/style.css" type="text/css" charset="utf-8" />
13
+ <link rel="stylesheet" href="css/style.css" type="text/css" />
14
14
 
15
- <link rel="stylesheet" href="css/common.css" type="text/css" charset="utf-8" />
15
+ <link rel="stylesheet" href="css/common.css" type="text/css" />
16
16
 
17
- <script type="text/javascript" charset="utf-8">
17
+ <script type="text/javascript">
18
18
  pathId = "";
19
19
  relpath = '';
20
20
  </script>
@@ -100,9 +100,9 @@
100
100
  </div>
101
101
 
102
102
  <div id="footer">
103
- Generated on Sun Oct 6 23:09:11 2019 by
103
+ Generated on Wed Jun 10 21:24:09 2020 by
104
104
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
105
- 0.9.20 (ruby-2.6.5).
105
+ 0.9.25 (ruby-2.7.1).
106
106
  </div>
107
107
 
108
108
  </div>
@@ -2,7 +2,10 @@
2
2
 
3
3
  # This class provides an effect instance.
4
4
  class Ruff::Effect
5
- # Each instance must be unique so they have unique id with UUID
5
+ # Each instance must be unique so they have unique id with an annonymous class instance.
6
+ #
7
+ # The class instance may have subtyping relation.
8
+ # @see <<
6
9
  attr_reader :id
7
10
 
8
11
  # instaciates an effect setting `id`.
@@ -10,13 +13,39 @@ class Ruff::Effect
10
13
  # @example
11
14
  # Log = Effect.new #==> it _might_ be Effect<string, nil>
12
15
  def initialize
13
- @id = SecureRandom.uuid
14
- @id.freeze
16
+ @id = Class.new.new
17
+ end
18
+
19
+ # instanciates an effect, which has an relation `self <: parent`
20
+ # from the subtyping of `id` object.
21
+ #
22
+ # @param [Effect<Arg, Ret>] parent
23
+ # @return [Effect<Arg, Ret>] with an relation `it <: parent`
24
+ #
25
+ # @example
26
+ # Exception = Ruff::Effect.new
27
+ # RuntimeException = Ruff::Effect << Exception
28
+ #
29
+ # Ruff::Handler.new
30
+ # .on(Exception){
31
+ # puts "catch"
32
+ # }
33
+ # .run {
34
+ # RuntimeException.perform
35
+ # }
36
+ # # ==> prints "catch"
37
+ def self.<<(parent)
38
+ inst = new
39
+ parent_id = parent.instance_variable_get('@id')
40
+ inst.instance_variable_set('@id', (Class.new parent_id.class).new)
41
+ inst
15
42
  end
16
43
 
17
44
  # sends an effect ID and its arguments to a nearmost handler.
45
+ #
18
46
  # @param [Arg] a of the object `Effect<Arg, Ret>`
19
47
  # @return [Ret] of the object `Effect<Arg, Ret>`
48
+ #
20
49
  # @example
21
50
  # Log.perform "hello"
22
51
  def perform(*a)
@@ -2,17 +2,41 @@
2
2
 
3
3
  # In algebraic effects, handler is an first-class object.
4
4
  class Ruff::Handler
5
- include Ruff::Throws
6
-
7
5
  # makes a new handler, internally having fresh empty hash.
8
6
  #
9
7
  # This is a effect-handler store and when handliong it is looked up.
10
- # Value handler is set `id` function to by default.
11
- #
8
+ # Value handler is set an identity function to by default.
9
+
10
+ class Store
11
+ # is a private class to manage registered handlers
12
+ def initialize
13
+ @handler = {}
14
+ end
15
+
16
+ def []=(r, e)
17
+ @handler[r.id] = e
18
+ end
19
+
20
+ def [](eff)
21
+ # get a set {(eff', f) | forall (eff', f) in store. eff <: eff'}
22
+ fns = @handler.filter do |effky, _fun|
23
+ eff.id.is_a? effky.class
24
+ end
25
+
26
+ # pick a function with *smallest* effect class
27
+ return fns.min_by { |effky, _| effky.class }[1] unless fns.empty?
28
+
29
+ # if found nothing
30
+ nil
31
+ end
32
+ end
33
+
34
+ private_constant :Store
35
+
12
36
  # @example
13
37
  # handler = Handler.new
14
38
  def initialize
15
- @handlers = {}
39
+ @handlers = Store.new
16
40
  @valh = ->(x) { x }
17
41
  end
18
42
 
@@ -56,7 +80,10 @@ class Ruff::Handler
56
80
  self
57
81
  end
58
82
 
59
- # sets effec handler `&fun` for `eff`
83
+ # sets or updates effec handler `&fun` for `eff`
84
+ #
85
+ # Note that `eff` can be a supertype of an effect to be caught.
86
+ # @see Effect.<<
60
87
  #
61
88
  # @param [Effect<Arg, Ret>] eff
62
89
  # the effect instance to be handled
@@ -73,7 +100,7 @@ class Ruff::Handler
73
100
  # k[]
74
101
  # }
75
102
  def on(eff, &fun)
76
- @handlers[eff.id] = fun
103
+ @handlers[eff] = fun
77
104
 
78
105
  self
79
106
  end
@@ -107,13 +134,13 @@ class Ruff::Handler
107
134
  continue(co).call(nil)
108
135
  end
109
136
 
110
- # is also private method.
137
+ protected
138
+
139
+ # receives `handlers` as new handlers.
111
140
  def handlers=(handlers)
112
141
  @handlers = handlers.dup
113
142
  end
114
143
 
115
- private
116
-
117
144
  def continue(co)
118
145
  ->(*arg) { handle(co, co.resume(*arg)) }
119
146
  end
@@ -121,20 +148,20 @@ class Ruff::Handler
121
148
  # rubocop:disable Metrics/AbcSize
122
149
  def handle(co, r)
123
150
  case r
124
- when Eff
125
- if (effh = @handlers[r.id])
151
+ when Ruff::Throws::Eff
152
+ if (effh = @handlers[r])
126
153
  effh[continue(co), *r.args]
127
154
  else
128
- Fiber.yield Resend.new(r, continue(co))
155
+ Fiber.yield Ruff::Throws::Resend.new(r, continue(co))
129
156
  end
130
- when Resend then
157
+ when Ruff::Throws::Resend then
131
158
  eff = r.eff
132
159
  next_k = rehandles(co, r.k)
133
160
 
134
- if (effh = @handlers[eff.id])
161
+ if (effh = @handlers[eff])
135
162
  effh.call(next_k, *eff.args)
136
163
  else
137
- Fiber.yield Resend.new(eff, next_k)
164
+ Fiber.yield Ruff::Throws::Resend.new(eff, next_k)
138
165
  end
139
166
  else
140
167
  @valh.call(r)
@@ -153,6 +180,4 @@ class Ruff::Handler
153
180
  .run { k.call(*args) }
154
181
  }
155
182
  end
156
-
157
- private_methods :handlers=
158
183
  end
@@ -24,3 +24,4 @@ require 'ruff/standard/measure_time'
24
24
  require 'ruff/standard/defer'
25
25
  require 'ruff/standard/state'
26
26
  require 'ruff/standard/async'
27
+ require 'ruff/standard/delim_ctrl'
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # `Async` provides effects `Async.async`, `Async.yield` and `Async.await`, and the implementation async/await.
3
+ # `Async` provides effects `Async.async`, `Async.yield` and `Async.await`,
4
+ # and the implementation async/await.
4
5
  # This implementation is based on the tutorial for Multicore OCaml.
5
6
  # @see https://github.com/ocamllabs/ocaml-effects-tutorial/blob/master/sources/solved/async_await.ml
6
7
  #
@@ -47,8 +48,8 @@ module Ruff::Standard::Async
47
48
  # type 'a promise =
48
49
  # | Waiting of ('a, unit) continuation list
49
50
  # | Done of 'a
50
- _Waiting = Util::ADT.create
51
- _Done = Util::ADT.create
51
+ Waiting = Util::ADT.create
52
+ Done = Util::ADT.create
52
53
 
53
54
  # makes a new instance.
54
55
  def initialize
@@ -88,14 +89,14 @@ module Ruff::Standard::Async
88
89
  @eff.await.perform p
89
90
  end
90
91
 
91
- # @method with
92
+ # @method with(&th)
92
93
  # @param [Proc<(), _A!{Async.async, Async.yield, Async.await, e}>] th
93
94
  # is a thunk returning `_A` with te possibility to invoke effects,
94
95
  # including `Async.async` , `Async.yield` and `Async.await` .
95
96
  # @return [()!{e}]
96
97
  # returns unit but still has the possibility to invoke effects `e` .
97
98
  define_method :with do |&th|
98
- fork(Util::Ref.new(_Waiting.new([])), th)
99
+ fork(Util::Ref.new(Waiting.new([])), th)
99
100
  end
100
101
 
101
102
  # You can reimplement the handler using these effect instances
@@ -104,46 +105,50 @@ module Ruff::Standard::Async
104
105
 
105
106
  private
106
107
 
108
+ # rubocop:disable Metrics/AbcSize
109
+ # rubocop:disable Metrics/BlockLength
107
110
  define_method :fork do |pr, th|
108
- Ruff.handler
109
- .to do |v|
111
+ h = Ruff::Handler.new
112
+ h.to do |v|
110
113
  pp = pr.get
111
114
  l = case pp
112
- when _Waiting
113
- pp.get
114
- else
115
- raise 'impossible'
115
+ when Waiting then pp.get
116
+ else raise 'impossible'
116
117
  end
117
118
 
118
119
  l.each do |k|
119
120
  @q.enqueue(-> { k[v] })
120
121
  end
121
122
 
122
- pr.set(_Done.new(v))
123
+ pr.set(Done.new(v))
123
124
  @q.dequeue
124
125
  end
125
- .on(@eff.async) do |k, f|
126
- pr_ = Util::Ref.new(_Waiting.new([]))
126
+
127
+ h.on(@eff.async) do |k, f|
128
+ pr_ = Util::Ref.new(Waiting.new([]))
127
129
  @q.enqueue(-> { k[pr_] })
128
130
  fork(pr_, f)
129
131
  end
130
- .on(@eff.yield) do |k|
132
+ h.on(@eff.yield) do |k|
131
133
  @q.enqueue(-> { k[] })
132
134
  @q.dequeue.call
133
135
  end
134
- .on(@eff.await) do |k, pr|
135
- pp = pr.get
136
+
137
+ h.on(@eff.await) do |k, ppr|
138
+ pp = ppr.get
136
139
 
137
140
  return case pp
138
- when _Done
139
- k[pp.get]
140
- when _Waiting
141
- pr.set(_Waiting.new(@q.cons(k)))
141
+ when Done then k[pp.get]
142
+ when Waiting
143
+ pr.set(Waiting.new(@q.cons(k)))
142
144
  @q.dequeue.call
143
145
  end
144
146
  end
145
- .run { th[] }
147
+
148
+ h.run { th[] }
146
149
  end
150
+ # rubocop:enable Metrics/BlockLength
151
+ # rubocop:enable Metrics/AbcSize
147
152
  end
148
153
 
149
154
  # ---
@@ -30,7 +30,7 @@ module Ruff::Standard::CurrentTime
30
30
  # returns `A` , without modification by value handler.
31
31
  # But it still has the possibility to invoke effects(`e`).
32
32
  def with(&th)
33
- @handler.run(&th)
33
+ @handler.run(&th)
34
34
  end
35
35
 
36
36
  # You can reimplement the handler using this effect instance.
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ # `DelimCtrl` provides one-shot delimited control operators, `shift` and `reset`.
4
+ # @example
5
+ # DelimCtrl.reset {
6
+ # puts "hello"
7
+ # DelimCtrl.shift { |k|
8
+ # k.call
9
+ # puts "!"
10
+ # }
11
+ #
12
+ # puts "world"
13
+ # }
14
+ # # ==>
15
+ # # hello
16
+ # # world
17
+ # # !
18
+ module Ruff::Standard::DelimCtrl
19
+ # prompt stack
20
+ @stack = []
21
+
22
+ # delimits a continuation
23
+ # @param [Proc<(), A>] th
24
+ # is a thunk. In this thunk `shift` captures a continuation delimited with the thunk.
25
+ def reset(&th)
26
+ eff = Ruff::Effect.new
27
+ @stack.push eff
28
+
29
+ ret = Ruff.handler
30
+ .on(eff) do |k, f|
31
+ f.call(k)
32
+ end
33
+ .run(&th)
34
+
35
+ @stack.pop
36
+ ret
37
+ end
38
+
39
+ # captures a continuation.
40
+ # @param [Proc<Proc<C, A>, A/B>] k
41
+ # is a continuation.
42
+ def shift(&k)
43
+ # fetch nearmost prompt
44
+ top = @stack.last
45
+ top.perform(k)
46
+ end
47
+
48
+ module_function :reset, :shift
49
+ end
@@ -22,13 +22,13 @@ module Ruff::Standard::MeasureTime
22
22
  def initialize
23
23
  @eff = Ruff.instance
24
24
  @handler = Ruff.handler
25
- .on(@eff) do |k, label|
25
+ @handler.on(@eff) do |k, label|
26
26
  t1 = Time.now
27
27
  result = k[]
28
28
  t2 = Time.now
29
29
  result + [{ label: label, time: t2 - t1 }]
30
30
  end
31
- .to { |x| [x] }
31
+ @handler.to { |x| [x] }
32
32
  end
33
33
 
34
34
  # is a smart method to invoke the effect operation.
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Ruff
4
- VERSION = '1.3.0'
4
+ VERSION = '2.1.0'
5
5
  end
@@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
21
21
  spec.require_paths = ['lib']
22
22
 
23
23
  spec.add_development_dependency 'bundler', '~> 2.0'
24
- spec.add_development_dependency 'rake', '~> 10.0'
24
+ spec.add_development_dependency 'rake', '~> 13.0'
25
25
 
26
26
  spec.metadata = {
27
27
  'documentation_uri' => 'https://nymphium.github.io/ruff'
data/version CHANGED
@@ -1 +1 @@
1
- 1.3.0
1
+ 2.1.0
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruff
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - nymphium
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-10-06 00:00:00.000000000 Z
11
+ date: 2020-06-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '10.0'
33
+ version: '13.0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '10.0'
40
+ version: '13.0'
41
41
  description: ONE-SHOT Algebraic Effects for Ruby!
42
42
  email:
43
43
  - s1311350@gmail.com
@@ -49,20 +49,22 @@ files:
49
49
  - ".rubocop.yml"
50
50
  - ".solargraph.yml"
51
51
  - Gemfile
52
- - Gemfile.lock
53
52
  - LICENSE
54
53
  - README.md
55
54
  - Rakefile
55
+ - docs/.nojekyll
56
56
  - docs/Ruff.html
57
57
  - docs/Ruff/Effect.html
58
58
  - docs/Ruff/Handler.html
59
59
  - docs/Ruff/Standard.html
60
60
  - docs/Ruff/Standard/Async.html
61
61
  - docs/Ruff/Standard/Async/Instance.html
62
+ - docs/Ruff/Standard/Call1cc.html
62
63
  - docs/Ruff/Standard/CurrentTime.html
63
64
  - docs/Ruff/Standard/CurrentTime/Instance.html
64
65
  - docs/Ruff/Standard/Defer.html
65
66
  - docs/Ruff/Standard/Defer/Instance.html
67
+ - docs/Ruff/Standard/DelimCtrl.html
66
68
  - docs/Ruff/Standard/MeasureTime.html
67
69
  - docs/Ruff/Standard/MeasureTime/Instance.html
68
70
  - docs/Ruff/Standard/State.html
@@ -96,6 +98,7 @@ files:
96
98
  - lib/ruff/standard/async.rb
97
99
  - lib/ruff/standard/current_time.rb
98
100
  - lib/ruff/standard/defer.rb
101
+ - lib/ruff/standard/delim_ctrl.rb
99
102
  - lib/ruff/standard/measure_time.rb
100
103
  - lib/ruff/standard/state.rb
101
104
  - lib/ruff/standard/util.rb
@@ -108,7 +111,7 @@ licenses:
108
111
  - MIT
109
112
  metadata:
110
113
  documentation_uri: https://nymphium.github.io/ruff
111
- post_install_message:
114
+ post_install_message:
112
115
  rdoc_options: []
113
116
  require_paths:
114
117
  - lib
@@ -123,8 +126,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
123
126
  - !ruby/object:Gem::Version
124
127
  version: '0'
125
128
  requirements: []
126
- rubygems_version: 3.0.6
127
- signing_key:
129
+ rubygems_version: 3.1.3
130
+ signing_key:
128
131
  specification_version: 4
129
132
  summary: ONE-SHOT Algebraic Effects for Ruby!
130
133
  test_files: []