eventbox 0.1.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/.appveyor.yml +5 -3
- data/.travis.yml +4 -4
- data/.yardopts +2 -2
- data/CHANGELOG.md +19 -0
- data/README.md +91 -48
- data/docs/downloads.md +6 -5
- data/docs/images/my_queue_calls.svg +761 -0
- data/docs/my_queue_calls_github.md +1 -0
- data/docs/my_queue_calls_local.md +1 -0
- data/docs/server.md +25 -14
- data/docs/threadpool.md +4 -1
- data/eventbox.gemspec +3 -2
- data/lib/eventbox.rb +63 -11
- data/lib/eventbox/argument_wrapper.rb +11 -10
- data/lib/eventbox/boxable.rb +41 -33
- data/lib/eventbox/call_context.rb +47 -0
- data/lib/eventbox/event_loop.rb +167 -70
- data/lib/eventbox/sanitizer.rb +155 -39
- data/lib/eventbox/thread_pool.rb +10 -0
- data/lib/eventbox/timer.rb +17 -7
- data/lib/eventbox/version.rb +1 -1
- metadata +50 -30
- metadata.gz.sig +0 -0
data/lib/eventbox/sanitizer.rb
CHANGED
@@ -18,18 +18,18 @@ class Eventbox
|
|
18
18
|
#
|
19
19
|
# In detail this works as following.
|
20
20
|
# Objects which are passed through unchanged are:
|
21
|
-
# * {Eventbox}, {Eventbox::Action} and
|
21
|
+
# * {Eventbox}, {Eventbox::Action} and +Module+ objects
|
22
22
|
# * Proc objects created by {Eventbox#async_proc}, {Eventbox#sync_proc} and {Eventbox#yield_proc}
|
23
23
|
#
|
24
24
|
# The following rules apply for wrapping/unwrapping:
|
25
|
-
# * If the object has been marked as {Eventbox#shared_object}, it is wrapped as {WrappedObject} depending on the direction of the data flow (return value or call argument).
|
25
|
+
# * If the object has been marked as {Eventbox#shared_object}, it is wrapped as {WrappedObject} or {ExternalObject} depending on the direction of the data flow (return value or call argument).
|
26
26
|
# * If the object is a {WrappedObject} or {ExternalProc} and fits to the target scope, it is unwrapped.
|
27
27
|
# Both cases even work if the object is encapsulated by another object.
|
28
28
|
#
|
29
29
|
# In all other cases the following rules apply:
|
30
|
-
# * If the object is marshalable, it is passed as a deep copy through
|
31
|
-
# * An object which failed to marshal as a whole is tried to be dissected and values are sanitized recursively.
|
32
|
-
# * If the object can't be marshaled or dissected, it is wrapped as {WrappedObject}.
|
30
|
+
# * If the object is marshalable, it is passed as a deep copy through +Marshal.dump+ and +Marshal.load+ .
|
31
|
+
# * An object which failed to marshal as a whole is tried to be dissected and values are sanitized separately and recursively.
|
32
|
+
# * If the object can't be marshaled or dissected, it is wrapped as {ExternalObject} when passed from external scope to event scope and wrapped as {WrappedObject} when passed from the event scope.
|
33
33
|
# They are unwrapped when passed back to origin scope.
|
34
34
|
# * Proc objects passed from event scope to external are wrapped as {WrappedObject}.
|
35
35
|
# They are unwrapped when passed back to event scope.
|
@@ -46,24 +46,25 @@ class Eventbox
|
|
46
46
|
# Separate the instance variables from the object
|
47
47
|
ivns = arg.instance_variables
|
48
48
|
ivvs = ivns.map do |ivn|
|
49
|
-
arg.instance_variable_get(ivn)
|
50
|
-
|
51
|
-
|
52
|
-
# Temporary set all instance variables to nil
|
53
|
-
ivns.each do |ivn|
|
49
|
+
ivv = arg.instance_variable_get(ivn)
|
50
|
+
# Temporary set all instance variables to nil
|
54
51
|
arg.instance_variable_set(ivn, nil)
|
52
|
+
ivv
|
55
53
|
end
|
56
54
|
|
57
55
|
# Copy the object
|
58
56
|
arg2 = yield(arg)
|
59
|
-
|
60
|
-
# Restore the original object
|
57
|
+
rescue
|
58
|
+
# Restore the original object in case of Marshal.dump failure
|
61
59
|
ivns.each_with_index do |ivn, ivni|
|
62
60
|
arg.instance_variable_set(ivn, ivvs[ivni])
|
63
61
|
end
|
64
|
-
|
65
|
-
|
62
|
+
raise
|
63
|
+
else
|
66
64
|
ivns.each_with_index do |ivn, ivni|
|
65
|
+
# Restore the original object
|
66
|
+
arg.instance_variable_set(ivn, ivvs[ivni])
|
67
|
+
# sanitize instance variables independently and write them to the copied object
|
67
68
|
ivv = sanitize_value(ivvs[ivni], source_event_loop, target_event_loop, ivn)
|
68
69
|
arg2.instance_variable_set(ivn, ivv)
|
69
70
|
end
|
@@ -81,12 +82,15 @@ class Eventbox
|
|
81
82
|
end
|
82
83
|
|
83
84
|
arg2 = yield(arg)
|
84
|
-
|
85
|
+
rescue
|
86
|
+
# Restore the original object in case of Marshal.dump failure
|
85
87
|
ms.each_with_index do |m, i|
|
86
88
|
arg[m] = vs[i]
|
87
89
|
end
|
88
|
-
|
90
|
+
raise
|
91
|
+
else
|
89
92
|
ms.each_with_index do |m, i|
|
93
|
+
arg[m] = vs[i]
|
90
94
|
v2 = sanitize_value(vs[i], source_event_loop, target_event_loop, m)
|
91
95
|
arg2[m] = v2
|
92
96
|
end
|
@@ -102,12 +106,15 @@ class Eventbox
|
|
102
106
|
end
|
103
107
|
|
104
108
|
arg2 = yield(arg)
|
105
|
-
|
109
|
+
rescue
|
110
|
+
# Restore the original object in case of Marshal.dump failure
|
106
111
|
h.each do |k, v|
|
107
112
|
arg[k] = v
|
108
113
|
end
|
109
|
-
|
114
|
+
raise
|
115
|
+
else
|
110
116
|
h.each do |k, v|
|
117
|
+
arg[k] = v
|
111
118
|
arg2[k] = sanitize_value(v, source_event_loop, target_event_loop, k)
|
112
119
|
end
|
113
120
|
|
@@ -122,12 +129,15 @@ class Eventbox
|
|
122
129
|
end
|
123
130
|
|
124
131
|
arg2 = yield(arg)
|
125
|
-
|
126
|
-
|
132
|
+
rescue
|
133
|
+
# Restore the original object in case of Marshal.dump failure
|
134
|
+
vs.each_with_index do |v, i|
|
127
135
|
arg[i] = vs[i]
|
128
136
|
end
|
129
|
-
|
137
|
+
raise
|
138
|
+
else
|
130
139
|
vs.each_with_index do |v, i|
|
140
|
+
arg[i] = vs[i]
|
131
141
|
v2 = sanitize_value(v, source_event_loop, target_event_loop, name)
|
132
142
|
arg2[i] = v2
|
133
143
|
end
|
@@ -158,9 +168,9 @@ class Eventbox
|
|
158
168
|
unless mel == source_event_loop
|
159
169
|
raise InvalidAccess, "object #{arg.inspect} #{"wrapped by #{name} " if name} was marked as shared_object in a different eventbox object than the calling eventbox"
|
160
170
|
end
|
161
|
-
|
171
|
+
wrap_object(arg, mel, target_event_loop, name)
|
162
172
|
when ExternalSharedObject # External object marked as shared_object
|
163
|
-
|
173
|
+
wrap_object(arg, source_event_loop, target_event_loop, name)
|
164
174
|
else
|
165
175
|
# Not tagged -> try to deep copy the object
|
166
176
|
begin
|
@@ -219,16 +229,23 @@ class Eventbox
|
|
219
229
|
args.map { |arg| sanitize_value(arg, source_event_loop, target_event_loop, name) }
|
220
230
|
end
|
221
231
|
|
232
|
+
def sanitize_kwargs(args, source_event_loop, target_event_loop, name=nil)
|
233
|
+
args.transform_values { |arg| sanitize_value(arg, source_event_loop, target_event_loop, name) }
|
234
|
+
end
|
235
|
+
|
222
236
|
def wrap_proc(arg, name, source_event_loop, target_event_loop)
|
223
237
|
if target_event_loop&.event_scope?
|
224
|
-
ExternalProc.new(arg, source_event_loop, name) do |*args, &block|
|
238
|
+
ExternalProc.new(arg, source_event_loop, name) do |*args, **kwargs, &block|
|
225
239
|
if target_event_loop&.event_scope?
|
226
240
|
# called in the event scope
|
241
|
+
|
227
242
|
if block && !(WrappedProc === block)
|
228
243
|
raise InvalidAccess, "calling #{arg.inspect} with block argument #{block.inspect} is not allowed - use async_proc, sync_proc, yield_proc or an external proc instead"
|
229
244
|
end
|
230
|
-
|
231
|
-
|
245
|
+
|
246
|
+
call_context = args.shift if CallContext === args.first
|
247
|
+
cbblock = args.pop if Proc === args.last
|
248
|
+
target_event_loop._external_object_call(arg, :call, name, args, kwargs, block, cbblock, source_event_loop, call_context)
|
232
249
|
else
|
233
250
|
# called externally
|
234
251
|
raise InvalidAccess, "external proc #{arg.inspect} #{"wrapped by #{name} " if name} can not be called in a different eventbox instance"
|
@@ -238,6 +255,14 @@ class Eventbox
|
|
238
255
|
WrappedObject.new(arg, source_event_loop, name)
|
239
256
|
end
|
240
257
|
end
|
258
|
+
|
259
|
+
def wrap_object(object, source_event_loop, target_event_loop, name)
|
260
|
+
if target_event_loop&.event_scope?
|
261
|
+
ExternalObject.new(object, source_event_loop, target_event_loop, name)
|
262
|
+
else
|
263
|
+
WrappedObject.new(object, source_event_loop, name)
|
264
|
+
end
|
265
|
+
end
|
241
266
|
end
|
242
267
|
|
243
268
|
# Generic wrapper for objects that are passed through a foreign scope as reference.
|
@@ -245,19 +270,87 @@ class Eventbox
|
|
245
270
|
# Access to the object from a different scope is denied, but the wrapper object can be stored and passed back to the origin scope to unwrap it.
|
246
271
|
class WrappedObject
|
247
272
|
attr_reader :name
|
273
|
+
# @private
|
248
274
|
def initialize(object, event_loop, name=nil)
|
249
|
-
@object = object
|
250
|
-
@event_loop = event_loop
|
251
|
-
@name = name
|
275
|
+
@object = object # the object to be wrapped
|
276
|
+
@event_loop = event_loop # the event_loop @object originates from, nil if external scope
|
277
|
+
@name = name # some information to get more meaningful error messages
|
252
278
|
@dont_marshal = ExternalSharedObject # protect self from being marshaled
|
253
279
|
end
|
254
280
|
|
281
|
+
# @private
|
255
282
|
def object_for(target_event_loop)
|
256
283
|
@event_loop == target_event_loop ? @object : self
|
257
284
|
end
|
258
285
|
|
259
286
|
def inspect
|
260
|
-
|
287
|
+
el = case @event_loop
|
288
|
+
when EventLoop then @event_loop.object_id.to_s(16)
|
289
|
+
else @event_loop.inspect
|
290
|
+
end
|
291
|
+
"#<#{self.class} @object=#{@object.inspect} @name=#{@name.inspect} @event_loop=#{el}>"
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
# Wrapper for objects created external or in the action scope of some Eventbox instance.
|
296
|
+
#
|
297
|
+
# External objects can be called from event scope by {ExternalObject#send}.
|
298
|
+
#
|
299
|
+
# External objects can also be passed to action or to external scope.
|
300
|
+
# In this case a {ExternalObject} is unwrapped back to the ordinary object.
|
301
|
+
#
|
302
|
+
# @see ExternalProc
|
303
|
+
class ExternalObject < WrappedObject
|
304
|
+
# @private
|
305
|
+
def initialize(object, event_loop, target_event_loop, name=nil)
|
306
|
+
super(object, event_loop, name)
|
307
|
+
@target_event_loop = target_event_loop
|
308
|
+
end
|
309
|
+
|
310
|
+
# Invoke the external objects within the event scope.
|
311
|
+
#
|
312
|
+
# It can be called within {Eventbox::Boxable#sync_call sync_call} and {Eventbox::Boxable#yield_call yield_call} methods and from {Eventbox#sync_proc} and {Eventbox#yield_proc} closures.
|
313
|
+
# The method then runs in the background on the thread that called the event scope method in execution.
|
314
|
+
#
|
315
|
+
# It's also possible to invoke the external object with an explicit {Eventbox::CallContext} instead of the implicit call context of a sync or yield call.
|
316
|
+
# The explicit {Eventbox::CallContext} must be given as the very first parameter and it is not passed to the object call.
|
317
|
+
# The object call is then done in the given context of an arbitrary event scope method or closure that didn't return yet.
|
318
|
+
# In this case the method runs in the background on the thread that is waiting for the call to return.
|
319
|
+
#
|
320
|
+
# If the call to the external object doesn't return immediately, it blocks the calling thread or the thread of the {Eventbox::CallContext}.
|
321
|
+
# If this is not desired, an {Eventbox::Boxable#action action} can be used instead, to invoke the method of the object on a dedicated thread.
|
322
|
+
# However in any case calling the external object doesn't block the Eventbox instance itself.
|
323
|
+
# It still keeps responsive to calls from other threads.
|
324
|
+
#
|
325
|
+
# Optionally a proc can be provided as the last argument which acts as a completion callback.
|
326
|
+
# This proc is invoked, when the call has finished, with the result value as argument.
|
327
|
+
#
|
328
|
+
# class Sender < Eventbox
|
329
|
+
# sync_call def init(€obj) # €-variables are passed as reference instead of copy
|
330
|
+
# # invoke the object given to Sender.new
|
331
|
+
# # and when completed, print the result of strip
|
332
|
+
# €obj.send :strip, ->(res){ p res }
|
333
|
+
# end
|
334
|
+
# end
|
335
|
+
# Sender.new(" a b c ") # Output: "a b c"
|
336
|
+
def send(method, *args, **kwargs, &block)
|
337
|
+
if @target_event_loop&.event_scope?
|
338
|
+
# called in the event scope
|
339
|
+
if CallContext === method
|
340
|
+
call_context = method
|
341
|
+
method = args.shift
|
342
|
+
end
|
343
|
+
|
344
|
+
if block && !(WrappedProc === block)
|
345
|
+
raise InvalidAccess, "calling `#{method}' with block argument #{block.inspect} is not allowed - use async_proc, sync_proc, yield_proc or an external proc instead"
|
346
|
+
end
|
347
|
+
|
348
|
+
cbblock = args.pop if Proc === args.last
|
349
|
+
@target_event_loop._external_object_call(@object, method, @name, args, kwargs, block, cbblock, @event_loop, call_context)
|
350
|
+
else
|
351
|
+
# called externally
|
352
|
+
raise InvalidAccess, "external object #{self.inspect} #{"wrapped by #{name} " if name} can not be called in a different eventbox instance"
|
353
|
+
end
|
261
354
|
end
|
262
355
|
end
|
263
356
|
|
@@ -283,9 +376,21 @@ class Eventbox
|
|
283
376
|
|
284
377
|
WrappedException = Struct.new(:exc)
|
285
378
|
|
286
|
-
# Proc object provided as the last argument of {Eventbox
|
379
|
+
# Proc object provided as the last argument of {Eventbox::Boxable#yield_call yield_call} and {Eventbox#yield_proc}.
|
380
|
+
#
|
381
|
+
# Used to let the corresponding yield call return a value:
|
382
|
+
# class MyBox < Eventbox
|
383
|
+
# yield_call def number(result)
|
384
|
+
# result.yield 42
|
385
|
+
# end
|
386
|
+
# end
|
387
|
+
# MyBox.new.number # => 42
|
388
|
+
#
|
389
|
+
# Alternatively the yield call can respond with an exception by {CompletionProc#raise}.
|
287
390
|
class CompletionProc < AsyncProc
|
288
|
-
|
391
|
+
include CallContext
|
392
|
+
|
393
|
+
# Raise an exception in the context of the waiting {Eventbox::Boxable#yield_call yield_call} or {Eventbox#yield_proc} method.
|
289
394
|
#
|
290
395
|
# This allows to raise an exception to the calling scope from external or action scope:
|
291
396
|
#
|
@@ -300,38 +405,49 @@ class Eventbox
|
|
300
405
|
# end
|
301
406
|
# MyBox.new # => raises RuntimeError (raise from action MyBox#process)
|
302
407
|
#
|
303
|
-
# In contrast to a direct call of
|
408
|
+
# In contrast to a direct call of +Kernel.raise+, calling this method doesn't abort the current context.
|
304
409
|
# Instead when in the event scope, raising the exception is deferred until returning to the calling external or action scope.
|
305
410
|
def raise(*args)
|
306
411
|
self.call(WrappedException.new(args))
|
307
412
|
end
|
308
413
|
end
|
309
414
|
|
310
|
-
# Wrapper for Proc objects created external of some Eventbox instance.
|
415
|
+
# Wrapper for Proc objects created external or in the action scope of some Eventbox instance.
|
416
|
+
#
|
417
|
+
# External Proc objects can be invoked from event scope by {ExternalProc#call}.
|
418
|
+
# It can be called within {Eventbox::Boxable#sync_call sync_call} and {Eventbox::Boxable#yield_call yield_call} methods and from {Eventbox#sync_proc} and {Eventbox#yield_proc} closures.
|
419
|
+
# The proc then runs in the background on the thread that called the event scope method in execution.
|
420
|
+
#
|
421
|
+
# It's also possible to invoke it within a {Eventbox::Boxable#async_call async_call} or {Eventbox#async_proc}, when the method or proc that brought the external proc into the event scope, is a yield call that didn't return yet.
|
422
|
+
# In this case the proc runs in the background on the thread that is waiting for the yield call to return.
|
311
423
|
#
|
312
|
-
# External Proc objects can be invoked from event scope through {Eventbox.sync_call} and {Eventbox.yield_call} methods.
|
313
424
|
# Optionally a proc can be provided as the last argument which acts as a completion callback.
|
314
425
|
# This proc is invoked, when the call has finished, with the result value as argument.
|
315
426
|
#
|
316
427
|
# class Callback < Eventbox
|
317
428
|
# sync_call def init(&block)
|
318
|
-
#
|
319
|
-
#
|
320
|
-
#
|
429
|
+
# # invoke the block given to Callback.new
|
430
|
+
# # and when completed, print the result of the block
|
431
|
+
# block.call 5, ->(res){ p res }
|
321
432
|
# end
|
322
433
|
# end
|
323
434
|
# Callback.new {|num| num + 1 } # Output: 6
|
324
435
|
#
|
325
436
|
# External Proc objects can also be passed to action or to external scope.
|
326
|
-
# In this case a {ExternalProc} is unwrapped back to
|
437
|
+
# In this case a {ExternalProc} is unwrapped back to the ordinary Proc object.
|
438
|
+
#
|
439
|
+
# @see ExternalObject
|
327
440
|
class ExternalProc < WrappedProc
|
441
|
+
# @private
|
328
442
|
attr_reader :name
|
443
|
+
# @private
|
329
444
|
def initialize(object, event_loop, name=nil)
|
330
445
|
@object = object
|
331
446
|
@event_loop = event_loop
|
332
447
|
@name = name
|
333
448
|
end
|
334
449
|
|
450
|
+
# @private
|
335
451
|
def object_for(target_event_loop)
|
336
452
|
@event_loop == target_event_loop ? @object : self
|
337
453
|
end
|
data/lib/eventbox/thread_pool.rb
CHANGED
@@ -68,6 +68,10 @@ class Eventbox
|
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
71
|
+
async_call def terminate
|
72
|
+
@action.abort
|
73
|
+
end
|
74
|
+
|
71
75
|
# @private
|
72
76
|
async_call def __start__(action, input)
|
73
77
|
# Send the block to the start_pool_thread as result of next_job
|
@@ -120,6 +124,8 @@ class Eventbox
|
|
120
124
|
Thread.handle_interrupt(Exception => :immediate) do
|
121
125
|
sleep # Aborted by the exception
|
122
126
|
end
|
127
|
+
rescue Eventbox::AbortAction
|
128
|
+
raise # The thread-pool was requested to shutdown
|
123
129
|
rescue Exception
|
124
130
|
end
|
125
131
|
end
|
@@ -166,5 +172,9 @@ class Eventbox
|
|
166
172
|
private async_call def gc_finished
|
167
173
|
@run_gc_when_busy = true
|
168
174
|
end
|
175
|
+
|
176
|
+
def inspect
|
177
|
+
"#<#{self.class}:#{self.object_id} @requests=#{@requests.length} @jobless=#{@jobless.length} @run_gc_when_busy=#{@run_gc_when_busy.inspect}>"
|
178
|
+
end
|
169
179
|
end
|
170
180
|
end
|
data/lib/eventbox/timer.rb
CHANGED
@@ -9,28 +9,36 @@ class Eventbox
|
|
9
9
|
# include Eventbox::Timer
|
10
10
|
#
|
11
11
|
# async_call def init
|
12
|
-
# super
|
12
|
+
# super # Make sure Timer#init is called
|
13
13
|
# timer_after(1) do
|
14
14
|
# puts "one second elapsed"
|
15
15
|
# end
|
16
16
|
# end
|
17
17
|
# end
|
18
18
|
#
|
19
|
+
# MyBox.new # Schedule the alarm after 1 sec
|
20
|
+
# sleep 2 # Wait for the timer to be triggered
|
21
|
+
#
|
19
22
|
# The main functions are timer_after and timer_every.
|
20
23
|
# They schedule asynchronous calls to the given block:
|
21
|
-
# timer_after(3) do
|
24
|
+
# timer_after(3.0) do
|
22
25
|
# # executed once after 3 seconds
|
23
26
|
# end
|
24
27
|
#
|
25
|
-
# timer_every(
|
26
|
-
# # executed repeatedly every
|
28
|
+
# timer_every(1.5) do
|
29
|
+
# # executed repeatedly every 1.5 seconds
|
27
30
|
# end
|
28
31
|
#
|
29
|
-
# Both functions return an Alarm object which can be used to cancel the alarm through timer_cancel.
|
32
|
+
# Both functions return an {Alarm} object which can be used to cancel the alarm through {timer_cancel}.
|
30
33
|
#
|
31
|
-
#
|
34
|
+
# {Timer} always uses one {Eventbox::Boxable#action action} thread per Eventbox object, regardless of the number of scheduled timers.
|
35
|
+
# All alarms are called from this thread.
|
36
|
+
# {timer_after}, {timer_every} and {timer_cancel} can be used within the {file:README.md#event-scope event scope}, in actions and from external scope.
|
37
|
+
# Alarms defined within the event scope must be non-blocking, as any other code in the event scope.
|
38
|
+
# Alarms defined in action or external scope should also avoid blocking code, otherwise one alarm can delay the next alarm.
|
32
39
|
#
|
33
|
-
#
|
40
|
+
# *Note:* Each object that includes the {Timer} module must be explicit terminated by {Eventbox#shutdown!}.
|
41
|
+
# It is (currently) not freed by the garbarge collector.
|
34
42
|
module Timer
|
35
43
|
class Reload < RuntimeError
|
36
44
|
end
|
@@ -124,6 +132,8 @@ class Eventbox
|
|
124
132
|
end
|
125
133
|
|
126
134
|
# Cancel an alarm previously scheduled per timer_after or timer_every
|
135
|
+
#
|
136
|
+
# The method does nothing, if the alarm is no longer active.
|
127
137
|
async_call def timer_cancel(alarm)
|
128
138
|
a = @timer_alarms.delete(alarm)
|
129
139
|
if a
|
data/lib/eventbox/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: eventbox
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lars Kanis
|
@@ -10,26 +10,26 @@ bindir: exe
|
|
10
10
|
cert_chain:
|
11
11
|
- |
|
12
12
|
-----BEGIN CERTIFICATE-----
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
13
|
+
MIIDLjCCAhagAwIBAgIBCTANBgkqhkiG9w0BAQsFADA9MQ4wDAYDVQQDDAVrYW5p
|
14
|
+
czEXMBUGCgmSJomT8ixkARkWB2NvbWNhcmQxEjAQBgoJkiaJk/IsZAEZFgJkZTAe
|
15
|
+
Fw0yMTA0MDcxMzQzNTZaFw0yMjA0MDcxMzQzNTZaMD0xDjAMBgNVBAMMBWthbmlz
|
16
|
+
MRcwFQYKCZImiZPyLGQBGRYHY29tY2FyZDESMBAGCgmSJomT8ixkARkWAmRlMIIB
|
17
|
+
IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApop+rNmg35bzRugZ21VMGqI6
|
18
|
+
HGzPLO4VHYncWn/xmgPU/ZMcZdfj6MzIaZJ/czXyt4eHpBk1r8QOV3gBXnRXEjVW
|
19
|
+
9xi+EdVOkTV2/AVFKThcbTAQGiF/bT1n2M+B1GTybRzMg6hyhOJeGPqIhLfJEpxn
|
20
|
+
lJi4+ENAVT4MpqHEAGB8yFoPC0GqiOHQsdHxQV3P3c2OZqG+yJey74QtwA2tLcLn
|
21
|
+
Q53c63+VLGsOjODl1yPn/2ejyq8qWu6ahfTxiIlSar2UbwtaQGBDFdb2CXgEufXT
|
22
|
+
L7oaPxlmj+Q2oLOfOnInd2Oxop59HoJCQPsg8f921J43NCQGA8VHK6paxIRDLQID
|
23
|
+
AQABozkwNzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNVHQ4EFgQUvgTdT7fe
|
24
|
+
x17ugO3IOsjEJwW7KP4wDQYJKoZIhvcNAQELBQADggEBAGCQhS4TBqUG1bSY5gw5
|
25
|
+
emj2GNePHFNlXTZ/W0/7FlnXQz/LyBZeYmy4AIHcdY0w9xsu3bPNGk8kLBkHgK3Y
|
26
|
+
l/yWiUK0NYRI3K3yI2EoTfrHPDT8XIgBPeUUGv5Nje+SUYMQWsfYWKo3+vLEG64a
|
27
|
+
n1xP+1+g2Za39WCS5LwnDWMiIk47NnxR9yXErKd0Iau/Q/IarYsHFX6kWWmlMoln
|
28
|
+
W1lMomCcOJFwIPnsy6aqq7YfS0YcqyHjcvs1h5k3zPaIRWhoPlQivniMVMa3Txh+
|
29
|
+
NEF/4atY64rruzkyfxGEcrFFOHJIkWnWQjRGaiZdgULxf7ira2gEFvV/ZtamqJWF
|
30
|
+
c+I=
|
31
31
|
-----END CERTIFICATE-----
|
32
|
-
date:
|
32
|
+
date: 2021-07-07 00:00:00.000000000 Z
|
33
33
|
dependencies:
|
34
34
|
- !ruby/object:Gem::Dependency
|
35
35
|
name: bundler
|
@@ -57,14 +57,14 @@ dependencies:
|
|
57
57
|
requirements:
|
58
58
|
- - "~>"
|
59
59
|
- !ruby/object:Gem::Version
|
60
|
-
version: '
|
60
|
+
version: '13.0'
|
61
61
|
type: :development
|
62
62
|
prerelease: false
|
63
63
|
version_requirements: !ruby/object:Gem::Requirement
|
64
64
|
requirements:
|
65
65
|
- - "~>"
|
66
66
|
- !ruby/object:Gem::Version
|
67
|
-
version: '
|
67
|
+
version: '13.0'
|
68
68
|
- !ruby/object:Gem::Dependency
|
69
69
|
name: minitest
|
70
70
|
requirement: !ruby/object:Gem::Requirement
|
@@ -79,6 +79,20 @@ dependencies:
|
|
79
79
|
- - "~>"
|
80
80
|
- !ruby/object:Gem::Version
|
81
81
|
version: '5.0'
|
82
|
+
- !ruby/object:Gem::Dependency
|
83
|
+
name: minitest-hooks
|
84
|
+
requirement: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
89
|
+
type: :development
|
90
|
+
prerelease: false
|
91
|
+
version_requirements: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - ">="
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0'
|
82
96
|
- !ruby/object:Gem::Dependency
|
83
97
|
name: yard
|
84
98
|
requirement: !ruby/object:Gem::Requirement
|
@@ -94,10 +108,9 @@ dependencies:
|
|
94
108
|
- !ruby/object:Gem::Version
|
95
109
|
version: '0.9'
|
96
110
|
description: |-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
This is similar to the typical JavaScript programming style.
|
111
|
+
Eventbox is a model of concurrent computation that is used to build thread-safe objects with arbitrary interfaces.
|
112
|
+
It is [kind of advancement](#comparison-threading-abstractions) of the well known [actor model](https://en.wikipedia.org/wiki/Actor_model) leveraging the possibilities of the ruby language.
|
113
|
+
It is a small, consistent but powerful threading abstraction which **integrates well into existing environments**.
|
101
114
|
email:
|
102
115
|
- lars@greiz-reinsdorf.de
|
103
116
|
executables: []
|
@@ -108,6 +121,7 @@ files:
|
|
108
121
|
- ".gitignore"
|
109
122
|
- ".travis.yml"
|
110
123
|
- ".yardopts"
|
124
|
+
- CHANGELOG.md
|
111
125
|
- CODE_OF_CONDUCT.md
|
112
126
|
- Gemfile
|
113
127
|
- LICENSE.txt
|
@@ -116,12 +130,16 @@ files:
|
|
116
130
|
- bin/console
|
117
131
|
- bin/setup
|
118
132
|
- docs/downloads.md
|
133
|
+
- docs/images/my_queue_calls.svg
|
134
|
+
- docs/my_queue_calls_github.md
|
135
|
+
- docs/my_queue_calls_local.md
|
119
136
|
- docs/server.md
|
120
137
|
- docs/threadpool.md
|
121
138
|
- eventbox.gemspec
|
122
139
|
- lib/eventbox.rb
|
123
140
|
- lib/eventbox/argument_wrapper.rb
|
124
141
|
- lib/eventbox/boxable.rb
|
142
|
+
- lib/eventbox/call_context.rb
|
125
143
|
- lib/eventbox/event_loop.rb
|
126
144
|
- lib/eventbox/object_registry.rb
|
127
145
|
- lib/eventbox/sanitizer.rb
|
@@ -139,17 +157,19 @@ require_paths:
|
|
139
157
|
- lib
|
140
158
|
required_ruby_version: !ruby/object:Gem::Requirement
|
141
159
|
requirements:
|
142
|
-
- - "
|
160
|
+
- - ">="
|
161
|
+
- !ruby/object:Gem::Version
|
162
|
+
version: '3.0'
|
163
|
+
- - "<"
|
143
164
|
- !ruby/object:Gem::Version
|
144
|
-
version: '
|
165
|
+
version: '4.0'
|
145
166
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
146
167
|
requirements:
|
147
168
|
- - ">="
|
148
169
|
- !ruby/object:Gem::Version
|
149
170
|
version: '0'
|
150
171
|
requirements: []
|
151
|
-
|
152
|
-
rubygems_version: 2.7.7
|
172
|
+
rubygems_version: 3.3.0.dev
|
153
173
|
signing_key:
|
154
174
|
specification_version: 4
|
155
175
|
summary: Manage multithreading with the safety of event based programming
|