wash_out 0.1

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/README.rdoc ADDED
@@ -0,0 +1,55 @@
1
+ == Wash Out
2
+
3
+ Wash Out is very simple SOAP service solution. It allows you to create SOAP services on top of your controllers in 3 steps (see Usage).
4
+
5
+ == Install
6
+
7
+ gem install wash_out
8
+
9
+ == Usage
10
+
11
+ === I. Define structure in your controller
12
+
13
+ class TestController < ApplicationController
14
+ wash_with_soap :my_soap_method => {
15
+ :in => { 'structure' => { 'foo' => :string }, 'bar' => :integer },
16
+ :out => :boolean
17
+ }
18
+
19
+ Defined this way method "my_soap_method" will wait for two parameters:
20
+
21
+ 1. 'structure' will wait for complex type (defined separately in WSDL)
22
+ 2. 'bar' will wait for string (xsd:string in WSDL)
23
+
24
+ On the other side it will return boolean (xsd:boolean in WSDL).
25
+
26
+ === II. Define worker
27
+
28
+ At same controller define action "my_soap_method"
29
+
30
+ def my_soap_method
31
+ @soap # this will contain data passed by SOAP request
32
+ end
33
+
34
+ Parameters are handling by WashOut::Param entity. To get values use 'value' and '[]' methods.
35
+
36
+ To get 'bar' parameter:
37
+ @soap['bar'].value
38
+
39
+ To get 'foo' from 'structure':
40
+ @soap['structure']['foo'].value
41
+
42
+ === III. Return something
43
+
44
+ Return from your method to respond. In our case we should just respond with
45
+ return true #or return false
46
+
47
+ In complex scenarios we can do
48
+ return { :foo => 'foo', :bar => 'bar' }
49
+
50
+
51
+ == Complex cases
52
+
53
+ === I have same substructures for several methods. Are there any ways to define WSDL besides hash?
54
+
55
+ === How to respond with SOAP error?
@@ -0,0 +1,41 @@
1
+ module WashOutHelper
2
+ def wsdl_data(xml, param)
3
+ if param.struct?
4
+ param.value.values.each do |p|
5
+ wsdl_data xml, p
6
+ end
7
+ else
8
+ xml.tag! param.name, param.value.to_s
9
+ end
10
+ end
11
+
12
+ def wsdl_type(xml, param)
13
+ more = []
14
+
15
+ if param.struct?
16
+ return if param.value.blank?
17
+
18
+ xml.complexType :name => param.name do
19
+ xml.sequence do
20
+ param.value.each do |key, value|
21
+ more << value if value.struct?
22
+ xml.element wsdl_occurence(value, :name => key, :type => value.namespaced_type)
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ more.each do |p|
29
+ wsdl_type xml, p
30
+ end
31
+ end
32
+
33
+ def wsdl_occurence(param, extend_with = {})
34
+ data = !param.multiplied ? {} : {
35
+ :minOccurs => 0,
36
+ :maxOccurs => 'unbounded'
37
+ }
38
+
39
+ return extend_with.merge(data)
40
+ end
41
+ end
@@ -0,0 +1,10 @@
1
+ xml.instruct!
2
+ xml.Envelope "xmlns:xsi" => 'http://www.w3.org/2001/XMLSchema-instance',
3
+ :xmlns => 'http://schemas.xmlsoap.org/soap/envelope/' do
4
+ xml.Body do
5
+ xml.Fault :encodingStyle => 'http://schemas.xmlsoap.org/soap/encoding/' do
6
+ xml.faultcode "Server", 'xsi:type' => 'xsd:QName'
7
+ xml.faultstring @error, 'xsi:type' => 'xsd:string'
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,7 @@
1
+ xml.instruct!
2
+ xml.Envelope "xmlns:xsi" => 'http://www.w3.org/2001/XMLSchema-instance',
3
+ :xmlns => 'http://schemas.xmlsoap.org/soap/envelope/' do
4
+ xml.Body do
5
+ wsdl_data xml, @result
6
+ end
7
+ end
@@ -0,0 +1,75 @@
1
+ xml.instruct!
2
+ xml.definitions 'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema',
3
+ 'xmlns:soap' => 'http://schemas.xmlsoap.org/wsdl/soap/',
4
+ 'xmlns:soapenc' => 'http://schemas.xmlsoap.org/soap/encoding/',
5
+ 'xmlns:wsdl' => 'http://schemas.xmlsoap.org/wsdl/',
6
+ 'xmlns:typens' => @namespace,
7
+ 'targetNamespace' => @namespace,
8
+ 'xmlns' => 'http://schemas.xmlsoap.org/wsdl/' do
9
+ xml.types do
10
+ xml.tag! "xsd:schema", :xmlns => 'http://www.w3.org/2001/XMLSchema', :targetNamespace => @namespace
11
+
12
+ @map.each do |operation, formats|
13
+ formats.each do |kind, params|
14
+ if params.struct?
15
+ params.value.each{|foo, p| wsdl_type xml, p}
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ @map.each do |operation, formats|
22
+ xml.message :name => "#{operation}" do
23
+ if formats[:in].struct?
24
+ formats[:in].value.each do |name, p|
25
+ xml.part wsdl_occurence(p, :name => p.name, :type => p.namespaced_type)
26
+ end
27
+ else
28
+ xml.part wsdl_occurence(formats[:in], :name => operation, :type => formats[:in].namespaced_type)
29
+ end
30
+ end
31
+ xml.message :name => "#{operation}_responce" do
32
+ if formats[:out].struct?
33
+ formats[:out].value.each do |name, p|
34
+ xml.part wsdl_occurence(p, :name => p.name, :type => p.namespaced_type)
35
+ end
36
+ else
37
+ xml.part wsdl_occurence(formats[:out], :name => operation, :type => formats[:out].namespaced_type)
38
+ end
39
+ end
40
+ end
41
+
42
+ xml.portType :name => "#{@name}_port" do
43
+ @map.keys.each do |operation|
44
+ xml.operation :name => operation do
45
+ xml.input :message => "typens:#{operation}"
46
+ xml.otput :message => "typens:#{operation}_responce"
47
+ end
48
+ end
49
+ end
50
+
51
+ xml.binding :name => "#{@name}_binding", :type => "typens:#{@name}_port" do
52
+ xml.tag! "soap:binding", :style => 'rpc', :transport => 'http://schemas.xmlsoap.org/soap/http'
53
+ @map.keys.each do |operation|
54
+ xml.operation :name => operation do
55
+ xml.tag! "soap:operation", :soapAction => operation
56
+ xml.input do
57
+ xml.tag! "soap:body",
58
+ :use => "encoded", :encodingStyle => 'http://schemas.xmlsoap.org/soap/encoding/',
59
+ :namespace => @namespace
60
+ end
61
+ xml.output do
62
+ xml.tag! "soap:body",
63
+ :use => "encoded", :encodingStyle => 'http://schemas.xmlsoap.org/soap/encoding/',
64
+ :namespace => @namespace
65
+ end
66
+ end
67
+ end
68
+ end
69
+
70
+ xml.service :name => "service" do
71
+ xml.port :name => "#{@name}_port", :binding => "#{@name}_binding" do
72
+ xml.tag! "soap:address", :location => url_for(:action => :soap, :only_path => false)
73
+ end
74
+ end
75
+ end
data/init.rb ADDED
@@ -0,0 +1,19 @@
1
+ require 'crack/xml'
2
+ require 'wash_out/param'
3
+ require 'wash_out/dispatcher'
4
+ require 'wash_out/wash_with_soap'
5
+
6
+ ActionController::Base.class_eval do
7
+ include WashOut::WashWithSoap
8
+ end
9
+
10
+ ActionController::Base.helper(WashOutHelper)
11
+
12
+ module ActionDispatch::Routing
13
+ class Mapper
14
+ def wash_with_soap(controller)
15
+ match "#{controller.to_s}/wsdl" => "#{controller.to_s}#wsdl"
16
+ match "#{controller.to_s}/soap" => "#{controller.to_s}#soap"
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,32 @@
1
+ module WashOut
2
+ module Dispatcher
3
+ def wsdl
4
+ @map = self.class.wash_with_soap_map
5
+ @name = controller_path.gsub('/', '_')
6
+ @namespace = 'urn:WashOut'
7
+
8
+ render :template => 'wash_with_soap/wsdl'
9
+ end
10
+
11
+ def soap
12
+ @map = self.class.wash_with_soap_map
13
+ @method = request.env['HTTP_SOAPACTION'].gsub(/^\"(.*)\"$/, '\1')
14
+ @current = @map[@method] || @map[@method.to_sym]
15
+
16
+ wash_out_error("Method does not exist") and return if @current.blank?
17
+
18
+ data = Crack::XML.parse(request.raw_post).values.first.select{|k,v| k[-4,4] == "Body"}.values.first[@method]
19
+
20
+ @soap = @current[:in].load(data)
21
+ @result = @current[:out].load(send @method.to_sym)
22
+
23
+ render :template => 'wash_with_soap/response'
24
+ end
25
+
26
+ private
27
+
28
+ def wash_out_error(description)
29
+ @error = description and render :template => 'wash_with_soap/error'
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,66 @@
1
+ module WashOut
2
+ class Param
3
+ attr_accessor :name
4
+ attr_accessor :map
5
+ attr_accessor :type
6
+ attr_accessor :multiplied
7
+
8
+ attr_accessor :value
9
+ def value
10
+ struct? ? map : @value
11
+ end
12
+
13
+ def [](key)
14
+ map[key]
15
+ end
16
+
17
+ def struct?
18
+ type == 'struct'
19
+ end
20
+
21
+ def namespaced_type
22
+ struct? ? "typens:#{name}" : "xsd:#{type}"
23
+ end
24
+
25
+ def initialize(name, type, multiplied = false)
26
+ type ||= {}
27
+
28
+ @name = name.to_s
29
+ @map = {}
30
+ @multiplied = multiplied
31
+
32
+ if type.is_a?(Hash)
33
+ @type = 'struct'
34
+
35
+ type.each do |name, type|
36
+ if type.is_a?(Array)
37
+ @map[name.to_s] = Param.new(name, type[0], true)
38
+ else
39
+ @map[name.to_s] = Param.new(name, type)
40
+ end
41
+ end
42
+ else
43
+ @type = type.to_s
44
+ end
45
+ end
46
+
47
+ def load(data)
48
+ if struct?
49
+ map.each do |name, param|
50
+ param.load(data[name] || data[name.to_sym])
51
+ end
52
+ else
53
+ @value = Param.convert_scalar(data, type)
54
+ end
55
+
56
+ self
57
+ end
58
+
59
+ def self.convert_scalar(data, type)
60
+ return data.to_s if type == 'string'
61
+ return data.to_i if type == 'integer'
62
+ return data.to_f if type == 'double'
63
+ return data.to_bool if type == 'boolean'
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,24 @@
1
+ module WashOut
2
+ module WashWithSoap
3
+ def self.included(base)
4
+
5
+ base.class_eval do
6
+ class <<self
7
+ attr_accessor :wash_with_soap_map
8
+ end
9
+
10
+ def self.wash_with_soap(map)
11
+ map.each do |method, params|
12
+ params[:in] = WashOut::Param.new(method, map[method][:in]) unless map[method][:in].is_a?(Param)
13
+ params[:out] = WashOut::Param.new("#{method}_responce", map[method][:out]) unless map[method][:out].is_a?(Param)
14
+ end
15
+
16
+ self.wash_with_soap_map = map
17
+
18
+ include WashOut::Dispatcher
19
+ end
20
+ end
21
+
22
+ end
23
+ end
24
+ end
data/wash_out.gemspec ADDED
@@ -0,0 +1,16 @@
1
+ SPEC = Gem::Specification.new do |s|
2
+ s.name = "wash_out"
3
+ s.version = "0.1"
4
+ s.platform = Gem::Platform::RUBY
5
+ s.summary = "Dead simple Rails 3 SOAP server library"
6
+ s.email = "boris@roundlake.ru"
7
+ s.homepage = "http://github.com/roundlake/wash_out"
8
+ s.description = "Dead simple Rails 3 SOAP server library"
9
+ s.authors = ['Boris Staal']
10
+
11
+ s.add_dependency "crack"
12
+
13
+ s.has_rdoc = false # disable rdoc generation until we've got more
14
+ s.files = `git ls-files`.split("\n")
15
+ s.require_paths = ["lib"]
16
+ end
metadata ADDED
@@ -0,0 +1,65 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: wash_out
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Boris Staal
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-08-15 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: crack
16
+ requirement: &70092761237000 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70092761237000
25
+ description: Dead simple Rails 3 SOAP server library
26
+ email: boris@roundlake.ru
27
+ executables: []
28
+ extensions: []
29
+ extra_rdoc_files: []
30
+ files:
31
+ - README.rdoc
32
+ - app/helpers/wash_out_helper.rb
33
+ - app/views/wash_with_soap/error.builder
34
+ - app/views/wash_with_soap/response.builder
35
+ - app/views/wash_with_soap/wsdl.builder
36
+ - init.rb
37
+ - lib/wash_out/dispatcher.rb
38
+ - lib/wash_out/param.rb
39
+ - lib/wash_out/wash_with_soap.rb
40
+ - wash_out.gemspec
41
+ homepage: http://github.com/roundlake/wash_out
42
+ licenses: []
43
+ post_install_message:
44
+ rdoc_options: []
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ none: false
49
+ requirements:
50
+ - - ! '>='
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ! '>='
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ requirements: []
60
+ rubyforge_project:
61
+ rubygems_version: 1.8.6
62
+ signing_key:
63
+ specification_version: 3
64
+ summary: Dead simple Rails 3 SOAP server library
65
+ test_files: []