actionwebservice 0.6.2 → 0.7.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.
Files changed (58) hide show
  1. data/CHANGELOG +21 -0
  2. data/README +50 -6
  3. data/Rakefile +9 -9
  4. data/TODO +6 -6
  5. data/lib/action_web_service.rb +4 -3
  6. data/lib/action_web_service/api.rb +248 -1
  7. data/lib/action_web_service/casting.rb +111 -0
  8. data/lib/action_web_service/client/soap_client.rb +17 -33
  9. data/lib/action_web_service/client/xmlrpc_client.rb +10 -34
  10. data/lib/action_web_service/container/delegated_container.rb +1 -1
  11. data/lib/action_web_service/dispatcher/abstract.rb +52 -72
  12. data/lib/action_web_service/dispatcher/action_controller_dispatcher.rb +71 -55
  13. data/lib/action_web_service/protocol/abstract.rb +82 -3
  14. data/lib/action_web_service/protocol/discovery.rb +2 -2
  15. data/lib/action_web_service/protocol/soap_protocol.rb +95 -22
  16. data/lib/action_web_service/protocol/soap_protocol/marshaler.rb +197 -0
  17. data/lib/action_web_service/protocol/xmlrpc_protocol.rb +56 -24
  18. data/lib/action_web_service/scaffolding.rb +237 -0
  19. data/lib/action_web_service/struct.rb +17 -4
  20. data/lib/action_web_service/support/signature_types.rb +194 -0
  21. data/lib/action_web_service/templates/scaffolds/layout.rhtml +65 -0
  22. data/lib/action_web_service/templates/scaffolds/methods.rhtml +6 -0
  23. data/lib/action_web_service/templates/scaffolds/parameters.rhtml +28 -0
  24. data/lib/action_web_service/templates/scaffolds/result.rhtml +30 -0
  25. data/lib/action_web_service/test_invoke.rb +23 -42
  26. data/test/abstract_dispatcher.rb +102 -48
  27. data/test/abstract_unit.rb +1 -1
  28. data/test/api_test.rb +40 -7
  29. data/test/casting_test.rb +82 -0
  30. data/test/client_soap_test.rb +3 -0
  31. data/test/client_xmlrpc_test.rb +5 -1
  32. data/test/dispatcher_action_controller_soap_test.rb +9 -12
  33. data/test/dispatcher_action_controller_xmlrpc_test.rb +1 -11
  34. data/test/run +1 -0
  35. data/test/scaffolded_controller_test.rb +67 -0
  36. data/test/struct_test.rb +33 -21
  37. data/test/test_invoke_test.rb +1 -1
  38. metadata +18 -31
  39. data/lib/action_web_service/api/base.rb +0 -135
  40. data/lib/action_web_service/vendor/ws.rb +0 -4
  41. data/lib/action_web_service/vendor/ws/common.rb +0 -8
  42. data/lib/action_web_service/vendor/ws/encoding.rb +0 -3
  43. data/lib/action_web_service/vendor/ws/encoding/abstract.rb +0 -26
  44. data/lib/action_web_service/vendor/ws/encoding/soap_rpc_encoding.rb +0 -90
  45. data/lib/action_web_service/vendor/ws/encoding/xmlrpc_encoding.rb +0 -53
  46. data/lib/action_web_service/vendor/ws/marshaling.rb +0 -3
  47. data/lib/action_web_service/vendor/ws/marshaling/abstract.rb +0 -17
  48. data/lib/action_web_service/vendor/ws/marshaling/soap_marshaling.rb +0 -277
  49. data/lib/action_web_service/vendor/ws/marshaling/xmlrpc_marshaling.rb +0 -116
  50. data/lib/action_web_service/vendor/ws/types.rb +0 -165
  51. data/test/ws/abstract_encoding.rb +0 -68
  52. data/test/ws/abstract_unit.rb +0 -13
  53. data/test/ws/gencov +0 -3
  54. data/test/ws/run +0 -5
  55. data/test/ws/soap_marshaling_test.rb +0 -91
  56. data/test/ws/soap_rpc_encoding_test.rb +0 -47
  57. data/test/ws/types_test.rb +0 -43
  58. data/test/ws/xmlrpc_encoding_test.rb +0 -34
@@ -0,0 +1,65 @@
1
+ <html>
2
+ <head>
3
+ <title><%= @scaffold_class.wsdl_service_name %> Web Service</title>
4
+ <style>
5
+ body { background-color: #fff; color: #333; }
6
+
7
+ body, p, ol, ul, td {
8
+ font-family: verdana, arial, helvetica, sans-serif;
9
+ font-size: 13px;
10
+ line-height: 18px;
11
+ }
12
+
13
+ pre {
14
+ background-color: #eee;
15
+ padding: 10px;
16
+ font-size: 11px;
17
+ }
18
+
19
+ a { color: #000; }
20
+ a:visited { color: #666; }
21
+ a:hover { color: #fff; background-color:#000; }
22
+
23
+ .fieldWithErrors {
24
+ padding: 2px;
25
+ background-color: red;
26
+ display: table;
27
+ }
28
+
29
+ #ErrorExplanation {
30
+ width: 400px;
31
+ border: 2px solid #red;
32
+ padding: 7px;
33
+ padding-bottom: 12px;
34
+ margin-bottom: 20px;
35
+ background-color: #f0f0f0;
36
+ }
37
+
38
+ #ErrorExplanation h2 {
39
+ text-align: left;
40
+ font-weight: bold;
41
+ padding: 5px 5px 5px 15px;
42
+ font-size: 12px;
43
+ margin: -7px;
44
+ background-color: #c00;
45
+ color: #fff;
46
+ }
47
+
48
+ #ErrorExplanation p {
49
+ color: #333;
50
+ margin-bottom: 0;
51
+ padding: 5px;
52
+ }
53
+
54
+ #ErrorExplanation ul li {
55
+ font-size: 12px;
56
+ list-style: square;
57
+ }
58
+ </style>
59
+ </head>
60
+ <body>
61
+
62
+ <%= @content_for_layout %>
63
+
64
+ </body>
65
+ </html>
@@ -0,0 +1,6 @@
1
+ <% @scaffold_container.services.each do |service| %>
2
+
3
+ <h4>API Methods for <%= service %></h4>
4
+ <%= service_method_list(service) %>
5
+
6
+ <% end %>
@@ -0,0 +1,28 @@
1
+ <h4>Method Invocation Details for <em><%= @scaffold_service %>#<%= @scaffold_method.public_name %></em></h4>
2
+
3
+ <%= form_tag :action => @scaffold_action_name + '_submit' %>
4
+ <%= hidden_field_tag "service", @scaffold_service.name %>
5
+ <%= hidden_field_tag "method", @scaffold_method.public_name %>
6
+
7
+ <p>
8
+ <label for="protocol">Protocol:</label><br />
9
+ <%= select_tag 'protocol', options_for_select([['SOAP', 'soap'], ['XML-RPC', 'xmlrpc']], @params['protocol']) %>
10
+ </p>
11
+
12
+ <% if @scaffold_method.expects %>
13
+
14
+ <strong>Method Parameters:</strong><br />
15
+ <% @scaffold_method.expects.each do |type| %>
16
+ <p>
17
+ <label for="method_params[]"><%= type.name.to_s.camelize %></label><br />
18
+ <%= method_parameter_input_fields(@scaffold_method, type) %>
19
+ </p>
20
+ <% end %>
21
+
22
+ <% end %>
23
+
24
+ <%= submit_tag "Invoke" %>
25
+
26
+ <p>
27
+ <%= link_to "Back", :action => @scaffold_action_name %>
28
+ </p>
@@ -0,0 +1,30 @@
1
+ <h4>Method Invocation Result for <em><%= @scaffold_service %>#<%= @scaffold_method.public_name %></em></h4>
2
+
3
+ <p>
4
+ Invocation took <tt><%= '%f' % @method_elapsed %></tt> seconds
5
+ </p>
6
+
7
+ <p>
8
+ <strong>Return Value:</strong><br />
9
+ <pre>
10
+ <%= h @method_return_value.inspect %>
11
+ </pre>
12
+ </p>
13
+
14
+ <p>
15
+ <strong>Request XML:</strong><br />
16
+ <pre>
17
+ <%= h @method_request_xml %>
18
+ </pre>
19
+ </p>
20
+
21
+ <p>
22
+ <strong>Response XML:</strong><br />
23
+ <pre>
24
+ <%= h @method_response_xml %>
25
+ </pre>
26
+ </p>
27
+
28
+ <p>
29
+ <%= link_to "Back", :action => @scaffold_action_name + '_method_params', :method => @scaffold_method.public_name, :service => @scaffold_service.name %>
30
+ </p>
@@ -21,7 +21,7 @@ module Test # :nodoc:
21
21
 
22
22
  # invoke the specified layered API method on the correct service
23
23
  def invoke_layered(service_name, method_name, *args)
24
- if protocol == :soap
24
+ if protocol.is_a?(ActionWebService::Protocol::Soap::SoapProtocol)
25
25
  raise "SOAP protocol support for :layered dispatching mode is not available"
26
26
  end
27
27
  prepare_request('api', service_name, method_name, *args)
@@ -37,10 +37,10 @@ module Test # :nodoc:
37
37
  @request.env['HTTP_CONTENT_TYPE'] = 'text/xml'
38
38
  @request.env['RAW_POST_DATA'] = encode_rpc_call(service_name, api_method_name, *args)
39
39
  case protocol
40
- when :soap
40
+ when ActionWebService::Protocol::Soap::SoapProtocol
41
41
  soap_action = "/#{@controller.controller_name}/#{service_name}/#{public_method_name(service_name, api_method_name)}"
42
42
  @request.env['HTTP_SOAPACTION'] = soap_action
43
- when :xmlrpc
43
+ when ActionWebService::Protocol::XmlRpc::XmlRpcProtocol
44
44
  @request.env.delete('HTTP_SOAPACTION')
45
45
  end
46
46
  end
@@ -52,28 +52,16 @@ module Test # :nodoc:
52
52
  when :delegated, :layered
53
53
  api = @controller.web_service_object(service_name.to_sym).class.web_service_api
54
54
  end
55
- info = api.api_methods[api_method_name.to_sym]
56
- ((info[:expects] || []) + (info[:returns] || [])).each do |spec|
57
- marshaler.register_type spec
58
- end
59
- expects = info[:expects]
60
- args = args.dup
61
- (0..(args.length-1)).each do |i|
62
- type_binding = marshaler.register_type(expects ? expects[i] : args[i].class)
63
- info = WS::ParamInfo.create(expects ? expects[i] : args[i].class, type_binding, i)
64
- args[i] = marshaler.marshal(WS::Param.new(args[i], info))
65
- end
66
- encoder.encode_rpc_call(public_method_name(service_name, api_method_name), args)
55
+ protocol.register_api(api)
56
+ method = api.api_methods[api_method_name.to_sym]
57
+ protocol.encode_request(public_method_name(service_name, api_method_name), args.dup, method.expects)
67
58
  end
68
59
 
69
60
  def decode_rpc_response
70
- public_method_name, return_value = encoder.decode_rpc_response(@response.body)
71
- result = marshaler.unmarshal(return_value).value
72
- unless @return_exceptions
73
- exception = is_exception?(result)
74
- raise exception if exception
75
- end
76
- result
61
+ public_method_name, return_value = protocol.decode_response(@response.body)
62
+ exception = is_exception?(return_value)
63
+ raise exception if exception
64
+ return_value
77
65
  end
78
66
 
79
67
  def public_method_name(service_name, api_method_name)
@@ -95,33 +83,26 @@ module Test # :nodoc:
95
83
  end
96
84
 
97
85
  def protocol
98
- @protocol ||= :soap
99
- end
100
-
101
- def marshaler
102
- case protocol
103
- when :soap
104
- @soap_marshaler ||= WS::Marshaling::SoapMarshaler.new 'urn:ActionWebService'
105
- when :xmlrpc
106
- @xmlrpc_marshaler ||= WS::Marshaling::XmlRpcMarshaler.new
107
- end
108
- end
109
-
110
- def encoder
111
- case protocol
112
- when :soap
113
- @soap_encoder ||= WS::Encoding::SoapRpcEncoding.new 'urn:ActionWebService'
114
- when :xmlrpc
115
- @xmlrpc_encoder ||= WS::Encoding::XmlRpcEncoding.new
86
+ if @protocol.nil?
87
+ @protocol ||= ActionWebService::Protocol::Soap::SoapProtocol.new
88
+ else
89
+ case @protocol
90
+ when :xmlrpc
91
+ @protocol = ActionWebService::Protocol::XmlRpc::XmlRpcProtocol.new
92
+ when :soap
93
+ @protocol = ActionWebService::Protocol::Soap::SoapProtocol.new
94
+ else
95
+ @protocol
96
+ end
116
97
  end
117
98
  end
118
99
 
119
100
  def is_exception?(obj)
120
101
  case protocol
121
- when :soap
102
+ when :soap, ActionWebService::Protocol::Soap::SoapProtocol
122
103
  (obj.respond_to?(:detail) && obj.detail.respond_to?(:cause) && \
123
104
  obj.detail.cause.is_a?(Exception)) ? obj.detail.cause : nil
124
- when :xmlrpc
105
+ when :xmlrpc, ActionWebService::Protocol::XmlRpc::XmlRpcProtocol
125
106
  obj.is_a?(XMLRPC::FaultException) ? obj : nil
126
107
  end
127
108
  end
@@ -1,4 +1,7 @@
1
1
  require File.dirname(__FILE__) + '/abstract_unit'
2
+ require 'stringio'
3
+
4
+ class ActionController::Base; def rescue_action(e) raise e end; end
2
5
 
3
6
  module DispatcherTest
4
7
  class Node < ActiveRecord::Base
@@ -29,6 +32,10 @@ module DispatcherTest
29
32
  class Person < ActionWebService::Struct
30
33
  member :id, :int
31
34
  member :name, :string
35
+
36
+ def ==(other)
37
+ self.id == other.id && self.name == other.name
38
+ end
32
39
  end
33
40
 
34
41
  class API < ActionWebService::API::Base
@@ -44,7 +51,9 @@ module DispatcherTest
44
51
  api_method :before_filtered
45
52
  api_method :after_filtered, :returns => [[:int]]
46
53
  api_method :struct_return, :returns => [[Node]]
54
+ api_method :struct_pass, :expects => [{:person => Person}]
47
55
  api_method :base_struct_return, :returns => [[Person]]
56
+ api_method :hash_struct_return, :returns => [[Person]]
48
57
  api_method :thrower
49
58
  api_method :void
50
59
  end
@@ -148,6 +157,7 @@ module DispatcherTest
148
157
  attr :after_filter_called
149
158
  attr :after_filter_target_called
150
159
  attr :void_called
160
+ attr :struct_pass_value
151
161
 
152
162
  def initialize
153
163
  @before_filter_called = false
@@ -155,6 +165,7 @@ module DispatcherTest
155
165
  @after_filter_called = false
156
166
  @after_filter_target_called = false
157
167
  @void_called = false
168
+ @struct_pass_value = false
158
169
  end
159
170
 
160
171
  def add
@@ -184,11 +195,21 @@ module DispatcherTest
184
195
  [n1, n2]
185
196
  end
186
197
 
198
+ def struct_pass(person)
199
+ @struct_pass_value = person
200
+ end
201
+
187
202
  def base_struct_return
188
203
  p1 = Person.new('id' => 1, 'name' => 'person1')
189
204
  p2 = Person.new('id' => 2, 'name' => 'person2')
190
205
  [p1, p2]
191
206
  end
207
+
208
+ def hash_struct_return
209
+ p1 = { :id => '1', 'name' => 'test' }
210
+ p2 = { 'id' => '2', :name => 'person2' }
211
+ [p1, p2]
212
+ end
192
213
 
193
214
  def void
194
215
  @void_called = @method_params
@@ -221,22 +242,11 @@ module DispatcherCommonTests
221
242
  assert_equal(50, do_method_call(@direct_controller, 'Add2', 25, 25))
222
243
  assert_equal(50, @direct_controller.added2)
223
244
  assert(@direct_controller.void_called == false)
224
- case @encoder
225
- when WS::Encoding::SoapRpcEncoding
226
- assert(do_method_call(@direct_controller, 'Void', 3, 4, 5).nil?)
227
- when WS::Encoding::XmlRpcEncoding
228
- assert(do_method_call(@direct_controller, 'Void', 3, 4, 5) == true)
229
- end
245
+ assert(do_method_call(@direct_controller, 'Void', 3, 4, 5).nil?)
230
246
  assert(@direct_controller.void_called == [])
231
247
  result = do_method_call(@direct_controller, 'BaseStructReturn')
232
- case @encoder
233
- when WS::Encoding::SoapRpcEncoding
234
- assert(result[0].is_a?(DispatcherTest::Person))
235
- assert(result[1].is_a?(DispatcherTest::Person))
236
- when WS::Encoding::XmlRpcEncoding
237
- assert(result[0].is_a?(Hash))
238
- assert(result[1].is_a?(Hash))
239
- end
248
+ assert(result[0].is_a?(DispatcherTest::Person))
249
+ assert(result[1].is_a?(DispatcherTest::Person))
240
250
  end
241
251
 
242
252
  def test_direct_entrypoint
@@ -275,12 +285,7 @@ module DispatcherCommonTests
275
285
  assert(is_exception?(result))
276
286
  assert_match(/NonExistentMethod/, exception_message(result))
277
287
  assert(service.void_called == false)
278
- case @encoder
279
- when WS::Encoding::SoapRpcEncoding
280
- assert(do_method_call(@delegated_controller, 'Void', 3, 4, 5).nil?)
281
- when WS::Encoding::XmlRpcEncoding
282
- assert(do_method_call(@delegated_controller, 'Void', 3, 4, 5) == true)
283
- end
288
+ assert(do_method_call(@delegated_controller, 'Void', 3, 4, 5).nil?)
284
289
  assert(service.void_called == [])
285
290
  end
286
291
 
@@ -288,7 +293,8 @@ module DispatcherCommonTests
288
293
  [@direct_controller, @delegated_controller].each do |controller|
289
294
  controller.class.web_service_exception_reporting = true
290
295
  send_garbage_request = lambda do
291
- request = create_ap_request(controller, 'invalid request body', 'xxx')
296
+ service_name = service_name(controller)
297
+ request = @protocol.encode_action_pack_request(service_name, 'broken, method, name!', 'broken request body', :request_class => ActionController::TestRequest)
292
298
  response = ActionController::TestResponse.new
293
299
  controller.process(request, response)
294
300
  # puts response.body
@@ -313,21 +319,53 @@ module DispatcherCommonTests
313
319
  def test_ar_struct_return
314
320
  [@direct_controller, @delegated_controller].each do |controller|
315
321
  result = do_method_call(controller, 'StructReturn')
316
- case @encoder
317
- when WS::Encoding::SoapRpcEncoding
318
- assert(result[0].is_a?(DispatcherTest::Node))
319
- assert(result[1].is_a?(DispatcherTest::Node))
320
- assert_equal('node1', result[0].name)
321
- assert_equal('node2', result[1].name)
322
- when WS::Encoding::XmlRpcEncoding
323
- assert(result[0].is_a?(Hash))
324
- assert(result[1].is_a?(Hash))
325
- assert_equal('node1', result[0]['name'])
326
- assert_equal('node2', result[1]['name'])
327
- end
322
+ assert(result[0].is_a?(DispatcherTest::Node))
323
+ assert(result[1].is_a?(DispatcherTest::Node))
324
+ assert_equal('node1', result[0].name)
325
+ assert_equal('node2', result[1].name)
326
+ end
327
+ end
328
+
329
+ def test_casting
330
+ assert_equal 70, do_method_call(@direct_controller, 'Add', "50", "20")
331
+ assert_equal false, @direct_controller.struct_pass_value
332
+ person = DispatcherTest::Person.new(:id => 1, :name => 'test')
333
+ result = do_method_call(@direct_controller, 'StructPass', person)
334
+ assert(nil == result || true == result)
335
+ assert_equal person, @direct_controller.struct_pass_value
336
+ assert !person.equal?(@direct_controller.struct_pass_value)
337
+ result = do_method_call(@direct_controller, 'StructPass', {'id' => '1', 'name' => 'test'})
338
+ case @protocol
339
+ when ActionWebService::Protocol::Soap::SoapProtocol
340
+ assert_equal(person, @direct_controller.struct_pass_value)
341
+ assert !person.equal?(@direct_controller.struct_pass_value)
342
+ when ActionWebService::Protocol::XmlRpc::XmlRpcProtocol
343
+ assert_equal(person, @direct_controller.struct_pass_value)
344
+ assert !person.equal?(@direct_controller.struct_pass_value)
345
+ end
346
+ assert_equal person, do_method_call(@direct_controller, 'HashStructReturn')[0]
347
+ result = do_method_call(@direct_controller, 'StructPass', {'id' => '1', 'name' => 'test', 'nonexistent_attribute' => 'value'})
348
+ case @protocol
349
+ when ActionWebService::Protocol::Soap::SoapProtocol
350
+ assert_equal(person, @direct_controller.struct_pass_value)
351
+ assert !person.equal?(@direct_controller.struct_pass_value)
352
+ when ActionWebService::Protocol::XmlRpc::XmlRpcProtocol
353
+ assert_equal(person, @direct_controller.struct_pass_value)
354
+ assert !person.equal?(@direct_controller.struct_pass_value)
328
355
  end
329
356
  end
330
357
 
358
+ def test_logging
359
+ buf = ""
360
+ ActionController::Base.logger = Logger.new(StringIO.new(buf))
361
+ test_casting
362
+ test_garbage_request
363
+ test_exception_marshaling
364
+ ActionController::Base.logger = nil
365
+ assert_match /Web Service Response/, buf
366
+ assert_match /Web Service Request/, buf
367
+ end
368
+
331
369
  protected
332
370
  def service_name(container)
333
371
  raise NotImplementedError
@@ -342,37 +380,53 @@ module DispatcherCommonTests
342
380
  end
343
381
 
344
382
  def do_method_call(container, public_method_name, *params)
383
+ request_env = {}
345
384
  mode = container.web_service_dispatching_mode
346
385
  case mode
347
386
  when :direct
387
+ service_name = service_name(container)
348
388
  api = container.class.web_service_api
389
+ method = api.public_api_method_instance(public_method_name)
349
390
  when :delegated
350
- api = container.web_service_object(service_name(container)).class.web_service_api
391
+ service_name = service_name(container)
392
+ api = container.web_service_object(service_name).class.web_service_api
393
+ method = api.public_api_method_instance(public_method_name)
351
394
  when :layered
352
395
  service_name = nil
396
+ real_method_name = nil
353
397
  if public_method_name =~ /^([^\.]+)\.(.*)$/
354
398
  service_name = $1
399
+ real_method_name = $2
400
+ end
401
+ if @protocol.is_a? ActionWebService::Protocol::Soap::SoapProtocol
402
+ public_method_name = real_method_name
403
+ request_env['HTTP_SOAPACTION'] = "/soap/#{service_name}/#{real_method_name}"
355
404
  end
356
405
  api = container.web_service_object(service_name.to_sym).class.web_service_api
406
+ method = api.public_api_method_instance(real_method_name)
407
+ service_name = self.service_name(container)
357
408
  end
358
- info = api.api_methods[method_name] || {}
359
- params = params.dup
360
- ((info[:expects] || []) + (info[:returns] || [])).each do |spec|
361
- @marshaler.register_type(spec)
362
- end
363
- expects = info[:expects]
364
- (0..(params.length-1)).each do |i|
365
- type_binding = @marshaler.register_type(expects ? expects[i] : params[i].class)
366
- info = WS::ParamInfo.create(expects ? expects[i] : params[i].class, type_binding, i)
367
- params[i] = @marshaler.marshal(WS::Param.new(params[i], info))
409
+ @protocol.register_api(api)
410
+ virtual = false
411
+ unless method
412
+ virtual = true
413
+ method ||= ActionWebService::API::Method.new(public_method_name.underscore.to_sym, public_method_name, nil, nil)
368
414
  end
369
- body = @encoder.encode_rpc_call(public_method_name, params)
415
+ body = @protocol.encode_request(public_method_name, params.dup, method.expects)
370
416
  # puts body
371
- ap_request = create_ap_request(container, body, public_method_name, *params)
417
+ ap_request = @protocol.encode_action_pack_request(service_name, public_method_name, body, :request_class => ActionController::TestRequest)
418
+ ap_request.env.update(request_env)
372
419
  ap_response = ActionController::TestResponse.new
373
420
  container.process(ap_request, ap_response)
374
421
  # puts ap_response.body
375
- public_method_name, return_value = @encoder.decode_rpc_response(ap_response.body)
376
- @marshaler.unmarshal(return_value).value
422
+ public_method_name, return_value = @protocol.decode_response(ap_response.body)
423
+ unless is_exception?(return_value) || virtual
424
+ return_value = method.cast_returns(return_value)
425
+ end
426
+ if @protocol.is_a?(ActionWebService::Protocol::Soap::SoapProtocol)
427
+ # http://dev.rubyonrails.com/changeset/920
428
+ assert_match(/Response$/, public_method_name) unless public_method_name == "fault"
429
+ end
430
+ return_value
377
431
  end
378
432
  end