wash_out 0.10.0.beta.1 → 0.10.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.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -1
  3. data/.travis.yml +23 -3
  4. data/Appraisals +11 -5
  5. data/Gemfile +2 -2
  6. data/README.md +66 -2
  7. data/Rakefile +6 -7
  8. data/app/helpers/wash_out_helper.rb +49 -18
  9. data/app/views/{wash_with_soap → wash_out}/document/error.builder +0 -0
  10. data/app/views/{wash_with_soap → wash_out}/document/response.builder +1 -3
  11. data/app/views/{wash_with_soap → wash_out}/document/wsdl.builder +15 -15
  12. data/app/views/{wash_with_soap → wash_out}/rpc/error.builder +0 -0
  13. data/app/views/{wash_with_soap → wash_out}/rpc/response.builder +1 -3
  14. data/app/views/{wash_with_soap → wash_out}/rpc/wsdl.builder +16 -16
  15. data/gemfiles/rails_3.1.3.gemfile +20 -0
  16. data/gemfiles/rails_3.2.12.gemfile +20 -0
  17. data/gemfiles/rails_4.0.0.gemfile +19 -0
  18. data/gemfiles/rails_4.1.0.gemfile +19 -0
  19. data/gemfiles/rails_4.2.0.gemfile +19 -0
  20. data/lib/wash_out.rb +48 -16
  21. data/lib/wash_out/configurable.rb +41 -0
  22. data/lib/wash_out/dispatcher.rb +212 -0
  23. data/lib/wash_out/engine.rb +12 -0
  24. data/lib/wash_out/middleware.rb +41 -0
  25. data/lib/wash_out/model.rb +29 -0
  26. data/lib/wash_out/param.rb +43 -16
  27. data/lib/wash_out/router.rb +95 -0
  28. data/lib/wash_out/soap.rb +48 -0
  29. data/lib/wash_out/soap_config.rb +93 -0
  30. data/lib/wash_out/type.rb +20 -13
  31. data/lib/wash_out/version.rb +1 -1
  32. data/lib/wash_out/wsse.rb +29 -10
  33. data/spec/dummy/config/environments/test.rb +1 -0
  34. data/spec/lib/wash_out/dispatcher_spec.rb +28 -13
  35. data/spec/lib/wash_out/middleware_spec.rb +33 -0
  36. data/spec/lib/wash_out/param_spec.rb +47 -17
  37. data/spec/lib/wash_out/router_spec.rb +22 -0
  38. data/spec/lib/wash_out/type_spec.rb +9 -9
  39. data/spec/lib/wash_out_spec.rb +139 -87
  40. data/spec/spec_helper.rb +7 -1
  41. metadata +32 -25
  42. data/lib/wash_out/exceptions/programmer_error.rb +0 -10
  43. data/lib/wash_out/exceptions/soap_error.rb +0 -19
  44. data/lib/wash_out/middlewares/catcher.rb +0 -42
  45. data/lib/wash_out/middlewares/router.rb +0 -132
  46. data/lib/wash_out/rails/active_record.rb +0 -27
  47. data/lib/wash_out/rails/controller.rb +0 -201
  48. data/lib/wash_out/rails/engine.rb +0 -74
  49. data/spec/lib/wash_out/rack_spec.rb +0 -55
@@ -27,7 +27,11 @@ RSpec.configure do |config|
27
27
 
28
28
  config.mock_with :rspec
29
29
  config.before(:all) do
30
- WashOut::Rails::Engine.config.wash_out = WashOut::Rails::Engine.defaults
30
+ WashOut::Engine.config.wash_out = {
31
+ snakecase_input: false,
32
+ camelize_wsdl: false,
33
+ namespace: false
34
+ }
31
35
  end
32
36
 
33
37
  config.after(:suite) do
@@ -52,6 +56,8 @@ end
52
56
  def mock_controller(options = {}, &block)
53
57
  Object.send :remove_const, :ApiController if defined?(ApiController)
54
58
  Object.send :const_set, :ApiController, Class.new(ApplicationController) {
59
+ include RSpec::Matchers
60
+
55
61
  soap_service options.reverse_merge({
56
62
  snakecase_input: true,
57
63
  camelize_wsdl: true,
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.10.0.beta.1
4
+ version: 0.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Boris Staal
@@ -9,20 +9,20 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-12-07 00:00:00.000000000 Z
12
+ date: 2016-02-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: nori
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
- - - '>='
18
+ - - ">="
19
19
  - !ruby/object:Gem::Version
20
20
  version: 2.0.0
21
21
  type: :runtime
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
- - - '>='
25
+ - - ">="
26
26
  - !ruby/object:Gem::Version
27
27
  version: 2.0.0
28
28
  description: Dead simple Rails 3 SOAP server library
@@ -31,9 +31,9 @@ executables: []
31
31
  extensions: []
32
32
  extra_rdoc_files: []
33
33
  files:
34
- - .gitignore
35
- - .rspec
36
- - .travis.yml
34
+ - ".gitignore"
35
+ - ".rspec"
36
+ - ".travis.yml"
37
37
  - Appraisals
38
38
  - CHANGELOG.md
39
39
  - Gemfile
@@ -42,22 +42,28 @@ files:
42
42
  - README.md
43
43
  - Rakefile
44
44
  - app/helpers/wash_out_helper.rb
45
- - app/views/wash_with_soap/document/error.builder
46
- - app/views/wash_with_soap/document/response.builder
47
- - app/views/wash_with_soap/document/wsdl.builder
48
- - app/views/wash_with_soap/rpc/error.builder
49
- - app/views/wash_with_soap/rpc/response.builder
50
- - app/views/wash_with_soap/rpc/wsdl.builder
45
+ - app/views/wash_out/document/error.builder
46
+ - app/views/wash_out/document/response.builder
47
+ - app/views/wash_out/document/wsdl.builder
48
+ - app/views/wash_out/rpc/error.builder
49
+ - app/views/wash_out/rpc/response.builder
50
+ - app/views/wash_out/rpc/wsdl.builder
51
+ - gemfiles/rails_3.1.3.gemfile
52
+ - gemfiles/rails_3.2.12.gemfile
53
+ - gemfiles/rails_4.0.0.gemfile
54
+ - gemfiles/rails_4.1.0.gemfile
55
+ - gemfiles/rails_4.2.0.gemfile
51
56
  - init.rb
52
57
  - lib/wash_out.rb
53
- - lib/wash_out/exceptions/programmer_error.rb
54
- - lib/wash_out/exceptions/soap_error.rb
55
- - lib/wash_out/middlewares/catcher.rb
56
- - lib/wash_out/middlewares/router.rb
58
+ - lib/wash_out/configurable.rb
59
+ - lib/wash_out/dispatcher.rb
60
+ - lib/wash_out/engine.rb
61
+ - lib/wash_out/middleware.rb
62
+ - lib/wash_out/model.rb
57
63
  - lib/wash_out/param.rb
58
- - lib/wash_out/rails/active_record.rb
59
- - lib/wash_out/rails/controller.rb
60
- - lib/wash_out/rails/engine.rb
64
+ - lib/wash_out/router.rb
65
+ - lib/wash_out/soap.rb
66
+ - lib/wash_out/soap_config.rb
61
67
  - lib/wash_out/type.rb
62
68
  - lib/wash_out/version.rb
63
69
  - lib/wash_out/wsse.rb
@@ -85,8 +91,9 @@ files:
85
91
  - spec/dummy/public/stylesheets/.gitkeep
86
92
  - spec/dummy/script/rails
87
93
  - spec/lib/wash_out/dispatcher_spec.rb
94
+ - spec/lib/wash_out/middleware_spec.rb
88
95
  - spec/lib/wash_out/param_spec.rb
89
- - spec/lib/wash_out/rack_spec.rb
96
+ - spec/lib/wash_out/router_spec.rb
90
97
  - spec/lib/wash_out/type_spec.rb
91
98
  - spec/lib/wash_out_spec.rb
92
99
  - spec/spec_helper.rb
@@ -102,17 +109,17 @@ require_paths:
102
109
  - lib
103
110
  required_ruby_version: !ruby/object:Gem::Requirement
104
111
  requirements:
105
- - - '>='
112
+ - - ">="
106
113
  - !ruby/object:Gem::Version
107
114
  version: '0'
108
115
  required_rubygems_version: !ruby/object:Gem::Requirement
109
116
  requirements:
110
- - - '>'
117
+ - - ">="
111
118
  - !ruby/object:Gem::Version
112
- version: 1.3.1
119
+ version: '0'
113
120
  requirements: []
114
121
  rubyforge_project:
115
- rubygems_version: 2.0.3
122
+ rubygems_version: 2.2.5
116
123
  signing_key:
117
124
  specification_version: 4
118
125
  summary: Dead simple Rails 3 SOAP server library
@@ -1,10 +0,0 @@
1
- module WashOut
2
- #
3
- # An exception reflection unexpected error
4
- #
5
- # Used internally to remark badly composited definitions of
6
- # actions and other violations
7
- #
8
- class ProgrammerError < Exception
9
- end
10
- end
@@ -1,19 +0,0 @@
1
- module WashOut
2
- #
3
- # An exception reflecting expected logical error
4
- #
5
- # Such exception (or its descendants) will be intercepted and rendered
6
- # into proper SOAP error XML response.
7
- #
8
- class SOAPError < Exception
9
- attr_accessor :code
10
-
11
- def initialize(message, code=nil)
12
- super(message)
13
- @code = code
14
- end
15
- end
16
- end
17
-
18
- # Backward compatibility hack
19
- class SOAPError < WashOut::SOAPError; end
@@ -1,42 +0,0 @@
1
- module WashOut
2
- module Middlewares
3
- class Catcher
4
- def initialize(app)
5
- @app = app
6
- end
7
-
8
- def call(env)
9
- @app.call env
10
- rescue REXML::ParseException => e
11
- raise e unless env.has_key?('HTTP_SOAPACTION')
12
-
13
- input = env['rack.input'].respond_to?(:string) ? env['rack.input'].string
14
- : env['rack.input'].read
15
-
16
- env['rack.errors'].puts <<-TEXT
17
- WashOut::Exception: #{e.continued_exception} for:
18
- #{input}
19
- TEXT
20
-
21
- [
22
- 400,
23
- {'Content-Type' => 'text/xml'},
24
- [self.class.render_client_soap_fault("Error parsing SOAP Request XML")]
25
- ]
26
- end
27
-
28
- def self.render_client_soap_fault(msg)
29
- xml = Builder::XmlMarkup.new
30
- xml.tag! 'soap:Envelope', 'xmlns:soap' => 'http://schemas.xmlsoap.org/soap/envelope/',
31
- 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance' do
32
- xml.tag! 'soap:Body' do
33
- xml.tag! 'soap:Fault', :encodingStyle => 'http://schemas.xmlsoap.org/soap/encoding/' do
34
- xml.faultcode 'Client'
35
- xml.faultstring msg
36
- end
37
- end
38
- end
39
- end
40
- end
41
- end
42
- end
@@ -1,132 +0,0 @@
1
- require 'nori'
2
-
3
- module WashOut
4
- module Middlewares
5
- #
6
- # This class is a Rack middleware used to route SOAP requests to a proper
7
- # action of a given SOAP controller.
8
- #
9
- # WashOut engine adds routing helper `wash_out` that registeres this middleware
10
- # as a main responder internally.
11
- #
12
- # @see WashOut::Rails::Engine
13
- #
14
- class Router
15
- def initialize(controller_name)
16
- @controller_name = "#{controller_name.to_s}_controller".camelize
17
- end
18
-
19
- def parse_soap_action(env)
20
- return env['wash_out.soap_action'] if env['wash_out.soap_action']
21
-
22
- # SOAPACTION is expected to come in quotes that have to be stripped
23
- soap_action = env['HTTP_SOAPACTION'].to_s.gsub(/^"(.*)"$/, '\1')
24
-
25
- # Clients can sometimes send empty SOAPACTION to avoid duplication
26
- # In this cases we have to get it from the body
27
- if soap_action.blank?
28
- soap_action = nori.parse(soap_body env)[:Envelope][:Body].keys.first.to_s
29
- end
30
-
31
- # RUBY18
32
- soap_action.force_encoding('UTF-8') if soap_action.respond_to? :force_encoding
33
-
34
- # And finally we have to strip namespace from the action name
35
- if @controller.soap_config.namespace
36
- namespace = Regexp.escape @controller.soap_config.namespace.to_s
37
- soap_action.gsub!(/^(#{namespace}(\/|#)?)?([^"]*)$/, '\3')
38
- end
39
-
40
- env['wash_out.soap_action'] = soap_action
41
- end
42
-
43
- def parse_soap_parameters(env)
44
- return env['wash_out.soap_data'] if env['wash_out.soap_data']
45
-
46
- env['wash_out.soap_data'] = nori(@controller.soap_config.snakecase_input).parse(soap_body env)
47
-
48
- # Seeking for in-XML substitutions marked by attribute `id`
49
- references = self.class.deep_select(env['wash_out.soap_data']) do |k,v|
50
- v.is_a?(Hash) && v.has_key?(:@id)
51
- end
52
-
53
- # Replacing the found substitutions with nodes having proper `href` attribute
54
- unless references.blank?
55
- replaces = {}
56
- references.each { |r| replaces['#'+r[:@id]] = r }
57
-
58
- env['wash_out.soap_data'] = self.class.deep_replace_href(env['wash_out.soap_data'], replaces)
59
- end
60
-
61
- env['wash_out.soap_data']
62
- end
63
-
64
- #
65
- # Nori parser builder
66
- #
67
- def nori(snakecase=false)
68
- Nori.new(
69
- parser: @controller.soap_config.parser,
70
- strip_namespaces: true,
71
- advanced_typecasting: true,
72
- convert_tags_to: (
73
- snakecase ? lambda { |tag| tag.snakecase.to_sym }
74
- : lambda { |tag| tag.to_sym }
75
- )
76
- )
77
- end
78
-
79
- #
80
- # Universal body accessor working with any Rack server
81
- #
82
- def soap_body(env)
83
- env['rack.input'].respond_to?(:string) ? env['rack.input'].string
84
- : env['rack.input'].read
85
- end
86
-
87
- def call(env)
88
- @controller = @controller_name.constantize
89
-
90
- parse_soap_action(env)
91
- parse_soap_parameters(env)
92
-
93
- action_spec = @controller.soap_actions[env['wash_out.soap_action']]
94
-
95
- if action_spec
96
- action = action_spec[:to]
97
- else
98
- action = '_invalid_action'
99
- end
100
-
101
- @controller.action(action).call(env)
102
- end
103
-
104
- #
105
- # Recursively seeks XML tree for nodes matching given block
106
- #
107
- def self.deep_select(hash, result=[], &blk)
108
- result += Hash[hash.select(&blk)].values
109
-
110
- hash.each do |key, value|
111
- result = deep_select(value, result, &blk) if value.is_a? Hash
112
- end
113
-
114
- result
115
- end
116
-
117
- #
118
- # Recursively replaces nodes in the tree matching the given
119
- # map of `href` attributes
120
- #
121
- def self.deep_replace_href(hash, replace)
122
- return replace[hash[:@href]] if hash.has_key?(:@href)
123
-
124
- hash.keys.each do |key, value|
125
- hash[key] = deep_replace_href(hash[key], replace) if hash[key].is_a?(Hash)
126
- end
127
-
128
- hash
129
- end
130
- end
131
- end
132
- end
@@ -1,27 +0,0 @@
1
- module WashOut
2
- module Rails
3
- module ActiveRecord
4
- def wash_out_param_map
5
- types = {
6
- text: :string,
7
- float: :double,
8
- decimal: :double,
9
- timestamp: :string
10
- }
11
- map = {}
12
-
13
- columns_hash.each do |key, column|
14
- type = column.type
15
- type = types[type] if types.has_key?(type)
16
- map[key] = type
17
- end
18
-
19
- map
20
- end
21
-
22
- def wash_out_param_name(soap_config = nil)
23
- WashOut.normalize(name.underscore.gsub('/', '.'), soap_config)
24
- end
25
- end
26
- end
27
- end
@@ -1,201 +0,0 @@
1
- module WashOut
2
- module Rails
3
- # The WashOut::Rails::Controller module should be included in a controller acting
4
- # as a SOAP endpoint. It includes actions for generating WSDL and handling
5
- # SOAP requests.
6
- module Controller extend ActiveSupport::Concern
7
-
8
- included do
9
- helper :wash_out
10
-
11
- around_filter :_catch_soap_errors
12
- before_filter :_authenticate_wsse, :except => [ :_generate_wsdl, :_invalid_action ]
13
- before_filter :_map_soap_parameters, :except => [ :_generate_wsdl, :_invalid_action ]
14
-
15
- skip_before_filter :verify_authenticity_token
16
-
17
- cattr_reader :soap_config
18
- cattr_accessor :soap_actions
19
-
20
- self.soap_actions = {}
21
- end
22
-
23
- module ClassMethods
24
- #
25
- # Overrides WashOut settings on a controller level
26
- #
27
- def soap_config=(options)
28
- class_variable_set :@@soap_config, OpenStruct.new(
29
- WashOut::Rails::Engine.config.wash_out.merge(options)
30
- )
31
- end
32
-
33
- #
34
- # Define a SOAP action +action+. The function has two required +options+:
35
- # :args and :return. Each is a type +definition+ of format described in
36
- # WashOut::Param#parse_def.
37
- #
38
- # An optional option :to can be passed to allow for names of SOAP actions
39
- # which are not valid Ruby function names.
40
- #
41
- def soap_action(action, options={})
42
- exposed_name = if action.is_a?(Symbol)
43
- WashOut.normalize(action, soap_config)
44
- else
45
- action.to_s
46
- end
47
-
48
- self.soap_actions[exposed_name] = options.merge(
49
- in: WashOut::Param.parse_def(soap_config, options[:args]),
50
- out: WashOut::Param.parse_def(soap_config, options[:return]),
51
- to: options[:to] || action.to_s
52
- )
53
- end
54
- end
55
-
56
- #
57
- # Render a SOAP error response.
58
- #
59
- def render_soap_error(message, code=nil)
60
- render :template => "wash_with_soap/#{soap_config.wsdl_style}/error", :status => 500,
61
- :layout => false,
62
- :locals => { :error_message => message, :error_code => (code || 'Server') },
63
- :content_type => 'text/xml'
64
- end
65
-
66
- def _authenticate_wsse
67
- begin
68
- xml_security = env['wash_out.soap_data'].values_at(:envelope, :Envelope).compact.first
69
- xml_security = xml_security.values_at(:header, :Header).compact.first
70
- xml_security = xml_security.values_at(:security, :Security).compact.first
71
- username_token = xml_security.values_at(:username_token, :UsernameToken).compact.first
72
- rescue
73
- username_token = nil
74
- end
75
-
76
- WashOut::Wsse.authenticate(soap_config, username_token)
77
-
78
- request.env['WSSE_TOKEN'] = username_token.with_indifferent_access unless username_token.blank?
79
- end
80
-
81
- def _map_soap_parameters
82
- soap_action = request.env['wash_out.soap_action']
83
- action_spec = self.class.soap_actions[soap_action]
84
-
85
- xml_data = env['wash_out.soap_data'].values_at(:envelope, :Envelope).compact.first
86
- xml_data = xml_data.values_at(:body, :Body).compact.first
87
- xml_data = xml_data.values_at(soap_action.underscore.to_sym,
88
- soap_action.to_sym).compact.first || {}
89
-
90
- strip_empty_nodes = lambda{|hash|
91
- hash.keys.each do |key|
92
- if hash[key].is_a? Hash
93
- value = hash[key].delete_if{|k, v| key.to_s[0] == '@'}
94
-
95
- if value.length > 0
96
- hash[key] = strip_empty_nodes.call(value)
97
- else
98
- hash[key] = nil
99
- end
100
- end
101
- end
102
-
103
- hash
104
- }
105
- xml_data = strip_empty_nodes.call(xml_data)
106
- @_params = _load_params(action_spec[:in], xml_data)
107
- end
108
-
109
- # Creates the final parameter hash based on the request spec and xml_data from the request
110
- def _load_params(spec, xml_data)
111
- params = HashWithIndifferentAccess.new
112
- spec.each do |param|
113
- key = param.raw_name.to_sym
114
- if xml_data.has_key? key
115
- params[param.raw_name] = param.load(xml_data, key)
116
- end
117
- end
118
- params
119
- end
120
-
121
- # This action generates the WSDL for defined SOAP methods.
122
- def _generate_wsdl
123
-
124
- @map = self.class.soap_actions
125
- @namespace = soap_config.namespace
126
- @name = controller_path.gsub('/', '_')
127
-
128
- render :template => "wash_with_soap/#{soap_config.wsdl_style}/wsdl", :layout => false,
129
- :content_type => 'text/xml'
130
- end
131
-
132
- # Render a SOAP response.
133
- def _render_soap(result, options)
134
- @namespace = soap_config.namespace
135
- @operation = soap_action = request.env['wash_out.soap_action']
136
- @action_spec = self.class.soap_actions[soap_action]
137
-
138
- result = { 'value' => result } unless result.is_a? Hash
139
- result = HashWithIndifferentAccess.new(result)
140
-
141
- inject = lambda {|data, map|
142
- result_spec = []
143
- return result_spec if data.nil?
144
-
145
- map.each_with_index do |param, i|
146
- result_spec[i] = param.flat_copy
147
-
148
- unless data.is_a?(Hash)
149
- raise WashOut::ProgrammerError,
150
- "SOAP response used #{data.inspect} (which is #{data.class.name}), " +
151
- "in the context where a Hash with key of '#{param.raw_name}' " +
152
- "was expected."
153
- end
154
-
155
- value = data[param.raw_name]
156
-
157
- unless value.nil?
158
- if param.multiplied && !value.is_a?(Array)
159
- raise WashOut::ProgrammerError,
160
- "SOAP response tried to use '#{value.inspect}' " +
161
- "(which is of type #{value.class.name}), as the value for " +
162
- "'#{param.raw_name}' (which expects an Array)."
163
- end
164
-
165
- # Inline complex structure {:foo => {bar: ...}}
166
- if param.struct? && !param.multiplied
167
- result_spec[i].map = inject.call(value, param.map)
168
-
169
- # Inline array of complex structures {:foo => [{bar: ...}]}
170
- elsif param.struct? && param.multiplied
171
- result_spec[i].map = value.map{|e| inject.call(e, param.map)}
172
-
173
- # Inline scalar {:foo => :string}
174
- else
175
- result_spec[i].value = value
176
- end
177
- end
178
- end
179
-
180
- return result_spec
181
- }
182
-
183
- render :template => "wash_with_soap/#{soap_config.wsdl_style}/response",
184
- :layout => false,
185
- :locals => { :result => inject.call(result, @action_spec[:out]) },
186
- :content_type => 'text/xml'
187
- end
188
-
189
- # This action is a fallback for all undefined SOAP actions.
190
- def _invalid_action
191
- render_soap_error("Cannot find SOAP action mapping for #{request.env['wash_out.soap_action']}")
192
- end
193
-
194
- def _catch_soap_errors
195
- yield
196
- rescue WashOut::SOAPError => error
197
- render_soap_error(error.message, error.code)
198
- end
199
- end
200
- end
201
- end