dramatis 0.0.1

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.
Files changed (120) hide show
  1. data/History.txt +7 -0
  2. data/License.txt +20 -0
  3. data/Manifest.txt +119 -0
  4. data/README.txt +57 -0
  5. data/Rakefile +4 -0
  6. data/config/hoe.rb +70 -0
  7. data/config/requirements.rb +17 -0
  8. data/examples/README.txt +20 -0
  9. data/examples/auction.rb +90 -0
  10. data/examples/bank/bank.rb +7 -0
  11. data/examples/bank/bank_test.rb +7 -0
  12. data/examples/exception.rb +40 -0
  13. data/examples/fib/conservative.rb +50 -0
  14. data/examples/fib/future.rb +5 -0
  15. data/examples/fib/original.rb +33 -0
  16. data/examples/fib/threads.rb +51 -0
  17. data/examples/im/distributed/chat/client.rb +49 -0
  18. data/examples/im/distributed/chat/screen/fox.rb +92 -0
  19. data/examples/im/distributed/chat/screen.rb +11 -0
  20. data/examples/im/distributed/chat/server.rb +72 -0
  21. data/examples/im/distributed/chat.rb +5 -0
  22. data/examples/im/distributed/client.rb +9 -0
  23. data/examples/im/distributed/run.rb +18 -0
  24. data/examples/im/distributed/server.rb +11 -0
  25. data/examples/im/single/chat/client.rb +50 -0
  26. data/examples/im/single/chat/screen/fox.rb +96 -0
  27. data/examples/im/single/chat/screen/wxs.rb +63 -0
  28. data/examples/im/single/chat/screen.rb +11 -0
  29. data/examples/im/single/chat/server.rb +72 -0
  30. data/examples/im/single/chat.rb +5 -0
  31. data/examples/im/single/fox.rb +18 -0
  32. data/examples/im/single/wxchat.rb +19 -0
  33. data/examples/pingpong/actor.rb +33 -0
  34. data/examples/pingpong/actor_rec.rb +34 -0
  35. data/examples/pingpong/pingpong.txt +315 -0
  36. data/examples/pingpong/scala.rb +41 -0
  37. data/examples/pingpong/serial.rb +26 -0
  38. data/examples/pretty.txt +108 -0
  39. data/examples/telephone/.irbrc +2 -0
  40. data/examples/telephone/3esl.txt +21877 -0
  41. data/examples/telephone/fifth/kid.rb +36 -0
  42. data/examples/telephone/fifth/run.rb +26 -0
  43. data/examples/telephone/first/kid.rb +31 -0
  44. data/examples/telephone/first/run.rb +20 -0
  45. data/examples/telephone/fourth/kid.rb +31 -0
  46. data/examples/telephone/fourth/run.rb +26 -0
  47. data/examples/telephone/mangler.rb +53 -0
  48. data/examples/telephone/second/kid.rb +26 -0
  49. data/examples/telephone/second/run.rb +20 -0
  50. data/examples/telephone/seventh/kid.rb +40 -0
  51. data/examples/telephone/seventh/run.rb +35 -0
  52. data/examples/telephone/seventh/test.rb +28 -0
  53. data/examples/telephone/seventh/test2.rb +10 -0
  54. data/examples/telephone/sixth/kid.rb +39 -0
  55. data/examples/telephone/sixth/run.rb +26 -0
  56. data/examples/telephone/third/kid.rb +31 -0
  57. data/examples/telephone/third/run.rb +21 -0
  58. data/lib/dramatis/actor/interface.rb +118 -0
  59. data/lib/dramatis/actor/name/interface.rb +128 -0
  60. data/lib/dramatis/actor/name.rb +44 -0
  61. data/lib/dramatis/actor.rb +96 -0
  62. data/lib/dramatis/deadlock.rb +123 -0
  63. data/lib/dramatis/error/uncaught.rb +19 -0
  64. data/lib/dramatis/error.rb +125 -0
  65. data/lib/dramatis/future/interface.rb +45 -0
  66. data/lib/dramatis/future.rb +32 -0
  67. data/lib/dramatis/runtime/actor/main.rb +3 -0
  68. data/lib/dramatis/runtime/actor.rb +294 -0
  69. data/lib/dramatis/runtime/gate.rb +244 -0
  70. data/lib/dramatis/runtime/scheduler.rb +374 -0
  71. data/lib/dramatis/runtime/task.rb +390 -0
  72. data/lib/dramatis/runtime/thread_pool.rb +149 -0
  73. data/lib/dramatis/runtime/timer.rb +5 -0
  74. data/lib/dramatis/runtime.rb +129 -0
  75. data/lib/dramatis/shoes/runtime.rb +7 -0
  76. data/lib/dramatis/shoes.rb +14 -0
  77. data/lib/dramatis/version.rb +8 -0
  78. data/lib/dramatis.rb +73 -0
  79. data/log/debug.log +0 -0
  80. data/script/destroy +14 -0
  81. data/script/generate +14 -0
  82. data/script/txt2html +74 -0
  83. data/setup.rb +1585 -0
  84. data/spec/dramatis/actor/become_spec.rb +17 -0
  85. data/spec/dramatis/actor/future_spec.rb +189 -0
  86. data/spec/dramatis/actor/name_spec.rb +141 -0
  87. data/spec/dramatis/actor/task_spec.rb +75 -0
  88. data/spec/dramatis/actor_spec.rb +492 -0
  89. data/spec/dramatis/dramatis_spec.rb +23 -0
  90. data/spec/dramatis/exc_spec.rb +78 -0
  91. data/spec/dramatis/runtime/gate_spec.rb +57 -0
  92. data/spec/dramatis/runtime/thread_pool.rb +30 -0
  93. data/spec/dramatis/shoes_spec.rb +11 -0
  94. data/spec/dramatis/simple_spec.rb +32 -0
  95. data/spec/exp_spec.rb +21 -0
  96. data/spec/simple2_spec.rb +36 -0
  97. data/spec/simple_spec.rb +30 -0
  98. data/spec/spec.opts +0 -0
  99. data/spec/spec_helper.rb +26 -0
  100. data/spec/thread_spec.rb +13 -0
  101. data/tasks/deployment.rake +34 -0
  102. data/tasks/environment.rake +7 -0
  103. data/tasks/rspec.rake +21 -0
  104. data/tasks/website.rake +17 -0
  105. data/test/jruby_lm.rb +13 -0
  106. data/test/test.rb +19 -0
  107. data/test/test10.rb +43 -0
  108. data/test/test11.rb +45 -0
  109. data/test/test12.rb +60 -0
  110. data/test/test13.rb +71 -0
  111. data/test/test2.rb +12 -0
  112. data/test/test3.rb +10 -0
  113. data/test/test4.rb +29 -0
  114. data/test/test5.rb +8 -0
  115. data/test/test6.rb +32 -0
  116. data/test/test7.rb +48 -0
  117. data/test/test8.rb +133 -0
  118. data/test/test9.rb +105 -0
  119. data/test/test_exc.rb +22 -0
  120. metadata +180 -0
@@ -0,0 +1,390 @@
1
+ module Dramatis; end
2
+ class Dramatis::Runtime; end
3
+
4
+ require 'dramatis/runtime/scheduler'
5
+ require 'dramatis/future'
6
+ require 'thread'
7
+
8
+ class Dramatis::Runtime::Task #:nodoc: all
9
+
10
+ attr_reader :actor
11
+
12
+ def type
13
+ @dest
14
+ end
15
+
16
+ def method
17
+ @args[0]
18
+ end
19
+
20
+ def arguments
21
+ @args[1,@args.length]
22
+ end
23
+
24
+ attr_reader :call_thread
25
+
26
+ def initialize actor, dest, args, options
27
+ @actor = actor
28
+ @dest = dest
29
+ @args = args.dup
30
+
31
+ @call_thread = nil
32
+
33
+ name = Dramatis::Runtime::Scheduler.actor
34
+ actor = name.instance_eval { @actor }
35
+
36
+ object_id = actor.object.object_id
37
+
38
+ @args.each_with_index do |arg,i|
39
+ if arg.object_id == object_id
40
+ @args[i] = name
41
+ end
42
+ end
43
+
44
+ if actor.call_threading?
45
+ # warn "oct #{options[:call_thread]} act #{actor.call_thread}"
46
+ raise "hell" if options[:call_thread] and
47
+ actor.call_thread and
48
+ options[:call_thread] != actor.call_thread
49
+ @call_thread = actor.call_thread
50
+ if @call_thread == nil
51
+ @call_thread = self.to_s
52
+ end
53
+ end
54
+
55
+ # warn "task #{self} #{args[0]} call thread [ #{@call_thread} ] #{options.to_a.join(' ')}"
56
+
57
+ case options[:continuation]
58
+ when :none
59
+ @continuation = Continuation::None.new name, @call_thread
60
+ when :rpc
61
+ @continuation = Continuation::RPC.new name, @call_thread, options[:nonblocking]
62
+ when :future
63
+ @continuation = Continuation::Future.new name, @call_thread
64
+ when Proc
65
+ @continuation = Continuation::Proc.new name, @call_thread, options[:continuation],
66
+ options[:exception]
67
+ else
68
+ raise Dramatis::Internal.new( "invalid contiunation type" )
69
+ end
70
+ end
71
+
72
+ def exception e
73
+ @continuation.exception e
74
+ end
75
+
76
+ def queued
77
+ @continuation.queued
78
+ end
79
+
80
+ def deliver
81
+ @actor.deliver @dest, @args, @continuation, @call_thread
82
+ end
83
+
84
+ private
85
+
86
+ module Continuation
87
+
88
+ class None
89
+
90
+ include Dramatis
91
+
92
+ def queued
93
+ end
94
+
95
+ def result result
96
+ end
97
+
98
+ def exception exception
99
+ # warn "except nil #{exception}"
100
+ # true and pp exception.backtrace
101
+ interface( release( @name ) ).exception exception
102
+ end
103
+
104
+ def initialize name, call_thread
105
+ @name = name
106
+ end
107
+ end
108
+
109
+ class RPC
110
+
111
+ include Dramatis
112
+
113
+ def actor
114
+ @actor.instance_eval { @actor }
115
+ end
116
+
117
+ def initialize name, call_thread, nonblocking
118
+ # all the synchronizaton here probably gets tossed
119
+ # proof:
120
+ # to create the continuation, you have to have the actor lock
121
+ # to deliver the continuation you have to have the actor lock
122
+ # QED
123
+ # when this wasn't a message send, you could try to execute before
124
+ # but now that's not possible; it'll get queued
125
+ # i think
126
+ # of course, it should be harmless
127
+ # fix ... might want to seperate the two parts of a continuation
128
+ # the value part and the thread state part
129
+ @blocking = !nonblocking
130
+ @state = :start
131
+ @mutex = Mutex.new
132
+ @wait = ConditionVariable.new
133
+ @call_thread = call_thread
134
+ # warn "contiunation to #{actor}"
135
+ @actor = interface( Dramatis::Runtime::Scheduler.actor ).send :continuation, self, :call_thread => call_thread
136
+ end
137
+
138
+ def queued
139
+
140
+ @mutex.synchronize do
141
+ raise "hell " + @state.to_s if @state != :start and @state != :signaled
142
+ if @state == :start
143
+ @state = :waiting
144
+ begin
145
+ tag = to_s
146
+ call_thread = @call_thread
147
+ blocking = @blocking
148
+ @actor.instance_eval do
149
+ @actor.instance_eval do
150
+ # warn "#{self} ct [ #{call_thread} ]"
151
+ @call_thread = call_thread
152
+ end
153
+ if blocking
154
+ @actor.gate.only [ :continuation, tag ], :tag => tag
155
+ end
156
+ @actor.schedule self
157
+ end
158
+ begin
159
+ Dramatis::Runtime::Scheduler.current.suspend_notification self
160
+ @wait.wait @mutex
161
+ # this causes a deadlock if the waking thread, which may be
162
+ # retiring, does so before this thead has awakend and notified
163
+ # the scheduler
164
+ # sleep 1
165
+ ensure
166
+ # Dramatis::Runtime::Scheduler.current.wakeup_notification self
167
+ end
168
+ ensure
169
+ tag = to_s
170
+ @actor.instance_eval do
171
+ @actor.gate.default_by_tag tag
172
+ end
173
+ end
174
+ raise "hell" if @state != :done
175
+ end
176
+ end
177
+
178
+ raise "hell " + @type.inspect if ![ :return, :exception ].include? @type
179
+ case @type
180
+ when :return
181
+ return @value
182
+ when :exception
183
+ # if Dramatis::Deadlock === @value
184
+ # @value = Dramatis::Deadlock.new nil, :next => @value
185
+ # end
186
+ # pp "reraise", caller
187
+ @value._dramatis_reraise
188
+ raise @value
189
+ end
190
+ end
191
+
192
+ def result result
193
+ @actor.result result
194
+ end
195
+
196
+ def exception exception
197
+ # warn "4 exception " + exception.to_s
198
+ # warn "4 exception " + exception.backtrace.join("\n")
199
+ @actor.exception exception
200
+ # warn "4 delivered ".to_s
201
+ end
202
+
203
+ def continuation_result result
204
+ @mutex.synchronize do
205
+ raise "hell" if @state != :start and @state != :waiting
206
+ @type = :return
207
+ @value = result
208
+ if @state == :start
209
+ @state = :signaled
210
+ else
211
+ @state = :done
212
+ Dramatis::Runtime::Scheduler.current.wakeup_notification self
213
+ @wait.signal
214
+ end
215
+ end
216
+ end
217
+
218
+ def continuation_exception exception
219
+ # warn "except rpc"
220
+ @mutex.synchronize do
221
+ raise "hell" if @state != :start and @state != :waiting
222
+ @type = :exception
223
+ @value = exception
224
+ if @state == :start
225
+ @state = :signaled
226
+ else
227
+ @state = :done
228
+ Dramatis::Runtime::Scheduler.current.wakeup_notification self
229
+ @wait.signal
230
+ end
231
+ end
232
+ end
233
+
234
+ end
235
+
236
+ class Proc
237
+
238
+ include Dramatis
239
+
240
+ def initialize name, call_thread, result, except
241
+ # p "p.n #{call_thread} #{result} #{except}"
242
+ @result_block = result
243
+ @exception_block = except
244
+ @name = name
245
+ @continuation = \
246
+ interface( Dramatis::Runtime::Scheduler.actor ) \
247
+ .send :continuation, self, :call_thread => call_thread
248
+ end
249
+
250
+ def queued; end
251
+
252
+ def result result
253
+ @continuation.result result
254
+ end
255
+
256
+ def exception exception
257
+ @continuation.exception exception
258
+ end
259
+
260
+ def continuation_result result
261
+ @result_block.call result
262
+ end
263
+
264
+ def continuation_exception exception
265
+ # warn "delivering #{exception} => #{@exception_block}"
266
+ # pp exception.backtrace
267
+ if @exception_block
268
+ @exception_block.call exception
269
+ else
270
+ release( @name ).dramatis_exception exception
271
+ end
272
+ end
273
+
274
+ end
275
+
276
+ class Future
277
+
278
+ include Dramatis
279
+
280
+ def initialize name, call_thread
281
+ @state = :start
282
+ @mutex = Mutex.new
283
+ @wait = ConditionVariable.new
284
+ @call_thread = call_thread
285
+ # warn "contiunation to #{actor}"
286
+ @actor = interface( Dramatis::Runtime::Scheduler.actor ) \
287
+ .send :continuation, self, :call_thread => call_thread
288
+ end
289
+
290
+ def ready?
291
+ @mutex.synchronize { @state == :done or @state == :signaled }
292
+ end
293
+
294
+ def value
295
+ @mutex.synchronize do
296
+ if @state == :start
297
+ @state = :waiting
298
+ begin
299
+ tag = to_s
300
+ call_thread = @call_thread
301
+ @actor.instance_eval do
302
+ @actor.instance_eval do
303
+ @call_thread = call_thread
304
+ end
305
+ @actor.gate.only [ :continuation, tag ], :tag => tag
306
+ @actor.schedule self
307
+ end
308
+ begin
309
+ Dramatis::Runtime::Scheduler.current.suspend_notification self
310
+ @wait.wait @mutex
311
+ # this causes a deadlock if the waking thread, which may be
312
+ # retiring, does so before this thead has awakend and notified
313
+ # the scheduler
314
+ # sleep 1
315
+ ensure
316
+ # Dramatis::Runtime::Scheduler.current.wakeup_notification self
317
+ end
318
+ ensure
319
+ tag = to_s
320
+ @actor.instance_eval do
321
+ @actor.gate.default_by_tag tag
322
+ end
323
+ end
324
+ raise "hell" if @state != :done
325
+ end
326
+ end
327
+
328
+ raise "hell " + @type.inspect if ![ :return, :exception ].include? @type
329
+ case @type
330
+ when :return
331
+ return @value
332
+ when :exception
333
+ begin
334
+ # raise "hell for #{@value}"
335
+ rescue Exception => e
336
+ pp "#{e}", e.backtrace
337
+ end
338
+ raise @value
339
+ end
340
+ end
341
+
342
+ def queued
343
+ Dramatis::Future.new( self )
344
+ end
345
+
346
+ def result result
347
+ @actor.result result
348
+ end
349
+
350
+ def exception exception
351
+ # warn "4 exception " + exception.to_s
352
+ # warn "4 exception " + exception.backtrace.join("\n")
353
+ @actor.exception exception
354
+ # warn "4 delivered ".to_s
355
+ end
356
+
357
+ def continuation_result result
358
+ @mutex.synchronize do
359
+ raise "hell" if @state != :start and @state != :waiting
360
+ @type = :return
361
+ @value = result
362
+ if @state == :start
363
+ @state = :signaled
364
+ else
365
+ @state = :done
366
+ Dramatis::Runtime::Scheduler.current.wakeup_notification self
367
+ @wait.signal
368
+ end
369
+ end
370
+ end
371
+
372
+ def continuation_exception exception
373
+ # warn "except rpc"
374
+ @mutex.synchronize do
375
+ raise "hell" if @state != :start and @state != :waiting
376
+ @type = :exception
377
+ @value = exception
378
+ if @state == :start
379
+ @state = :signaled
380
+ else
381
+ @state = :done
382
+ Dramatis::Runtime::Scheduler.current.wakeup_notification self
383
+ @wait.signal
384
+ end
385
+ end
386
+ end
387
+ end
388
+ end
389
+
390
+ end
@@ -0,0 +1,149 @@
1
+ module Dramatis; end
2
+ class Dramatis::Runtime; end
3
+
4
+ class Dramatis::Runtime::ThreadPool; end
5
+ class Dramatis::Runtime::ThreadPool::PoolThread < Thread; end
6
+
7
+ class Dramatis::Runtime::ThreadPool #:nodoc: all
8
+
9
+ def reset
10
+ shutdown
11
+ @state = :running
12
+ end
13
+
14
+ def initialize
15
+ super
16
+ @mutex = Mutex.new
17
+ @threads = []
18
+ @state = :running
19
+ end
20
+
21
+ def new &block
22
+ checkout( &block )
23
+ end
24
+
25
+ def length
26
+ @mutex.synchronize do
27
+ @threads.length
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def shutdown
34
+ @mutex.synchronize do
35
+ @state = :exiting
36
+ @threads.each do |thread|
37
+ thread.send :shutdown
38
+ end
39
+ @threads.each do |thread|
40
+ thread.true_join
41
+ end
42
+ @threads = []
43
+ end
44
+ end
45
+
46
+ def checkin thread
47
+ @mutex.synchronize do
48
+ if @state != :exiting
49
+ @threads << thread
50
+ else
51
+ warn("POST EXIT CHECKIN")
52
+ end
53
+ end
54
+ end
55
+
56
+ def checkout &block
57
+ raise "hell" if @state == :exiting
58
+ t = nil
59
+ @mutex.synchronize do
60
+ if @threads.length == 0
61
+ pt = PoolThread.new self
62
+ @threads << pt
63
+ end
64
+ t = @threads.pop
65
+ end
66
+ t.send :awaken, &block
67
+ t
68
+ end
69
+
70
+ end
71
+
72
+ class Dramatis::Runtime::ThreadPool::PoolThread < Thread
73
+
74
+ def initialize pool
75
+ @pool = pool
76
+ @mutex = Mutex.new
77
+ @wait = ConditionVariable.new
78
+ @state = :running
79
+ super() do
80
+ self.abort_on_exception = true
81
+ target
82
+ end
83
+ end
84
+
85
+ alias true_join join
86
+
87
+ def join
88
+ # I've thought about this. It would be cool to implement join. It's not
89
+ # too hard to do it when threads aren't reused ... which is kinda dumb.
90
+ # It's possible to do it when threads are reused, by coding an allocation
91
+ # counter in the "thread" object (but not the native thread). It'd be
92
+ # cool, but I don't need it, so, oh well.
93
+ raise "not implemented"
94
+ end
95
+
96
+ private
97
+
98
+ def shutdown
99
+ @mutex.synchronize do
100
+ old_state, @state = @state, :exiting
101
+ # p "#{Thread.current} shutdown #{old_state} #{@state}"
102
+ if old_state == :waiting
103
+ @wait.signal
104
+ end
105
+ end
106
+ end
107
+
108
+ def awaken &block
109
+ @mutex.synchronize do
110
+ @block = block
111
+ old_state, @state = @state, :called
112
+ if old_state == :waiting
113
+ # p "#{Thread.current} signalling"
114
+ @wait.signal
115
+ elsif old_state == :exiting
116
+ warn("AWAKEN AFTER EXIT")
117
+ raise "AWAKEN AFTER EXIT"
118
+ elsif old_state != :running
119
+ warn("AWAKEN BAD STATE " + old_state)
120
+ raise "AWAKEN BAD STATE " + old_state
121
+ end
122
+ end
123
+ end
124
+
125
+ def target
126
+ while true do
127
+ @mutex.synchronize do
128
+ if @state == :exiting
129
+ return
130
+ elsif @state == :running
131
+ @state = :waiting
132
+ @wait.wait @mutex
133
+ raise "hell" if @state == :waiting
134
+ elsif @state == :called
135
+ begin
136
+ @block.call
137
+ ensure
138
+ @state = :running
139
+ @pool.send :checkin, self
140
+ end
141
+ else
142
+ warn( "!!FAIL!! " + @state)
143
+ raise "!!FAIL!! " + @state
144
+ end
145
+ end
146
+ end
147
+ end
148
+
149
+ end
@@ -0,0 +1,5 @@
1
+ module Dramatis; end
2
+ class Dramatis::Runtime; end
3
+
4
+ class Dramatis::Runtime::Timer #:nodoc: all
5
+ end
@@ -0,0 +1,129 @@
1
+ module Dramatis; end
2
+
3
+ require 'thread'
4
+
5
+ # Dramatis::Runtime is the top level class managing the running of the
6
+ # various pieces of the dramatis runtime. Typically programs don't
7
+ # need to deal with the runtime directly, though some functions are
8
+ # useful, particularly for debugging and testing.
9
+
10
+ class Dramatis::Runtime
11
+
12
+ # Returns a reference to the current Dramatis::Runtime object.
13
+
14
+ def self.current
15
+ @@current ||= self.new
16
+ end
17
+
18
+ # Resets the current runtime instance. Note that this method hard
19
+ # resets counters and ignore exceptions which is generally a bad
20
+ # idea. It is typical only used in unit test after methods to keep
21
+ # failing tests from cascading.
22
+
23
+ def self.reset
24
+ # this swallows exceptions: it's assumed to be used to clean up
25
+ # a failed test so there's no connection between tests
26
+ begin
27
+ Dramatis::Runtime.current.quiesce
28
+ rescue Exception => e
29
+ end
30
+ Dramatis::Runtime::Scheduler.reset
31
+ Dramatis::Runtime::Actor::Main.reset
32
+ @@current = nil
33
+ end
34
+
35
+ # Causes the runtime to suspend the current thread until there are
36
+ # no more tasks that can be executed. If no tasks remain, returns
37
+ # normally. If tasks remain but are gated off,
38
+ # Dramtis::Error::Deadlock is raised.
39
+ #
40
+ # As a side effect, this method releases the current actor to
41
+ # process messages but does not change the task gate.
42
+
43
+ def quiesce
44
+ Dramatis::Runtime::Scheduler.current.quiesce
45
+ maybe_raise_exceptions true
46
+ end
47
+
48
+ def maybe_raise_exceptions quiescing #:nodoc:
49
+ @mutex.synchronize do
50
+ if !@exceptions.empty?
51
+ # warn "no maybe about it"
52
+ if !quiescing and warnings?
53
+ warn "the following #{@exceptions.length} exception(s) were raised and not caught"
54
+ @exceptions.each do |exception|
55
+ # warn "#{exception}"
56
+ # pp exception.backtrace
57
+ end
58
+ end
59
+ raise Dramatis::Error::Uncaught.new( @exceptions )
60
+ end
61
+ @exceptions.clear
62
+ end
63
+ end
64
+
65
+ # Returns the list of uncaught exceptions.
66
+
67
+ def exceptions
68
+ result = nil
69
+ @mutex.synchronize do
70
+ result = @exceptions.dup
71
+ end
72
+ result
73
+ end
74
+
75
+ # Clears the list of uncaught exceptions. Used in unit tests to
76
+ # clear expected exceptions. If exceptions are raised and not
77
+ # clear, they will be raised at the end of the program via a
78
+ # Dramatis::Error::Uncaught.
79
+
80
+ def clear_exceptions
81
+ @mutex.synchronize do
82
+ # warn "runtime clearing exceptions"
83
+ @exceptions.clear
84
+ end
85
+ end
86
+
87
+ def exception exception #:nodoc:
88
+ @mutex.synchronize do
89
+ @exceptions << exception
90
+ warn "runtime recording exception: #{exception} [#{@exceptions.length}]" if warnings?
91
+ # backtrace
92
+ # pp exception.backtrace
93
+ end
94
+ end
95
+
96
+ def backtrace #:nodoc:
97
+ begin
98
+ raise "backtrace"
99
+ rescue ::Exception => e
100
+ pp e.backtrace
101
+ end
102
+ end
103
+
104
+ # Enables or disables printing warnings, e.g., when uncaugh
105
+ # exceptions are detected.
106
+
107
+ def warnings= value
108
+ @warnings = value
109
+ end
110
+
111
+ # Returns true if warnings are enabled.
112
+
113
+ def warnings?
114
+ @warnings
115
+ end
116
+
117
+ def at_exit #:nodoc:
118
+ Dramatis::Runtime::Actor::Main.current.finalize
119
+ end
120
+
121
+ private
122
+
123
+ def initialize #:nodoc:
124
+ @warnings = true
125
+ @mutex = Mutex.new
126
+ @exceptions = []
127
+ end
128
+
129
+ end
@@ -0,0 +1,7 @@
1
+ module Dramatis; end
2
+ module Dramatis::Shoes; end
3
+
4
+ class Dramatis::Shoes::Runtime #:nodoc: all
5
+ end
6
+
7
+
@@ -0,0 +1,14 @@
1
+ module Dramatis; end
2
+ module Dramatis::Shoes; end
3
+
4
+ require 'dramatis/shoes/runtime'
5
+
6
+ module Dramatis::Shoes #:nodoc: all
7
+
8
+ def self.runtime
9
+ @runtime ||= Dramatis::Shoes::Runtime.new
10
+ end
11
+
12
+ end
13
+
14
+
@@ -0,0 +1,8 @@
1
+ module Dramatis
2
+ module VERSION #:nodoc:
3
+ MAJOR = 0
4
+ MINOR = 0
5
+ TINY = 1
6
+ STRING = [MAJOR, MINOR, TINY].join('.')
7
+ end
8
+ end