wash_out 0.3.6 → 0.4.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.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/
|