eventbox 0.1.0 → 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.
- 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
|