jeremydurham-serviceproxy 0.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/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ LICENSE
2
+
3
+ The MIT License
4
+
5
+ Copyright (c) 2008 Jeremy Durham
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ of this software and associated documentation files (the "Software"), to deal
9
+ in the Software without restriction, including without limitation the rights
10
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ copies of the Software, and to permit persons to whom the Software is
12
+ furnished to do so, subject to the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be included in
15
+ all copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
+ THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,45 @@
1
+ ServiceProxy
2
+
3
+ ServiceProxy is a lightweight SOAP library for Ruby.
4
+
5
+ How it works
6
+
7
+ Unlike SOAP4R, this library takes a very different approach to building
8
+ requests and parsing responses. There is little magic and no code
9
+ generation with this library.
10
+
11
+ You will need to understand some simple things about SOAP before you
12
+ can use this library. Using a tool like SOAPUI or SoapClient, you can
13
+ easily get enough information to use this library with existing SOAP
14
+ services.
15
+
16
+ For each service endpoint you want to connect to, you will need to
17
+ subclass ServiceProxy.
18
+
19
+ Let's say you want to call the method cool1 on a service:
20
+
21
+ First, you create a subclass:
22
+
23
+ class SuperCoolService < ServiceProxy
24
+
25
+ def build_cool1(options)
26
+ # This will generate a simple SOAP envelope. Using the xml block local, you
27
+ # can inject XML into the body of the envelope.
28
+ soap_envelope(options) do |xml|
29
+ # your XML here
30
+ end
31
+ end
32
+
33
+ def parse_cool1(response)
34
+ # The response parameter is a simple Net::HTTP response
35
+ # here, we use Hpricot to parse it, but you could use
36
+ # Nokogiri, REXML, etc
37
+ xml = Hpricot.XML(response.body)
38
+ xml.at("cool1Result").inner_text
39
+ end
40
+ end
41
+
42
+ Next, you can attempt to call the service:
43
+
44
+ service = SuperCoolService.new(url_to_wsdl)
45
+ service.cool1
data/Rakefile ADDED
@@ -0,0 +1,94 @@
1
+ require 'rubygems'
2
+ require 'rake/gempackagetask'
3
+ require 'rubygems/specification'
4
+ require 'rake/rdoctask'
5
+ require 'spec/rake/spectask'
6
+ require File.join(File.dirname(__FILE__), 'lib', 'service_proxy')
7
+
8
+ NAME = "serviceproxy"
9
+ AUTHOR = "Jeremy Durham"
10
+ EMAIL = "jeremydurham@gmail.com"
11
+ HOMEPAGE = ""
12
+ SUMMARY = "Lightweight SOAP library for Ruby"
13
+
14
+ # Used by release task
15
+ GEM_NAME = NAME
16
+ PROJECT_URL = HOMEPAGE
17
+ PROJECT_SUMMARY = SUMMARY
18
+ PROJECT_DESCRIPTION = SUMMARY
19
+
20
+ PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : ''
21
+ GEM_VERSION = ServiceProxy::VERSION + PKG_BUILD
22
+ RELEASE_NAME = "REL #{GEM_VERSION}"
23
+ #
24
+ # ==== Gemspec and installation
25
+ #
26
+
27
+ spec = Gem::Specification.new do |s|
28
+ s.name = NAME
29
+ s.version = ServiceProxy::VERSION
30
+ s.platform = Gem::Platform::RUBY
31
+ s.has_rdoc = true
32
+ s.extra_rdoc_files = ["README", "LICENSE"]
33
+ s.summary = SUMMARY
34
+ s.description = s.summary
35
+ s.author = AUTHOR
36
+ s.email = EMAIL
37
+ s.homepage = HOMEPAGE
38
+ s.require_path = 'lib'
39
+ s.files = %w(LICENSE README Rakefile) + Dir.glob("{lib,spec}/**/*")
40
+
41
+ s.add_dependency "nokogiri"
42
+ s.add_dependency "hpricot"
43
+ end
44
+
45
+ Rake::GemPackageTask.new(spec) do |pkg|
46
+ pkg.gem_spec = spec
47
+ end
48
+
49
+ desc "install the gem locally"
50
+ task :install => [:clean, :package] do
51
+ sh %{sudo gem install pkg/#{NAME}-#{ServiceProxy::VERSION} --no-update-sources}
52
+ end
53
+
54
+ desc "create a gemspec file"
55
+ task :make_spec do
56
+ File.open("#{GEM_NAME}.gemspec", "w") do |file|
57
+ file.puts spec.to_ruby
58
+ end
59
+ end
60
+
61
+ desc "Run coverage suite"
62
+ task :rcov do
63
+ require 'fileutils'
64
+ FileUtils.rm_rf("coverage") if File.directory?("coverage")
65
+ FileUtils.mkdir("coverage")
66
+ path = File.expand_path(Dir.pwd)
67
+ files = Dir["spec/**/*_spec.rb"]
68
+ files.each do |spec|
69
+ puts "Getting coverage for #{File.expand_path(spec)}"
70
+ command = %{rcov #{File.expand_path(spec)} --aggregate #{path}/coverage/data.data}
71
+ command += " --no-html" unless spec == files.last
72
+ `#{command} 2>&1`
73
+ end
74
+ end
75
+
76
+ file_list = FileList['spec/**/*_spec.rb']
77
+
78
+ desc "Run all examples"
79
+ Spec::Rake::SpecTask.new('spec') do |t|
80
+ t.spec_files = file_list
81
+ end
82
+
83
+ namespace :spec do
84
+ desc "Run all examples with RCov"
85
+ Spec::Rake::SpecTask.new('rcov') do |t|
86
+ t.spec_files = file_list
87
+ t.rcov = true
88
+ t.rcov_dir = "doc/coverage"
89
+ t.rcov_opts = ['--exclude', 'spec']
90
+ end
91
+ end
92
+
93
+ desc 'Default: run unit tests.'
94
+ task :default => 'spec'
@@ -0,0 +1,111 @@
1
+ require 'rubygems'
2
+ require 'nokogiri'
3
+ require 'net/http'
4
+ require 'net/https'
5
+ require 'builder'
6
+ require 'uri'
7
+
8
+ class ServiceProxy
9
+ VERSION = '0.0.1'
10
+
11
+ attr_accessor :endpoint, :service_methods, :soap_actions, :service_uri, :http, :uri, :debug, :wsdl, :target_namespace
12
+
13
+ def initialize(endpoint)
14
+ self.endpoint = endpoint
15
+ self.setup
16
+ end
17
+
18
+ def call_service(options)
19
+ method = options[:method]
20
+ headers = { 'content-type' => 'text/xml; charset=utf-8', 'SOAPAction' => self.soap_actions[method] }
21
+ body = build_request(method, options)
22
+ response = self.http.request_post(self.uri.path, body, headers)
23
+ parse_response(method, response)
24
+ end
25
+
26
+ protected
27
+
28
+ def setup
29
+ self.soap_actions = {}
30
+ self.service_methods = []
31
+ setup_http
32
+ get_wsdl
33
+ parse_wsdl
34
+ setup_namespace
35
+ end
36
+
37
+ private
38
+
39
+ def setup_http
40
+ self.uri = URI.parse(self.endpoint)
41
+ raise ArgumentError, "Endpoint URI must be valid" unless self.uri.scheme
42
+ self.http = Net::HTTP.new(self.uri.host, self.uri.port)
43
+ setup_https if self.uri.scheme == 'https'
44
+ self.http.set_debug_output(STDOUT) if self.debug
45
+ end
46
+
47
+ def setup_https
48
+ self.http.use_ssl = true
49
+ self.http.verify_mode = OpenSSL::SSL::VERIFY_NONE
50
+ end
51
+
52
+ def get_wsdl
53
+ response = self.http.get("#{self.uri.path}?#{self.uri.query}")
54
+ self.wsdl = Nokogiri.XML(response.body)
55
+ end
56
+
57
+ def parse_wsdl
58
+ method_list = []
59
+ self.wsdl.xpath('//*[name()="soap:operation"]').each do |operation|
60
+ operation_name = operation.parent.get_attribute('name')
61
+ method_list << operation_name
62
+ self.soap_actions[operation_name] = operation.get_attribute('soapAction')
63
+ end
64
+ raise RuntimeError, "Could not parse WSDL" if method_list.empty?
65
+ self.service_methods = method_list.sort
66
+ end
67
+
68
+ def setup_namespace
69
+ self.target_namespace = self.wsdl.namespaces['xmlns:tns']
70
+ end
71
+
72
+ def build_request(method, options)
73
+ builder = underscore("build_#{method}")
74
+ self.respond_to?(builder) ? self.send(builder, options).target! : soap_envelope(options).target!
75
+ end
76
+
77
+ def parse_response(method, response)
78
+ parser = underscore("parse_#{method}")
79
+ self.respond_to?(parser) ? self.send(parser, response) :
80
+ raise(NoMethodError, "You must define the parse method: #{parser}")
81
+ end
82
+
83
+ def soap_envelope(options, &block)
84
+ xsd = 'http://www.w3.org/2001/XMLSchema'
85
+ env = 'http://schemas.xmlsoap.org/soap/envelope/'
86
+ xsi = 'http://www.w3.org/2001/XMLSchema-instance'
87
+ xml = Builder::XmlMarkup.new
88
+ xml.env(:Envelope, 'xmlns:xsd' => xsd, 'xmlns:env' => env, 'xmlns:xsi' => xsi) do
89
+ xml.env(:Body) do
90
+ xml.__send__(options[:method].to_sym, "xmlns" => self.target_namespace) do
91
+ yield xml if block_given?
92
+ end
93
+ end
94
+ end
95
+ xml
96
+ end
97
+
98
+ def method_missing(method, *args)
99
+ options = args.pop || {}
100
+ super unless self.service_methods.include?(method.to_s)
101
+ call_service(options.update(:method => method.to_s))
102
+ end
103
+
104
+ def underscore(camel_cased_word)
105
+ camel_cased_word.to_s.gsub(/::/, '/').
106
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
107
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
108
+ tr("-", "_").
109
+ downcase
110
+ end
111
+ end
@@ -0,0 +1,50 @@
1
+ require 'hpricot'
2
+
3
+ # Service Endpoints
4
+ class InstantMessageService < ServiceProxy
5
+
6
+ def parse_get_version(response)
7
+ xml = Hpricot.XML(response.body)
8
+ xml.at("GetVersionResult").inner_text
9
+ end
10
+
11
+ def build_login(options)
12
+ soap_envelope(options) do |xml|
13
+ xml.userId(options[:userId])
14
+ xml.password(options[:password])
15
+ end
16
+ end
17
+
18
+ def parse_login(response)
19
+ 'Invalid username/password' if response.code == "500"
20
+ end
21
+ end
22
+
23
+ class ISBNService < ServiceProxy
24
+
25
+ def build_is_valid_isbn13(options)
26
+ soap_envelope(options) do |xml|
27
+ xml.sISBN(options[:isbn])
28
+ end
29
+ end
30
+
31
+ def parse_is_valid_isbn13(response)
32
+ xml = Hpricot.XML(response.body)
33
+ xml.at("m:IsValidISBN13Result").inner_text == 'true' ? true : false
34
+ end
35
+ end
36
+
37
+ class SHAGeneratorService < ServiceProxy
38
+
39
+ def build_gen_ssha(options)
40
+ soap_envelope(options) do |xml|
41
+ xml.text(options[:text])
42
+ xml.hashtype(options[:hash_type])
43
+ end
44
+ end
45
+
46
+ def parse_gen_ssha(response)
47
+ xml = Hpricot.XML(response.body)
48
+ xml.at("return").inner_text
49
+ end
50
+ end
@@ -0,0 +1,65 @@
1
+ require 'rubygems'
2
+ require 'spec'
3
+ require File.dirname(__FILE__) + '/../lib/service_proxy.rb'
4
+ require File.dirname(__FILE__) + '/service_helper.rb'
5
+
6
+ describe ServiceProxy do
7
+ it "should raise on an invalid URI" do
8
+ lambda { ServiceProxy.new('bacon') }.should raise_error(ArgumentError)
9
+ end
10
+
11
+ it "should raise on invalid WSDL" do
12
+ lambda { ServiceProxy.new('http://www.jeremydurham.com') }.should raise_error(RuntimeError)
13
+ end
14
+
15
+ describe "connecting to an Instant Message Service" do
16
+ before do
17
+ @proxy = InstantMessageService.new('http://www.imcomponents.com/imsoap/?wsdl')
18
+ end
19
+
20
+ describe "calling GetVersion" do
21
+ it "should return the version" do
22
+ version = @proxy.GetVersion
23
+ version.should == 'v1.0.20080508'
24
+ end
25
+ end
26
+
27
+ describe "calling Login" do
28
+ it "should return nil" do
29
+ result = @proxy.Login(:userId => 'test', :password => 'test')
30
+ result.should == 'Invalid username/password'
31
+ end
32
+ end
33
+ end
34
+
35
+ describe "connecting to an ISBN validator" do
36
+ before do
37
+ @proxy = ISBNService.new('http://webservices.daehosting.com/services/isbnservice.wso?WSDL')
38
+ end
39
+
40
+ describe "calling IsValidISBN13" do
41
+ it "should return true for a valid ISBN" do
42
+ @proxy.IsValidISBN13(:isbn => '978-0977616633').should == true
43
+ end
44
+
45
+ it "should return false for an invalid ISBN" do
46
+ @proxy.IsValidISBN13(:isbn => '999-9999391939').should == false
47
+ end
48
+ end
49
+ end
50
+
51
+ describe "connecting to the SHA hash generator Service" do
52
+ before do
53
+ @proxy = SHAGeneratorService.new('https://sec.neurofuzz-software.com/paos/genSSHA-SOAP.php?wsdl')
54
+ end
55
+
56
+ it "should be SSL" do
57
+ @proxy.http.use_ssl.should be_true
58
+ end
59
+
60
+ it "should generate a SSH hash" do
61
+ result = @proxy.genSSHA(:text => 'hello world', :hash_type => 'sha512')
62
+ result.should =~ /^[{SSHA512}]/
63
+ end
64
+ end
65
+ end
metadata ADDED
@@ -0,0 +1,76 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jeremydurham-serviceproxy
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Jeremy Durham
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-12-13 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: nokogiri
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: "0"
23
+ version:
24
+ - !ruby/object:Gem::Dependency
25
+ name: hpricot
26
+ version_requirement:
27
+ version_requirements: !ruby/object:Gem::Requirement
28
+ requirements:
29
+ - - ">="
30
+ - !ruby/object:Gem::Version
31
+ version: "0"
32
+ version:
33
+ description: Lightweight SOAP library for Ruby
34
+ email: jeremydurham@gmail.com
35
+ executables: []
36
+
37
+ extensions: []
38
+
39
+ extra_rdoc_files:
40
+ - README
41
+ - LICENSE
42
+ files:
43
+ - LICENSE
44
+ - README
45
+ - Rakefile
46
+ - lib/service_proxy.rb
47
+ - spec/service_helper.rb
48
+ - spec/service_proxy_spec.rb
49
+ has_rdoc: true
50
+ homepage: ""
51
+ post_install_message:
52
+ rdoc_options: []
53
+
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: "0"
61
+ version:
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: "0"
67
+ version:
68
+ requirements: []
69
+
70
+ rubyforge_project:
71
+ rubygems_version: 1.2.0
72
+ signing_key:
73
+ specification_version: 2
74
+ summary: Lightweight SOAP library for Ruby
75
+ test_files: []
76
+