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.
@@ -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/