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.
- data/CHANGELOG +21 -0
- data/README +50 -6
- data/Rakefile +9 -9
- data/TODO +6 -6
- data/lib/action_web_service.rb +4 -3
- data/lib/action_web_service/api.rb +248 -1
- data/lib/action_web_service/casting.rb +111 -0
- data/lib/action_web_service/client/soap_client.rb +17 -33
- data/lib/action_web_service/client/xmlrpc_client.rb +10 -34
- data/lib/action_web_service/container/delegated_container.rb +1 -1
- data/lib/action_web_service/dispatcher/abstract.rb +52 -72
- data/lib/action_web_service/dispatcher/action_controller_dispatcher.rb +71 -55
- data/lib/action_web_service/protocol/abstract.rb +82 -3
- data/lib/action_web_service/protocol/discovery.rb +2 -2
- data/lib/action_web_service/protocol/soap_protocol.rb +95 -22
- data/lib/action_web_service/protocol/soap_protocol/marshaler.rb +197 -0
- data/lib/action_web_service/protocol/xmlrpc_protocol.rb +56 -24
- data/lib/action_web_service/scaffolding.rb +237 -0
- data/lib/action_web_service/struct.rb +17 -4
- data/lib/action_web_service/support/signature_types.rb +194 -0
- data/lib/action_web_service/templates/scaffolds/layout.rhtml +65 -0
- data/lib/action_web_service/templates/scaffolds/methods.rhtml +6 -0
- data/lib/action_web_service/templates/scaffolds/parameters.rhtml +28 -0
- data/lib/action_web_service/templates/scaffolds/result.rhtml +30 -0
- data/lib/action_web_service/test_invoke.rb +23 -42
- data/test/abstract_dispatcher.rb +102 -48
- data/test/abstract_unit.rb +1 -1
- data/test/api_test.rb +40 -7
- data/test/casting_test.rb +82 -0
- data/test/client_soap_test.rb +3 -0
- data/test/client_xmlrpc_test.rb +5 -1
- data/test/dispatcher_action_controller_soap_test.rb +9 -12
- data/test/dispatcher_action_controller_xmlrpc_test.rb +1 -11
- data/test/run +1 -0
- data/test/scaffolded_controller_test.rb +67 -0
- data/test/struct_test.rb +33 -21
- data/test/test_invoke_test.rb +1 -1
- metadata +18 -31
- data/lib/action_web_service/api/base.rb +0 -135
- data/lib/action_web_service/vendor/ws.rb +0 -4
- data/lib/action_web_service/vendor/ws/common.rb +0 -8
- data/lib/action_web_service/vendor/ws/encoding.rb +0 -3
- data/lib/action_web_service/vendor/ws/encoding/abstract.rb +0 -26
- data/lib/action_web_service/vendor/ws/encoding/soap_rpc_encoding.rb +0 -90
- data/lib/action_web_service/vendor/ws/encoding/xmlrpc_encoding.rb +0 -53
- data/lib/action_web_service/vendor/ws/marshaling.rb +0 -3
- data/lib/action_web_service/vendor/ws/marshaling/abstract.rb +0 -17
- data/lib/action_web_service/vendor/ws/marshaling/soap_marshaling.rb +0 -277
- data/lib/action_web_service/vendor/ws/marshaling/xmlrpc_marshaling.rb +0 -116
- data/lib/action_web_service/vendor/ws/types.rb +0 -165
- data/test/ws/abstract_encoding.rb +0 -68
- data/test/ws/abstract_unit.rb +0 -13
- data/test/ws/gencov +0 -3
- data/test/ws/run +0 -5
- data/test/ws/soap_marshaling_test.rb +0 -91
- data/test/ws/soap_rpc_encoding_test.rb +0 -47
- data/test/ws/types_test.rb +0 -43
- data/test/ws/xmlrpc_encoding_test.rb +0 -34
@@ -1,116 +0,0 @@
|
|
1
|
-
module WS
|
2
|
-
module Marshaling
|
3
|
-
class XmlRpcError < WSError
|
4
|
-
end
|
5
|
-
|
6
|
-
class XmlRpcMarshaler < AbstractMarshaler
|
7
|
-
def initialize
|
8
|
-
@caster = BaseTypeCaster.new
|
9
|
-
@spec2binding = {}
|
10
|
-
end
|
11
|
-
|
12
|
-
def marshal(param)
|
13
|
-
transform_outbound(param)
|
14
|
-
end
|
15
|
-
|
16
|
-
def unmarshal(obj)
|
17
|
-
obj.param.value = transform_inbound(obj.param)
|
18
|
-
obj.param
|
19
|
-
end
|
20
|
-
|
21
|
-
def typed_unmarshal(obj, spec)
|
22
|
-
param = obj.param
|
23
|
-
param.info.data = register_type(spec)
|
24
|
-
param.value = transform_inbound(param)
|
25
|
-
param
|
26
|
-
end
|
27
|
-
|
28
|
-
def register_type(spec)
|
29
|
-
if @spec2binding.has_key?(spec)
|
30
|
-
return @spec2binding[spec]
|
31
|
-
end
|
32
|
-
|
33
|
-
klass = BaseTypes.canonical_param_type_class(spec)
|
34
|
-
type_binding = nil
|
35
|
-
if klass.is_a?(Array)
|
36
|
-
type_binding = XmlRpcArrayBinding.new(klass[0])
|
37
|
-
else
|
38
|
-
type_binding = XmlRpcBinding.new(klass)
|
39
|
-
end
|
40
|
-
|
41
|
-
@spec2binding[spec] = type_binding
|
42
|
-
end
|
43
|
-
|
44
|
-
def transform_outbound(param)
|
45
|
-
binding = param.info.data
|
46
|
-
case binding
|
47
|
-
when XmlRpcArrayBinding
|
48
|
-
param.value.map{|x| cast_outbound(x, binding.element_klass)}
|
49
|
-
when XmlRpcBinding
|
50
|
-
cast_outbound(param.value, param.info.type)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
def transform_inbound(param)
|
55
|
-
return param.value if param.info.data.nil?
|
56
|
-
binding = param.info.data
|
57
|
-
param.info.type = binding.klass
|
58
|
-
case binding
|
59
|
-
when XmlRpcArrayBinding
|
60
|
-
param.value.map{|x| cast_inbound(x, binding.element_klass)}
|
61
|
-
when XmlRpcBinding
|
62
|
-
cast_inbound(param.value, param.info.type)
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
def cast_outbound(value, klass)
|
67
|
-
if BaseTypes.base_type?(klass)
|
68
|
-
@caster.cast(value, klass)
|
69
|
-
elsif value.is_a?(Exception)
|
70
|
-
XMLRPC::FaultException.new(2, value.message)
|
71
|
-
elsif Object.const_defined?('ActiveRecord') && value.is_a?(ActiveRecord::Base)
|
72
|
-
value.attributes
|
73
|
-
else
|
74
|
-
struct = {}
|
75
|
-
value.instance_variables.each do |name|
|
76
|
-
key = name.sub(/^@/, '')
|
77
|
-
struct[key] = value.instance_variable_get(name)
|
78
|
-
end
|
79
|
-
struct
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
def cast_inbound(value, klass)
|
84
|
-
if BaseTypes.base_type?(klass)
|
85
|
-
value = value.to_time if value.is_a?(XMLRPC::DateTime)
|
86
|
-
@caster.cast(value, klass)
|
87
|
-
elsif value.is_a?(XMLRPC::FaultException)
|
88
|
-
value
|
89
|
-
else
|
90
|
-
obj = klass.new
|
91
|
-
value.each do |name, val|
|
92
|
-
obj.send('%s=' % name.to_s, val)
|
93
|
-
end
|
94
|
-
obj
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
class XmlRpcBinding
|
100
|
-
attr :klass
|
101
|
-
|
102
|
-
def initialize(klass)
|
103
|
-
@klass = klass
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
class XmlRpcArrayBinding < XmlRpcBinding
|
108
|
-
attr :element_klass
|
109
|
-
|
110
|
-
def initialize(element_klass)
|
111
|
-
super(Array)
|
112
|
-
@element_klass = element_klass
|
113
|
-
end
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|
@@ -1,165 +0,0 @@
|
|
1
|
-
require 'time'
|
2
|
-
require 'date'
|
3
|
-
|
4
|
-
module WS
|
5
|
-
module BaseTypes
|
6
|
-
class << self
|
7
|
-
def type_name_to_class(name)
|
8
|
-
case canonical_type_name(name)
|
9
|
-
when :int
|
10
|
-
Integer
|
11
|
-
when :string
|
12
|
-
String
|
13
|
-
when :bool
|
14
|
-
TrueClass
|
15
|
-
when :float
|
16
|
-
Float
|
17
|
-
when :time
|
18
|
-
Time
|
19
|
-
when :date
|
20
|
-
Date
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def class_to_type_name(klass)
|
25
|
-
if WS.derived_from?(Integer, klass) || WS.derived_from?(Fixnum, klass) || WS.derived_from?(Bignum, klass)
|
26
|
-
:int
|
27
|
-
elsif klass == String
|
28
|
-
:string
|
29
|
-
elsif klass == TrueClass || klass == FalseClass
|
30
|
-
:bool
|
31
|
-
elsif WS.derived_from?(Float, klass) || WS.derived_from?(Precision, klass) || WS.derived_from?(Numeric, klass)
|
32
|
-
:float
|
33
|
-
elsif klass == Time || klass == DateTime
|
34
|
-
:time
|
35
|
-
elsif klass == Date
|
36
|
-
:date
|
37
|
-
else
|
38
|
-
raise(TypeError, "#{klass} is not a valid base type")
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def base_type?(klass)
|
43
|
-
!(canonical_type_class(klass) rescue nil).nil?
|
44
|
-
end
|
45
|
-
|
46
|
-
def canonical_type_class(klass)
|
47
|
-
type_name_to_class(class_to_type_name(klass))
|
48
|
-
end
|
49
|
-
|
50
|
-
def canonical_param_type_class(spec)
|
51
|
-
klass = spec.is_a?(Hash) ? spec.values[0] : spec
|
52
|
-
array_element_class = klass.is_a?(Array) ? klass[0] : nil
|
53
|
-
klass = array_element_class ? array_element_class : klass
|
54
|
-
klass = type_name_to_class(klass) if klass.is_a?(Symbol) || klass.is_a?(String)
|
55
|
-
base_class = canonical_type_class(klass) rescue nil
|
56
|
-
klass = base_class unless base_class.nil?
|
57
|
-
array_element_class ? [klass] : klass
|
58
|
-
end
|
59
|
-
|
60
|
-
def canonical_param_type_spec(spec)
|
61
|
-
klass = canonical_param_type_class(spec)
|
62
|
-
spec.is_a?(Hash) ? {spec.keys[0]=>klass} : klass
|
63
|
-
end
|
64
|
-
|
65
|
-
def canonical_type_name(name)
|
66
|
-
name = name.to_sym
|
67
|
-
case name
|
68
|
-
when :int, :integer, :fixnum, :bignum
|
69
|
-
:int
|
70
|
-
when :string, :base64
|
71
|
-
:string
|
72
|
-
when :bool, :boolean
|
73
|
-
:bool
|
74
|
-
when :float, :double
|
75
|
-
:float
|
76
|
-
when :time, :datetime, :timestamp
|
77
|
-
:time
|
78
|
-
when :date
|
79
|
-
:date
|
80
|
-
else
|
81
|
-
raise(TypeError, "#{name} is not a valid base type")
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
class Param
|
88
|
-
attr_accessor :value
|
89
|
-
attr_accessor :info
|
90
|
-
|
91
|
-
def initialize(value, info)
|
92
|
-
@value = value
|
93
|
-
@info = info
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
class ParamInfo
|
98
|
-
attr_accessor :name
|
99
|
-
attr_accessor :type
|
100
|
-
attr_accessor :data
|
101
|
-
|
102
|
-
def initialize(name, type, data=nil)
|
103
|
-
@name = name
|
104
|
-
@type = type
|
105
|
-
@data = data
|
106
|
-
end
|
107
|
-
|
108
|
-
def self.create(spec, data, index=nil)
|
109
|
-
name = spec.is_a?(Hash) ? spec.keys[0].to_s : (index ? "param#{index}" : nil)
|
110
|
-
type = BaseTypes.canonical_param_type_class(spec)
|
111
|
-
ParamInfo.new(name, type, data)
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
class BaseTypeCaster
|
116
|
-
def initialize
|
117
|
-
@handlers = {}
|
118
|
-
install_handlers
|
119
|
-
end
|
120
|
-
|
121
|
-
def cast(value, klass)
|
122
|
-
type_class = BaseTypes.canonical_type_class(klass)
|
123
|
-
return value unless type_class
|
124
|
-
@handlers[type_class].call(value, type_class)
|
125
|
-
end
|
126
|
-
|
127
|
-
protected
|
128
|
-
def install_handlers
|
129
|
-
handler = method(:cast_base_type)
|
130
|
-
[:int, :string, :bool, :float, :time, :date].each do |name|
|
131
|
-
type = BaseTypes.type_name_to_class(name)
|
132
|
-
@handlers[type] = handler
|
133
|
-
end
|
134
|
-
@handlers[Fixnum] = handler
|
135
|
-
end
|
136
|
-
|
137
|
-
def cast_base_type(value, type_class)
|
138
|
-
desired_class = BaseTypes.canonical_type_class(type_class)
|
139
|
-
value_class = BaseTypes.canonical_type_class(value.class)
|
140
|
-
return value if desired_class == value_class
|
141
|
-
desired_name = BaseTypes.class_to_type_name(desired_class)
|
142
|
-
case desired_name
|
143
|
-
when :int
|
144
|
-
Integer(value)
|
145
|
-
when :string
|
146
|
-
value.to_s
|
147
|
-
when :bool
|
148
|
-
return false if value.nil?
|
149
|
-
int_value = Integer(value) rescue nil
|
150
|
-
return true if int_value == 1
|
151
|
-
return false if int_value == 0
|
152
|
-
value = value.to_s
|
153
|
-
return true if value == 'true'
|
154
|
-
return false if value == 'false'
|
155
|
-
raise(TypeError, "can't convert #{value} to boolean")
|
156
|
-
when :float
|
157
|
-
Float(value)
|
158
|
-
when :time
|
159
|
-
Time.parse(value.to_s)
|
160
|
-
when :date
|
161
|
-
Date.parse(value.to_s)
|
162
|
-
end
|
163
|
-
end
|
164
|
-
end
|
165
|
-
end
|
@@ -1,68 +0,0 @@
|
|
1
|
-
require File.dirname(__FILE__) + '/abstract_unit'
|
2
|
-
|
3
|
-
module Nested
|
4
|
-
class StructClass
|
5
|
-
attr_accessor :name
|
6
|
-
attr_accessor :version
|
7
|
-
|
8
|
-
def initialize
|
9
|
-
@name = 5
|
10
|
-
@version = "1.0"
|
11
|
-
end
|
12
|
-
|
13
|
-
def ==(other)
|
14
|
-
@name == other.name && @version == other.version
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
module EncodingTest
|
20
|
-
def setup
|
21
|
-
@call_signature = [:int, :bool, :string, :float, [:time], Nested::StructClass]
|
22
|
-
@call_params = [1, true, "string", 5.0, [Time.now], Nested::StructClass.new]
|
23
|
-
@response_signature = [:string]
|
24
|
-
@response_param = "hello world"
|
25
|
-
test_setup
|
26
|
-
end
|
27
|
-
|
28
|
-
def test_abstract
|
29
|
-
obj = WS::Encoding::AbstractEncoding.new
|
30
|
-
assert_raises(NotImplementedError) do
|
31
|
-
obj.encode_rpc_call(nil, nil)
|
32
|
-
end
|
33
|
-
assert_raises(NotImplementedError) do
|
34
|
-
obj.decode_rpc_call(nil)
|
35
|
-
end
|
36
|
-
assert_raises(NotImplementedError) do
|
37
|
-
obj.encode_rpc_response(nil, nil)
|
38
|
-
end
|
39
|
-
assert_raises(NotImplementedError) do
|
40
|
-
obj.decode_rpc_response(nil)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def encode_rpc_call(method_name, signature, params)
|
45
|
-
params = params.dup
|
46
|
-
(0..(signature.length-1)).each do |i|
|
47
|
-
type_binding = @marshaler.register_type(signature[i])
|
48
|
-
info = WS::ParamInfo.create(signature[i], type_binding, i)
|
49
|
-
params[i] = @marshaler.marshal(WS::Param.new(params[i], info))
|
50
|
-
end
|
51
|
-
@encoder.encode_rpc_call(method_name, params)
|
52
|
-
end
|
53
|
-
|
54
|
-
def decode_rpc_call(obj)
|
55
|
-
@encoder.decode_rpc_call(obj)
|
56
|
-
end
|
57
|
-
|
58
|
-
def encode_rpc_response(method_name, signature, param)
|
59
|
-
type_binding = @marshaler.register_type(signature[0])
|
60
|
-
info = WS::ParamInfo.create(signature[0], type_binding, 0)
|
61
|
-
param = @marshaler.marshal(WS::Param.new(param, info))
|
62
|
-
@encoder.encode_rpc_response(method_name, param)
|
63
|
-
end
|
64
|
-
|
65
|
-
def decode_rpc_response(obj)
|
66
|
-
@encoder.decode_rpc_response(obj)
|
67
|
-
end
|
68
|
-
end
|
data/test/ws/abstract_unit.rb
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
require 'pathname'
|
2
|
-
$:.unshift(Pathname.new(File.dirname(__FILE__)).realpath.to_s + '/../../lib/action_web_service/vendor')
|
3
|
-
require 'test/unit'
|
4
|
-
require 'ws'
|
5
|
-
begin
|
6
|
-
require 'active_record'
|
7
|
-
rescue LoadError
|
8
|
-
begin
|
9
|
-
require 'rubygems'
|
10
|
-
require_gem 'activerecord', '>= 1.6.0'
|
11
|
-
rescue LoadError
|
12
|
-
end
|
13
|
-
end
|
data/test/ws/gencov
DELETED
data/test/ws/run
DELETED
@@ -1,91 +0,0 @@
|
|
1
|
-
require File.dirname(__FILE__) + '/abstract_unit'
|
2
|
-
|
3
|
-
module Nested
|
4
|
-
class MyClass
|
5
|
-
attr_accessor :id
|
6
|
-
attr_accessor :name
|
7
|
-
|
8
|
-
def initialize(id, name)
|
9
|
-
@id = id
|
10
|
-
@name = name
|
11
|
-
end
|
12
|
-
|
13
|
-
def ==(other)
|
14
|
-
@id == other.id && @name == other.name
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
class SoapMarshalingTest < Test::Unit::TestCase
|
20
|
-
def setup
|
21
|
-
@marshaler = WS::Marshaling::SoapMarshaler.new
|
22
|
-
end
|
23
|
-
|
24
|
-
def test_abstract
|
25
|
-
marshaler = WS::Marshaling::AbstractMarshaler.new
|
26
|
-
assert_raises(NotImplementedError) do
|
27
|
-
marshaler.marshal(nil)
|
28
|
-
end
|
29
|
-
assert_raises(NotImplementedError) do
|
30
|
-
marshaler.unmarshal(nil)
|
31
|
-
end
|
32
|
-
assert_equal(nil, marshaler.register_type(nil))
|
33
|
-
end
|
34
|
-
|
35
|
-
def test_marshaling
|
36
|
-
info = WS::ParamInfo.create(Nested::MyClass, @marshaler.register_type(Nested::MyClass))
|
37
|
-
param = WS::Param.new(Nested::MyClass.new(2, "name"), info)
|
38
|
-
new_param = @marshaler.unmarshal(@marshaler.marshal(param))
|
39
|
-
assert(param == new_param)
|
40
|
-
end
|
41
|
-
|
42
|
-
def test_exception_marshaling
|
43
|
-
info = WS::ParamInfo.create(RuntimeError, @marshaler.register_type(RuntimeError))
|
44
|
-
param = WS::Param.new(RuntimeError.new("hello, world"), info)
|
45
|
-
new_param = @marshaler.unmarshal(@marshaler.marshal(param))
|
46
|
-
assert_equal("hello, world", new_param.value.detail.cause.message)
|
47
|
-
end
|
48
|
-
|
49
|
-
def test_registration
|
50
|
-
type_binding1 = @marshaler.register_type(:int)
|
51
|
-
type_binding2 = @marshaler.register_type(:int)
|
52
|
-
assert(type_binding1.equal?(type_binding2))
|
53
|
-
end
|
54
|
-
|
55
|
-
def test_active_record
|
56
|
-
if Object.const_defined?('ActiveRecord')
|
57
|
-
node_class = Class.new(ActiveRecord::Base) do
|
58
|
-
def initialize(*args)
|
59
|
-
super(*args)
|
60
|
-
@new_record = false
|
61
|
-
end
|
62
|
-
|
63
|
-
class << self
|
64
|
-
def name
|
65
|
-
"Node"
|
66
|
-
end
|
67
|
-
|
68
|
-
def columns(*args)
|
69
|
-
[
|
70
|
-
ActiveRecord::ConnectionAdapters::Column.new('id', 0, 'int'),
|
71
|
-
ActiveRecord::ConnectionAdapters::Column.new('name', nil, 'string'),
|
72
|
-
ActiveRecord::ConnectionAdapters::Column.new('email', nil, 'string'),
|
73
|
-
]
|
74
|
-
end
|
75
|
-
|
76
|
-
def connection
|
77
|
-
self
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
info = WS::ParamInfo.create(node_class, @marshaler.register_type(node_class), 0)
|
82
|
-
ar_obj = node_class.new('name' => 'hello', 'email' => 'test@test.com')
|
83
|
-
param = WS::Param.new(ar_obj, info)
|
84
|
-
obj = @marshaler.marshal(param)
|
85
|
-
param = @marshaler.unmarshal(obj)
|
86
|
-
new_ar_obj = param.value
|
87
|
-
assert_equal(ar_obj, new_ar_obj)
|
88
|
-
assert(!ar_obj.equal?(new_ar_obj))
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|