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 +55 -0
- data/app/helpers/wash_out_helper.rb +41 -0
- data/app/views/wash_with_soap/error.builder +10 -0
- data/app/views/wash_with_soap/response.builder +7 -0
- data/app/views/wash_with_soap/wsdl.builder +75 -0
- data/init.rb +19 -0
- data/lib/wash_out/dispatcher.rb +32 -0
- data/lib/wash_out/param.rb +66 -0
- data/lib/wash_out/wash_with_soap.rb +24 -0
- data/wash_out.gemspec +16 -0
- metadata +65 -0
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,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: []
|