serviceproxy 0.1.5 → 0.2.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.
- data/LICENSE +1 -1
- data/README +5 -6
- data/bin/wsdl2proxy +2 -1
- data/lib/service_proxy/base.rb +38 -71
- data/lib/service_proxy/parser.rb +29 -0
- data/lib/templates/proxy.rbt +4 -1
- data/spec/service_helper.rb +14 -7
- data/spec/service_proxy_spec.rb +19 -4
- metadata +3 -2
data/LICENSE
CHANGED
data/README
CHANGED
@@ -4,11 +4,6 @@ ServiceProxy is a lightweight SOAP library for Ruby.
|
|
4
4
|
|
5
5
|
HOW IT WORKS
|
6
6
|
|
7
|
-
Loading the library:
|
8
|
-
|
9
|
-
require 'rubygems'
|
10
|
-
require 'service_proxy/base'
|
11
|
-
|
12
7
|
GENERATING A PROXY
|
13
8
|
|
14
9
|
ServiceProxy comes with a simple generator to get started. It can be invoked
|
@@ -18,7 +13,11 @@ wsdl2proxy [wsdl]
|
|
18
13
|
|
19
14
|
This will generate a file named default.rb, in the current directory. The class
|
20
15
|
will be named GeneratedService, and will define build and parse methods for all
|
21
|
-
of the available service methods
|
16
|
+
of the available service methods, as well as add some boilerplate code to inspect
|
17
|
+
the available methods on the service.
|
18
|
+
|
19
|
+
ServiceProxy does not have any dependencies on Rails or other frameworks, nor does
|
20
|
+
the generator.
|
22
21
|
|
23
22
|
Please refer to the specs for extended usage examples.
|
24
23
|
|
data/bin/wsdl2proxy
CHANGED
@@ -31,11 +31,12 @@ proxy.service_methods.each do |service_method|
|
|
31
31
|
|
32
32
|
def parse_#{underscore(service_method)}(response)
|
33
33
|
Hpricot.XML(response.body)
|
34
|
-
end
|
34
|
+
end
|
35
35
|
EOS
|
36
36
|
end
|
37
37
|
template = File.read(template_filename)
|
38
38
|
template.gsub!(/%name%/, output_klass_name)
|
39
39
|
template.gsub!(/%body%/, output)
|
40
|
+
template.gsub!(/%uri%/, ARGV[0])
|
40
41
|
File.open(output_filename, 'w') { |f| f.puts template }
|
41
42
|
puts "Generated proxy #{output_filename} - You can use the proxy by executing #{output_klass_name}.new('#{ARGV[0]}')"
|
data/lib/service_proxy/base.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'net/http'
|
2
2
|
require 'net/https'
|
3
3
|
require 'uri'
|
4
|
+
require 'open-uri'
|
4
5
|
|
5
6
|
begin
|
6
7
|
require 'nokogiri'
|
@@ -9,104 +10,77 @@ rescue LoadError
|
|
9
10
|
puts "Could not load nokogiri or builder. Please make sure they are installed and in your $LOAD_PATH."
|
10
11
|
end
|
11
12
|
|
13
|
+
require File.dirname(__FILE__) + '/parser'
|
14
|
+
|
12
15
|
module ServiceProxy
|
13
16
|
class Base
|
14
|
-
VERSION = '0.
|
17
|
+
VERSION = '0.2.0'
|
15
18
|
|
16
|
-
attr_accessor :endpoint, :service_methods, :soap_actions, :
|
19
|
+
attr_accessor :endpoint, :service_methods, :soap_actions, :http,
|
20
|
+
:uri, :debug, :wsdl, :target_namespace
|
17
21
|
|
18
22
|
def initialize(endpoint)
|
19
23
|
self.endpoint = endpoint
|
20
24
|
self.setup
|
21
25
|
end
|
22
|
-
|
26
|
+
|
23
27
|
def call_service(options)
|
24
28
|
method = options[:method]
|
25
29
|
headers = { 'content-type' => 'text/xml; charset=utf-8', 'SOAPAction' => self.soap_actions[method] }
|
26
30
|
body = build_request(method, options)
|
27
|
-
response = self.
|
31
|
+
response = self.http.request_post(self.uri.path, body, headers)
|
28
32
|
parse_response(method, response)
|
29
|
-
end
|
33
|
+
end
|
30
34
|
|
35
|
+
def debug=(value)
|
36
|
+
@debug = value
|
37
|
+
self.http.set_debug_output(STDOUT) if value
|
38
|
+
end
|
39
|
+
|
31
40
|
protected
|
32
41
|
|
33
42
|
def setup
|
34
|
-
self.soap_actions = {}
|
35
43
|
self.service_methods = []
|
36
44
|
setup_uri
|
37
|
-
|
45
|
+
setup_http
|
38
46
|
get_wsdl
|
39
47
|
parse_wsdl
|
40
|
-
setup_namespace
|
41
|
-
end
|
42
|
-
|
43
|
-
def service_uri
|
44
|
-
@service_uri ||= self.respond_to?(:service_port) ? self.service_port : self.uri
|
45
48
|
end
|
46
49
|
|
47
|
-
|
48
|
-
@service_http ||= unless self.service_uri == self.uri
|
49
|
-
local_http = self.setup_http(self.service_uri)
|
50
|
-
setup_https(local_http) if self.service_uri.scheme == 'https'
|
51
|
-
local_http
|
52
|
-
else
|
53
|
-
self.http
|
54
|
-
end
|
55
|
-
end
|
50
|
+
private
|
56
51
|
|
57
|
-
def setup_http
|
58
|
-
raise ArgumentError, "Endpoint URI must be valid" unless
|
59
|
-
|
60
|
-
setup_https
|
61
|
-
|
62
|
-
|
63
|
-
local_http
|
52
|
+
def setup_http
|
53
|
+
raise ArgumentError, "Endpoint URI must be valid" unless self.uri.scheme
|
54
|
+
self.http ||= Net::HTTP.new(self.uri.host, self.uri.port)
|
55
|
+
setup_https if self.uri.scheme == 'https'
|
56
|
+
self.http.set_debug_output(STDOUT) if self.debug
|
57
|
+
self.http.read_timeout = 5
|
64
58
|
end
|
65
59
|
|
66
|
-
def setup_https
|
67
|
-
|
68
|
-
|
60
|
+
def setup_https
|
61
|
+
self.http.use_ssl = true
|
62
|
+
self.http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
69
63
|
end
|
70
64
|
|
71
|
-
private
|
72
|
-
|
73
65
|
def setup_uri
|
74
66
|
self.uri = URI.parse(self.endpoint)
|
75
67
|
end
|
76
68
|
|
77
69
|
def get_wsdl
|
78
70
|
response = self.http.get("#{self.uri.path}?#{self.uri.query}")
|
79
|
-
self.wsdl =
|
71
|
+
self.wsdl = response.body
|
80
72
|
end
|
81
|
-
|
73
|
+
|
82
74
|
def parse_wsdl
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
operation_name = wsdl_operation.get_attribute('name')
|
91
|
-
method_list << operation_name
|
92
|
-
self.soap_actions[operation_name] = wsdl_operation.xpath('//*[name()="wsdlsoap:operation"]').first.get_attribute('soapAction')
|
93
|
-
end
|
94
|
-
raise RuntimeError, "Could not parse WSDL" if method_list.empty?
|
95
|
-
self.service_methods = method_list.sort
|
96
|
-
|
97
|
-
port_list = {}
|
98
|
-
self.wsdl.xpath('//wsdl:port', {"xmlns:wsdl" => 'http://schemas.xmlsoap.org/wsdl/'}).each do |port|
|
99
|
-
name = underscore(port['name'])
|
100
|
-
location = port.xpath('./*[@location]').first['location']
|
101
|
-
port_list[name] = location
|
102
|
-
end
|
103
|
-
self.service_ports = port_list
|
75
|
+
parser = ServiceProxy::Parser.new
|
76
|
+
sax_parser = Nokogiri::XML::SAX::Parser.new(parser)
|
77
|
+
sax_parser.parse(self.wsdl)
|
78
|
+
self.service_methods = parser.service_methods.sort
|
79
|
+
self.target_namespace = parser.target_namespace
|
80
|
+
self.soap_actions = parser.soap_actions
|
81
|
+
raise RuntimeError, "Could not parse WSDL" if self.service_methods.empty?
|
104
82
|
end
|
105
83
|
|
106
|
-
def setup_namespace
|
107
|
-
self.target_namespace = self.wsdl.namespaces['xmlns:tns']
|
108
|
-
end
|
109
|
-
|
110
84
|
def build_request(method, options)
|
111
85
|
builder = underscore("build_#{method}")
|
112
86
|
self.respond_to?(builder) ? self.send(builder, options).target! :
|
@@ -126,7 +100,7 @@ module ServiceProxy
|
|
126
100
|
xml = Builder::XmlMarkup.new
|
127
101
|
xml.env(:Envelope, 'xmlns:xsd' => xsd, 'xmlns:env' => env, 'xmlns:xsi' => xsi) do
|
128
102
|
xml.env(:Body) do
|
129
|
-
xml.__send__(options[:method].to_sym,
|
103
|
+
xml.__send__(options[:method].to_sym, 'xmlns' => self.target_namespace) do
|
130
104
|
yield xml if block_given?
|
131
105
|
end
|
132
106
|
end
|
@@ -136,16 +110,9 @@ module ServiceProxy
|
|
136
110
|
|
137
111
|
def method_missing(method, *args)
|
138
112
|
method_name = method.to_s
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
super unless self.service_ports.has_key?(sp_name)
|
143
|
-
URI.parse(self.service_ports[sp_name])
|
144
|
-
else
|
145
|
-
options = args.pop || {}
|
146
|
-
super unless self.service_methods.include?(method_name)
|
147
|
-
call_service(options.update(:method => method_name))
|
148
|
-
end
|
113
|
+
options = args.pop || {}
|
114
|
+
super unless self.service_methods.include?(method_name)
|
115
|
+
call_service(options.update(:method => method_name))
|
149
116
|
end
|
150
117
|
|
151
118
|
def underscore(camel_cased_word)
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module ServiceProxy
|
2
|
+
class Parser < Nokogiri::XML::SAX::Document
|
3
|
+
attr_accessor :wsdl_namespace, :soap_namespace, :target_namespace, :service_methods, :soap_actions
|
4
|
+
|
5
|
+
def initialize(*args)
|
6
|
+
self.service_methods = []
|
7
|
+
self.soap_actions = Hash.new('')
|
8
|
+
super
|
9
|
+
end
|
10
|
+
|
11
|
+
def start_element_namespace(name, attributes, prefix, uri, namespace)
|
12
|
+
case name
|
13
|
+
when 'definitions'
|
14
|
+
self.wsdl_namespace = prefix if uri == 'http://schemas.xmlsoap.org/wsdl/'
|
15
|
+
self.soap_namespace = prefix if uri == 'http://schemas.xmlsoap.org/wsdl/soap/'
|
16
|
+
attribute = attributes.find { |attribute| attribute.localname == 'targetNamespace' }
|
17
|
+
self.target_namespace = attribute.value if attribute
|
18
|
+
when "operation"
|
19
|
+
service_method = attributes.first.value if prefix == self.wsdl_namespace
|
20
|
+
soap_action = attributes.find { |attribute| attribute.localname == 'soapAction' }
|
21
|
+
self.soap_actions[self.service_methods.last] = soap_action.value if soap_action
|
22
|
+
(self.service_methods << service_method unless self.service_methods.include?(service_method)) if service_method
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def end_element_namespace(name, prefix, uri)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/templates/proxy.rbt
CHANGED
data/spec/service_helper.rb
CHANGED
@@ -12,13 +12,7 @@ class ISBNService < ServiceProxy::Base
|
|
12
12
|
def parse_is_valid_isbn13(response)
|
13
13
|
xml = Hpricot.XML(response.body)
|
14
14
|
xml.at("m:IsValidISBN13Result").inner_text == 'true' ? true : false
|
15
|
-
end
|
16
|
-
|
17
|
-
def service_port
|
18
|
-
local_uri = URI.parse(self.isbn_service_soap_uri.to_s)
|
19
|
-
local_uri.path << "?dummy=1"
|
20
|
-
local_uri
|
21
|
-
end
|
15
|
+
end
|
22
16
|
end
|
23
17
|
|
24
18
|
class SHAGeneratorService < ServiceProxy::Base
|
@@ -48,4 +42,17 @@ class InvalidSHAGeneratorService < ServiceProxy::Base
|
|
48
42
|
end
|
49
43
|
|
50
44
|
class EbayService < ServiceProxy::Base
|
45
|
+
end
|
46
|
+
|
47
|
+
class ZipcodeService < ServiceProxy::Base
|
48
|
+
|
49
|
+
def build_zip_code_world_us(options)
|
50
|
+
soap_envelope(options) do |xml|
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def parse_zip_code_world_us(response)
|
55
|
+
Hpricot.XML(response.body)
|
56
|
+
end
|
57
|
+
|
51
58
|
end
|
data/spec/service_proxy_spec.rb
CHANGED
@@ -53,23 +53,38 @@ describe ServiceProxy do
|
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
56
|
+
describe "connect to the Zipcode Service" do
|
57
|
+
before do
|
58
|
+
@proxy = ZipcodeService.new('http://ws.fraudlabs.com/zipcodeworldUS_webservice.asmx?wsdl')
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should be successful" do
|
62
|
+
@proxy.ZIPCodeWorld_US.should_not be_nil
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
56
66
|
describe "making a service call without a parse method" do
|
57
67
|
before do
|
58
68
|
@proxy = InvalidSHAGeneratorService.new('https://sec.neurofuzz-software.com/paos/genSSHA-SOAP.php?wsdl')
|
59
69
|
end
|
60
70
|
|
71
|
+
it "should be SSL" do
|
72
|
+
@proxy.http.use_ssl.should be_true
|
73
|
+
end
|
74
|
+
|
61
75
|
it "should raise a no method error" do
|
62
76
|
lambda { result = @proxy.genSSHA(:text => 'hello world', :hash_type => 'sha512') }.should raise_error(NoMethodError)
|
63
77
|
end
|
64
78
|
end
|
65
79
|
|
66
|
-
describe "
|
80
|
+
describe "debugging a service call" do
|
67
81
|
before do
|
68
|
-
@proxy =
|
82
|
+
@proxy = ZipcodeService.new('http://ws.fraudlabs.com/zipcodeworldUS_webservice.asmx?wsdl')
|
69
83
|
end
|
70
84
|
|
71
|
-
it "should
|
72
|
-
@proxy.
|
85
|
+
it "should set_debug_output on the HTTP connection" do
|
86
|
+
@proxy.http.should_receive(:set_debug_output)
|
87
|
+
@proxy.debug = true
|
73
88
|
end
|
74
89
|
end
|
75
90
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: serviceproxy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremy Durham
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-10-
|
12
|
+
date: 2009-10-25 00:00:00 -04:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -56,6 +56,7 @@ files:
|
|
56
56
|
- README
|
57
57
|
- Rakefile
|
58
58
|
- lib/service_proxy/base.rb
|
59
|
+
- lib/service_proxy/parser.rb
|
59
60
|
- lib/templates/proxy.rbt
|
60
61
|
- spec/service_helper.rb
|
61
62
|
- spec/service_proxy_spec.rb
|