async-bus 0.1.1 → 0.3.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/lib/async/bus/client.rb +74 -36
- data/lib/async/bus/controller.rb +58 -0
- data/lib/async/bus/protocol/connection.rb +254 -81
- data/lib/async/bus/protocol/invoke.rb +78 -0
- data/lib/async/bus/protocol/proxy.rb +44 -41
- data/lib/async/bus/protocol/release.rb +37 -0
- data/lib/async/bus/protocol/response.rb +51 -0
- data/lib/async/bus/protocol/transaction.rb +93 -63
- data/lib/async/bus/protocol/wrapper.rb +145 -35
- data/lib/async/bus/server.rb +27 -31
- data/lib/async/bus/version.rb +5 -20
- data/lib/async/bus.rb +3 -19
- data/license.md +21 -0
- data/readme.md +53 -0
- data/releases.md +12 -0
- data.tar.gz.sig +1 -0
- metadata +49 -16
- metadata.gz.sig +0 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Released under the MIT License.
|
|
4
|
+
# Copyright, 2025, by Samuel Williams.
|
|
5
|
+
|
|
6
|
+
require "msgpack"
|
|
7
|
+
require_relative "proxy"
|
|
8
|
+
|
|
9
|
+
module Async
|
|
10
|
+
module Bus
|
|
11
|
+
module Protocol
|
|
12
|
+
# Represents a method invocation.
|
|
13
|
+
class Invoke
|
|
14
|
+
# Initialize a new invocation message.
|
|
15
|
+
# @parameter id [Integer] The transaction ID.
|
|
16
|
+
# @parameter name [Symbol] The method name to invoke.
|
|
17
|
+
# @parameter arguments [Array] The positional arguments.
|
|
18
|
+
# @parameter options [Hash] The keyword arguments.
|
|
19
|
+
# @parameter block_given [Boolean] Whether a block was provided.
|
|
20
|
+
def initialize(id, name, arguments, options, block_given)
|
|
21
|
+
@id = id
|
|
22
|
+
@name = name
|
|
23
|
+
@arguments = arguments
|
|
24
|
+
@options = options
|
|
25
|
+
@block_given = block_given
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# @attribute [Integer] The transaction ID.
|
|
29
|
+
attr :id
|
|
30
|
+
|
|
31
|
+
# @attribute [Symbol] The method name.
|
|
32
|
+
attr :name
|
|
33
|
+
|
|
34
|
+
# @attribute [Array] The positional arguments.
|
|
35
|
+
attr :arguments
|
|
36
|
+
|
|
37
|
+
# @attribute [Hash] The keyword arguments.
|
|
38
|
+
attr :options
|
|
39
|
+
|
|
40
|
+
# @attribute [Boolean] Whether a block was provided.
|
|
41
|
+
attr :block_given
|
|
42
|
+
|
|
43
|
+
# Pack the invocation into a MessagePack packer.
|
|
44
|
+
# @parameter packer [MessagePack::Packer] The packer to write to.
|
|
45
|
+
def pack(packer)
|
|
46
|
+
packer.write(@id)
|
|
47
|
+
packer.write(@name)
|
|
48
|
+
|
|
49
|
+
packer.write(@arguments.size)
|
|
50
|
+
@arguments.each do |argument|
|
|
51
|
+
packer.write(argument)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
packer.write(@options.size)
|
|
55
|
+
@options.each do |key, value|
|
|
56
|
+
packer.write(key)
|
|
57
|
+
packer.write(value)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
packer.write(@block_given)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Unpack an invocation from a MessagePack unpacker.
|
|
64
|
+
# @parameter unpacker [MessagePack::Unpacker] The unpacker to read from.
|
|
65
|
+
# @returns [Invoke] A new invocation instance.
|
|
66
|
+
def self.unpack(unpacker)
|
|
67
|
+
id = unpacker.read
|
|
68
|
+
name = unpacker.read
|
|
69
|
+
arguments = Array.new(unpacker.read){unpacker.read}
|
|
70
|
+
options = Array.new(unpacker.read){[unpacker.read, unpacker.read]}.to_h
|
|
71
|
+
block_given = unpacker.read
|
|
72
|
+
|
|
73
|
+
return self.new(id, name, arguments, options, block_given)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -1,74 +1,77 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
# in the Software without restriction, including without limitation the rights
|
|
6
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
-
# copies of the Software, and to permit persons to whom the Software is
|
|
8
|
-
# furnished to do so, subject to the following conditions:
|
|
9
|
-
#
|
|
10
|
-
# The above copyright notice and this permission notice shall be included in
|
|
11
|
-
# all copies or substantial portions of the Software.
|
|
12
|
-
#
|
|
13
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
19
|
-
# THE SOFTWARE.
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Released under the MIT License.
|
|
4
|
+
# Copyright, 2021-2025, by Samuel Williams.
|
|
20
5
|
|
|
21
6
|
module Async
|
|
22
7
|
module Bus
|
|
23
8
|
module Protocol
|
|
9
|
+
# A proxy object that forwards method calls to a remote object.
|
|
10
|
+
#
|
|
11
|
+
# We must be extremely careful not to invoke any methods on the proxy object that would recursively call the proxy object.
|
|
24
12
|
class Proxy < BasicObject
|
|
13
|
+
# Create a new proxy object.
|
|
14
|
+
#
|
|
15
|
+
# @parameter connection [Connection] The connection to the remote object.
|
|
16
|
+
# @parameter name [Symbol] The name (address) of the remote object.
|
|
25
17
|
def initialize(connection, name)
|
|
26
18
|
@connection = connection
|
|
27
19
|
@name = name
|
|
28
20
|
end
|
|
29
21
|
|
|
22
|
+
# Get the connection to the remote object.
|
|
23
|
+
# @returns [Connection] The connection to the remote object.
|
|
24
|
+
def __connection__
|
|
25
|
+
@connection
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Get the name of the remote object.
|
|
29
|
+
# @returns [Symbol] The name of the remote object.
|
|
30
|
+
def __name__
|
|
31
|
+
@name
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Logical negation operator.
|
|
35
|
+
# @returns [Object] The result of the negation.
|
|
30
36
|
def !
|
|
31
37
|
@connection.invoke(@name, [:!])
|
|
32
38
|
end
|
|
33
39
|
|
|
40
|
+
# Equality operator.
|
|
41
|
+
# @parameter object [Object] The object to compare with.
|
|
42
|
+
# @returns [Boolean] True if equal.
|
|
34
43
|
def == object
|
|
35
44
|
@connection.invoke(@name, [:==, object])
|
|
36
45
|
end
|
|
37
46
|
|
|
47
|
+
# Inequality operator.
|
|
48
|
+
# @parameter object [Object] The object to compare with.
|
|
49
|
+
# @returns [Boolean] True if not equal.
|
|
38
50
|
def != object
|
|
39
51
|
@connection.invoke(@name, [:!=, object])
|
|
40
52
|
end
|
|
41
53
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
@connection.invoke(@name, [:methods, all]) | super
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def protected_methods(all = true)
|
|
51
|
-
@connection.invoke(@name, [:protected_methods, all]) | super
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def public_methods(all = true)
|
|
55
|
-
@connection.invoke(@name, [:public_methods, all]) | super
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
def inspect
|
|
59
|
-
"[Proxy (#{@name}) #{method_missing(:inspect)}]"
|
|
60
|
-
end
|
|
61
|
-
|
|
54
|
+
# Forward method calls to the remote object.
|
|
55
|
+
# @parameter arguments [Array] The method arguments.
|
|
56
|
+
# @parameter options [Hash] The keyword arguments.
|
|
57
|
+
# @yields {|*args| ...} Optional block to pass to the method.
|
|
58
|
+
# @returns [Object] The result of the method call.
|
|
62
59
|
def method_missing(*arguments, **options, &block)
|
|
63
60
|
@connection.invoke(@name, arguments, options, &block)
|
|
64
61
|
end
|
|
65
62
|
|
|
63
|
+
# Check if the remote object responds to a method.
|
|
64
|
+
# @parameter name [Symbol] The method name to check.
|
|
65
|
+
# @parameter include_all [Boolean] Whether to include private methods.
|
|
66
|
+
# @returns [Boolean] True if the method exists.
|
|
66
67
|
def respond_to?(name, include_all = false)
|
|
67
68
|
@connection.invoke(@name, [:respond_to?, name, include_all])
|
|
68
69
|
end
|
|
69
70
|
|
|
70
|
-
|
|
71
|
-
|
|
71
|
+
# Return a string representation of the proxy.
|
|
72
|
+
# @returns [String] A string describing the proxy.
|
|
73
|
+
def inspect
|
|
74
|
+
"#<proxy #{@name}>"
|
|
72
75
|
end
|
|
73
76
|
end
|
|
74
77
|
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Released under the MIT License.
|
|
4
|
+
# Copyright, 2025, by Samuel Williams.
|
|
5
|
+
|
|
6
|
+
module Async
|
|
7
|
+
module Bus
|
|
8
|
+
module Protocol
|
|
9
|
+
# Represents a named object that has been released (no longer available).
|
|
10
|
+
class Release
|
|
11
|
+
# Initialize a new release message.
|
|
12
|
+
# @parameter name [Symbol] The name of the released object.
|
|
13
|
+
def initialize(name)
|
|
14
|
+
@name = name
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# @attribute [Symbol] The name of the released object.
|
|
18
|
+
attr :name
|
|
19
|
+
|
|
20
|
+
# Pack the release into a MessagePack packer.
|
|
21
|
+
# @parameter packer [MessagePack::Packer] The packer to write to.
|
|
22
|
+
def pack(packer)
|
|
23
|
+
packer.write(@name)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Unpack a release from a MessagePack unpacker.
|
|
27
|
+
# @parameter unpacker [MessagePack::Unpacker] The unpacker to read from.
|
|
28
|
+
# @returns [Release] A new release instance.
|
|
29
|
+
def self.unpack(unpacker)
|
|
30
|
+
name = unpacker.read
|
|
31
|
+
|
|
32
|
+
return self.new(name)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Released under the MIT License.
|
|
4
|
+
# Copyright, 2025, by Samuel Williams.
|
|
5
|
+
|
|
6
|
+
module Async
|
|
7
|
+
module Bus
|
|
8
|
+
module Protocol
|
|
9
|
+
# Represents a response message from a remote procedure call.
|
|
10
|
+
class Response
|
|
11
|
+
# Initialize a new response message.
|
|
12
|
+
# @parameter id [Integer] The transaction ID.
|
|
13
|
+
# @parameter result [Object] The result value.
|
|
14
|
+
def initialize(id, result)
|
|
15
|
+
@id = id
|
|
16
|
+
@result = result
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# @attribute [Integer] The transaction ID.
|
|
20
|
+
attr :id
|
|
21
|
+
|
|
22
|
+
# @attribute [Object] The result value.
|
|
23
|
+
attr :result
|
|
24
|
+
|
|
25
|
+
# Pack the response into a MessagePack packer.
|
|
26
|
+
# @parameter packer [MessagePack::Packer] The packer to write to.
|
|
27
|
+
def pack(packer)
|
|
28
|
+
packer.write(@id)
|
|
29
|
+
packer.write(@result)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Unpack a response from a MessagePack unpacker.
|
|
33
|
+
# @parameter unpacker [MessagePack::Unpacker] The unpacker to read from.
|
|
34
|
+
# @returns [Response] A new response instance.
|
|
35
|
+
def self.unpack(unpacker)
|
|
36
|
+
id = unpacker.read
|
|
37
|
+
result = unpacker.read
|
|
38
|
+
|
|
39
|
+
return self.new(id, result)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
Return = Class.new(Response)
|
|
44
|
+
Yield = Class.new(Response)
|
|
45
|
+
Error = Class.new(Response)
|
|
46
|
+
Next = Class.new(Response)
|
|
47
|
+
Throw = Class.new(Response)
|
|
48
|
+
Close = Class.new(Response)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -1,121 +1,151 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
# of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
# in the Software without restriction, including without limitation the rights
|
|
8
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
# copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
# furnished to do so, subject to the following conditions:
|
|
11
|
-
#
|
|
12
|
-
# The above copyright notice and this permission notice shall be included in
|
|
13
|
-
# all copies or substantial portions of the Software.
|
|
14
|
-
#
|
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
-
# THE SOFTWARE.
|
|
3
|
+
# Released under the MIT License.
|
|
4
|
+
# Copyright, 2021-2025, by Samuel Williams.
|
|
22
5
|
|
|
23
|
-
require
|
|
6
|
+
require "async/queue"
|
|
24
7
|
|
|
25
8
|
module Async
|
|
26
9
|
module Bus
|
|
27
10
|
module Protocol
|
|
11
|
+
# Represents a transaction for a remote procedure call.
|
|
28
12
|
class Transaction
|
|
29
|
-
|
|
13
|
+
# Initialize a new transaction.
|
|
14
|
+
# @parameter connection [Connection] The connection for this transaction.
|
|
15
|
+
# @parameter id [Integer] The transaction ID.
|
|
16
|
+
# @parameter timeout [Float] The timeout for the transaction.
|
|
17
|
+
def initialize(connection, id, timeout: nil)
|
|
30
18
|
@connection = connection
|
|
31
19
|
@id = id
|
|
32
20
|
|
|
33
|
-
@
|
|
21
|
+
@timeout = timeout
|
|
22
|
+
|
|
23
|
+
@received = Thread::Queue.new
|
|
34
24
|
@accept = nil
|
|
35
25
|
end
|
|
36
26
|
|
|
27
|
+
# @attribute [Connection] The connection for this transaction.
|
|
28
|
+
attr :connection
|
|
29
|
+
|
|
30
|
+
# @attribute [Integer] The transaction ID.
|
|
37
31
|
attr :id
|
|
32
|
+
|
|
33
|
+
# @attribute [Float] The timeout for the transaction.
|
|
34
|
+
attr_accessor :timeout
|
|
35
|
+
|
|
36
|
+
# @attribute [Thread::Queue] The queue of received messages.
|
|
38
37
|
attr :received
|
|
39
38
|
|
|
39
|
+
# @attribute [Object] The accept handler.
|
|
40
|
+
attr :accept
|
|
41
|
+
|
|
42
|
+
# Read a message from the transaction queue.
|
|
43
|
+
# @returns [Object] The next message.
|
|
40
44
|
def read
|
|
41
45
|
if @received.empty?
|
|
42
|
-
@connection.
|
|
46
|
+
@connection.flush
|
|
43
47
|
end
|
|
44
48
|
|
|
45
|
-
@received.
|
|
49
|
+
@received.pop(timeout: @timeout)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Write a message to the connection.
|
|
53
|
+
# @parameter message [Object] The message to write.
|
|
54
|
+
# @raises [RuntimeError] If the transaction is closed.
|
|
55
|
+
def write(message)
|
|
56
|
+
if @connection
|
|
57
|
+
@connection.write(message)
|
|
58
|
+
else
|
|
59
|
+
raise RuntimeError, "Transaction is closed!"
|
|
60
|
+
end
|
|
46
61
|
end
|
|
47
62
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
63
|
+
# Push a message to the transaction's received queue.
|
|
64
|
+
# Silently ignores messages if the queue is already closed.
|
|
65
|
+
# @parameter message [Object] The message to push.
|
|
66
|
+
def push(message)
|
|
67
|
+
@received.push(message)
|
|
68
|
+
rescue ClosedQueueError
|
|
69
|
+
# Queue is closed (transaction already finished/closed) - ignore silently.
|
|
51
70
|
end
|
|
52
71
|
|
|
72
|
+
# Close the transaction and clean up resources.
|
|
53
73
|
def close
|
|
54
|
-
if @connection
|
|
55
|
-
connection = @connection
|
|
74
|
+
if connection = @connection
|
|
56
75
|
@connection = nil
|
|
76
|
+
@received.close
|
|
57
77
|
|
|
58
78
|
connection.transactions.delete(@id)
|
|
59
79
|
end
|
|
60
80
|
end
|
|
61
81
|
|
|
62
82
|
# Invoke a remote procedure.
|
|
83
|
+
# @parameter name [Symbol] The name of the remote object.
|
|
84
|
+
# @parameter arguments [Array] The positional arguments.
|
|
85
|
+
# @parameter options [Hash] The keyword arguments.
|
|
86
|
+
# @yields {|*args| ...} Optional block for yielding operations.
|
|
87
|
+
# @returns [Object] The result of the invocation.
|
|
63
88
|
def invoke(name, arguments, options, &block)
|
|
64
|
-
Console.
|
|
89
|
+
Console.debug(self){[name, arguments, options, block]}
|
|
65
90
|
|
|
66
|
-
self.write(
|
|
91
|
+
self.write(Invoke.new(@id, name, arguments, options, block_given?))
|
|
67
92
|
|
|
68
93
|
while response = self.read
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
when
|
|
73
|
-
raise(result)
|
|
74
|
-
when :return
|
|
75
|
-
return(result)
|
|
76
|
-
when :yield
|
|
94
|
+
case response
|
|
95
|
+
when Return
|
|
96
|
+
return response.result
|
|
97
|
+
when Yield
|
|
77
98
|
begin
|
|
78
|
-
result = yield(*result)
|
|
79
|
-
self.write(
|
|
99
|
+
result = yield(*response.result)
|
|
100
|
+
self.write(Next.new(@id, result))
|
|
80
101
|
rescue => error
|
|
81
|
-
self.write(
|
|
102
|
+
self.write(Error.new(@id, error))
|
|
82
103
|
end
|
|
104
|
+
when Error
|
|
105
|
+
raise(response.result)
|
|
106
|
+
when Throw
|
|
107
|
+
# Re-throw the tag and value that was thrown on the server side
|
|
108
|
+
# Throw.result contains [tag, value] array
|
|
109
|
+
tag, value = response.result
|
|
110
|
+
throw(tag, value)
|
|
83
111
|
end
|
|
84
112
|
end
|
|
85
|
-
|
|
86
|
-
# ensure
|
|
87
|
-
# self.write(:close)
|
|
88
113
|
end
|
|
89
114
|
|
|
90
|
-
# Accept a remote procedure
|
|
91
|
-
|
|
92
|
-
|
|
115
|
+
# Accept a remote procedure invocation.
|
|
116
|
+
# @parameter object [Object] The object to invoke the method on.
|
|
117
|
+
# @parameter arguments [Array] The positional arguments.
|
|
118
|
+
# @parameter options [Hash] The keyword arguments.
|
|
119
|
+
# @parameter block_given [Boolean] Whether a block was provided.
|
|
120
|
+
def accept(object, arguments, options, block_given)
|
|
121
|
+
if block_given
|
|
93
122
|
result = object.public_send(*arguments, **options) do |*yield_arguments|
|
|
94
|
-
self.write(
|
|
95
|
-
|
|
123
|
+
self.write(Yield.new(@id, yield_arguments))
|
|
124
|
+
|
|
125
|
+
response = self.read
|
|
96
126
|
|
|
97
|
-
case
|
|
98
|
-
when
|
|
99
|
-
result
|
|
100
|
-
when
|
|
101
|
-
|
|
102
|
-
when
|
|
103
|
-
|
|
127
|
+
case response
|
|
128
|
+
when Next
|
|
129
|
+
response.result
|
|
130
|
+
when Error
|
|
131
|
+
raise(response.result)
|
|
132
|
+
when Close
|
|
133
|
+
break
|
|
104
134
|
end
|
|
105
135
|
end
|
|
106
136
|
else
|
|
107
137
|
result = object.public_send(*arguments, **options)
|
|
108
138
|
end
|
|
109
139
|
|
|
110
|
-
self.write(
|
|
140
|
+
self.write(Return.new(@id, result))
|
|
111
141
|
rescue UncaughtThrowError => error
|
|
112
|
-
|
|
142
|
+
# UncaughtThrowError has both tag and value attributes
|
|
143
|
+
# Store both in the Throw message: result is tag, we'll add value handling
|
|
144
|
+
self.write(Throw.new(@id, [error.tag, error.value]))
|
|
113
145
|
rescue => error
|
|
114
|
-
self.write(
|
|
115
|
-
# ensure
|
|
116
|
-
# self.write(:close)
|
|
146
|
+
self.write(Error.new(@id, error))
|
|
117
147
|
end
|
|
118
148
|
end
|
|
119
149
|
end
|
|
120
150
|
end
|
|
121
|
-
end
|
|
151
|
+
end
|