melomel 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
- send("<create class=\"#{class_name}\"/>")
10
- parse_message_value(Nokogiri::XML(receive()).root)
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
- send("<get-class name=\"#{class_name}\"/>")
16
- parse_message_value(Nokogiri::XML(receive()).root)
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
- send("<get object=\"#{proxy_id}\" property=\"#{property}\"/>")
22
- parse_message_value(Nokogiri::XML(receive()).root)
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
- # Create message and format value to set
28
- xml = Nokogiri::XML("<set object=\"#{proxy_id}\" property=\"#{property}\"><arg/></set>")
29
- format_message_value(xml.at_xpath('/set/arg'), value)
30
-
31
- # Send & Receive
32
- send(xml.root.to_xml(:indent => 0))
33
- parse_message_value(Nokogiri::XML(receive()).root)
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
- xml = Nokogiri::XML("<invoke object=\"#{proxy_id}\" method=\"#{method_name}\"><args/></invoke>")
39
-
40
- # Loop over and add arguments to call
41
- args_node = xml.at_xpath('invoke/args')
42
- args.each do |arg|
43
- arg_node = Nokogiri::XML::Node.new('arg', xml)
44
- format_message_value(arg_node, arg)
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
- def invoke_function(function, *args)
55
- xml = Nokogiri::XML("<invoke-function name=\"#{function}\"><args/></invoke>")
56
-
57
- # Loop over and add arguments to call
58
- args_node = xml.at_xpath('invoke-function/args')
59
- args.each do |arg|
60
- arg_node = Nokogiri::XML::Node.new('arg', xml)
61
- format_message_value(arg_node, arg)
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
- # Send and receive
66
- send(xml.root.to_xml(:indent => 0))
67
- parse_message_value(Nokogiri::XML(receive()).root)
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
- value = xml['value']
110
- data_type = xml['dataType']
155
+ name = xml.name()
111
156
 
112
- if data_type == 'null'
113
- return nil
114
- elsif data_type == 'int'
115
- return value.to_i
116
- elsif data_type == 'float'
117
- return value.to_f
118
- elsif data_type == 'boolean'
119
- return value == 'true'
120
- elsif data_type == 'object'
121
- return Melomel::ObjectProxy.new(self, value.to_i)
122
- elsif data_type == 'string' || data_type.nil?
123
- return value
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
- raise UnrecognizedTypeError, "Unknown type: #{data_type}"
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
@@ -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
- return invoke_method(method_name, *args)
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
- return get_property(method_name)
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
@@ -1,3 +1,3 @@
1
1
  module Melomel
2
- VERSION = "0.3.1"
2
+ VERSION = "0.4.0"
3
3
  end
data/lib/melomel.rb CHANGED
@@ -1,4 +1,7 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless $:.index(File.dirname(__FILE__))
2
+
1
3
  require 'melomel/bridge'
4
+ require 'melomel/error'
2
5
  require 'melomel/object_proxy'
3
6
  require 'melomel/ui'
4
7
  require 'melomel/version'
data/test/sandbox.rb ADDED
@@ -0,0 +1,14 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), *%w[helper])
2
+
3
+ class SandboxTestCase < RunnerTestCase
4
+ def setup
5
+ start_runner
6
+ Melomel.connect()
7
+ end
8
+
9
+ def teardown
10
+ stop_runner
11
+ end
12
+
13
+ # Add tests here.
14
+ end
@@ -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' # TODO: Do not make other tests dependent on this
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: 17
4
+ hash: 15
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 3
9
- - 1
10
- version: 0.3.1
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-27 00:00:00 -06:00
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