wash_out 0.2.6 → 0.3.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/Gemfile.lock +1 -1
- data/README.md +6 -1
- data/app/helpers/wash_out_helper.rb +21 -8
- data/app/views/wash_with_soap/response.builder +8 -5
- data/app/views/wash_with_soap/wsdl.builder +1 -0
- data/lib/wash_out/dispatcher.rb +18 -7
- data/lib/wash_out/param.rb +32 -19
- data/lib/wash_out/version.rb +1 -1
- data/spec/wash_out_spec.rb +98 -15
- metadata +12 -12
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -59,7 +59,7 @@ class RumbasController < ApplicationController
|
|
59
59
|
:args => { :circle => { :center => { :x => :integer,
|
60
60
|
:y => :integer },
|
61
61
|
:radius => :double } },
|
62
|
-
:return => []
|
62
|
+
:return => nil, # [] for wash_out below 0.3.0
|
63
63
|
:to => :add_circle
|
64
64
|
def add_circle
|
65
65
|
circle = params[:circle]
|
@@ -100,6 +100,11 @@ client.wsdl.soap_actions # => [:integer_to_string, :concat, :add_circle]
|
|
100
100
|
result = client.request(:concat) do
|
101
101
|
soap.body = { :a => "123", :b => "abc" }
|
102
102
|
end
|
103
|
+
|
104
|
+
# actual wash_out
|
105
|
+
result.to_hash # => {:concat_reponse => {:value=>"123abc"}}
|
106
|
+
|
107
|
+
# wash_out below 0.3.0 (and this is malformed response so please update)
|
103
108
|
result.to_hash # => {:value=>"123abc"}
|
104
109
|
```
|
105
110
|
|
@@ -1,11 +1,24 @@
|
|
1
1
|
module WashOutHelper
|
2
|
-
def wsdl_data(xml,
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
xml
|
2
|
+
def wsdl_data(xml, params)
|
3
|
+
params.each do |param|
|
4
|
+
if param.multiplied
|
5
|
+
param.value.each{|v| wsdl_data_value xml, param, v}
|
6
|
+
else
|
7
|
+
wsdl_data_value xml, param
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def wsdl_data_value(xml, param, value=false)
|
13
|
+
value ||= param.value.to_s
|
14
|
+
tag_name = "tns:#{param.name}"
|
15
|
+
|
16
|
+
if param.struct?
|
17
|
+
xml.tag! tag_name, "xsi:type" => param.namespaced_type do
|
18
|
+
wsdl_data(xml, param.map)
|
8
19
|
end
|
20
|
+
else
|
21
|
+
xml.tag! tag_name, value, "xsi:type" => param.namespaced_type
|
9
22
|
end
|
10
23
|
end
|
11
24
|
|
@@ -30,8 +43,8 @@ module WashOutHelper
|
|
30
43
|
|
31
44
|
def wsdl_occurence(param, extend_with = {})
|
32
45
|
data = !param.multiplied ? {} : {
|
33
|
-
:minOccurs => 0,
|
34
|
-
:maxOccurs => 'unbounded'
|
46
|
+
"xsi:minOccurs" => 0,
|
47
|
+
"xsi:maxOccurs" => 'unbounded'
|
35
48
|
}
|
36
49
|
|
37
50
|
extend_with.merge(data)
|
@@ -1,7 +1,10 @@
|
|
1
1
|
xml.instruct!
|
2
|
-
xml.Envelope "xmlns:
|
3
|
-
:
|
4
|
-
|
5
|
-
|
2
|
+
xml.tag! "soap:Envelope", "xmlns:soap" => 'http://schemas.xmlsoap.org/soap/envelope/',
|
3
|
+
"xmlns:xsi" => 'http://www.w3.org/2001/XMLSchema-instance',
|
4
|
+
"xmlns:tns" => @namespace do
|
5
|
+
xml.tag! "soap:Body" do
|
6
|
+
xml.tag! "tns:#{@operation}_response" do
|
7
|
+
wsdl_data xml, result
|
8
|
+
end
|
6
9
|
end
|
7
|
-
end
|
10
|
+
end
|
@@ -3,6 +3,7 @@ xml.definitions 'xmlns' => 'http://schemas.xmlsoap.org/wsdl/',
|
|
3
3
|
'xmlns:tns' => @namespace,
|
4
4
|
'xmlns:soap' => 'http://schemas.xmlsoap.org/wsdl/soap/',
|
5
5
|
'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema',
|
6
|
+
"xmlns:xsi" => 'http://www.w3.org/2001/XMLSchema-instance',
|
6
7
|
'xmlns:soap-enc' => 'http://schemas.xmlsoap.org/soap/encoding/',
|
7
8
|
'xmlns:wsdl' => 'http://schemas.xmlsoap.org/wsdl/',
|
8
9
|
'name' => @name,
|
data/lib/wash_out/dispatcher.rb
CHANGED
@@ -5,6 +5,9 @@ module WashOut
|
|
5
5
|
# as a SOAP endpoint. It includes actions for generating WSDL and handling
|
6
6
|
# SOAP requests.
|
7
7
|
module Dispatcher
|
8
|
+
# Default Type namespace
|
9
|
+
NAMESPACE = 'urn:WashOut'
|
10
|
+
|
8
11
|
# A SOAPError exception can be raised to return a correct SOAP error
|
9
12
|
# response.
|
10
13
|
class SOAPError < Exception; end
|
@@ -35,7 +38,7 @@ module WashOut
|
|
35
38
|
# This action generates the WSDL for defined SOAP methods.
|
36
39
|
def _generate_wsdl
|
37
40
|
@map = self.class.soap_actions
|
38
|
-
@namespace =
|
41
|
+
@namespace = NAMESPACE
|
39
42
|
@name = controller_path.gsub('/', '_')
|
40
43
|
|
41
44
|
render :template => 'wash_with_soap/wsdl'
|
@@ -43,17 +46,25 @@ module WashOut
|
|
43
46
|
|
44
47
|
# Render a SOAP response.
|
45
48
|
def _render_soap(result, options)
|
46
|
-
|
47
|
-
|
49
|
+
@namespace = NAMESPACE
|
50
|
+
@operation = soap_action = request.env['wash_out.soap_action']
|
51
|
+
action_spec = self.class.soap_actions[soap_action][:out].clone
|
48
52
|
|
49
53
|
result = { 'value' => result } unless result.is_a? Hash
|
50
54
|
result = HashWithIndifferentAccess.new(result)
|
51
|
-
|
52
|
-
|
53
|
-
|
55
|
+
|
56
|
+
inject = lambda {|data, spec|
|
57
|
+
spec.each do |param|
|
58
|
+
if param.struct?
|
59
|
+
inject.call(data[param.name], param.map)
|
60
|
+
else
|
61
|
+
param.value = data[param.name]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
}
|
54
65
|
|
55
66
|
render :template => 'wash_with_soap/response',
|
56
|
-
:locals => { :result => result }
|
67
|
+
:locals => { :result => inject.call(result, action_spec) }
|
57
68
|
end
|
58
69
|
|
59
70
|
# This action is a fallback for all undefined SOAP actions.
|
data/lib/wash_out/param.rb
CHANGED
@@ -4,6 +4,7 @@ module WashOut
|
|
4
4
|
attr_accessor :map
|
5
5
|
attr_accessor :type
|
6
6
|
attr_accessor :multiplied
|
7
|
+
attr_accessor :value
|
7
8
|
|
8
9
|
# Defines a WSDL parameter with name +name+ and type specifier +type+.
|
9
10
|
# The type specifier format is described in #parse_def.
|
@@ -27,27 +28,26 @@ module WashOut
|
|
27
28
|
def load(data)
|
28
29
|
check_if_missing(data)
|
29
30
|
|
31
|
+
data = Array(data) if @multiplied
|
32
|
+
|
30
33
|
if struct?
|
31
34
|
map_struct(data) { |param, elem| param.load(elem) }
|
32
35
|
else
|
33
|
-
case type
|
34
|
-
when 'string';
|
35
|
-
when 'integer';
|
36
|
-
when 'double';
|
37
|
-
when 'boolean';
|
36
|
+
operation = case type
|
37
|
+
when 'string'; :to_s
|
38
|
+
when 'integer'; :to_i
|
39
|
+
when 'double'; :to_f
|
40
|
+
when 'boolean'; nil # Nori handles that for us
|
38
41
|
else raise RuntimeError, "Invalid WashOut simple type: #{type}"
|
39
42
|
end
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
map_struct(data) { |param, elem| param.store(elem) }
|
49
|
-
else
|
50
|
-
data.to_s
|
43
|
+
|
44
|
+
if operation.nil?
|
45
|
+
data
|
46
|
+
elsif data.is_a? Array
|
47
|
+
data.map{|x| x.send(operation)}
|
48
|
+
else
|
49
|
+
data.send(operation)
|
50
|
+
end
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
@@ -78,24 +78,37 @@ module WashOut
|
|
78
78
|
#
|
79
79
|
# This function returns an array of WashOut::Param objects.
|
80
80
|
def self.parse_def(definition)
|
81
|
-
|
81
|
+
raise RuntimeError, "[] should not be used in your params. Use nil if you want to mark empty set." if definition == []
|
82
|
+
return [] if definition == nil
|
83
|
+
|
84
|
+
if [Array, Symbol].include?(definition.class)
|
85
|
+
definition = { :value => definition }
|
86
|
+
end
|
82
87
|
|
83
88
|
if definition.is_a? Hash
|
84
89
|
definition.map do |name, opt|
|
85
90
|
if opt.is_a? WashOut::Param
|
86
91
|
opt
|
92
|
+
elsif opt.is_a? Array
|
93
|
+
WashOut::Param.new(name, opt[0], true)
|
87
94
|
else
|
88
95
|
WashOut::Param.new(name, opt)
|
89
96
|
end
|
90
97
|
end
|
91
98
|
else
|
92
|
-
definition.
|
99
|
+
raise RuntimeError, "Wrong definition: #{type.inspect}"
|
93
100
|
end
|
94
101
|
end
|
102
|
+
|
103
|
+
def clone
|
104
|
+
copy = self.class.new(@name, @type.to_sym, @multiplied)
|
105
|
+
copy.map = @map.map{|x| x.clone}
|
106
|
+
copy
|
107
|
+
end
|
95
108
|
|
96
109
|
private
|
97
110
|
|
98
|
-
# Used to load
|
111
|
+
# Used to load an entire structure.
|
99
112
|
def map_struct(data)
|
100
113
|
data = data.with_indifferent_access
|
101
114
|
struct = {}.with_indifferent_access
|
data/lib/wash_out/version.rb
CHANGED
data/spec/wash_out_spec.rb
CHANGED
@@ -17,12 +17,12 @@ describe WashOut do
|
|
17
17
|
|
18
18
|
it "should generate WSDL" do
|
19
19
|
mock_controller do
|
20
|
-
soap_action "answer", :args =>
|
20
|
+
soap_action "answer", :args => nil, :return => :int
|
21
21
|
def answer
|
22
22
|
render :soap => "42"
|
23
23
|
end
|
24
24
|
|
25
|
-
soap_action "getArea", :args => { :circle => { :center => { :x => :integer,
|
25
|
+
soap_action "getArea", :args => { :circle => { :center => { :x => [:integer],
|
26
26
|
:y => :integer },
|
27
27
|
:radius => :double } },
|
28
28
|
:return => { :area => :double,
|
@@ -34,7 +34,7 @@ describe WashOut do
|
|
34
34
|
:distance_from_o => Math.sqrt(circle[:center][:x] ** 2 + circle[:center][:y] ** 2) }
|
35
35
|
end
|
36
36
|
end
|
37
|
-
|
37
|
+
|
38
38
|
client = savon_instance
|
39
39
|
xml = Nori.parse client.wsdl.xml
|
40
40
|
|
@@ -42,27 +42,31 @@ describe WashOut do
|
|
42
42
|
# get back just what we have at controller
|
43
43
|
client.wsdl.soap_actions.should == [:answer, :get_area]
|
44
44
|
|
45
|
+
x = xml[:definitions][:types][:schema][:complex_type].find{|x| x[:'@name'] == 'center'}[:sequence][:element].find{|x| x[:'@name'] == 'x'}
|
46
|
+
x[:'@xsi:min_occurs'].should == "0"
|
47
|
+
x[:'@xsi:max_occurs'].should == "unbounded"
|
48
|
+
|
45
49
|
xml[:definitions][:binding][:operation].map{|e| e[:'@name']}.should == ['answer', 'getArea']
|
46
50
|
end
|
47
51
|
|
48
52
|
it "should allow definition of a simple action" do
|
49
53
|
lambda {
|
50
54
|
mock_controller do
|
51
|
-
soap_action "answer", :args =>
|
55
|
+
soap_action "answer", :args => nil, :return => :int
|
52
56
|
end
|
53
57
|
}.should_not raise_exception
|
54
58
|
end
|
55
59
|
|
56
60
|
it "should answer to request without parameters" do
|
57
61
|
mock_controller do
|
58
|
-
soap_action "answer", :args =>
|
62
|
+
soap_action "answer", :args => nil, :return => :int
|
59
63
|
def answer
|
60
64
|
render :soap => "42"
|
61
65
|
end
|
62
66
|
end
|
63
67
|
|
64
68
|
client = savon_instance
|
65
|
-
client.request(:answer).to_hash[:value].should == "42"
|
69
|
+
client.request(:answer).to_hash[:answer_response][:value].should == "42"
|
66
70
|
end
|
67
71
|
|
68
72
|
it "should answer to request with one parameter" do
|
@@ -76,10 +80,10 @@ describe WashOut do
|
|
76
80
|
client = savon_instance
|
77
81
|
client.request(:check_answer) do
|
78
82
|
soap.body = { :value => 42 }
|
79
|
-
end.to_hash[:value].should == true
|
83
|
+
end.to_hash[:check_answer_response][:value].should == true
|
80
84
|
client.request(:check_answer) do
|
81
85
|
soap.body = { :value => 13 }
|
82
|
-
end.to_hash[:value].should == false
|
86
|
+
end.to_hash[:check_answer_response][:value].should == false
|
83
87
|
end
|
84
88
|
|
85
89
|
it "should answer to request with two parameter" do
|
@@ -93,7 +97,7 @@ describe WashOut do
|
|
93
97
|
client = savon_instance
|
94
98
|
client.request(:funky) do
|
95
99
|
soap.body = { :a => 42, :b => 'k' }
|
96
|
-
end.to_hash[:value].should == '420k'
|
100
|
+
end.to_hash[:funky_response][:value].should == '420k'
|
97
101
|
end
|
98
102
|
|
99
103
|
it "should understand nested parameter specifications" do
|
@@ -115,25 +119,27 @@ describe WashOut do
|
|
115
119
|
client.request(:get_area) do
|
116
120
|
soap.body = { :circle => { :center => { :x => 3, :y => 4 },
|
117
121
|
:radius => 5 } }
|
118
|
-
end.to_hash.should == ({ :area => (Math::PI * 25).to_s, :distance_from_o => (5.0).to_s })
|
122
|
+
end.to_hash[:get_area_response].should == ({ :area => (Math::PI * 25).to_s, :distance_from_o => (5.0).to_s })
|
119
123
|
end
|
120
124
|
|
121
125
|
it "should allow arbitrary action names" do
|
126
|
+
name = 'AnswerToTheUltimateQuestionOfLifeTheUniverseAndEverything'
|
127
|
+
|
122
128
|
mock_controller do
|
123
|
-
soap_action
|
124
|
-
:args =>
|
129
|
+
soap_action name,
|
130
|
+
:args => nil, :return => :integer, :to => :answer
|
125
131
|
def answer
|
126
132
|
render :soap => "forty two"
|
127
133
|
end
|
128
134
|
end
|
129
135
|
|
130
136
|
client = savon_instance
|
131
|
-
client.request(
|
137
|
+
client.request(name).to_hash["#{name.underscore}_response".to_sym][:value].should == "forty two"
|
132
138
|
end
|
133
139
|
|
134
140
|
it "should correctly report SOAP errors" do
|
135
141
|
mock_controller do
|
136
|
-
soap_action "error", :args => { :need_error => :boolean }, :return =>
|
142
|
+
soap_action "error", :args => { :need_error => :boolean }, :return => nil
|
137
143
|
def error
|
138
144
|
raise self.class.const_get(:SOAPError), "you wanted one" if params[:need_error]
|
139
145
|
|
@@ -165,7 +171,7 @@ describe WashOut do
|
|
165
171
|
|
166
172
|
it "should be possible to explicitly render a SOAP error" do
|
167
173
|
mock_controller do
|
168
|
-
soap_action "error", :args =>
|
174
|
+
soap_action "error", :args => nil, :return => nil
|
169
175
|
def error
|
170
176
|
render_soap_error "a message"
|
171
177
|
end
|
@@ -176,4 +182,81 @@ describe WashOut do
|
|
176
182
|
client.request(:error)
|
177
183
|
}.should raise_exception(Savon::SOAP::Fault)
|
178
184
|
end
|
185
|
+
|
186
|
+
it "should handle nested returns" do
|
187
|
+
mock_controller do
|
188
|
+
soap_action "gogogo",
|
189
|
+
:args => nil,
|
190
|
+
:return => {
|
191
|
+
:zoo => :string,
|
192
|
+
:boo => {
|
193
|
+
:moo => :string,
|
194
|
+
:doo => :string
|
195
|
+
}
|
196
|
+
}
|
197
|
+
def gogogo
|
198
|
+
render :soap => {
|
199
|
+
:zoo => 'zoo',
|
200
|
+
:boo => {
|
201
|
+
:moo => 'moo',
|
202
|
+
:doo => 'doo'
|
203
|
+
}
|
204
|
+
}
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
savon_instance.request(:gogogo)[:gogogo_response].should == {:zoo=>"zoo", :boo=>{:moo=>"moo", :doo=>"doo", :"@xsi:type"=>"tns:boo"}}
|
209
|
+
end
|
210
|
+
|
211
|
+
it "should handle arrays" do
|
212
|
+
mock_controller do
|
213
|
+
soap_action "rumba",
|
214
|
+
:args => {
|
215
|
+
:rumbas => [:integer]
|
216
|
+
},
|
217
|
+
:return => nil
|
218
|
+
def rumba
|
219
|
+
params.should == {"rumbas" => [1, 2, 3]}
|
220
|
+
render :soap => nil
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
savon_instance.request(:rumba) do
|
225
|
+
soap.body = {
|
226
|
+
:rumbas => [1, 2, 3]
|
227
|
+
}
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
it "should be able to return arrays" do
|
232
|
+
mock_controller do
|
233
|
+
soap_action "rumba",
|
234
|
+
:args => nil,
|
235
|
+
:return => {
|
236
|
+
:rumbas => [:integer]
|
237
|
+
}
|
238
|
+
def rumba
|
239
|
+
render :soap => {:rumbas => [1, 2, 3]}
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
savon_instance.request(:rumba).to_hash[:rumba_response].should == {:rumbas => ["1", "2", "3"]}
|
244
|
+
end
|
245
|
+
|
246
|
+
it "should deprecate old syntax" do
|
247
|
+
# save rspec context check
|
248
|
+
raise_runtime_exception = raise_exception(RuntimeError)
|
249
|
+
|
250
|
+
mock_controller do
|
251
|
+
lambda {
|
252
|
+
soap_action "rumba",
|
253
|
+
:args => :integer,
|
254
|
+
:return => []
|
255
|
+
}.should raise_runtime_exception
|
256
|
+
def rumba
|
257
|
+
render :soap => nil
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
179
262
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wash_out
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,11 +10,11 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2012-01-
|
13
|
+
date: 2012-01-22 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: nori
|
17
|
-
requirement: &
|
17
|
+
requirement: &70332337988240 !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
20
|
- - ! '>='
|
@@ -22,10 +22,10 @@ dependencies:
|
|
22
22
|
version: '0'
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
|
-
version_requirements: *
|
25
|
+
version_requirements: *70332337988240
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: rspec-rails
|
28
|
-
requirement: &
|
28
|
+
requirement: &70332337984940 !ruby/object:Gem::Requirement
|
29
29
|
none: false
|
30
30
|
requirements:
|
31
31
|
- - ! '>='
|
@@ -33,10 +33,10 @@ dependencies:
|
|
33
33
|
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
|
-
version_requirements: *
|
36
|
+
version_requirements: *70332337984940
|
37
37
|
- !ruby/object:Gem::Dependency
|
38
38
|
name: appraisal
|
39
|
-
requirement: &
|
39
|
+
requirement: &70332346016840 !ruby/object:Gem::Requirement
|
40
40
|
none: false
|
41
41
|
requirements:
|
42
42
|
- - ! '>='
|
@@ -44,10 +44,10 @@ dependencies:
|
|
44
44
|
version: '0'
|
45
45
|
type: :development
|
46
46
|
prerelease: false
|
47
|
-
version_requirements: *
|
47
|
+
version_requirements: *70332346016840
|
48
48
|
- !ruby/object:Gem::Dependency
|
49
49
|
name: tzinfo
|
50
|
-
requirement: &
|
50
|
+
requirement: &70332346016420 !ruby/object:Gem::Requirement
|
51
51
|
none: false
|
52
52
|
requirements:
|
53
53
|
- - ! '>='
|
@@ -55,10 +55,10 @@ dependencies:
|
|
55
55
|
version: '0'
|
56
56
|
type: :development
|
57
57
|
prerelease: false
|
58
|
-
version_requirements: *
|
58
|
+
version_requirements: *70332346016420
|
59
59
|
- !ruby/object:Gem::Dependency
|
60
60
|
name: savon
|
61
|
-
requirement: &
|
61
|
+
requirement: &70332346016000 !ruby/object:Gem::Requirement
|
62
62
|
none: false
|
63
63
|
requirements:
|
64
64
|
- - ! '>='
|
@@ -66,7 +66,7 @@ dependencies:
|
|
66
66
|
version: '0'
|
67
67
|
type: :development
|
68
68
|
prerelease: false
|
69
|
-
version_requirements: *
|
69
|
+
version_requirements: *70332346016000
|
70
70
|
description: Dead simple Rails 3 SOAP server library
|
71
71
|
email: boris@roundlake.ru
|
72
72
|
executables: []
|