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