melomel 0.3.1 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|