serviceproxy 0.1.5 → 0.2.0

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