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.
@@ -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
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- wash_out (0.3.5)
4
+ wash_out (0.4.0)
5
5
  nori
6
6
 
7
7
  GEM
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 true.
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
- xml.tag! "xsd:complexType", :name => param.name do
35
- xml.tag! "xsd:sequence" do
36
- param.map.each do |value|
37
- more << value if value.struct?
38
- xml.tag! "xsd:element", wsdl_occurence(value, false, :name => value.name, :type => value.namespaced_type)
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
- "xmlns:xsi" => 'http://www.w3.org/2001/XMLSchema-instance',
4
- "xmlns:tns" => @namespace do
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
- xml.tag! "tns:#{@operation}_response" do
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
@@ -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(controller_name), :defaults => { :action => '_action' }
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
@@ -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.snakecase
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
- params = Nori.parse(request.body.read)
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 = params.values_at(:envelope, :Envelope).compact.first
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.name.to_sym
61
+ key = param.raw_name.to_sym
60
62
 
61
63
  if xml_data.has_key? key
62
- @_params[param.name] = param.load(xml_data, key)
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.name], param.map)
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
- result_spec[i].map = data[param.name].map{|e| inject.call(e, param.map)}
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.name]
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)
@@ -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 = false
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
@@ -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'; :to_s
51
- when 'integer'; :to_i
52
- when 'double'; :to_f
53
- when 'boolean'; nil # Nori handles that for us
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:#{name}" : "xsd:#{type}"
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: #{type.inspect}"
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.name
130
- struct[param.name] = yield param, data, param.name
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
 
@@ -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
- # RUBY18 1.8 does not have force_encoding.
15
- soap_action.force_encoding('UTF-8') if soap_action.respond_to? :force_encoding
16
+ soap_action.gsub!(/^\"(.*)\"$/, '\1')
16
17
 
17
- soap_action.gsub!(/^\"(.*)\"$/, '\1')
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
@@ -1,3 +1,3 @@
1
1
  module WashOut
2
- VERSION = "0.3.6"
2
+ VERSION = "0.4.0"
3
3
  end
@@ -35,7 +35,7 @@ Dummy::Application.routes.draw do
35
35
  wash_out :api
36
36
  end
37
37
 
38
- def savon_instance
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
@@ -4,7 +4,8 @@ require 'spec_helper'
4
4
 
5
5
  describe WashOut do
6
6
  before(:each) do
7
- WashOut::Engine.snakecase = true
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'] == 'center'}[:sequence][:element].find{|x| x[:'@name'] == 'x'}
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.snakecase = false
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
- savon_instance.request(:gogogo)[:gogogo_response].should == {:zoo=>"zoo", :boo=>{:moo=>"moo", :doo=>"doo", :"@xsi:type"=>"tns:boo"}}
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
- savon_instance.request(:rumba) do
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
- savon_instance.request(:rumba) do
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
- savon_instance.request(:rumba).to_hash[:rumba_response].should == {:value => ["1", "2", "3"]}
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
- savon_instance.request(:rumba)[:rumba_response].should == {
390
+ client.request(:rumba)[:rumba_response].should == {
357
391
  :rumbas => [
358
- {:zombies => "suck1",:puppies => "rock1", :"@xsi:type"=>"tns:rumbas"},
359
- {:zombies => "suck2", :puppies => "rock2", :"@xsi:type"=>"tns:rumbas" }
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
- savon_instance.request(:rumba)[:rumba_response].should == {
409
+ client.request(:rumba)[:rumba_response].should == {
376
410
  :value => [
377
411
  {
378
412
  :rumbas => {
379
413
  :zombies => "100000",
380
- :"@xsi:type" => "tns:rumbas"
414
+ :"@xsi:type" => "tns:Rumbas"
381
415
  },
382
- :"@xsi:type" => "tns:value"
416
+ :"@xsi:type" => "tns:Value"
383
417
  },
384
418
  {
385
419
  :rumbas => {
386
420
  :zombies => "2",
387
- :"@xsi:type" => "tns:rumbas"
421
+ :"@xsi:type" => "tns:Rumbas"
388
422
  },
389
- :"@xsi:type"=>"tns:value"
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
- savon_instance.request(:rumba)[:rumba_response].should == {
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:puppies"
472
+ :"@xsi:type" => "tns:Puppies"
439
473
  },
440
474
  {
441
475
  :kittens => "5",
442
- :"@xsi:type" => "tns:puppies"
476
+ :"@xsi:type" => "tns:Puppies"
443
477
  }
444
478
  ],
445
- :"@xsi:type"=>"tns:rumbas"
479
+ :"@xsi:type"=>"tns:Rumbas"
446
480
  },
447
481
  {
448
482
  :zombies => "def",
449
483
  :puppies => {
450
484
  :kittens => "4",
451
- :"@xsi:type" => "tns:puppies"
485
+ :"@xsi:type" => "tns:Puppies"
452
486
  },
453
- :"@xsi:type"=>"tns:rumbas"
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.3.6
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-04-06 00:00:00.000000000 Z
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: &70309445502780 !ruby/object:Gem::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: *70309445502780
25
+ version_requirements: *70304488309860
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: rspec-rails
28
- requirement: &70309445499440 !ruby/object:Gem::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: *70309445499440
36
+ version_requirements: *70304488307640
37
37
  - !ruby/object:Gem::Dependency
38
38
  name: appraisal
39
- requirement: &70309445483420 !ruby/object:Gem::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: *70309445483420
47
+ version_requirements: *70304488307020
48
48
  - !ruby/object:Gem::Dependency
49
49
  name: tzinfo
50
- requirement: &70309457795880 !ruby/object:Gem::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: *70309457795880
58
+ version_requirements: *70304488305960
59
59
  - !ruby/object:Gem::Dependency
60
60
  name: savon
61
- requirement: &70309457794620 !ruby/object:Gem::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: *70309457794620
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/