melomel 0.3.1 → 0.4.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.
- data/lib/melomel/bridge/messaging.rb +189 -54
- data/lib/melomel/error.rb +43 -0
- data/lib/melomel/object_proxy.rb +23 -2
- data/lib/melomel/version.rb +1 -1
- data/lib/melomel.rb +3 -0
- data/test/sandbox.rb +14 -0
- data/test/test_integration.rb +20 -1
- metadata +8 -5
@@ -3,70 +3,116 @@ require 'nokogiri'
|
|
3
3
|
# These add-on methods enable the message encoding and decoding.
|
4
4
|
module Melomel
|
5
5
|
class Bridge
|
6
|
+
###########################################################################
|
7
|
+
#
|
8
|
+
# Basic Messages
|
9
|
+
#
|
10
|
+
###########################################################################
|
11
|
+
|
6
12
|
# Creates an object in the Flash virtual machine and returns the reference
|
7
13
|
# to it.
|
14
|
+
#
|
15
|
+
# class_name - The name of the class to instantiate.
|
16
|
+
#
|
17
|
+
# Returns an instance of the class if the class is found. Otherwise, nil.
|
8
18
|
def create_object(class_name)
|
9
|
-
|
10
|
-
|
19
|
+
send_create_object(class_name, false)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Same as `create_object` except that an error is thrown if the class is
|
23
|
+
# not found.
|
24
|
+
def create_object!(class_name)
|
25
|
+
send_create_object(class_name, true)
|
11
26
|
end
|
12
27
|
|
13
28
|
# Retrieves a reference to a class in the Flash virtual machine.
|
29
|
+
#
|
30
|
+
# class_name - The name of the class to retrieve a reference to.
|
31
|
+
#
|
32
|
+
# Returns a reference to the class if it exists. Otherwise, nil.
|
14
33
|
def get_class(class_name)
|
15
|
-
|
16
|
-
|
34
|
+
send_get_class(class_name, false)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Same as `get_class` except that an error is thrown if the class is not
|
38
|
+
# found.
|
39
|
+
def get_class!(class_name)
|
40
|
+
send_get_class(class_name, true)
|
17
41
|
end
|
18
42
|
|
19
43
|
# Retrieves a property of an object in the Flash virtual machine
|
44
|
+
#
|
45
|
+
# proxy_id - The identifier for the object proxy.
|
46
|
+
# property - The name of the property to access.
|
47
|
+
#
|
48
|
+
# Returns the value of the property if it exists. Otherwise, nil.
|
20
49
|
def get_property(proxy_id, property)
|
21
|
-
|
22
|
-
|
50
|
+
send_get_property(proxy_id, property, false)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Same as `get_property` except that an error is thrown if the property
|
54
|
+
# does not exist.
|
55
|
+
def get_property!(proxy_id, property)
|
56
|
+
send_get_property(proxy_id, property, true)
|
23
57
|
end
|
24
58
|
|
25
59
|
# Sets a property on an object in the Flash virtual machine
|
60
|
+
#
|
61
|
+
# proxy_id - The identifier of the object proxy.
|
62
|
+
# property - The name of the property to mutate.
|
63
|
+
# value - The value to set the property to.
|
64
|
+
#
|
65
|
+
# Returns the value of the property after being set.
|
26
66
|
def set_property(proxy_id, property, value)
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
67
|
+
send_set_property(proxy_id, property, value, false)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Same as `set_property` except that an error is thrown if the property
|
71
|
+
# does not exist.
|
72
|
+
def set_property!(proxy_id, property, value)
|
73
|
+
send_set_property(proxy_id, property, value, true)
|
34
74
|
end
|
35
75
|
|
36
76
|
# Invokes a method on an object in the Flash virtual machine
|
77
|
+
#
|
78
|
+
# proxy_id - The identifier of the object proxy.
|
79
|
+
# method_name - The name of the method to invoke.
|
80
|
+
# *args - List of arguments passed to the method.
|
81
|
+
#
|
82
|
+
# Returns the value returned from the Flash method.
|
37
83
|
def invoke_method(proxy_id, method_name, *args)
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
args_node.add_child(arg_node)
|
46
|
-
end
|
47
|
-
|
48
|
-
# Send and receive
|
49
|
-
send(xml.root.to_xml(:indent => 0))
|
50
|
-
parse_message_value(Nokogiri::XML(receive()).root)
|
84
|
+
send_invoke_method(proxy_id, method_name, args, false)
|
85
|
+
end
|
86
|
+
|
87
|
+
# Same as `invoke_method` except that an error is thrown if the method
|
88
|
+
# does not exist.
|
89
|
+
def invoke_method!(proxy_id, method_name, *args)
|
90
|
+
send_invoke_method(proxy_id, method_name, args, true)
|
51
91
|
end
|
52
92
|
|
53
93
|
# Invokes a package level function in the Flash virtual machine
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
args_node.add_child(arg_node)
|
63
|
-
end
|
94
|
+
#
|
95
|
+
# function_name - The fully qualified name of the function to invoke.
|
96
|
+
# *args - List of arguments passed to the function.
|
97
|
+
#
|
98
|
+
# Returns the return value of the Flash function.
|
99
|
+
def invoke_function(function_name, *args)
|
100
|
+
send_invoke_function(function_name, args, false)
|
101
|
+
end
|
64
102
|
|
65
|
-
|
66
|
-
|
67
|
-
|
103
|
+
# Same as `invoke_function` except that an error is thrown if the method
|
104
|
+
# does not exist.
|
105
|
+
def invoke_function!(function_name, *args)
|
106
|
+
send_invoke_function(function_name, args, true)
|
68
107
|
end
|
69
108
|
|
109
|
+
|
110
|
+
###########################################################################
|
111
|
+
#
|
112
|
+
# Utility Methods
|
113
|
+
#
|
114
|
+
###########################################################################
|
115
|
+
|
70
116
|
# Creates an object proxy from a hash
|
71
117
|
def create_hash(hash)
|
72
118
|
proxy = create_object('Object')
|
@@ -106,24 +152,113 @@ module Melomel
|
|
106
152
|
|
107
153
|
# Parses a return message and converts it into an appropriate type
|
108
154
|
def parse_message_value(xml)
|
109
|
-
|
110
|
-
data_type = xml['dataType']
|
155
|
+
name = xml.name()
|
111
156
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
157
|
+
# If we receive an error back then raise it in the Ruby VM.
|
158
|
+
if name == 'error'
|
159
|
+
stack_trace_xml = xml.at_xpath('stack-trace')
|
160
|
+
object = Melomel::ObjectProxy.new(self, xml['proxyId'].to_i)
|
161
|
+
error_id = xml['errorId'].to_i
|
162
|
+
message = xml['message']
|
163
|
+
name = xml['name']
|
164
|
+
stack_trace = stack_trace_xml ? stack_trace_xml.to_str : nil
|
165
|
+
$stderr.puts(stack_trace)
|
166
|
+
raise Melomel::Error.new(object, error_id, message, name, stack_trace), message
|
167
|
+
|
168
|
+
# Otherwise we have a return value so we should parse it.
|
124
169
|
else
|
125
|
-
|
170
|
+
value = xml['value']
|
171
|
+
data_type = xml['dataType']
|
172
|
+
|
173
|
+
if data_type == 'null'
|
174
|
+
return nil
|
175
|
+
elsif data_type == 'int'
|
176
|
+
return value.to_i
|
177
|
+
elsif data_type == 'float'
|
178
|
+
return value.to_f
|
179
|
+
elsif data_type == 'boolean'
|
180
|
+
return value == 'true'
|
181
|
+
elsif data_type == 'object'
|
182
|
+
return Melomel::ObjectProxy.new(self, value.to_i)
|
183
|
+
elsif data_type == 'string' || data_type.nil?
|
184
|
+
return value
|
185
|
+
else
|
186
|
+
raise UnrecognizedTypeError, "Unknown type: #{data_type}"
|
187
|
+
end
|
126
188
|
end
|
127
189
|
end
|
190
|
+
|
191
|
+
|
192
|
+
###########################################################################
|
193
|
+
#
|
194
|
+
# Private Methods
|
195
|
+
#
|
196
|
+
###########################################################################
|
197
|
+
|
198
|
+
private
|
199
|
+
|
200
|
+
# Creates an object in the Flash virtual machine and returns the reference
|
201
|
+
# to it.
|
202
|
+
def send_create_object(class_name, throwable=true)
|
203
|
+
send("<create class=\"#{class_name}\" throwable=\"#{throwable}\"/>")
|
204
|
+
parse_message_value(Nokogiri::XML(receive()).root)
|
205
|
+
end
|
206
|
+
|
207
|
+
# Retrieves a reference to a class in the Flash virtual machine.
|
208
|
+
def send_get_class(class_name, throwable=true)
|
209
|
+
send("<get-class name=\"#{class_name}\" throwable=\"#{throwable}\"/>")
|
210
|
+
parse_message_value(Nokogiri::XML(receive()).root)
|
211
|
+
end
|
212
|
+
|
213
|
+
# Retrieves a property of an object in the Flash virtual machine
|
214
|
+
def send_get_property(proxy_id, property, throwable)
|
215
|
+
send("<get object=\"#{proxy_id}\" property=\"#{property}\" throwable=\"#{throwable}\"/>")
|
216
|
+
parse_message_value(Nokogiri::XML(receive()).root)
|
217
|
+
end
|
218
|
+
|
219
|
+
# Sets a property on an object in the Flash virtual machine
|
220
|
+
def send_set_property(proxy_id, property, value, throwable)
|
221
|
+
# Create message and format value to set
|
222
|
+
xml = Nokogiri::XML("<set object=\"#{proxy_id}\" property=\"#{property}\" throwable=\"#{throwable}\"><arg/></set>")
|
223
|
+
format_message_value(xml.at_xpath('/set/arg'), value)
|
224
|
+
|
225
|
+
# Send & Receive
|
226
|
+
send(xml.root.to_xml(:indent => 0))
|
227
|
+
parse_message_value(Nokogiri::XML(receive()).root)
|
228
|
+
end
|
229
|
+
|
230
|
+
# Invokes a method on an object in the Flash virtual machine
|
231
|
+
def send_invoke_method(proxy_id, method_name, args, throwable)
|
232
|
+
xml = Nokogiri::XML("<invoke object=\"#{proxy_id}\" method=\"#{method_name}\" throwable=\"#{throwable}\"><args/></invoke>")
|
233
|
+
|
234
|
+
# Loop over and add arguments to call
|
235
|
+
args_node = xml.at_xpath('invoke/args')
|
236
|
+
args.each do |arg|
|
237
|
+
arg_node = Nokogiri::XML::Node.new('arg', xml)
|
238
|
+
format_message_value(arg_node, arg)
|
239
|
+
args_node.add_child(arg_node)
|
240
|
+
end
|
241
|
+
|
242
|
+
# Send and receive
|
243
|
+
send(xml.root.to_xml(:indent => 0))
|
244
|
+
parse_message_value(Nokogiri::XML(receive()).root)
|
245
|
+
end
|
246
|
+
|
247
|
+
# Invokes a package level function in the Flash virtual machine
|
248
|
+
def send_invoke_function(function_name, args, throwable)
|
249
|
+
xml = Nokogiri::XML("<invoke-function name=\"#{function_name}\" throwable=\"#{throwable}\"><args/></invoke>")
|
250
|
+
|
251
|
+
# Loop over and add arguments to call
|
252
|
+
args_node = xml.at_xpath('invoke-function/args')
|
253
|
+
args.each do |arg|
|
254
|
+
arg_node = Nokogiri::XML::Node.new('arg', xml)
|
255
|
+
format_message_value(arg_node, arg)
|
256
|
+
args_node.add_child(arg_node)
|
257
|
+
end
|
258
|
+
|
259
|
+
# Send and receive
|
260
|
+
send(xml.root.to_xml(:indent => 0))
|
261
|
+
parse_message_value(Nokogiri::XML(receive()).root)
|
262
|
+
end
|
128
263
|
end
|
129
264
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# This class is used for all errors returned from the Flash virtual machine.
|
2
|
+
module Melomel
|
3
|
+
class Error < StandardError
|
4
|
+
############################################################################
|
5
|
+
#
|
6
|
+
# Constructor
|
7
|
+
#
|
8
|
+
############################################################################
|
9
|
+
|
10
|
+
def initialize(object, error_id, message, name, stack_trace)
|
11
|
+
@object = object
|
12
|
+
@error_id = error_id
|
13
|
+
@message = message
|
14
|
+
@name = name
|
15
|
+
@stack_trace = stack_trace
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
############################################################################
|
20
|
+
#
|
21
|
+
# Public Properties
|
22
|
+
#
|
23
|
+
############################################################################
|
24
|
+
|
25
|
+
# A proxied reference to the original Flash error object.
|
26
|
+
#
|
27
|
+
# Returns a Melomel::ObjectProxy.
|
28
|
+
attr_reader :object
|
29
|
+
|
30
|
+
# The error identifier of the Flash error.
|
31
|
+
attr_reader :error_id
|
32
|
+
|
33
|
+
# The Flash error message.
|
34
|
+
attr_reader :message
|
35
|
+
|
36
|
+
# The name of the Flash error.
|
37
|
+
attr_reader :name
|
38
|
+
|
39
|
+
# The Flash stack trace. This is only available when using the Flash debug
|
40
|
+
# player or the AIR Debug Launcher (ADL).
|
41
|
+
attr_reader :stack_trace
|
42
|
+
end
|
43
|
+
end
|
data/lib/melomel/object_proxy.rb
CHANGED
@@ -22,16 +22,29 @@ module Melomel
|
|
22
22
|
@bridge.get_property(@proxy_id, name)
|
23
23
|
end
|
24
24
|
|
25
|
+
def get_property!(name)
|
26
|
+
@bridge.get_property!(@proxy_id, name)
|
27
|
+
end
|
28
|
+
|
25
29
|
# Sets the value of a property for the proxied object.
|
26
30
|
def set_property(name, value)
|
27
31
|
@bridge.set_property(@proxy_id, name, value)
|
28
32
|
end
|
33
|
+
|
34
|
+
# Sets the value of a property for the proxied object.
|
35
|
+
def set_property!(name, value)
|
36
|
+
@bridge.set_property!(@proxy_id, name, value)
|
37
|
+
end
|
29
38
|
|
30
39
|
# Invokes a method on the proxied object. Arguments passed into the method
|
31
40
|
# are passed through to the invoked method
|
32
41
|
def invoke_method(method_name, *args)
|
33
42
|
@bridge.invoke_method(@proxy_id, method_name, *args)
|
34
43
|
end
|
44
|
+
|
45
|
+
def invoke_method!(method_name, *args)
|
46
|
+
@bridge.invoke_method!(@proxy_id, method_name, *args)
|
47
|
+
end
|
35
48
|
|
36
49
|
alias :invoke :invoke_method
|
37
50
|
|
@@ -45,10 +58,18 @@ module Melomel
|
|
45
58
|
return set_property(method_name.chop, *args)
|
46
59
|
# Methods with arguments are methods
|
47
60
|
elsif args.length > 0
|
48
|
-
|
61
|
+
if last_char == '!'
|
62
|
+
return invoke_method!(method_name.chop, *args)
|
63
|
+
else
|
64
|
+
return invoke_method(method_name, *args)
|
65
|
+
end
|
49
66
|
# Methods with no arguments are aliased to get_property
|
50
67
|
else
|
51
|
-
|
68
|
+
if last_char == '!'
|
69
|
+
return get_property!(method_name.chop)
|
70
|
+
else
|
71
|
+
return get_property(method_name)
|
72
|
+
end
|
52
73
|
end
|
53
74
|
end
|
54
75
|
end
|
data/lib/melomel/version.rb
CHANGED
data/lib/melomel.rb
CHANGED
data/test/sandbox.rb
ADDED
data/test/test_integration.rb
CHANGED
@@ -20,6 +20,25 @@ class IntegrationTestCase < RunnerTestCase
|
|
20
20
|
assert_equal 'bar', runner.foo
|
21
21
|
end
|
22
22
|
|
23
|
+
def test_should_get_missing_property_as_nil
|
24
|
+
app = Melomel.get_class('mx.core.FlexGlobals').topLevelApplication
|
25
|
+
assert_nil app.no_such_property
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_should_throw_error_when_getting_missing_instance_property!
|
29
|
+
app = Melomel.get_class('mx.core.FlexGlobals').topLevelApplication
|
30
|
+
assert_raises Melomel::Error do
|
31
|
+
app.no_such_property!
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_should_throw_error_when_getting_missing_static_property!
|
36
|
+
runner = Melomel.get_class('MelomelRunner')
|
37
|
+
assert_raises Melomel::Error do
|
38
|
+
runner.no_such_property!
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
23
42
|
# Tests the ability for a get_property to call a no-arg method if unavailable.
|
24
43
|
def test_should_get_property_passthrough
|
25
44
|
app = Melomel.get_class('mx.core.FlexGlobals').topLevelApplication
|
@@ -30,7 +49,7 @@ class IntegrationTestCase < RunnerTestCase
|
|
30
49
|
runner = Melomel.get_class('MelomelRunner')
|
31
50
|
runner.name = 'Susy'
|
32
51
|
assert_equal 'Susy', runner.name
|
33
|
-
runner.name = 'John'
|
52
|
+
runner.name = 'John'
|
34
53
|
end
|
35
54
|
|
36
55
|
def test_should_invoke_method
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: melomel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 15
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
8
|
+
- 4
|
9
|
+
- 0
|
10
|
+
version: 0.4.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Ben Johnson
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-09-
|
18
|
+
date: 2010-09-29 00:00:00 -06:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -79,6 +79,7 @@ files:
|
|
79
79
|
- lib/melomel/bridge/messaging.rb
|
80
80
|
- lib/melomel/bridge/ui.rb
|
81
81
|
- lib/melomel/bridge.rb
|
82
|
+
- lib/melomel/error.rb
|
82
83
|
- lib/melomel/object_proxy.rb
|
83
84
|
- lib/melomel/ui.rb
|
84
85
|
- lib/melomel/version.rb
|
@@ -86,6 +87,7 @@ files:
|
|
86
87
|
- README.md
|
87
88
|
- CHANGELOG.md
|
88
89
|
- test/helper.rb
|
90
|
+
- test/sandbox.rb
|
89
91
|
- test/test_bridge.rb
|
90
92
|
- test/test_integration.rb
|
91
93
|
- test/test_messaging.rb
|
@@ -127,6 +129,7 @@ specification_version: 3
|
|
127
129
|
summary: A Ruby interface to Melomel
|
128
130
|
test_files:
|
129
131
|
- test/helper.rb
|
132
|
+
- test/sandbox.rb
|
130
133
|
- test/test_bridge.rb
|
131
134
|
- test/test_integration.rb
|
132
135
|
- test/test_messaging.rb
|