rubinius-actor 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.
- data/README.txt +4 -0
- data/lib/rubinius/actor.rb +427 -0
- data/lib/rubinius/actor/filter.rb +69 -0
- data/rubinius-actor.gemspec +15 -0
- metadata +84 -0
data/README.txt
ADDED
@@ -0,0 +1,427 @@
|
|
1
|
+
# actor.rb - implementation of the actor model
|
2
|
+
#
|
3
|
+
# Copyright 2007-2008 MenTaLguY <mental@rydia.net>
|
4
|
+
# 2007-2011 Evan Phoenix <evan@fallingsnow.net>
|
5
|
+
#
|
6
|
+
# All rights reserved.
|
7
|
+
#
|
8
|
+
# Redistribution and use in source and binary forms, with or without
|
9
|
+
# modification, are permitted provided that the following conditions are met:
|
10
|
+
#
|
11
|
+
# * Redistributions of source code must retain the above copyright notice,
|
12
|
+
# thi slist of conditions and the following disclaimer.
|
13
|
+
# * Redistributions in binary form must reproduce the above copyright notice
|
14
|
+
# this list of conditions and the following disclaimer in the documentatio
|
15
|
+
# and/or other materials provided with the distribution.
|
16
|
+
# * Neither the name of the Evan Phoenix nor the names of its contributors
|
17
|
+
# may be used to endorse or promote products derived from this software
|
18
|
+
# without specific prior written permission.
|
19
|
+
#
|
20
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
21
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
22
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
23
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
24
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
25
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
26
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
27
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
28
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
29
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
30
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
31
|
+
|
32
|
+
require 'rubinius/core-api'
|
33
|
+
|
34
|
+
class Rubinius::Actor
|
35
|
+
class DeadActorError < RuntimeError
|
36
|
+
attr_reader :actor
|
37
|
+
attr_reader :reason
|
38
|
+
def initialize(actor, reason)
|
39
|
+
super(reason)
|
40
|
+
@actor = actor
|
41
|
+
@reason = reason
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
ANY = Object.new
|
46
|
+
def ANY.===(other)
|
47
|
+
true
|
48
|
+
end
|
49
|
+
|
50
|
+
class << self
|
51
|
+
alias_method :private_new, :new
|
52
|
+
private :private_new
|
53
|
+
|
54
|
+
@@registered_lock = Rubinius::Channel.new
|
55
|
+
@@registered = {}
|
56
|
+
@@registered_lock << nil
|
57
|
+
|
58
|
+
def current
|
59
|
+
Thread.current[:__current_actor__] ||= private_new
|
60
|
+
end
|
61
|
+
|
62
|
+
# Spawn a new Actor that will run in its own thread
|
63
|
+
def spawn(*args, &block)
|
64
|
+
raise ArgumentError, "no block given" unless block
|
65
|
+
spawned = Rubinius::Channel.new
|
66
|
+
Thread.new do
|
67
|
+
private_new do |actor|
|
68
|
+
Thread.current[:__current_actor__] = actor
|
69
|
+
spawned << actor
|
70
|
+
block.call *args
|
71
|
+
end
|
72
|
+
end
|
73
|
+
spawned.receive
|
74
|
+
end
|
75
|
+
alias_method :new, :spawn
|
76
|
+
|
77
|
+
# Atomically spawn an actor and link it to the current actor
|
78
|
+
def spawn_link(*args, &block)
|
79
|
+
current = self.current
|
80
|
+
link_complete = Rubinius::Channel.new
|
81
|
+
spawn do
|
82
|
+
begin
|
83
|
+
Actor.link(current)
|
84
|
+
ensure
|
85
|
+
link_complete << Actor.current
|
86
|
+
end
|
87
|
+
block.call *args
|
88
|
+
end
|
89
|
+
link_complete.receive
|
90
|
+
end
|
91
|
+
|
92
|
+
# Polls for exit notifications
|
93
|
+
def check_for_interrupt
|
94
|
+
current._check_for_interrupt
|
95
|
+
self
|
96
|
+
end
|
97
|
+
|
98
|
+
# Waits until a matching message is received in the current actor's
|
99
|
+
# mailbox, and executes the appropriate action. May be interrupted by
|
100
|
+
# exit notifications.
|
101
|
+
def receive #:yields: filter
|
102
|
+
filter = Filter.new
|
103
|
+
if block_given?
|
104
|
+
yield filter
|
105
|
+
else
|
106
|
+
filter.when(ANY) { |m| m }
|
107
|
+
end
|
108
|
+
current._receive(filter)
|
109
|
+
end
|
110
|
+
|
111
|
+
# Send a "fake" exit notification to another actor, as if the current
|
112
|
+
# actor had exited with +reason+
|
113
|
+
def send_exit(recipient, reason)
|
114
|
+
recipient.notify_exited(current, reason)
|
115
|
+
self
|
116
|
+
end
|
117
|
+
|
118
|
+
# Link the current Actor to another one.
|
119
|
+
def link(actor)
|
120
|
+
current = self.current
|
121
|
+
current.notify_link actor
|
122
|
+
actor.notify_link current
|
123
|
+
self
|
124
|
+
end
|
125
|
+
|
126
|
+
# Unlink the current Actor from another one
|
127
|
+
def unlink(actor)
|
128
|
+
current = self.current
|
129
|
+
current.notify_unlink actor
|
130
|
+
actor.notify_unlink current
|
131
|
+
self
|
132
|
+
end
|
133
|
+
|
134
|
+
# Actors trapping exit do not die when an error occurs in an Actor they
|
135
|
+
# are linked to. Instead the exit message is sent to their regular
|
136
|
+
# mailbox in the form [:exit, actor, reason]. This allows certain
|
137
|
+
# Actors to supervise sets of others and restart them in the event
|
138
|
+
# of an error. Setting the trap flag may be interrupted by pending
|
139
|
+
# exit notifications.
|
140
|
+
#
|
141
|
+
def trap_exit=(value)
|
142
|
+
current._trap_exit = value
|
143
|
+
self
|
144
|
+
end
|
145
|
+
|
146
|
+
# Is the Actor trapping exit?
|
147
|
+
def trap_exit
|
148
|
+
current._trap_exit
|
149
|
+
end
|
150
|
+
alias_method :trap_exit?, :trap_exit
|
151
|
+
|
152
|
+
# Lookup a locally named service
|
153
|
+
def lookup(name)
|
154
|
+
raise ArgumentError, "name must be a symbol" unless Symbol === name
|
155
|
+
@@registered_lock.receive
|
156
|
+
begin
|
157
|
+
@@registered[name]
|
158
|
+
ensure
|
159
|
+
@@registered_lock << nil
|
160
|
+
end
|
161
|
+
end
|
162
|
+
alias_method :[], :lookup
|
163
|
+
|
164
|
+
# Register an Actor locally as a named service
|
165
|
+
def register(name, actor)
|
166
|
+
raise ArgumentError, "name must be a symbol" unless Symbol === name
|
167
|
+
unless actor.nil? or actor.is_a?(Actor)
|
168
|
+
raise ArgumentError, "only actors may be registered"
|
169
|
+
end
|
170
|
+
|
171
|
+
@@registered_lock.receive
|
172
|
+
begin
|
173
|
+
if actor.nil?
|
174
|
+
@@registered.delete(name)
|
175
|
+
else
|
176
|
+
@@registered[name] = actor
|
177
|
+
end
|
178
|
+
ensure
|
179
|
+
@@registered_lock << nil
|
180
|
+
end
|
181
|
+
end
|
182
|
+
alias_method :[]=, :register
|
183
|
+
|
184
|
+
def _unregister(actor) #:nodoc:
|
185
|
+
@@registered_lock.receive
|
186
|
+
begin
|
187
|
+
@@registered.delete_if { |n, a| actor.equal? a }
|
188
|
+
ensure
|
189
|
+
@@registered_lock << nil
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
def initialize
|
195
|
+
@lock = Rubinius::Channel.new
|
196
|
+
|
197
|
+
@filter = nil
|
198
|
+
@ready = Rubinius::Channel.new
|
199
|
+
@action = nil
|
200
|
+
@message = nil
|
201
|
+
|
202
|
+
@mailbox = []
|
203
|
+
@interrupts = []
|
204
|
+
@links = []
|
205
|
+
@alive = true
|
206
|
+
@exit_reason = nil
|
207
|
+
@trap_exit = false
|
208
|
+
@thread = Thread.current
|
209
|
+
|
210
|
+
@lock << nil
|
211
|
+
|
212
|
+
if block_given?
|
213
|
+
watchdog { yield self }
|
214
|
+
else
|
215
|
+
Thread.new { watchdog { @thread.join } }
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
def send(message)
|
220
|
+
@lock.receive
|
221
|
+
begin
|
222
|
+
return self unless @alive
|
223
|
+
if @filter
|
224
|
+
@action = @filter.action_for(message)
|
225
|
+
if @action
|
226
|
+
@filter = nil
|
227
|
+
@message = message
|
228
|
+
@ready << nil
|
229
|
+
else
|
230
|
+
@mailbox << message
|
231
|
+
end
|
232
|
+
else
|
233
|
+
@mailbox << message
|
234
|
+
end
|
235
|
+
ensure
|
236
|
+
@lock << nil
|
237
|
+
end
|
238
|
+
self
|
239
|
+
end
|
240
|
+
alias_method :<<, :send
|
241
|
+
|
242
|
+
def _check_for_interrupt #:nodoc:
|
243
|
+
check_thread
|
244
|
+
@lock.receive
|
245
|
+
begin
|
246
|
+
raise @interrupts.shift unless @interrupts.empty?
|
247
|
+
ensure
|
248
|
+
@lock << nil
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
def _receive(filter) #:nodoc:
|
253
|
+
check_thread
|
254
|
+
|
255
|
+
action = nil
|
256
|
+
message = nil
|
257
|
+
timed_out = false
|
258
|
+
|
259
|
+
@lock.receive
|
260
|
+
begin
|
261
|
+
raise @interrupts.shift unless @interrupts.empty?
|
262
|
+
|
263
|
+
for i in 0...(@mailbox.size)
|
264
|
+
message = @mailbox[i]
|
265
|
+
action = filter.action_for(message)
|
266
|
+
if action
|
267
|
+
@mailbox.delete_at(i)
|
268
|
+
break
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
unless action
|
273
|
+
@filter = filter
|
274
|
+
@lock << nil
|
275
|
+
begin
|
276
|
+
if filter.timeout?
|
277
|
+
timed_out = @ready.receive_timeout(filter.timeout) == false
|
278
|
+
else
|
279
|
+
@ready.receive
|
280
|
+
end
|
281
|
+
ensure
|
282
|
+
@lock.receive
|
283
|
+
end
|
284
|
+
|
285
|
+
if !timed_out and @interrupts.empty?
|
286
|
+
action = @action
|
287
|
+
message = @message
|
288
|
+
else
|
289
|
+
@mailbox << @message if @action
|
290
|
+
end
|
291
|
+
|
292
|
+
@action = nil
|
293
|
+
@message = nil
|
294
|
+
|
295
|
+
raise @interrupts.shift unless @interrupts.empty?
|
296
|
+
end
|
297
|
+
ensure
|
298
|
+
@lock << nil
|
299
|
+
end
|
300
|
+
|
301
|
+
if timed_out
|
302
|
+
filter.timeout_action.call
|
303
|
+
else
|
304
|
+
action.call message
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
# Notify this actor that it's now linked to the given one; this is not
|
309
|
+
# intended to be used directly except by actor implementations. Most
|
310
|
+
# users will want to use Actor.link instead.
|
311
|
+
#
|
312
|
+
def notify_link(actor)
|
313
|
+
@lock.receive
|
314
|
+
alive = nil
|
315
|
+
exit_reason = nil
|
316
|
+
begin
|
317
|
+
alive = @alive
|
318
|
+
exit_reason = @exit_reason
|
319
|
+
@links << actor if alive and not @links.include? actor
|
320
|
+
ensure
|
321
|
+
@lock << nil
|
322
|
+
end
|
323
|
+
actor.notify_exited(self, exit_reason) unless alive
|
324
|
+
self
|
325
|
+
end
|
326
|
+
|
327
|
+
# Notify this actor that it's now unlinked from the given one; this is
|
328
|
+
# not intended to be used directly except by actor implementations. Most
|
329
|
+
# users will want to use Actor.unlink instead.
|
330
|
+
#
|
331
|
+
def notify_unlink(actor)
|
332
|
+
@lock.receive
|
333
|
+
begin
|
334
|
+
return self unless @alive
|
335
|
+
@links.delete(actor)
|
336
|
+
ensure
|
337
|
+
@lock << nil
|
338
|
+
end
|
339
|
+
self
|
340
|
+
end
|
341
|
+
|
342
|
+
# Notify this actor that one of the Actors it's linked to has exited;
|
343
|
+
# this is not intended to be used directly except by actor implementations.
|
344
|
+
# Most users will want to use Actor.send_exit instead.
|
345
|
+
#
|
346
|
+
def notify_exited(actor, reason)
|
347
|
+
to_send = nil
|
348
|
+
@lock.receive
|
349
|
+
begin
|
350
|
+
return self unless @alive
|
351
|
+
@links.delete(actor)
|
352
|
+
ex = DeadActorError.new(actor, reason)
|
353
|
+
if @trap_exit
|
354
|
+
to_send = ex
|
355
|
+
elsif reason
|
356
|
+
@interrupts << ex
|
357
|
+
if @filter
|
358
|
+
@filter = nil
|
359
|
+
@ready << nil
|
360
|
+
end
|
361
|
+
end
|
362
|
+
ensure
|
363
|
+
@lock << nil
|
364
|
+
end
|
365
|
+
send to_send if to_send
|
366
|
+
self
|
367
|
+
end
|
368
|
+
|
369
|
+
def watchdog
|
370
|
+
reason = nil
|
371
|
+
begin
|
372
|
+
yield
|
373
|
+
rescue Exception => reason
|
374
|
+
ensure
|
375
|
+
links = nil
|
376
|
+
Actor._unregister(self)
|
377
|
+
@lock.receive
|
378
|
+
begin
|
379
|
+
@alive = false
|
380
|
+
@mailbox = nil
|
381
|
+
@interrupts = nil
|
382
|
+
@exit_reason = reason
|
383
|
+
links = @links
|
384
|
+
@links = nil
|
385
|
+
ensure
|
386
|
+
@lock << nil
|
387
|
+
end
|
388
|
+
links.each do |actor|
|
389
|
+
begin
|
390
|
+
actor.notify_exited(self, reason)
|
391
|
+
rescue Exception
|
392
|
+
end
|
393
|
+
end
|
394
|
+
end
|
395
|
+
end
|
396
|
+
private :watchdog
|
397
|
+
|
398
|
+
def check_thread
|
399
|
+
unless Thread.current == @thread
|
400
|
+
raise ThreadError, "illegal cross-actor call"
|
401
|
+
end
|
402
|
+
end
|
403
|
+
private :check_thread
|
404
|
+
|
405
|
+
def _trap_exit=(value) #:nodoc:
|
406
|
+
check_thread
|
407
|
+
@lock.receive
|
408
|
+
begin
|
409
|
+
raise @interrupts.shift unless @interrupts.empty?
|
410
|
+
@trap_exit = !!value
|
411
|
+
ensure
|
412
|
+
@lock << nil
|
413
|
+
end
|
414
|
+
end
|
415
|
+
|
416
|
+
def _trap_exit #:nodoc:
|
417
|
+
check_thread
|
418
|
+
@lock.receive
|
419
|
+
begin
|
420
|
+
@trap_exit
|
421
|
+
ensure
|
422
|
+
@lock << nil
|
423
|
+
end
|
424
|
+
end
|
425
|
+
end
|
426
|
+
|
427
|
+
require 'rubinius/actor/filter'
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# actor/filter.rb - actor message filters
|
2
|
+
#
|
3
|
+
# Copyright 2007-2008 MenTaLguY <mental@rydia.net>
|
4
|
+
# 2007-2011 Evan Phoenix <evan@fallingsnow.net>
|
5
|
+
#
|
6
|
+
# All rights reserved.
|
7
|
+
#
|
8
|
+
# Redistribution and use in source and binary forms, with or without
|
9
|
+
# modification, are permitted provided that the following conditions are met:
|
10
|
+
#
|
11
|
+
# * Redistributions of source code must retain the above copyright notice,
|
12
|
+
# thi slist of conditions and the following disclaimer.
|
13
|
+
# * Redistributions in binary form must reproduce the above copyright notice
|
14
|
+
# this list of conditions and the following disclaimer in the documentatio
|
15
|
+
# and/or other materials provided with the distribution.
|
16
|
+
# * Neither the name of the Evan Phoenix nor the names of its contributors
|
17
|
+
# may be used to endorse or promote products derived from this software
|
18
|
+
# without specific prior written permission.
|
19
|
+
#
|
20
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
21
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
22
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
23
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
24
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
25
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
26
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
27
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
28
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
29
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
30
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
31
|
+
|
32
|
+
class Rubinius::Actor
|
33
|
+
class Filter
|
34
|
+
attr_reader :timeout
|
35
|
+
attr_reader :timeout_action
|
36
|
+
|
37
|
+
def initialize
|
38
|
+
@pairs = []
|
39
|
+
@timeout = nil
|
40
|
+
@timeout_action = nil
|
41
|
+
end
|
42
|
+
|
43
|
+
def timeout?
|
44
|
+
not @timeout.nil?
|
45
|
+
end
|
46
|
+
|
47
|
+
def when(pattern, &action)
|
48
|
+
raise ArgumentError, "no block given" unless action
|
49
|
+
@pairs.push [pattern, action]
|
50
|
+
self
|
51
|
+
end
|
52
|
+
|
53
|
+
def after(seconds, &action)
|
54
|
+
raise ArgumentError, "no block given" unless action
|
55
|
+
|
56
|
+
seconds = seconds.to_f
|
57
|
+
if !@timeout or seconds < @timeout
|
58
|
+
@timeout = seconds
|
59
|
+
@timeout_action = action
|
60
|
+
end
|
61
|
+
self
|
62
|
+
end
|
63
|
+
|
64
|
+
def action_for(value)
|
65
|
+
pair = @pairs.find { |pattern, action| pattern === value }
|
66
|
+
pair ? pair.last : nil
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{rubinius-actor}
|
5
|
+
s.version = "0.0.1"
|
6
|
+
s.authors = ["Evan Phoenix", "MenTaLguY"]
|
7
|
+
s.date = Time.now
|
8
|
+
s.description = "Rubinius's Actor implementation"
|
9
|
+
s.email = ["evan@fallingsnow.net", "mental@rydia.net"]
|
10
|
+
s.files = Dir['{lib}/**/*'] + Dir['{*.txt,*.gemspec,Rakefile}']
|
11
|
+
s.homepage = "http://github.com/rubinius/rubinius-actor"
|
12
|
+
s.require_paths = ["lib"]
|
13
|
+
s.summary = "Rubinius's Actor implementation"
|
14
|
+
s.add_dependency 'rubinius-core-api'
|
15
|
+
end
|
metadata
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rubinius-actor
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Evan Phoenix
|
14
|
+
- MenTaLguY
|
15
|
+
autorequire:
|
16
|
+
bindir: bin
|
17
|
+
cert_chain: []
|
18
|
+
|
19
|
+
date: 2011-06-16 00:00:00 Z
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: rubinius-core-api
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
35
|
+
description: Rubinius's Actor implementation
|
36
|
+
email:
|
37
|
+
- evan@fallingsnow.net
|
38
|
+
- mental@rydia.net
|
39
|
+
executables: []
|
40
|
+
|
41
|
+
extensions: []
|
42
|
+
|
43
|
+
extra_rdoc_files: []
|
44
|
+
|
45
|
+
files:
|
46
|
+
- lib/rubinius/actor/filter.rb
|
47
|
+
- lib/rubinius/actor.rb
|
48
|
+
- README.txt
|
49
|
+
- rubinius-actor.gemspec
|
50
|
+
homepage: http://github.com/rubinius/rubinius-actor
|
51
|
+
licenses: []
|
52
|
+
|
53
|
+
post_install_message:
|
54
|
+
rdoc_options: []
|
55
|
+
|
56
|
+
require_paths:
|
57
|
+
- lib
|
58
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
59
|
+
none: false
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
hash: 3
|
64
|
+
segments:
|
65
|
+
- 0
|
66
|
+
version: "0"
|
67
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
68
|
+
none: false
|
69
|
+
requirements:
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
hash: 3
|
73
|
+
segments:
|
74
|
+
- 0
|
75
|
+
version: "0"
|
76
|
+
requirements: []
|
77
|
+
|
78
|
+
rubyforge_project:
|
79
|
+
rubygems_version: 1.8.5
|
80
|
+
signing_key:
|
81
|
+
specification_version: 3
|
82
|
+
summary: Rubinius's Actor implementation
|
83
|
+
test_files: []
|
84
|
+
|