wash_out 0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|