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 CHANGED
@@ -2,7 +2,7 @@ LICENSE
2
2
 
3
3
  The MIT License
4
4
 
5
- Copyright (c) 2008 Jeremy Durham
5
+ Copyright (c) 2008-2009 Jeremy Durham
6
6
 
7
7
  Permission is hereby granted, free of charge, to any person obtaining a copy
8
8
  of this software and associated documentation files (the "Software"), to deal
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]}')"
@@ -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.1.4'
17
+ VERSION = '0.2.0'
15
18
 
16
- attr_accessor :endpoint, :service_methods, :soap_actions, :service_uri, :http, :service_http, :uri, :debug, :wsdl, :target_namespace, :service_ports
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.service_http.request_post(self.service_uri.path, body, headers)
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
- self.http = setup_http(self.uri)
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
- def service_http
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(local_uri)
58
- raise ArgumentError, "Endpoint URI must be valid" unless local_uri.scheme
59
- local_http = Net::HTTP.new(local_uri.host, local_uri.port)
60
- setup_https(local_http) if local_uri.scheme == 'https'
61
- local_http.set_debug_output(STDOUT) if self.debug
62
- local_http.read_timeout = 5
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(local_http)
67
- local_http.use_ssl = true
68
- local_http.verify_mode = OpenSSL::SSL::VERIFY_NONE
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 = Nokogiri.XML(response.body)
71
+ self.wsdl = response.body
80
72
  end
81
-
73
+
82
74
  def parse_wsdl
83
- method_list = []
84
- self.wsdl.xpath('//*[name()="soap:operation"]').each do |operation|
85
- operation_name = operation.parent.get_attribute('name')
86
- method_list << operation_name
87
- self.soap_actions[operation_name] = operation.get_attribute('soapAction')
88
- end
89
- self.wsdl.xpath('//*[name()="wsdl:operation"]').each do |wsdl_operation|
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, "xmlns" => self.target_namespace) do
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
- case method_name
140
- when /_uri$/
141
- sp_name = method_name.gsub(/_uri$/, '')
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
@@ -4,4 +4,7 @@ require 'hpricot'
4
4
 
5
5
  class %name% < ServiceProxy::Base
6
6
  %body%
7
- end
7
+ end
8
+
9
+ proxy = %name%.new('%uri%')
10
+ p proxy.service_methods
@@ -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
@@ -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 "using the #service_port hook" do
80
+ describe "debugging a service call" do
67
81
  before do
68
- @proxy = ISBNService.new('http://webservices.daehosting.com/services/isbnservice.wso?WSDL')
82
+ @proxy = ZipcodeService.new('http://ws.fraudlabs.com/zipcodeworldUS_webservice.asmx?wsdl')
69
83
  end
70
84
 
71
- it "should have the dummy query argument" do
72
- @proxy.send(:service_uri).path.should match(/\?dummy=1/)
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.1.5
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-23 00:00:00 -04:00
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