wash-out 0.10.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.rspec +1 -0
- data/.travis.yml +35 -0
- data/Appraisals +25 -0
- data/CHANGELOG.md +102 -0
- data/Gemfile +16 -0
- data/Guardfile +12 -0
- data/LICENSE +22 -0
- data/README.md +246 -0
- data/Rakefile +13 -0
- data/app/helpers/wash_out_helper.rb +106 -0
- data/app/views/wash_out/document/error.builder +9 -0
- data/app/views/wash_out/document/response.builder +10 -0
- data/app/views/wash_out/document/wsdl.builder +68 -0
- data/app/views/wash_out/rpc/error.builder +10 -0
- data/app/views/wash_out/rpc/response.builder +11 -0
- data/app/views/wash_out/rpc/wsdl.builder +68 -0
- data/gemfiles/rails_3.1.3.gemfile +20 -0
- data/gemfiles/rails_3.2.12.gemfile +20 -0
- data/gemfiles/rails_4.0.0.gemfile +19 -0
- data/gemfiles/rails_4.1.0.gemfile +19 -0
- data/gemfiles/rails_4.2.0.gemfile +19 -0
- data/gemfiles/rails_5.0.0.beta2.gemfile +19 -0
- data/init.rb +1 -0
- data/lib/wash_out.rb +53 -0
- data/lib/wash_out/configurable.rb +41 -0
- data/lib/wash_out/dispatcher.rb +218 -0
- data/lib/wash_out/engine.rb +12 -0
- data/lib/wash_out/middleware.rb +41 -0
- data/lib/wash_out/model.rb +29 -0
- data/lib/wash_out/param.rb +200 -0
- data/lib/wash_out/router.rb +95 -0
- data/lib/wash_out/soap.rb +48 -0
- data/lib/wash_out/soap_config.rb +93 -0
- data/lib/wash_out/type.rb +29 -0
- data/lib/wash_out/version.rb +3 -0
- data/lib/wash_out/wsse.rb +101 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +51 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +23 -0
- data/spec/dummy/config/environments/test.rb +30 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +10 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +8 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +58 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +26 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/public/stylesheets/.gitkeep +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/lib/wash_out/dispatcher_spec.rb +99 -0
- data/spec/lib/wash_out/middleware_spec.rb +33 -0
- data/spec/lib/wash_out/param_spec.rb +94 -0
- data/spec/lib/wash_out/router_spec.rb +22 -0
- data/spec/lib/wash_out/type_spec.rb +41 -0
- data/spec/lib/wash_out_spec.rb +754 -0
- data/spec/spec_helper.rb +82 -0
- data/wash_out.gemspec +21 -0
- metadata +128 -0
@@ -0,0 +1,41 @@
|
|
1
|
+
module WashOut
|
2
|
+
module Configurable
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
cattr_reader :soap_config
|
7
|
+
class_variable_set :@@soap_config, WashOut::SoapConfig.new({})
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
|
12
|
+
def soap_config=(obj)
|
13
|
+
|
14
|
+
unless obj.is_a?(Hash)
|
15
|
+
raise "Value needs to be a Hash."
|
16
|
+
end
|
17
|
+
|
18
|
+
if class_variable_defined?(:@@soap_config)
|
19
|
+
class_variable_get(:@@soap_config).configure obj
|
20
|
+
else
|
21
|
+
class_variable_set :@@soap_config, WashOut::SoapConfig.new(obj)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def soap_config=(obj)
|
27
|
+
|
28
|
+
unless obj.is_a?(Hash)
|
29
|
+
raise "Value needs to be a Hash."
|
30
|
+
end
|
31
|
+
|
32
|
+
class_eval do
|
33
|
+
if class_variable_defined?(:@@soap_config)
|
34
|
+
class_variable_get(:@@soap_config).configure obj
|
35
|
+
else
|
36
|
+
class_variable_set :@@soap_config, WashOut::SoapConfig.new(obj)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,218 @@
|
|
1
|
+
module WashOut
|
2
|
+
# The WashOut::Dispatcher module should be included in a controller acting
|
3
|
+
# as a SOAP endpoint. It includes actions for generating WSDL and handling
|
4
|
+
# SOAP requests.
|
5
|
+
module Dispatcher
|
6
|
+
# A SOAPError exception can be raised to return a correct SOAP error
|
7
|
+
# response.
|
8
|
+
class SOAPError < Exception
|
9
|
+
attr_accessor :code
|
10
|
+
def initialize(message, code=nil)
|
11
|
+
super(message)
|
12
|
+
@code = code
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class ProgrammerError < Exception; end
|
17
|
+
|
18
|
+
def _authenticate_wsse
|
19
|
+
|
20
|
+
begin
|
21
|
+
xml_security = request.env['wash_out.soap_data'].values_at(:envelope, :Envelope).compact.first
|
22
|
+
xml_security = xml_security.values_at(:header, :Header).compact.first
|
23
|
+
xml_security = xml_security.values_at(:security, :Security).compact.first
|
24
|
+
username_token = xml_security.values_at(:username_token, :UsernameToken).compact.first
|
25
|
+
rescue
|
26
|
+
username_token = nil
|
27
|
+
end
|
28
|
+
|
29
|
+
WashOut::Wsse.authenticate soap_config, username_token
|
30
|
+
|
31
|
+
request.env['WSSE_TOKEN'] = username_token.with_indifferent_access unless username_token.blank?
|
32
|
+
end
|
33
|
+
|
34
|
+
def _map_soap_parameters
|
35
|
+
@_params = _load_params action_spec[:in],
|
36
|
+
_strip_empty_nodes(action_spec[:in], xml_data)
|
37
|
+
end
|
38
|
+
|
39
|
+
def _strip_empty_nodes(params, hash)
|
40
|
+
hash.keys.each do |key|
|
41
|
+
param = params.detect { |a| a.raw_name.to_s == key.to_s }
|
42
|
+
next if !(param && hash[key].is_a?(Hash))
|
43
|
+
|
44
|
+
value = hash[key].delete_if do |k, _|
|
45
|
+
k.to_s[0] == '@' && !param.map.detect { |a| a.raw_name.to_s == k.to_s }
|
46
|
+
end
|
47
|
+
|
48
|
+
if value.length > 0
|
49
|
+
hash[key] = _strip_empty_nodes param.map, value
|
50
|
+
else
|
51
|
+
hash[key] = nil
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
hash
|
56
|
+
end
|
57
|
+
|
58
|
+
# Creates the final parameter hash based on the request spec and xml_data from the request
|
59
|
+
def _load_params(spec, xml_data)
|
60
|
+
params = HashWithIndifferentAccess.new
|
61
|
+
spec.each do |param|
|
62
|
+
key = param.raw_name.to_sym
|
63
|
+
if xml_data.has_key? key
|
64
|
+
params[param.raw_name] = param.load(xml_data, key)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
params
|
68
|
+
end
|
69
|
+
|
70
|
+
# This action generates the WSDL for defined SOAP methods.
|
71
|
+
def _generate_wsdl
|
72
|
+
|
73
|
+
@map = self.class.soap_actions
|
74
|
+
@namespace = soap_config.namespace
|
75
|
+
@name = controller_path.gsub('/', '_')
|
76
|
+
|
77
|
+
render :template => "wash_out/#{soap_config.wsdl_style}/wsdl", :layout => false,
|
78
|
+
:content_type => 'text/xml'
|
79
|
+
end
|
80
|
+
|
81
|
+
# Render a SOAP response.
|
82
|
+
def _render_soap(result, options)
|
83
|
+
@namespace = soap_config.namespace
|
84
|
+
@operation = soap_action = request.env['wash_out.soap_action']
|
85
|
+
@action_spec = self.class.soap_actions[soap_action]
|
86
|
+
|
87
|
+
result = { 'value' => result } unless result.is_a? Hash
|
88
|
+
result = HashWithIndifferentAccess.new(result)
|
89
|
+
|
90
|
+
inject = lambda {|data, map|
|
91
|
+
result_spec = []
|
92
|
+
return result_spec if data.nil?
|
93
|
+
|
94
|
+
map.each_with_index do |param, i|
|
95
|
+
result_spec[i] = param.flat_copy
|
96
|
+
|
97
|
+
unless data.is_a?(Hash)
|
98
|
+
raise ProgrammerError,
|
99
|
+
"SOAP response used #{data.inspect} (which is #{data.class.name}), " +
|
100
|
+
"in the context where a Hash with key of '#{param.raw_name}' " +
|
101
|
+
"was expected."
|
102
|
+
end
|
103
|
+
|
104
|
+
value = data[param.raw_name]
|
105
|
+
|
106
|
+
unless value.nil?
|
107
|
+
if param.multiplied && !value.is_a?(Array)
|
108
|
+
raise ProgrammerError,
|
109
|
+
"SOAP response tried to use '#{value.inspect}' " +
|
110
|
+
"(which is of type #{value.class.name}), as the value for " +
|
111
|
+
"'#{param.raw_name}' (which expects an Array)."
|
112
|
+
end
|
113
|
+
|
114
|
+
# Inline complex structure {:foo => {bar: ...}}
|
115
|
+
if param.struct? && !param.multiplied
|
116
|
+
result_spec[i].map = inject.call(value, param.map)
|
117
|
+
|
118
|
+
# Inline array of complex structures {:foo => [{bar: ...}]}
|
119
|
+
elsif param.struct? && param.multiplied
|
120
|
+
result_spec[i].map = value.map{|e| inject.call(e, param.map)}
|
121
|
+
|
122
|
+
# Inline scalar {:foo => :string}
|
123
|
+
else
|
124
|
+
result_spec[i].value = value
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
return result_spec
|
130
|
+
}
|
131
|
+
|
132
|
+
render :template => "wash_out/#{soap_config.wsdl_style}/response",
|
133
|
+
:layout => false,
|
134
|
+
:locals => { :result => inject.call(result, @action_spec[:out]) },
|
135
|
+
:content_type => 'text/xml'
|
136
|
+
end
|
137
|
+
|
138
|
+
# This action is a fallback for all undefined SOAP actions.
|
139
|
+
def _invalid_action
|
140
|
+
render_soap_error("Cannot find SOAP action mapping for #{request.env['wash_out.soap_action']}")
|
141
|
+
end
|
142
|
+
|
143
|
+
def _catch_soap_errors
|
144
|
+
yield
|
145
|
+
rescue SOAPError => error
|
146
|
+
render_soap_error(error.message, error.code)
|
147
|
+
end
|
148
|
+
|
149
|
+
# Render a SOAP error response.
|
150
|
+
#
|
151
|
+
# Rails do not support sequental rescue_from handling, that is, rescuing an
|
152
|
+
# exception from a rescue_from handler. Hence this function is a public API.
|
153
|
+
def render_soap_error(message, code=nil)
|
154
|
+
render :template => "wash_out/#{soap_config.wsdl_style}/error", :status => 500,
|
155
|
+
:layout => false,
|
156
|
+
:locals => { :error_message => message, :error_code => (code || 'Server') },
|
157
|
+
:content_type => 'text/xml'
|
158
|
+
end
|
159
|
+
|
160
|
+
def self.included(controller)
|
161
|
+
entity = if defined?(Rails::VERSION::MAJOR) && (Rails::VERSION::MAJOR >= 4)
|
162
|
+
'action'
|
163
|
+
else
|
164
|
+
'filter'
|
165
|
+
end
|
166
|
+
|
167
|
+
controller.send :"around_#{entity}", :_catch_soap_errors
|
168
|
+
controller.send :helper, :wash_out
|
169
|
+
controller.send :"before_#{entity}", :_authenticate_wsse, :except => [
|
170
|
+
:_generate_wsdl, :_invalid_action ]
|
171
|
+
controller.send :"before_#{entity}", :_map_soap_parameters, :except => [
|
172
|
+
:_generate_wsdl, :_invalid_action ]
|
173
|
+
controller.send :"skip_before_#{entity}", :verify_authenticity_token
|
174
|
+
end
|
175
|
+
|
176
|
+
def self.deep_select(hash, result=[], &blk)
|
177
|
+
result += Hash[hash.select(&blk)].values
|
178
|
+
|
179
|
+
hash.each do |key, value|
|
180
|
+
result = deep_select(value, result, &blk) if value.is_a? Hash
|
181
|
+
end
|
182
|
+
|
183
|
+
result
|
184
|
+
end
|
185
|
+
|
186
|
+
def self.deep_replace_href(hash, replace)
|
187
|
+
return replace[hash[:@href]] if hash.has_key?(:@href)
|
188
|
+
|
189
|
+
hash.keys.each do |key, value|
|
190
|
+
hash[key] = deep_replace_href(hash[key], replace) if hash[key].is_a?(Hash)
|
191
|
+
end
|
192
|
+
|
193
|
+
hash
|
194
|
+
end
|
195
|
+
|
196
|
+
private
|
197
|
+
|
198
|
+
def action_spec
|
199
|
+
self.class.soap_actions[soap_action]
|
200
|
+
end
|
201
|
+
|
202
|
+
def request_input_tag
|
203
|
+
action_spec[:request_tag]
|
204
|
+
end
|
205
|
+
|
206
|
+
def soap_action
|
207
|
+
request.env['wash_out.soap_action']
|
208
|
+
end
|
209
|
+
|
210
|
+
def xml_data
|
211
|
+
xml_data = request.env['wash_out.soap_data'].values_at(:envelope, :Envelope).compact.first
|
212
|
+
xml_data = xml_data.values_at(:body, :Body).compact.first || {}
|
213
|
+
return xml_data if soap_config.wsdl_style == "document"
|
214
|
+
xml_data = xml_data.values_at(soap_action.underscore.to_sym, soap_action.to_sym, request_input_tag.to_sym).compact.first || {}
|
215
|
+
end
|
216
|
+
|
217
|
+
end
|
218
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
|
2
|
+
module WashOut
|
3
|
+
class Engine < ::Rails::Engine
|
4
|
+
config.wash_out = ActiveSupport::OrderedOptions.new
|
5
|
+
initializer "wash_out.configuration" do |app|
|
6
|
+
if app.config.wash_out[:catch_xml_errors]
|
7
|
+
app.config.middleware.insert_after 'ActionDispatch::ShowExceptions', WashOut::Middleware
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
class WashOut::Middleware
|
2
|
+
def initialize app
|
3
|
+
@app = app
|
4
|
+
end
|
5
|
+
|
6
|
+
def call env
|
7
|
+
begin
|
8
|
+
@app.call env
|
9
|
+
rescue REXML::ParseException => e
|
10
|
+
self.class.raise_or_render_rexml_parse_error e, env
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.raise_or_render_rexml_parse_error e, env
|
15
|
+
raise e unless env.has_key? 'HTTP_SOAPACTION'
|
16
|
+
|
17
|
+
# Normally input would be a StringIO, but Passenger has a different API:
|
18
|
+
input = env['rack.input']
|
19
|
+
req = if input.respond_to? :string then input.string else input.read end
|
20
|
+
|
21
|
+
env['rack.errors'].puts <<-EOERR
|
22
|
+
WashOut::Exception: #{e.continued_exception} for:
|
23
|
+
#{req}
|
24
|
+
EOERR
|
25
|
+
[400, {'Content-Type' => 'text/xml'},
|
26
|
+
[render_client_soap_fault("Error parsing SOAP Request XML")]]
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.render_client_soap_fault msg
|
30
|
+
xml = Builder::XmlMarkup.new
|
31
|
+
xml.tag! 'soap:Envelope', 'xmlns:soap' => 'http://schemas.xmlsoap.org/soap/envelope/',
|
32
|
+
'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance' do
|
33
|
+
xml.tag! 'soap:Body' do
|
34
|
+
xml.tag! 'soap:Fault', :encodingStyle => 'http://schemas.xmlsoap.org/soap/encoding/' do
|
35
|
+
xml.faultcode 'Client'
|
36
|
+
xml.faultstring msg
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module WashOut
|
2
|
+
module Model
|
3
|
+
def wash_out_columns
|
4
|
+
columns_hash
|
5
|
+
end
|
6
|
+
|
7
|
+
def wash_out_param_map
|
8
|
+
types = {
|
9
|
+
:text => :string,
|
10
|
+
:float => :double,
|
11
|
+
:decimal => :double,
|
12
|
+
:timestamp => :string
|
13
|
+
}
|
14
|
+
map = {}
|
15
|
+
|
16
|
+
wash_out_columns.each do |key, column|
|
17
|
+
type = column.type
|
18
|
+
type = types[type] if types.has_key?(type)
|
19
|
+
map[key] = type
|
20
|
+
end
|
21
|
+
|
22
|
+
map
|
23
|
+
end
|
24
|
+
|
25
|
+
def wash_out_param_name(*args)
|
26
|
+
return name.underscore
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,200 @@
|
|
1
|
+
module WashOut
|
2
|
+
class Param
|
3
|
+
attr_accessor :raw_name
|
4
|
+
attr_accessor :name
|
5
|
+
attr_accessor :map
|
6
|
+
attr_accessor :type
|
7
|
+
attr_accessor :multiplied
|
8
|
+
attr_accessor :value
|
9
|
+
attr_accessor :source_class
|
10
|
+
attr_accessor :soap_config
|
11
|
+
|
12
|
+
# Defines a WSDL parameter with name +name+ and type specifier +type+.
|
13
|
+
# The type specifier format is described in #parse_def.
|
14
|
+
def initialize(soap_config, name, type, multiplied = false)
|
15
|
+
type ||= {}
|
16
|
+
@soap_config = soap_config
|
17
|
+
@name = name.to_s
|
18
|
+
@raw_name = name.to_s
|
19
|
+
@map = {}
|
20
|
+
@multiplied = multiplied
|
21
|
+
|
22
|
+
if soap_config.camelize_wsdl.to_s == 'lower'
|
23
|
+
@name = @name.camelize(:lower)
|
24
|
+
elsif soap_config.camelize_wsdl
|
25
|
+
@name = @name.camelize
|
26
|
+
end
|
27
|
+
|
28
|
+
if type.is_a?(Symbol)
|
29
|
+
@type = type.to_s
|
30
|
+
elsif type.is_a?(Class)
|
31
|
+
@type = 'struct'
|
32
|
+
@map = self.class.parse_def(soap_config, type.wash_out_param_map)
|
33
|
+
@source_class = type
|
34
|
+
else
|
35
|
+
@type = 'struct'
|
36
|
+
@map = self.class.parse_def(soap_config, type)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Converts a generic externally derived Ruby value, such as String or
|
41
|
+
# Hash, to a native Ruby object according to the definition of this type.
|
42
|
+
def load(data, key)
|
43
|
+
if !data.has_key? key
|
44
|
+
raise WashOut::Dispatcher::SOAPError, "Required SOAP parameter '#{key}' is missing"
|
45
|
+
end
|
46
|
+
|
47
|
+
data = data[key]
|
48
|
+
data = [data] if @multiplied && !data.is_a?(Array)
|
49
|
+
|
50
|
+
if struct?
|
51
|
+
data ||= {}
|
52
|
+
if @multiplied
|
53
|
+
data.map do |x|
|
54
|
+
map_struct x do |param, dat, elem|
|
55
|
+
param.load(dat, elem)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
else
|
59
|
+
map_struct data do |param, dat, elem|
|
60
|
+
param.load(dat, elem)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
else
|
64
|
+
operation = case type
|
65
|
+
when 'string'; :to_s
|
66
|
+
when 'integer'; :to_i
|
67
|
+
when 'long'; :to_i
|
68
|
+
when 'double'; :to_f
|
69
|
+
when 'boolean'; lambda{|dat| dat === "0" ? false : !!dat}
|
70
|
+
when 'date'; :to_date
|
71
|
+
when 'datetime'; :to_datetime
|
72
|
+
when 'time'; :to_time
|
73
|
+
when 'base64Binary'; lambda{|dat| Base64.decode64(dat)}
|
74
|
+
else raise RuntimeError, "Invalid WashOut simple type: #{type}"
|
75
|
+
end
|
76
|
+
|
77
|
+
begin
|
78
|
+
if data.nil?
|
79
|
+
data
|
80
|
+
elsif @multiplied
|
81
|
+
return data.map{|x| x.send(operation)} if operation.is_a?(Symbol)
|
82
|
+
return data.map{|x| operation.call(x)} if operation.is_a?(Proc)
|
83
|
+
elsif operation.is_a? Symbol
|
84
|
+
data.send(operation)
|
85
|
+
else
|
86
|
+
operation.call(data)
|
87
|
+
end
|
88
|
+
rescue
|
89
|
+
raise WashOut::Dispatcher::SOAPError, "Invalid SOAP parameter '#{key}' format"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# Checks if this Param defines a complex type.
|
95
|
+
def struct?
|
96
|
+
type == 'struct'
|
97
|
+
end
|
98
|
+
|
99
|
+
def classified?
|
100
|
+
!source_class.nil?
|
101
|
+
end
|
102
|
+
|
103
|
+
def basic_type
|
104
|
+
return name unless classified?
|
105
|
+
return source_class.wash_out_param_name(@soap_config)
|
106
|
+
end
|
107
|
+
|
108
|
+
def xsd_type
|
109
|
+
return 'int' if type.to_s == 'integer'
|
110
|
+
return 'dateTime' if type.to_s == 'datetime'
|
111
|
+
return type
|
112
|
+
end
|
113
|
+
|
114
|
+
# Returns a WSDL namespaced identifier for this type.
|
115
|
+
def namespaced_type
|
116
|
+
struct? ? "tns:#{basic_type}" : "xsd:#{xsd_type}"
|
117
|
+
end
|
118
|
+
|
119
|
+
# Parses a +definition+. The format of the definition is best described
|
120
|
+
# by the following BNF-like grammar.
|
121
|
+
#
|
122
|
+
# simple_type := :string | :integer | :double | :boolean
|
123
|
+
# nested_type := type_hash | simple_type | WashOut::Param instance
|
124
|
+
# type_hash := { :parameter_name => nested_type, ... }
|
125
|
+
# definition := [ WashOut::Param, ... ] |
|
126
|
+
# type_hash |
|
127
|
+
# simple_type
|
128
|
+
#
|
129
|
+
# If a simple type is passed as the +definition+, a single Param is returned
|
130
|
+
# with the +name+ set to "value".
|
131
|
+
# If a WashOut::Param instance is passed as a +nested_type+, the corresponding
|
132
|
+
# +:parameter_name+ is ignored.
|
133
|
+
#
|
134
|
+
# This function returns an array of WashOut::Param objects.
|
135
|
+
def self.parse_def(soap_config, definition)
|
136
|
+
raise RuntimeError, "[] should not be used in your params. Use nil if you want to mark empty set." if definition == []
|
137
|
+
return [] if definition == nil
|
138
|
+
|
139
|
+
if definition.is_a?(Class) && definition.ancestors.include?(WashOut::Type)
|
140
|
+
definition = definition.wash_out_param_map
|
141
|
+
end
|
142
|
+
|
143
|
+
if [Array, Symbol].include?(definition.class)
|
144
|
+
definition = { :value => definition }
|
145
|
+
end
|
146
|
+
|
147
|
+
if definition.is_a? Hash
|
148
|
+
definition.map do |name, opt|
|
149
|
+
if opt.is_a? WashOut::Param
|
150
|
+
opt
|
151
|
+
elsif opt.is_a? Array
|
152
|
+
WashOut::Param.new(soap_config, name, opt[0], true)
|
153
|
+
else
|
154
|
+
WashOut::Param.new(soap_config, name, opt)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
else
|
158
|
+
raise RuntimeError, "Wrong definition: #{definition.inspect}"
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def flat_copy
|
163
|
+
copy = self.class.new(@soap_config, @name, @type.to_sym, @multiplied)
|
164
|
+
copy.raw_name = raw_name
|
165
|
+
copy.source_class = source_class
|
166
|
+
copy
|
167
|
+
end
|
168
|
+
|
169
|
+
def attribute?
|
170
|
+
name[0] == "@"
|
171
|
+
end
|
172
|
+
|
173
|
+
def attr_name
|
174
|
+
raise 'Not attribute' unless attribute?
|
175
|
+
name[1..-1]
|
176
|
+
end
|
177
|
+
|
178
|
+
private
|
179
|
+
|
180
|
+
# Used to load an entire structure.
|
181
|
+
def map_struct(data)
|
182
|
+
unless data.is_a?(Hash)
|
183
|
+
raise WashOut::Dispatcher::SOAPError, "SOAP message structure is broken"
|
184
|
+
end
|
185
|
+
|
186
|
+
data = data.with_indifferent_access
|
187
|
+
struct = {}.with_indifferent_access
|
188
|
+
|
189
|
+
# RUBY18 Enumerable#each_with_object is better, but 1.9 only.
|
190
|
+
@map.map do |param|
|
191
|
+
if data.has_key? param.raw_name
|
192
|
+
param_name = param.attribute? ? param.attr_name : param.raw_name
|
193
|
+
struct[param_name] = yield param, data, param.raw_name
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
struct
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|