mame-dynamicwind 1.0.0
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/History.txt +6 -0
- data/Manifest.txt +6 -0
- data/README.txt +48 -0
- data/Rakefile +12 -0
- data/lib/dynamicwind.rb +50 -0
- data/test/test_dynamicwind.rb +188 -0
- metadata +70 -0
data/History.txt
ADDED
data/Manifest.txt
ADDED
data/README.txt
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
= dynamicwind
|
2
|
+
|
3
|
+
* http://github.com/mame/dynamicwind/tree/master
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
An implementation of dynamic-wind for ruby's continuation.
|
8
|
+
See R6RS 11.15 Control features for detail.
|
9
|
+
http://www.r6rs.org/final/html/r6rs/r6rs-Z-H-14.html#node_idx_764
|
10
|
+
|
11
|
+
== FEATURES/PROBLEMS:
|
12
|
+
|
13
|
+
* callcc becomes robust!
|
14
|
+
|
15
|
+
== SYNOPSIS:
|
16
|
+
|
17
|
+
require "dynamicwind"
|
18
|
+
|
19
|
+
callcc do |c|
|
20
|
+
dynamicwind(
|
21
|
+
proc { p :before },
|
22
|
+
proc { p :thunk; c.call },
|
23
|
+
proc { p :after }
|
24
|
+
)
|
25
|
+
end
|
26
|
+
#=> :before, :thunk, :after
|
27
|
+
|
28
|
+
dynamicwind(
|
29
|
+
proc { p :before },
|
30
|
+
proc { callcc {|c| $c = c }; p :thunk },
|
31
|
+
proc { p :after }
|
32
|
+
)
|
33
|
+
#=> :before, :thunk, :after
|
34
|
+
|
35
|
+
$c.call #=> :before, :thunk, :after, ...(infinite loop)
|
36
|
+
|
37
|
+
== REQUIREMENTS:
|
38
|
+
|
39
|
+
None
|
40
|
+
|
41
|
+
== INSTALL:
|
42
|
+
|
43
|
+
* gem install mame-dynamicwind
|
44
|
+
|
45
|
+
== LICENSE:
|
46
|
+
|
47
|
+
Copyright:: Yusuke Endoh <mame@tsg.ne.jp>
|
48
|
+
License:: Ruby's
|
data/Rakefile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'hoe'
|
5
|
+
require './lib/dynamicwind.rb'
|
6
|
+
|
7
|
+
Hoe.new('dynamicwind', DynamicWind::VERSION) do |p|
|
8
|
+
p.rubyforge_name = 'dynamicwind'
|
9
|
+
p.developer('Yusuke Endoh', 'mame@tsg.ne.jp')
|
10
|
+
end
|
11
|
+
|
12
|
+
# vim: syntax=ruby
|
data/lib/dynamicwind.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
begin
|
2
|
+
require "continuation"
|
3
|
+
rescue LoadError
|
4
|
+
end
|
5
|
+
|
6
|
+
module DynamicWind
|
7
|
+
VERSION = '1.0.0'
|
8
|
+
|
9
|
+
Stack = Struct.new(:fst, :snd, :next)
|
10
|
+
|
11
|
+
alias __callcc_orig callcc
|
12
|
+
|
13
|
+
def callcc
|
14
|
+
mark = __top
|
15
|
+
__callcc_orig do |ctn|
|
16
|
+
yield(proc {|*ret| __switch(mark); ctn.call(*ret) })
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def dynamicwind(before, thunk, after)
|
21
|
+
mark = __top
|
22
|
+
__switch(Stack[[before, nil], [nil, after], mark])
|
23
|
+
thunk.call ensure __switch(mark)
|
24
|
+
end
|
25
|
+
|
26
|
+
def __top
|
27
|
+
Thread.current[:dynamicwind_stack] ||= Stack.new
|
28
|
+
end
|
29
|
+
|
30
|
+
def __top=(x)
|
31
|
+
Thread.current[:dynamicwind_stack] = x
|
32
|
+
end
|
33
|
+
|
34
|
+
def __switch(mark)
|
35
|
+
return if __top.equal?(mark)
|
36
|
+
__switch(mark.next)
|
37
|
+
fst, snd = mark.fst, mark.snd
|
38
|
+
fst.first.call if fst.first
|
39
|
+
__top.fst = snd
|
40
|
+
__top.snd = fst
|
41
|
+
__top.next = mark
|
42
|
+
self.__top = mark
|
43
|
+
__top.fst = nil
|
44
|
+
__top.snd = nil
|
45
|
+
__top.next = nil
|
46
|
+
fst.last.call if fst.last
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
include DynamicWind
|
@@ -0,0 +1,188 @@
|
|
1
|
+
require "dynamicwind"
|
2
|
+
require "test/unit"
|
3
|
+
|
4
|
+
class TestDynamicWind < Test::Unit::TestCase
|
5
|
+
def test_leave
|
6
|
+
ary = []
|
7
|
+
callcc do |c|
|
8
|
+
dynamicwind(
|
9
|
+
proc { ary << :before },
|
10
|
+
proc { ary << :thunk; c.call },
|
11
|
+
proc { ary << :after }
|
12
|
+
)
|
13
|
+
end
|
14
|
+
assert_equal([:before, :thunk, :after], ary)
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_enter
|
18
|
+
ary = []
|
19
|
+
ctn = nil
|
20
|
+
flag = true
|
21
|
+
dynamicwind(
|
22
|
+
proc { ary << :before },
|
23
|
+
proc { callcc {|c| ctn = c }; ary << :thunk },
|
24
|
+
proc { ary << :after }
|
25
|
+
)
|
26
|
+
(flag = false; ctn.call) if flag
|
27
|
+
assert_equal([:before, :thunk, :after] * 2, ary)
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_leave_enter
|
31
|
+
ary = []
|
32
|
+
c2 = nil
|
33
|
+
flag = true
|
34
|
+
callcc do |c1|
|
35
|
+
dynamicwind(
|
36
|
+
proc { ary << :before },
|
37
|
+
proc do
|
38
|
+
ary << :thunk1
|
39
|
+
callcc {|c| c2 = c }
|
40
|
+
ary << :thunk2
|
41
|
+
c1.call
|
42
|
+
ary << :thunk3
|
43
|
+
end,
|
44
|
+
proc { ary << :after }
|
45
|
+
)
|
46
|
+
end
|
47
|
+
ary << :end
|
48
|
+
(flag = false; c2.call) if flag
|
49
|
+
assert_equal([:before, :thunk1, :thunk2, :after, :end, :before, :thunk2, :after, :end], ary)
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_leave_enter_2
|
53
|
+
ary = []
|
54
|
+
c2 = nil
|
55
|
+
flag = true
|
56
|
+
callcc do |c1|
|
57
|
+
dynamicwind(
|
58
|
+
proc { ary << :before },
|
59
|
+
proc do
|
60
|
+
ary << :thunk1
|
61
|
+
callcc do |c|
|
62
|
+
c2 = c
|
63
|
+
ary << :thunk2
|
64
|
+
c1.call
|
65
|
+
end
|
66
|
+
ary << :thunk3
|
67
|
+
end,
|
68
|
+
proc { ary << :after }
|
69
|
+
)
|
70
|
+
end
|
71
|
+
ary << :end
|
72
|
+
(flag = false; c2.call) if flag
|
73
|
+
assert_equal([:before, :thunk1, :thunk2, :after, :end, :before, :thunk3, :after, :end], ary)
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_callcc_in_before
|
77
|
+
ary = []
|
78
|
+
ctn = nil
|
79
|
+
flag = true
|
80
|
+
dynamicwind(
|
81
|
+
proc do
|
82
|
+
ary << :before1
|
83
|
+
callcc {|c| ctn = c }
|
84
|
+
ary << :before2
|
85
|
+
end,
|
86
|
+
proc { ary << :thunk },
|
87
|
+
proc do
|
88
|
+
ary << :after1
|
89
|
+
(flag = false; ctn.call) if flag
|
90
|
+
ary << :after2
|
91
|
+
end
|
92
|
+
)
|
93
|
+
assert_equal([:before1, :before2, :thunk, :after1, :before2, :thunk, :after1, :after2], ary)
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_raise
|
97
|
+
ary = []
|
98
|
+
assert_raise(RuntimeError) do
|
99
|
+
dynamicwind(
|
100
|
+
proc { ary << :before; raise },
|
101
|
+
proc { ary << :thunk },
|
102
|
+
proc { ary << :after }
|
103
|
+
)
|
104
|
+
end
|
105
|
+
assert_equal([:before], ary)
|
106
|
+
|
107
|
+
ary = []
|
108
|
+
assert_raise(RuntimeError) do
|
109
|
+
dynamicwind(
|
110
|
+
proc { ary << :before },
|
111
|
+
proc { ary << :thunk; raise },
|
112
|
+
proc { ary << :after }
|
113
|
+
)
|
114
|
+
end
|
115
|
+
assert_equal([:before, :thunk, :after], ary)
|
116
|
+
|
117
|
+
ary = []
|
118
|
+
assert_raise(RuntimeError) do
|
119
|
+
dynamicwind(
|
120
|
+
proc { ary << :before },
|
121
|
+
proc { ary << :thunk },
|
122
|
+
proc { ary << :after; raise }
|
123
|
+
)
|
124
|
+
end
|
125
|
+
assert_equal([:before, :thunk, :after], ary)
|
126
|
+
end
|
127
|
+
|
128
|
+
def test_throw
|
129
|
+
ary = []
|
130
|
+
assert_throws(:foo) do
|
131
|
+
dynamicwind(
|
132
|
+
proc { ary << :before; throw :foo },
|
133
|
+
proc { ary << :thunk },
|
134
|
+
proc { ary << :after }
|
135
|
+
)
|
136
|
+
end
|
137
|
+
assert_equal([:before], ary)
|
138
|
+
|
139
|
+
ary = []
|
140
|
+
assert_throws(:foo) do
|
141
|
+
dynamicwind(
|
142
|
+
proc { ary << :before },
|
143
|
+
proc { ary << :thunk; throw :foo },
|
144
|
+
proc { ary << :after }
|
145
|
+
)
|
146
|
+
end
|
147
|
+
assert_equal([:before, :thunk, :after], ary)
|
148
|
+
|
149
|
+
ary = []
|
150
|
+
assert_throws(:foo) do
|
151
|
+
dynamicwind(
|
152
|
+
proc { ary << :before },
|
153
|
+
proc { ary << :thunk },
|
154
|
+
proc { ary << :after; throw :foo }
|
155
|
+
)
|
156
|
+
end
|
157
|
+
assert_equal([:before, :thunk, :after], ary)
|
158
|
+
end
|
159
|
+
|
160
|
+
def test_double_wind
|
161
|
+
ary = []
|
162
|
+
c2 = nil
|
163
|
+
flag = true
|
164
|
+
callcc do |c1|
|
165
|
+
dynamicwind(
|
166
|
+
proc { ary << :before1 },
|
167
|
+
proc do
|
168
|
+
dynamicwind(
|
169
|
+
proc { ary << :before2 },
|
170
|
+
proc do
|
171
|
+
ary << :thunk1
|
172
|
+
callcc do |c|
|
173
|
+
c2 = c
|
174
|
+
c1.call
|
175
|
+
end
|
176
|
+
ary << :thunk2
|
177
|
+
end,
|
178
|
+
proc { ary << :after2 }
|
179
|
+
)
|
180
|
+
end,
|
181
|
+
proc { ary << :after1 }
|
182
|
+
)
|
183
|
+
end
|
184
|
+
ary << :end
|
185
|
+
(flag = false; c2.call) if flag
|
186
|
+
assert_equal([:before1, :before2, :thunk1, :after2, :after1, :end, :before1, :before2, :thunk2, :after2, :after1, :end], ary)
|
187
|
+
end
|
188
|
+
end
|
metadata
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mame-dynamicwind
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Yusuke Endoh
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-11-20 00:00:00 -08:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: hoe
|
17
|
+
version_requirement:
|
18
|
+
version_requirements: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 1.8.2
|
23
|
+
version:
|
24
|
+
description: An implementation of dynamic-wind for ruby's continuation. See R6RS 11.15 Control features for detail. http://www.r6rs.org/final/html/r6rs/r6rs-Z-H-14.html#node_idx_764
|
25
|
+
email:
|
26
|
+
- mame@tsg.ne.jp
|
27
|
+
executables: []
|
28
|
+
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files:
|
32
|
+
- History.txt
|
33
|
+
- Manifest.txt
|
34
|
+
- README.txt
|
35
|
+
files:
|
36
|
+
- History.txt
|
37
|
+
- Manifest.txt
|
38
|
+
- README.txt
|
39
|
+
- Rakefile
|
40
|
+
- lib/dynamicwind.rb
|
41
|
+
- test/test_dynamicwind.rb
|
42
|
+
has_rdoc: true
|
43
|
+
homepage: http://github.com/mame/dynamicwind/tree/master
|
44
|
+
post_install_message:
|
45
|
+
rdoc_options:
|
46
|
+
- --main
|
47
|
+
- README.txt
|
48
|
+
require_paths:
|
49
|
+
- lib
|
50
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: "0"
|
55
|
+
version:
|
56
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: "0"
|
61
|
+
version:
|
62
|
+
requirements: []
|
63
|
+
|
64
|
+
rubyforge_project: dynamicwind
|
65
|
+
rubygems_version: 1.2.0
|
66
|
+
signing_key:
|
67
|
+
specification_version: 2
|
68
|
+
summary: An implementation of dynamic-wind for ruby's continuation
|
69
|
+
test_files:
|
70
|
+
- test/test_dynamicwind.rb
|