wash_out 0.3.6 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +15 -0
- data/Gemfile.lock +1 -1
- data/README.md +41 -1
- data/app/helpers/wash_out_helper.rb +14 -7
- data/app/views/wash_with_soap/response.builder +6 -3
- data/app/views/wash_with_soap/wsdl.builder +2 -1
- data/lib/wash_out.rb +8 -2
- data/lib/wash_out/dispatcher.rb +24 -18
- data/lib/wash_out/engine.rb +9 -2
- data/lib/wash_out/model.rb +25 -0
- data/lib/wash_out/param.rb +41 -9
- data/lib/wash_out/router.rb +7 -7
- data/lib/wash_out/type.rb +21 -0
- data/lib/wash_out/version.rb +1 -1
- data/spec/spec_helper.rb +2 -2
- data/spec/wash_out/param_spec.rb +26 -0
- data/spec/wash_out/type_spec.rb +23 -0
- data/spec/wash_out_spec.rb +89 -37
- metadata +16 -12
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,17 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 0.4.0
|
4
|
+
|
5
|
+
* Better content-type for the response (#33) [@inossidabile][]
|
6
|
+
* Date type support (#18) [@inossidabile][]
|
7
|
+
* Avoid duplication of inner types [@inossidabile][]
|
8
|
+
* Output camelization support [@inossidabile][]
|
9
|
+
* External types declaration support (#21, #41) [@inossidabile][]
|
10
|
+
|
11
|
+
## 0.3.7
|
12
|
+
|
13
|
+
* Better empty parameters handling (#26, #30) [@rngtng][]
|
14
|
+
|
3
15
|
## 0.3.6
|
4
16
|
|
5
17
|
* Unicorn stream reading bug (#20)
|
@@ -37,3 +49,6 @@
|
|
37
49
|
* The syntax for empty set (no input params or output params) changed from [] to nil.
|
38
50
|
* SOAP response format improved. All results are now wrapped into tns:messages instead of soap:Body.
|
39
51
|
* Arrays (minOccurs/maxOccurs) are now supported with `:foo => [:integer]` syntax.
|
52
|
+
|
53
|
+
[@inossidabile]: https://twitter.com/#!/_inossidabile
|
54
|
+
[@rngtng]: https://github.com/rngtng
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -122,6 +122,38 @@ result.to_hash # => {:value=>"123abc"}
|
|
122
122
|
|
123
123
|
Take a look at [WashOut sample application](https://github.com/roundlake/wash_out-sample).
|
124
124
|
|
125
|
+
Reusable types
|
126
|
+
---------
|
127
|
+
|
128
|
+
Basic inline types definition is fast and furious for the simple cases. You have an option to describe SOAP types
|
129
|
+
inside separate classes for the complex ones. Here's the way to do that:
|
130
|
+
|
131
|
+
```ruby
|
132
|
+
class Fluffy < WashOut::Type
|
133
|
+
map(
|
134
|
+
:universe => {
|
135
|
+
:name => :string,
|
136
|
+
:age => :int
|
137
|
+
}
|
138
|
+
)
|
139
|
+
end
|
140
|
+
|
141
|
+
class FluffyContainer < WashOut::Type
|
142
|
+
type_name 'fluffy_con'
|
143
|
+
map :fluffy => Fluffy
|
144
|
+
end
|
145
|
+
```
|
146
|
+
|
147
|
+
To use defined type inside your inline declaration, pass the class instead of type symbol (`:fluffy => Fluffy`).
|
148
|
+
|
149
|
+
Note that WashOut extends the `ActiveRecord` so every model you use is already a WashOut::Type and can be used
|
150
|
+
inside your interface declarations.
|
151
|
+
|
152
|
+
.Net C# interoperability
|
153
|
+
---------
|
154
|
+
|
155
|
+
Please note that .Net clients require you to use :int instead of :integer
|
156
|
+
|
125
157
|
Configuration
|
126
158
|
---------
|
127
159
|
|
@@ -130,7 +162,9 @@ Use `config.wash_out...` inside your environment configuration to setup WashOut.
|
|
130
162
|
Available properties are:
|
131
163
|
|
132
164
|
* **namespace**: SOAP namespace to use. Default is `urn:WashOut`.
|
133
|
-
* **snakecase**: Determines if WashOut should modify parameters keys to snakecase. Default is
|
165
|
+
* **snakecase**: *(DEPRECATED SINCE 0.4.0)* Determines if WashOut should modify parameters keys to snakecase. Default is `false`.
|
166
|
+
* **snakecase_input**: Determines if WashOut should modify parameters keys to snakecase. Default is `false`.
|
167
|
+
* **camelize_wsdl**: Determinse if WashOut should camelize types within WSDL and responses. Default is `false`.
|
134
168
|
|
135
169
|
Credits
|
136
170
|
-------
|
@@ -140,6 +174,12 @@ Credits
|
|
140
174
|
* Boris Staal ([@_inossidabile](http://twitter.com/#!/_inossidabile))
|
141
175
|
* Peter Zotov ([@whitequark](http://twitter.com/#!/whitequark))
|
142
176
|
|
177
|
+
Contributors
|
178
|
+
------------
|
179
|
+
|
180
|
+
* Björn Nilsson ([@Bjorn-Nilsson](https://github.com/Bjorn-Nilsson))
|
181
|
+
* Tobias Bielohlawek ([@rngtng](https://github.com/rngtng))
|
182
|
+
|
143
183
|
LICENSE
|
144
184
|
-------
|
145
185
|
|
@@ -7,6 +7,7 @@ module WashOutHelper
|
|
7
7
|
if !param.multiplied
|
8
8
|
xml.tag! tag_name, param.value, "xsi:type" => param.namespaced_type
|
9
9
|
else
|
10
|
+
param.value = [] unless param.value.is_a?(Array)
|
10
11
|
param.value.each do |v|
|
11
12
|
xml.tag! tag_name, v, "xsi:type" => param.namespaced_type
|
12
13
|
end
|
@@ -27,22 +28,28 @@ module WashOutHelper
|
|
27
28
|
end
|
28
29
|
end
|
29
30
|
|
30
|
-
def wsdl_type(xml, param)
|
31
|
+
def wsdl_type(xml, param, defined=[])
|
31
32
|
more = []
|
32
33
|
|
33
34
|
if param.struct?
|
34
|
-
|
35
|
-
xml.tag! "xsd:
|
36
|
-
|
37
|
-
|
38
|
-
|
35
|
+
if !defined.include?(param.basic_type)
|
36
|
+
xml.tag! "xsd:complexType", :name => param.basic_type do
|
37
|
+
xml.tag! "xsd:sequence" do
|
38
|
+
param.map.each do |value|
|
39
|
+
more << value if value.struct?
|
40
|
+
xml.tag! "xsd:element", wsdl_occurence(value, false, :name => value.name, :type => value.namespaced_type)
|
41
|
+
end
|
39
42
|
end
|
40
43
|
end
|
44
|
+
|
45
|
+
defined << param.basic_type
|
46
|
+
elsif !param.classified?
|
47
|
+
raise RuntimeError, "Duplicate use of `#{param.basic_type}` type name. Consider using classified types."
|
41
48
|
end
|
42
49
|
end
|
43
50
|
|
44
51
|
more.each do |p|
|
45
|
-
wsdl_type xml, p
|
52
|
+
wsdl_type xml, p, defined
|
46
53
|
end
|
47
54
|
end
|
48
55
|
|
@@ -1,9 +1,12 @@
|
|
1
1
|
xml.instruct!
|
2
2
|
xml.tag! "soap:Envelope", "xmlns:soap" => 'http://schemas.xmlsoap.org/soap/envelope/',
|
3
|
-
|
4
|
-
|
3
|
+
"xmlns:xsd" => 'http://www.w3.org/2001/XMLSchema',
|
4
|
+
"xmlns:xsi" => 'http://www.w3.org/2001/XMLSchema-instance',
|
5
|
+
"xmlns:tns" => @namespace do
|
5
6
|
xml.tag! "soap:Body" do
|
6
|
-
|
7
|
+
key = "tns:#{@operation}#{WashOut::Engine.camelize_wsdl ? 'Response' : '_response'}"
|
8
|
+
|
9
|
+
xml.tag! key do
|
7
10
|
wsdl_data xml, result
|
8
11
|
end
|
9
12
|
end
|
@@ -10,9 +10,10 @@ xml.definitions 'xmlns' => 'http://schemas.xmlsoap.org/wsdl/',
|
|
10
10
|
'targetNamespace' => @namespace do
|
11
11
|
xml.types do
|
12
12
|
xml.tag! "schema", :targetNamespace => @namespace, :xmlns => 'http://www.w3.org/2001/XMLSchema' do
|
13
|
+
defined = []
|
13
14
|
@map.each do |operation, formats|
|
14
15
|
(formats[:in] + formats[:out]).each do |p|
|
15
|
-
wsdl_type xml, p
|
16
|
+
wsdl_type xml, p, defined
|
16
17
|
end
|
17
18
|
end
|
18
19
|
end
|
data/lib/wash_out.rb
CHANGED
@@ -3,18 +3,24 @@ require 'wash_out/param'
|
|
3
3
|
require 'wash_out/dispatcher'
|
4
4
|
require 'wash_out/soap'
|
5
5
|
require 'wash_out/router'
|
6
|
+
require 'wash_out/type'
|
7
|
+
require 'wash_out/model'
|
6
8
|
|
7
9
|
module ActionDispatch::Routing
|
8
10
|
class Mapper
|
9
11
|
# Adds the routes for a SOAP endpoint at +controller+.
|
10
12
|
def wash_out(controller_name, options={})
|
13
|
+
options.reverse_merge!(@scope) if @scope
|
14
|
+
controller_class_name = [options[:module], controller_name].compact.join("/")
|
15
|
+
|
11
16
|
match "#{controller_name}/wsdl" => "#{controller_name}#_generate_wsdl", :via => :get
|
12
|
-
match "#{controller_name}/action" => WashOut::Router.new(
|
17
|
+
match "#{controller_name}/action" => WashOut::Router.new(controller_class_name), :defaults => { :action => '_action' }
|
13
18
|
end
|
14
19
|
end
|
15
20
|
end
|
16
21
|
|
17
22
|
Mime::Type.register "application/soap+xml", :soap
|
23
|
+
ActiveRecord::Base.send :extend, WashOut::Model
|
18
24
|
|
19
25
|
ActionController::Renderers.add :soap do |what, options|
|
20
26
|
_render_soap(what, options)
|
@@ -25,4 +31,4 @@ module ActionView
|
|
25
31
|
cattr_accessor :washout_namespace
|
26
32
|
@@washout_namespace = false
|
27
33
|
end
|
28
|
-
end
|
34
|
+
end
|
data/lib/wash_out/dispatcher.rb
CHANGED
@@ -11,23 +11,29 @@ module WashOut
|
|
11
11
|
|
12
12
|
# This filter parses the SOAP request and puts it into +params+ array.
|
13
13
|
def _parse_soap_parameters
|
14
|
-
soap_action = request.env['wash_out.soap_action']
|
15
|
-
action_spec = self.class.soap_actions[soap_action]
|
16
|
-
|
17
14
|
# Do not interfere with project-space Nori setup
|
18
15
|
strip = Nori.strip_namespaces?
|
19
16
|
convert = Nori.convert_tags?
|
20
17
|
Nori.strip_namespaces = true
|
21
18
|
|
22
|
-
if WashOut::Engine.
|
19
|
+
if WashOut::Engine.snakecase_input
|
23
20
|
Nori.convert_tags_to { |tag| tag.snakecase.to_sym }
|
24
21
|
else
|
25
22
|
Nori.convert_tags_to { |tag| tag.to_sym }
|
26
23
|
end
|
27
24
|
|
28
|
-
|
25
|
+
@_params = Nori.parse(request.body.read)
|
26
|
+
|
27
|
+
# Reset Nori setup to project-space
|
28
|
+
Nori.strip_namespaces = strip
|
29
|
+
Nori.convert_tags_to convert
|
30
|
+
end
|
31
|
+
|
32
|
+
def _map_soap_parameters
|
33
|
+
soap_action = request.env['wash_out.soap_action']
|
34
|
+
action_spec = self.class.soap_actions[soap_action]
|
29
35
|
|
30
|
-
xml_data =
|
36
|
+
xml_data = @_params.values_at(:envelope, :Envelope).compact.first
|
31
37
|
xml_data = xml_data.values_at(:body, :Body).compact.first
|
32
38
|
xml_data = xml_data.values_at(soap_action.underscore.to_sym, soap_action.to_sym).compact.first || {}
|
33
39
|
|
@@ -49,17 +55,13 @@ module WashOut
|
|
49
55
|
|
50
56
|
xml_data = strip_empty_nodes.call(xml_data)
|
51
57
|
|
52
|
-
# Reset Nori setup to project-space
|
53
|
-
Nori.strip_namespaces = strip
|
54
|
-
Nori.convert_tags_to convert
|
55
|
-
|
56
58
|
@_params = HashWithIndifferentAccess.new
|
57
59
|
|
58
60
|
action_spec[:in].each do |param|
|
59
|
-
key = param.
|
61
|
+
key = param.raw_name.to_sym
|
60
62
|
|
61
63
|
if xml_data.has_key? key
|
62
|
-
@_params[param.
|
64
|
+
@_params[param.raw_name] = param.load(xml_data, key)
|
63
65
|
end
|
64
66
|
end
|
65
67
|
end
|
@@ -90,15 +92,16 @@ module WashOut
|
|
90
92
|
|
91
93
|
# Inline complex structure
|
92
94
|
if param.struct? && !param.multiplied
|
93
|
-
result_spec[i].map = inject.call(data[param.
|
95
|
+
result_spec[i].map = inject.call(data[param.raw_name], param.map)
|
94
96
|
|
95
97
|
# Inline array of complex structures
|
96
98
|
elsif param.struct? && param.multiplied
|
97
|
-
|
99
|
+
data ||= {} #fallback in case no data is given
|
100
|
+
data[param.raw_name] = [] unless data[param.raw_name].is_a?(Array)
|
101
|
+
result_spec[i].map = data[param.raw_name].map{|e| inject.call(e, param.map)}
|
98
102
|
|
99
103
|
else
|
100
|
-
result_spec[i].value = data[param.
|
101
|
-
|
104
|
+
result_spec[i].value = data[param.raw_name]
|
102
105
|
end
|
103
106
|
end
|
104
107
|
|
@@ -106,7 +109,8 @@ module WashOut
|
|
106
109
|
}
|
107
110
|
|
108
111
|
render :template => 'wash_with_soap/response',
|
109
|
-
:locals => { :result => inject.call(result, action_spec) }
|
112
|
+
:locals => { :result => inject.call(result, action_spec) },
|
113
|
+
:content_type => 'text/xml'
|
110
114
|
end
|
111
115
|
|
112
116
|
# This action is a fallback for all undefined SOAP actions.
|
@@ -120,7 +124,8 @@ module WashOut
|
|
120
124
|
# exception from a rescue_from handler. Hence this function is a public API.
|
121
125
|
def render_soap_error(message)
|
122
126
|
render :template => 'wash_with_soap/error', :status => 500,
|
123
|
-
:locals => { :error_message => message }
|
127
|
+
:locals => { :error_message => message },
|
128
|
+
:content_type => 'text/xml'
|
124
129
|
end
|
125
130
|
|
126
131
|
private
|
@@ -129,6 +134,7 @@ module WashOut
|
|
129
134
|
controller.send :rescue_from, SOAPError, :with => :_render_soap_exception
|
130
135
|
controller.send :helper, :wash_out
|
131
136
|
controller.send :before_filter, :_parse_soap_parameters, :except => [ :_generate_wsdl, :_invalid_action ]
|
137
|
+
controller.send :before_filter, :_map_soap_parameters, :except => [ :_generate_wsdl, :_invalid_action ]
|
132
138
|
end
|
133
139
|
|
134
140
|
def _render_soap_exception(error)
|
data/lib/wash_out/engine.rb
CHANGED
@@ -2,11 +2,14 @@ module WashOut
|
|
2
2
|
class Engine < ::Rails::Engine
|
3
3
|
class << self
|
4
4
|
attr_accessor :namespace
|
5
|
-
attr_accessor :snakecase
|
5
|
+
attr_accessor :snakecase, :snakecase_input, :camelize_wsdl
|
6
6
|
end
|
7
7
|
|
8
8
|
self.namespace = 'urn:WashOut'
|
9
|
-
self.snakecase =
|
9
|
+
self.snakecase = nil
|
10
|
+
|
11
|
+
self.snakecase_input = false
|
12
|
+
self.camelize_wsdl = false
|
10
13
|
|
11
14
|
config.wash_out = ActiveSupport::OrderedOptions.new
|
12
15
|
|
@@ -14,6 +17,10 @@ module WashOut
|
|
14
17
|
app.config.wash_out.each do |key, value|
|
15
18
|
self.class.send "#{key}=", value
|
16
19
|
end
|
20
|
+
|
21
|
+
unless self.class.snakecase.nil?
|
22
|
+
raise "Usage of wash_out.snakecase is deprecated. You should use wash_out.snakecase_input and wash_out.camelize_wsdl"
|
23
|
+
end
|
17
24
|
end
|
18
25
|
end
|
19
26
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module WashOut
|
2
|
+
module Model
|
3
|
+
def wash_out_param_map
|
4
|
+
types = {
|
5
|
+
:text => :string,
|
6
|
+
:float => :double,
|
7
|
+
:decimal => :double,
|
8
|
+
:timestamp => :string
|
9
|
+
}
|
10
|
+
map = {}
|
11
|
+
|
12
|
+
columns_hash.each do |key, column|
|
13
|
+
type = column.type
|
14
|
+
type = types[type] if types.has_key?(type)
|
15
|
+
map[key] = type
|
16
|
+
end
|
17
|
+
|
18
|
+
map
|
19
|
+
end
|
20
|
+
|
21
|
+
def wash_out_param_name
|
22
|
+
return name.underscore
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/wash_out/param.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
module WashOut
|
2
2
|
class Param
|
3
|
+
attr_accessor :raw_name
|
3
4
|
attr_accessor :name
|
4
5
|
attr_accessor :map
|
5
6
|
attr_accessor :type
|
6
7
|
attr_accessor :multiplied
|
7
8
|
attr_accessor :value
|
9
|
+
attr_accessor :source_class
|
8
10
|
|
9
11
|
# Defines a WSDL parameter with name +name+ and type specifier +type+.
|
10
12
|
# The type specifier format is described in #parse_def.
|
@@ -12,11 +14,22 @@ module WashOut
|
|
12
14
|
type ||= {}
|
13
15
|
|
14
16
|
@name = name.to_s
|
17
|
+
@raw_name = name.to_s
|
15
18
|
@map = {}
|
16
19
|
@multiplied = multiplied
|
17
20
|
|
21
|
+
if WashOut::Engine.camelize_wsdl.to_s == 'lower'
|
22
|
+
@name = @name.camelize(:lower)
|
23
|
+
elsif WashOut::Engine.camelize_wsdl
|
24
|
+
@name = @name.camelize
|
25
|
+
end
|
26
|
+
|
18
27
|
if type.is_a?(Symbol)
|
19
28
|
@type = type.to_s
|
29
|
+
elsif type.is_a?(Class)
|
30
|
+
@type = 'struct'
|
31
|
+
@map = self.class.parse_def(type.wash_out_param_map)
|
32
|
+
@source_class = type
|
20
33
|
else
|
21
34
|
@type = 'struct'
|
22
35
|
@map = self.class.parse_def(type)
|
@@ -47,10 +60,13 @@ module WashOut
|
|
47
60
|
end
|
48
61
|
else
|
49
62
|
operation = case type
|
50
|
-
when 'string';
|
51
|
-
when 'integer';
|
52
|
-
when 'double';
|
53
|
-
when 'boolean';
|
63
|
+
when 'string'; :to_s
|
64
|
+
when 'integer'; :to_i
|
65
|
+
when 'double'; :to_f
|
66
|
+
when 'boolean'; nil # Nori handles that for us
|
67
|
+
when 'date'; :to_date
|
68
|
+
when 'datetime'; :to_datetime
|
69
|
+
when 'time'; :to_time
|
54
70
|
else raise RuntimeError, "Invalid WashOut simple type: #{type}"
|
55
71
|
end
|
56
72
|
|
@@ -69,9 +85,23 @@ module WashOut
|
|
69
85
|
type == 'struct'
|
70
86
|
end
|
71
87
|
|
88
|
+
def classified?
|
89
|
+
!source_class.nil?
|
90
|
+
end
|
91
|
+
|
92
|
+
def basic_type
|
93
|
+
return name unless classified?
|
94
|
+
return source_class.wash_out_param_name
|
95
|
+
end
|
96
|
+
|
97
|
+
def xsd_type
|
98
|
+
return 'dateTime' if type.to_s == 'datetime'
|
99
|
+
return type
|
100
|
+
end
|
101
|
+
|
72
102
|
# Returns a WSDL namespaced identifier for this type.
|
73
103
|
def namespaced_type
|
74
|
-
struct? ? "tns:#{
|
104
|
+
struct? ? "tns:#{basic_type}" : "xsd:#{xsd_type}"
|
75
105
|
end
|
76
106
|
|
77
107
|
# Parses a +definition+. The format of the definition is best described
|
@@ -94,7 +124,7 @@ module WashOut
|
|
94
124
|
raise RuntimeError, "[] should not be used in your params. Use nil if you want to mark empty set." if definition == []
|
95
125
|
return [] if definition == nil
|
96
126
|
|
97
|
-
if [Array, Symbol].include?(definition.class)
|
127
|
+
if [Array, Symbol, Class].include?(definition.class)
|
98
128
|
definition = { :value => definition }
|
99
129
|
end
|
100
130
|
|
@@ -109,12 +139,14 @@ module WashOut
|
|
109
139
|
end
|
110
140
|
end
|
111
141
|
else
|
112
|
-
raise RuntimeError, "Wrong definition: #{
|
142
|
+
raise RuntimeError, "Wrong definition: #{definition.inspect}"
|
113
143
|
end
|
114
144
|
end
|
115
145
|
|
116
146
|
def flat_copy
|
117
147
|
copy = self.class.new(@name, @type.to_sym, @multiplied)
|
148
|
+
copy.raw_name = raw_name
|
149
|
+
copy
|
118
150
|
end
|
119
151
|
|
120
152
|
private
|
@@ -126,8 +158,8 @@ module WashOut
|
|
126
158
|
|
127
159
|
# RUBY18 Enumerable#each_with_object is better, but 1.9 only.
|
128
160
|
@map.map do |param|
|
129
|
-
if data.has_key? param.
|
130
|
-
struct[param.
|
161
|
+
if data.has_key? param.raw_name
|
162
|
+
struct[param.raw_name] = yield param, data, param.raw_name
|
131
163
|
end
|
132
164
|
end
|
133
165
|
|
data/lib/wash_out/router.rb
CHANGED
@@ -9,14 +9,14 @@ module WashOut
|
|
9
9
|
def call(env)
|
10
10
|
controller = @controller_name.constantize
|
11
11
|
|
12
|
-
soap_action = env['HTTP_SOAPACTION']
|
12
|
+
if soap_action = env['HTTP_SOAPACTION']
|
13
|
+
# RUBY18 1.8 does not have force_encoding.
|
14
|
+
soap_action.force_encoding('UTF-8') if soap_action.respond_to? :force_encoding
|
13
15
|
|
14
|
-
|
15
|
-
soap_action.force_encoding('UTF-8') if soap_action.respond_to? :force_encoding
|
16
|
+
soap_action.gsub!(/^\"(.*)\"$/, '\1')
|
16
17
|
|
17
|
-
|
18
|
-
|
19
|
-
env['wash_out.soap_action'] = soap_action
|
18
|
+
env['wash_out.soap_action'] = soap_action
|
19
|
+
end
|
20
20
|
|
21
21
|
action_spec = controller.soap_actions[soap_action]
|
22
22
|
if action_spec
|
@@ -28,4 +28,4 @@ module WashOut
|
|
28
28
|
controller.action(action).call(env)
|
29
29
|
end
|
30
30
|
end
|
31
|
-
end
|
31
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module WashOut
|
2
|
+
class Type
|
3
|
+
def self.type_name(value)
|
4
|
+
@param_type_name = value
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.map(value)
|
8
|
+
raise RuntimeError, "Wrong definition: #{value.inspect}" unless value.is_a?(Hash)
|
9
|
+
@param_map = value
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.wash_out_param_map
|
13
|
+
@param_map
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.wash_out_param_name
|
17
|
+
return name.underscore unless @param_type_name
|
18
|
+
@param_type_name
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/wash_out/version.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -35,7 +35,7 @@ Dummy::Application.routes.draw do
|
|
35
35
|
wash_out :api
|
36
36
|
end
|
37
37
|
|
38
|
-
def
|
38
|
+
def client
|
39
39
|
Savon::Client.new do
|
40
40
|
wsdl.document = 'http://app/api/wsdl'
|
41
41
|
end
|
@@ -48,4 +48,4 @@ def mock_controller(&block)
|
|
48
48
|
|
49
49
|
class_exec &block if block
|
50
50
|
}
|
51
|
-
end
|
51
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
#encoding:utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe WashOut::Param do
|
6
|
+
|
7
|
+
it "loads custom_types" do
|
8
|
+
class Abraka1 < WashOut::Type
|
9
|
+
map(
|
10
|
+
:test => :string
|
11
|
+
)
|
12
|
+
end
|
13
|
+
class Abraka2 < WashOut::Type
|
14
|
+
type_name 'test'
|
15
|
+
map :foo => Abraka1
|
16
|
+
end
|
17
|
+
|
18
|
+
map = WashOut::Param.parse_def Abraka2
|
19
|
+
|
20
|
+
map.should be_a_kind_of(Array)
|
21
|
+
map[0].name.should == 'Value'
|
22
|
+
map[0].map[0].name.should == 'Foo'
|
23
|
+
map[0].map[0].map[0].name.should == 'Test'
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
#encoding:utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe WashOut::Type do
|
6
|
+
|
7
|
+
it "defines custom type" do
|
8
|
+
class Abraka1 < WashOut::Type
|
9
|
+
map :test => :string
|
10
|
+
end
|
11
|
+
class Abraka2 < WashOut::Type
|
12
|
+
type_name 'test'
|
13
|
+
map :foo => Abraka1
|
14
|
+
end
|
15
|
+
|
16
|
+
Abraka1.wash_out_param_name.should == 'abraka1'
|
17
|
+
Abraka1.wash_out_param_map.should == {:test => :string}
|
18
|
+
|
19
|
+
Abraka2.wash_out_param_name.should == 'test'
|
20
|
+
Abraka2.wash_out_param_map.should == {:foo => Abraka1}
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
data/spec/wash_out_spec.rb
CHANGED
@@ -4,7 +4,8 @@ require 'spec_helper'
|
|
4
4
|
|
5
5
|
describe WashOut do
|
6
6
|
before(:each) do
|
7
|
-
WashOut::Engine.
|
7
|
+
WashOut::Engine.snakecase_input = true
|
8
|
+
WashOut::Engine.camelize_wsdl = true
|
8
9
|
WashOut::Engine.namespace = false
|
9
10
|
end
|
10
11
|
|
@@ -38,20 +39,25 @@ describe WashOut do
|
|
38
39
|
render :soap => { :area => Math::PI * circle[:radius] ** 2,
|
39
40
|
:distance_from_o => Math.sqrt(circle[:center][:x] ** 2 + circle[:center][:y] ** 2) }
|
40
41
|
end
|
42
|
+
|
43
|
+
soap_action "rocky", :args => { :circle1 => { :x => :integer } },
|
44
|
+
:return => { :circle2 => { :y => :integer } }
|
45
|
+
def rocky; end
|
41
46
|
end
|
42
47
|
|
43
|
-
client = savon_instance
|
44
48
|
xml = Nori.parse client.wsdl.xml
|
45
49
|
|
46
|
-
# Savon underscores method names so we
|
50
|
+
# Savon underscores method names so we
|
47
51
|
# get back just what we have at controller
|
48
|
-
client.wsdl.soap_actions.should == [:answer, :get_area]
|
52
|
+
client.wsdl.soap_actions.should == [:answer, :get_area, :rocky]
|
49
53
|
|
50
|
-
x = xml[:definitions][:types][:schema][:complex_type].find{|x| x[:'@name'] == '
|
54
|
+
x = xml[:definitions][:types][:schema][:complex_type].find{|x| x[:'@name'] == 'Center'}[:sequence][:element].find{|x| x[:'@name'] == 'X'}
|
51
55
|
x[:'@min_occurs'].should == "0"
|
52
56
|
x[:'@max_occurs'].should == "unbounded"
|
53
57
|
|
54
|
-
xml[:definitions][:binding][:operation].map{|e| e[:'@name']}.should == ['answer', 'getArea']
|
58
|
+
xml[:definitions][:binding][:operation].map{|e| e[:'@name']}.should == ['answer', 'getArea', 'rocky']
|
59
|
+
|
60
|
+
client.wsdl.xml.include?('<xsd:complexType name="Circle1">').should == true
|
55
61
|
end
|
56
62
|
|
57
63
|
it "should allow definition of a simple action" do
|
@@ -70,7 +76,6 @@ describe WashOut do
|
|
70
76
|
end
|
71
77
|
end
|
72
78
|
|
73
|
-
client = savon_instance
|
74
79
|
client.request(:answer).to_hash[:answer_response][:value].should == "42"
|
75
80
|
end
|
76
81
|
|
@@ -82,7 +87,6 @@ describe WashOut do
|
|
82
87
|
end
|
83
88
|
end
|
84
89
|
|
85
|
-
client = savon_instance
|
86
90
|
client.request(:answer).to_hash[:answer_response][:value].should == "42"
|
87
91
|
end
|
88
92
|
|
@@ -94,7 +98,6 @@ describe WashOut do
|
|
94
98
|
end
|
95
99
|
end
|
96
100
|
|
97
|
-
client = savon_instance
|
98
101
|
client.request(:answer) do
|
99
102
|
soap.body = { :a => '' }
|
100
103
|
end.to_hash[:answer_response][:a].should == {:"@xsi:type"=>"xsd:string"}
|
@@ -108,7 +111,6 @@ describe WashOut do
|
|
108
111
|
end
|
109
112
|
end
|
110
113
|
|
111
|
-
client = savon_instance
|
112
114
|
client.request(:check_answer) do
|
113
115
|
soap.body = { :value => 42 }
|
114
116
|
end.to_hash[:check_answer_response][:value].should == true
|
@@ -118,7 +120,8 @@ describe WashOut do
|
|
118
120
|
end
|
119
121
|
|
120
122
|
it "should handle snakecase option properly" do
|
121
|
-
WashOut::Engine.
|
123
|
+
WashOut::Engine.snakecase_input = false
|
124
|
+
WashOut::Engine.camelize_wsdl = false
|
122
125
|
|
123
126
|
mock_controller do
|
124
127
|
soap_action "rocknroll", :args => {:ZOMG => :string}, :return => nil
|
@@ -128,12 +131,49 @@ describe WashOut do
|
|
128
131
|
end
|
129
132
|
end
|
130
133
|
|
131
|
-
client = savon_instance
|
132
134
|
client.request(:rocknroll) do
|
133
135
|
soap.body = { "ZOMG" => 'yam!' }
|
134
136
|
end
|
135
137
|
end
|
136
138
|
|
139
|
+
context "optional arrays" do
|
140
|
+
it "should answer for simple structure" do
|
141
|
+
mock_controller do
|
142
|
+
soap_action "rocknroll",
|
143
|
+
:args => nil, :return => { :my_value => [:integer] }
|
144
|
+
def rocknroll
|
145
|
+
render :soap => {}
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
client.request(:rocknroll).to_hash[:rocknroll_response].should be_nil
|
150
|
+
end
|
151
|
+
|
152
|
+
it "should answer for complex structure" do
|
153
|
+
mock_controller do
|
154
|
+
soap_action "rocknroll",
|
155
|
+
:args => nil, :return => { :my_value => [{ :value => :integer}] }
|
156
|
+
def rocknroll
|
157
|
+
render :soap => {}
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
client.request(:rocknroll).to_hash[:rocknroll_response].should be_nil
|
162
|
+
end
|
163
|
+
|
164
|
+
it "should answer for nested complex structure" do
|
165
|
+
mock_controller do
|
166
|
+
soap_action "rocknroll",
|
167
|
+
:args => nil, :return => { :my_value => { :my_array => [{ :value => :integer}] } }
|
168
|
+
def rocknroll
|
169
|
+
render :soap => {}
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
client.request(:rocknroll).to_hash[:rocknroll_response][:my_value].should == { :"@xsi:type" => "tns:MyValue" }
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
137
177
|
it "should answer to request with two parameter" do
|
138
178
|
mock_controller do
|
139
179
|
soap_action "funky", :args => { :a => :integer, :b => :string }, :return => :string
|
@@ -142,7 +182,6 @@ describe WashOut do
|
|
142
182
|
end
|
143
183
|
end
|
144
184
|
|
145
|
-
client = savon_instance
|
146
185
|
client.request(:funky) do
|
147
186
|
soap.body = { :a => 42, :b => 'k' }
|
148
187
|
end.to_hash[:funky_response][:value].should == '420k'
|
@@ -163,7 +202,6 @@ describe WashOut do
|
|
163
202
|
end
|
164
203
|
end
|
165
204
|
|
166
|
-
client = savon_instance
|
167
205
|
client.request(:get_area) do
|
168
206
|
soap.body = { :circle => { :center => { :x => 3, :y => 4 },
|
169
207
|
:radius => 5 } }
|
@@ -181,7 +219,6 @@ describe WashOut do
|
|
181
219
|
end
|
182
220
|
end
|
183
221
|
|
184
|
-
client = savon_instance
|
185
222
|
client.request(name).to_hash["#{name.underscore}_response".to_sym][:value].should == "forty two"
|
186
223
|
end
|
187
224
|
|
@@ -195,7 +232,6 @@ describe WashOut do
|
|
195
232
|
end
|
196
233
|
end
|
197
234
|
|
198
|
-
client = savon_instance
|
199
235
|
lambda {
|
200
236
|
client.request(:error) do
|
201
237
|
soap.body = { :need_error => false }
|
@@ -211,7 +247,6 @@ describe WashOut do
|
|
211
247
|
it "should report a SOAP error if method does not exists" do
|
212
248
|
mock_controller
|
213
249
|
|
214
|
-
client = savon_instance
|
215
250
|
lambda {
|
216
251
|
client.request(:nonexistent)
|
217
252
|
}.should raise_exception(Savon::SOAP::Fault)
|
@@ -225,7 +260,6 @@ describe WashOut do
|
|
225
260
|
end
|
226
261
|
end
|
227
262
|
|
228
|
-
client = savon_instance
|
229
263
|
lambda {
|
230
264
|
client.request(:error)
|
231
265
|
}.should raise_exception(Savon::SOAP::Fault)
|
@@ -253,7 +287,7 @@ describe WashOut do
|
|
253
287
|
end
|
254
288
|
end
|
255
289
|
|
256
|
-
|
290
|
+
client.request(:gogogo)[:gogogo_response].should == {:zoo=>"zoo", :boo=>{:moo=>"moo", :doo=>"doo", :"@xsi:type"=>"tns:Boo"}}
|
257
291
|
end
|
258
292
|
|
259
293
|
it "should handle arrays" do
|
@@ -269,7 +303,7 @@ describe WashOut do
|
|
269
303
|
end
|
270
304
|
end
|
271
305
|
|
272
|
-
|
306
|
+
client.request(:rumba) do
|
273
307
|
soap.body = {
|
274
308
|
:rumbas => [1, 2, 3]
|
275
309
|
}
|
@@ -280,7 +314,7 @@ describe WashOut do
|
|
280
314
|
mock_controller do
|
281
315
|
soap_action "rumba",
|
282
316
|
:args => {
|
283
|
-
:rumbas => [ {
|
317
|
+
:rumbas => [ {
|
284
318
|
:zombies => :string,
|
285
319
|
:puppies => :string
|
286
320
|
} ]
|
@@ -297,7 +331,7 @@ describe WashOut do
|
|
297
331
|
end
|
298
332
|
end
|
299
333
|
|
300
|
-
|
334
|
+
client.request(:rumba) do
|
301
335
|
soap.body = {
|
302
336
|
:rumbas => [
|
303
337
|
{:zombies => 'suck', :puppies => 'rock'},
|
@@ -317,7 +351,7 @@ describe WashOut do
|
|
317
351
|
end
|
318
352
|
end
|
319
353
|
|
320
|
-
|
354
|
+
client.request(:rumba).to_hash[:rumba_response].should == {:value => ["1", "2", "3"]}
|
321
355
|
end
|
322
356
|
|
323
357
|
it "should deprecate old syntax" do
|
@@ -353,10 +387,10 @@ describe WashOut do
|
|
353
387
|
end
|
354
388
|
end
|
355
389
|
|
356
|
-
|
390
|
+
client.request(:rumba)[:rumba_response].should == {
|
357
391
|
:rumbas => [
|
358
|
-
{:zombies => "suck1",:puppies => "rock1", :"@xsi:type"=>"tns:
|
359
|
-
{:zombies => "suck2", :puppies => "rock2", :"@xsi:type"=>"tns:
|
392
|
+
{:zombies => "suck1",:puppies => "rock1", :"@xsi:type"=>"tns:Rumbas"},
|
393
|
+
{:zombies => "suck2", :puppies => "rock2", :"@xsi:type"=>"tns:Rumbas" }
|
360
394
|
]
|
361
395
|
}
|
362
396
|
end
|
@@ -372,21 +406,21 @@ describe WashOut do
|
|
372
406
|
end
|
373
407
|
end
|
374
408
|
|
375
|
-
|
409
|
+
client.request(:rumba)[:rumba_response].should == {
|
376
410
|
:value => [
|
377
411
|
{
|
378
412
|
:rumbas => {
|
379
413
|
:zombies => "100000",
|
380
|
-
:"@xsi:type" => "tns:
|
414
|
+
:"@xsi:type" => "tns:Rumbas"
|
381
415
|
},
|
382
|
-
:"@xsi:type" => "tns:
|
416
|
+
:"@xsi:type" => "tns:Value"
|
383
417
|
},
|
384
418
|
{
|
385
419
|
:rumbas => {
|
386
420
|
:zombies => "2",
|
387
|
-
:"@xsi:type" => "tns:
|
421
|
+
:"@xsi:type" => "tns:Rumbas"
|
388
422
|
},
|
389
|
-
:"@xsi:type"=>"tns:
|
423
|
+
:"@xsi:type"=>"tns:Value"
|
390
424
|
}
|
391
425
|
]
|
392
426
|
}
|
@@ -428,31 +462,49 @@ describe WashOut do
|
|
428
462
|
end
|
429
463
|
end
|
430
464
|
|
431
|
-
|
465
|
+
client.request(:rumba)[:rumba_response].should == {
|
432
466
|
:rumbas => [
|
433
467
|
{
|
434
468
|
:zombies => "abc",
|
435
469
|
:puppies => [
|
436
470
|
{
|
437
471
|
:kittens => "1",
|
438
|
-
:"@xsi:type" => "tns:
|
472
|
+
:"@xsi:type" => "tns:Puppies"
|
439
473
|
},
|
440
474
|
{
|
441
475
|
:kittens => "5",
|
442
|
-
:"@xsi:type" => "tns:
|
476
|
+
:"@xsi:type" => "tns:Puppies"
|
443
477
|
}
|
444
478
|
],
|
445
|
-
:"@xsi:type"=>"tns:
|
479
|
+
:"@xsi:type"=>"tns:Rumbas"
|
446
480
|
},
|
447
481
|
{
|
448
482
|
:zombies => "def",
|
449
483
|
:puppies => {
|
450
484
|
:kittens => "4",
|
451
|
-
:"@xsi:type" => "tns:
|
485
|
+
:"@xsi:type" => "tns:Puppies"
|
452
486
|
},
|
453
|
-
:"@xsi:type"=>"tns:
|
487
|
+
:"@xsi:type"=>"tns:Rumbas"
|
454
488
|
}
|
455
489
|
]
|
456
490
|
}
|
457
491
|
end
|
492
|
+
|
493
|
+
it "handles dates" do
|
494
|
+
mock_controller do
|
495
|
+
soap_action "date",
|
496
|
+
:args => :date,
|
497
|
+
:return => :nil
|
498
|
+
def date
|
499
|
+
params[:value].should == Date.parse('2000-12-30')
|
500
|
+
render :soap => nil
|
501
|
+
end
|
502
|
+
end
|
503
|
+
|
504
|
+
client.request(:date) do
|
505
|
+
soap.body = {
|
506
|
+
:value => '2000-12-30'
|
507
|
+
}
|
508
|
+
end
|
509
|
+
end
|
458
510
|
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.4.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-
|
13
|
+
date: 2012-05-14 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: nori
|
17
|
-
requirement: &
|
17
|
+
requirement: &70304488309860 !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: *70304488309860
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: rspec-rails
|
28
|
-
requirement: &
|
28
|
+
requirement: &70304488307640 !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: *70304488307640
|
37
37
|
- !ruby/object:Gem::Dependency
|
38
38
|
name: appraisal
|
39
|
-
requirement: &
|
39
|
+
requirement: &70304488307020 !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: *70304488307020
|
48
48
|
- !ruby/object:Gem::Dependency
|
49
49
|
name: tzinfo
|
50
|
-
requirement: &
|
50
|
+
requirement: &70304488305960 !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: *70304488305960
|
59
59
|
- !ruby/object:Gem::Dependency
|
60
60
|
name: savon
|
61
|
-
requirement: &
|
61
|
+
requirement: &70304488303260 !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: *70304488303260
|
70
70
|
description: Dead simple Rails 3 SOAP server library
|
71
71
|
email: boris@roundlake.ru
|
72
72
|
executables: []
|
@@ -94,9 +94,11 @@ files:
|
|
94
94
|
- lib/wash_out.rb
|
95
95
|
- lib/wash_out/dispatcher.rb
|
96
96
|
- lib/wash_out/engine.rb
|
97
|
+
- lib/wash_out/model.rb
|
97
98
|
- lib/wash_out/param.rb
|
98
99
|
- lib/wash_out/router.rb
|
99
100
|
- lib/wash_out/soap.rb
|
101
|
+
- lib/wash_out/type.rb
|
100
102
|
- lib/wash_out/version.rb
|
101
103
|
- spec/dummy/Rakefile
|
102
104
|
- spec/dummy/app/controllers/application_controller.rb
|
@@ -123,6 +125,8 @@ files:
|
|
123
125
|
- spec/dummy/script/rails
|
124
126
|
- spec/spec_helper.rb
|
125
127
|
- spec/support/httpi-rack.rb
|
128
|
+
- spec/wash_out/param_spec.rb
|
129
|
+
- spec/wash_out/type_spec.rb
|
126
130
|
- spec/wash_out_spec.rb
|
127
131
|
- wash_out.gemspec
|
128
132
|
homepage: http://roundlake.github.com/wash_out/
|