Skip to content

Instantly share code, notes, and snippets.

@csaunders
Created December 5, 2013 02:26
Show Gist options
  • Save csaunders/7799209 to your computer and use it in GitHub Desktop.
Save csaunders/7799209 to your computer and use it in GitHub Desktop.
diff --git a/.gitignore b/.gitignore
index 8b6632c..2a33328 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,4 @@ rdoc
pkg
doc
.yardoc
+.rbenv-version
diff --git a/Gemfile b/Gemfile
index bd074a7..95a7840 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,9 +1,9 @@
source "http://rubygems.org"
-gem "nokogiri", "~> 1.4.6"
+gem "libxml-ruby", "~> 2.6.0"
group :development do
- gem "libxml-ruby", "~> 2.1.2"
+ gem "nokogiri", "~> 1.4.6"
gem "jeweler"
gem "git"
gem "rake"
diff --git a/Gemfile.lock b/Gemfile.lock
index 2200795..e7b7d02 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,24 +1,44 @@
GEM
remote: http://rubygems.org/
specs:
- diff-lcs (1.1.2)
+ activesupport (3.2.13)
+ i18n (= 0.6.1)
+ multi_json (~> 1.0)
+ bourne (1.1.2)
+ mocha (= 0.10.5)
+ diff-lcs (1.2.1)
git (1.2.5)
- jeweler (1.6.4)
+ i18n (0.6.1)
+ jeweler (1.8.4)
bundler (~> 1.0)
git (>= 1.2.5)
rake
- libxml-ruby (2.1.2)
+ rdoc
+ json (1.7.7)
+ libxml-ruby (2.6.0)
+ metaclass (0.0.1)
+ mocha (0.10.5)
+ metaclass (~> 0.0.1)
+ multi_json (1.7.1)
nokogiri (1.4.7)
- rake (0.9.2)
- rspec (2.6.0)
- rspec-core (~> 2.6.0)
- rspec-expectations (~> 2.6.0)
- rspec-mocks (~> 2.6.0)
- rspec-core (2.6.4)
- rspec-expectations (2.6.0)
- diff-lcs (~> 1.1.2)
- rspec-mocks (2.6.0)
- shoulda (2.11.3)
+ rake (10.0.3)
+ rdoc (4.0.0)
+ json (~> 1.4)
+ rspec (2.13.0)
+ rspec-core (~> 2.13.0)
+ rspec-expectations (~> 2.13.0)
+ rspec-mocks (~> 2.13.0)
+ rspec-core (2.13.1)
+ rspec-expectations (2.13.0)
+ diff-lcs (>= 1.1.3, < 2.0)
+ rspec-mocks (2.13.0)
+ shoulda (3.3.2)
+ shoulda-context (~> 1.0.1)
+ shoulda-matchers (~> 1.4.1)
+ shoulda-context (1.0.2)
+ shoulda-matchers (1.4.2)
+ activesupport (>= 3.0.0)
+ bourne (~> 1.1.2)
PLATFORMS
ruby
@@ -26,7 +46,7 @@ PLATFORMS
DEPENDENCIES
git
jeweler
- libxml-ruby (~> 2.1.2)
+ libxml-ruby (~> 2.6.0)
nokogiri (~> 1.4.6)
rake
rspec (~> 2.0)
diff --git a/README.rdoc b/README.rdoc
index 436ebd1..cd26664 100644
--- a/README.rdoc
+++ b/README.rdoc
@@ -1,24 +1,27 @@
-= OpenSRS http://travis-ci.org/voxxit/opensrs.png
+= OpenSRS
+
+{<img src="https://travis-ci.org/voxxit/opensrs.png" />}[https://travis-ci.org/voxxit/opensrs]
+{<img src="https://codeclimate.com/github/voxxit/opensrs.png" />}[https://codeclimate.com/github/voxxit/opensrs]
This (unofficial) OpenSRS gem provides basic support to connect to, and utilize the OpenSRS API. This library has been well-tested in high-performance production
environments. More information on the API can be located here:
-http://opensrs.com/resources/documentation/opensrs_xmlapi.pdf
+http://www.opensrs.com/site/resources/documentation/api
== Installation
You can install this gem by doing the following:
$ gem install opensrs
-
+
You can then include it in a Ruby project, like so:
require 'opensrs'
-
+
Alternatively, you can include it in a Rails 2.x project in the <tt>environment.rb</tt> file, like so:
config.gem "opensrs"
-
+
For Rails 3.x, use the <tt>Gemfile</tt>:
gem "opensrs"
@@ -55,7 +58,7 @@ Once you have a server connection class, you can build from this to create the m
:object => "BALANCE"
)
end
-
+
Sometimes you might need to include attributes for the command, such as a cookie, or the data attributes themselves. You can do this, too:
def create_nameserver(nameserver)
@@ -69,7 +72,7 @@ Sometimes you might need to include attributes for the command, such as a cookie
}
)
end
-
+
Responses from OpenSRS are returned in an OpenSRS::Response object, which gives you access to a multitude of things.
* <tt>response.response</tt> - This gives you the response in a Hash form, which is highly accessible to most other actions in your application.
@@ -92,6 +95,11 @@ http://github.com/voxxit/opensrs/issues
* Commit, do not mess with rakefile, version, or history. If you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull.
* Send me a pull request. Bonus points for topic branches.
+== Contributors (in order of appearance)
+
+* Josh Delsman
+* Glenn Roberts
+
== Copyright
-Copyright (c) 2010-2011 Josh Delsman. Distributed under the MIT license. See LICENSE for details.
\ No newline at end of file
+Copyright (c) 2010-2013 Josh Delsman. Distributed under the MIT license. See LICENSE for details.
diff --git a/lib/opensrs.rb b/lib/opensrs.rb
index 49571b6..a3490b4 100644
--- a/lib/opensrs.rb
+++ b/lib/opensrs.rb
@@ -1,8 +1,8 @@
require File.dirname(__FILE__) + '/opensrs/xml_processor'
-require File.dirname(__FILE__) + '/opensrs/xml_processor/nokogiri.rb'
+require File.dirname(__FILE__) + '/opensrs/xml_processor/libxml.rb'
require File.dirname(__FILE__) + '/opensrs/server.rb'
require File.dirname(__FILE__) + '/opensrs/response.rb'
require File.dirname(__FILE__) + '/opensrs/version.rb'
module OpenSRS
-end
+end
\ No newline at end of file
diff --git a/lib/opensrs/server.rb b/lib/opensrs/server.rb
index 1e78d55..ea8e82d 100644
--- a/lib/opensrs/server.rb
+++ b/lib/opensrs/server.rb
@@ -5,33 +5,33 @@ require "openssl"
module OpenSRS
class BadResponse < StandardError; end
-
+ class TimeoutError < StandardError; end
+
class Server
- attr_accessor :server, :username, :password, :key, :logger
+ attr_accessor :server, :username, :password, :key, :timeout, :open_timeout
def initialize(options = {})
@server = URI.parse(options[:server] || "https://rr-n1-tor.opensrs.net:55443/")
@username = options[:username]
@password = options[:password]
@key = options[:key]
- @logger = options[:logger]
+ @timeout = options[:timeout]
+ @open_timeout = options[:open_timeout]
end
- def call(options = {})
- attributes = {
- :protocol => "XCP"
- }
-
- xml = xml_processor.build(attributes.merge!(options))
- log(xml, "Request XML for #{options[:object]} #{options[:action]}")
+ def call(data = {})
+ xml = xml_processor.build({ :protocol => "XCP" }.merge!(data))
+
+ begin
+ response = http.post(server_path, xml, headers(xml))
+ rescue Net::HTTPBadResponse
+ raise OpenSRS::BadResponse, "Received a bad response from OpenSRS. Please check that your IP address is added to the whitelist, and try again."
+ end
- response = http.post(server.path, xml, headers(xml))
- log(response.body, "Response XML for #{options[:object]} #{options[:action]}")
parsed_response = xml_processor.parse(response.body)
-
return OpenSRS::Response.new(parsed_response, xml, response.body)
- rescue Net::HTTPBadResponse
- raise OpenSRS::BadResponse, "Received a bad response from OpenSRS. Please check that your IP address is added to the whitelist, and try again."
+ rescue Timeout::Error => err
+ raise OpenSRS::TimeoutError, err
end
def xml_processor
@@ -43,40 +43,35 @@ module OpenSRS
@@xml_processor = OpenSRS::XmlProcessor.const_get("#{name.to_s.capitalize}")
end
- OpenSRS::Server.xml_processor = :nokogiri
-
+ OpenSRS::Server.xml_processor = :libxml
+
private
-
+
def headers(request)
- headers = {
- "Content-Length" => request.length.to_s,
+ { "Content-Length" => request.length.to_s,
"Content-Type" => "text/xml",
"X-Username" => username,
"X-Signature" => signature(request)
}
-
- return headers
end
-
+
def signature(request)
signature = Digest::MD5.hexdigest(request + key)
signature = Digest::MD5.hexdigest(signature + key)
signature
end
-
+
def http
http = Net::HTTP.new(server.host, server.port)
http.use_ssl = (server.scheme == "https")
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
+ http.read_timeout = http.open_timeout = @timeout if @timeout
+ http.open_timeout = @open_timeout if @open_timeout
http
end
- def log(data, message)
- return unless logger
-
- message = "[OpenSRS] " + message
- line = [message, data].join("\n")
- logger.info(line)
+ def server_path
+ server.path.empty? ? '/' : server.path
end
end
end
diff --git a/lib/opensrs/version.rb b/lib/opensrs/version.rb
index b361625..3c72fb0 100644
--- a/lib/opensrs/version.rb
+++ b/lib/opensrs/version.rb
@@ -1,5 +1,5 @@
module OpenSRS
class Version
- VERSION = "0.3.2"
+ VERSION = "0.3.4"
end
end
diff --git a/lib/opensrs/xml_processor.rb b/lib/opensrs/xml_processor.rb
index 325cf7a..d3d87eb 100644
--- a/lib/opensrs/xml_processor.rb
+++ b/lib/opensrs/xml_processor.rb
@@ -16,16 +16,16 @@ module OpenSRS
# Encodes individual elements, and their child elements, for the root XML document.
def self.encode_data(data, container = nil)
- case data
- when Array
- encode_dt_array(data, container)
- when Hash
- encode_dt_assoc(data, container)
- when String, Numeric, Date, Time, Symbol, NilClass
- data.to_s
+ case data.class.to_s
+ when "Array" then return encode_dt_array(data, container)
+ when "Hash" then return encode_dt_assoc(data, container)
+ when "String", "Numeric", "Date", "Time", "Symbol", "NilClass"
+ return data.to_s
else
- data.inspect
+ return data.inspect
end
+
+ return nil
end
def self.encode_dt_array(data, container)
@@ -39,7 +39,7 @@ module OpenSRS
dt_array << item_node
end
- dt_array
+ return dt_array
end
def self.encode_dt_assoc(data, container)
@@ -53,7 +53,7 @@ module OpenSRS
dt_assoc << item_node
end
- dt_assoc
+ return dt_assoc
end
# Recursively decodes individual data elements from OpenSRS
@@ -74,4 +74,4 @@ module OpenSRS
end
-end
+end
\ No newline at end of file
diff --git a/opensrs.gemspec b/opensrs.gemspec
index e368ddf..204a471 100644
--- a/opensrs.gemspec
+++ b/opensrs.gemspec
@@ -4,14 +4,14 @@
# -*- encoding: utf-8 -*-
Gem::Specification.new do |s|
- s.name = %q{opensrs}
- s.version = "0.3.2"
+ s.name = "opensrs"
+ s.version = "0.3.4"
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Josh Delsman"]
- s.date = %q{2011-08-08}
- s.description = %q{Provides support to utilize the OpenSRS API with Ruby/Rails.}
- s.email = %q{jdelsman@voxxit.com}
+ s.date = "2013-04-04"
+ s.description = "Provides support to utilize the OpenSRS API with Ruby/Rails."
+ s.email = "jdelsman@voxxit.com"
s.extra_rdoc_files = [
"LICENSE",
"README.rdoc"
@@ -37,26 +37,26 @@ Gem::Specification.new do |s|
"spec/opensrs/xml_processor/nokogiri_spec.rb",
"spec/spec_helper.rb"
]
- s.homepage = %q{http://github.com/voxxit/opensrs}
+ s.homepage = "http://github.com/voxxit/opensrs"
s.licenses = ["MIT"]
s.require_paths = ["lib"]
- s.rubygems_version = %q{1.6.2}
- s.summary = %q{Provides support to utilize the OpenSRS API with Ruby/Rails.}
+ s.rubygems_version = "1.8.23"
+ s.summary = "Provides support to utilize the OpenSRS API with Ruby/Rails."
if s.respond_to? :specification_version then
s.specification_version = 3
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
- s.add_runtime_dependency(%q<nokogiri>, ["~> 1.4.6"])
- s.add_development_dependency(%q<libxml-ruby>, ["~> 2.1.2"])
+ s.add_runtime_dependency(%q<libxml-ruby>, ["~> 2.6.0"])
+ s.add_development_dependency(%q<nokogiri>, ["~> 1.4.6"])
s.add_development_dependency(%q<jeweler>, [">= 0"])
s.add_development_dependency(%q<git>, [">= 0"])
s.add_development_dependency(%q<rake>, [">= 0"])
s.add_development_dependency(%q<shoulda>, [">= 0"])
s.add_development_dependency(%q<rspec>, ["~> 2.0"])
else
+ s.add_dependency(%q<libxml-ruby>, ["~> 2.6.0"])
s.add_dependency(%q<nokogiri>, ["~> 1.4.6"])
- s.add_dependency(%q<libxml-ruby>, ["~> 2.1.2"])
s.add_dependency(%q<jeweler>, [">= 0"])
s.add_dependency(%q<git>, [">= 0"])
s.add_dependency(%q<rake>, [">= 0"])
@@ -64,8 +64,8 @@ Gem::Specification.new do |s|
s.add_dependency(%q<rspec>, ["~> 2.0"])
end
else
+ s.add_dependency(%q<libxml-ruby>, ["~> 2.6.0"])
s.add_dependency(%q<nokogiri>, ["~> 1.4.6"])
- s.add_dependency(%q<libxml-ruby>, ["~> 2.1.2"])
s.add_dependency(%q<jeweler>, [">= 0"])
s.add_dependency(%q<git>, [">= 0"])
s.add_dependency(%q<rake>, [">= 0"])
diff --git a/spec/opensrs/server_spec.rb b/spec/opensrs/server_spec.rb
index 4f5fabe..2664031 100644
--- a/spec/opensrs/server_spec.rb
+++ b/spec/opensrs/server_spec.rb
@@ -1,21 +1,109 @@
require 'spec_helper'
describe OpenSRS::Server do
- before(:each) do
- @server = OpenSRS::Server.new
+ let(:server) { OpenSRS::Server.new }
+
+ describe '#new' do
+ it 'allows timeouts to be set' do
+ server = OpenSRS::Server.new({ :timeout => 90 })
+ server.timeout.should == 90
+ server.open_timeout.should be_nil
+ end
+
+ it 'allows open timeouts to be set' do
+ server = OpenSRS::Server.new({ :timeout => 90, :open_timeout => 10 })
+ server.timeout.should eq(90)
+ server.open_timeout.should eq(10)
+ end
+
+ it 'leaves it up to Net::HTTP if no timeouts given' do
+ server.timeout.should be_nil
+ server.open_timeout.should be_nil
+ end
+ end
+
+ describe ".call" do
+ let(:response) { double(:body => 'some response') }
+ let(:header) { {"some" => "header" } }
+ let(:xml) { '<some xml></some xml>' }
+ let(:response_xml) { xml }
+ let(:xml_processor) { double OpenSRS::XmlProcessor }
+ let(:http) { double(Net::HTTP, :use_ssl= => true, :verify_mode= => true) }
+
+ before :each do
+ server.stub(:headers).and_return header
+ xml_processor.stub(:build).and_return xml
+ xml_processor.stub(:parse).and_return response_xml
+ server.stub(:xml_processor).and_return xml_processor
+ http.stub(:post).and_return response
+ Net::HTTP.stub(:new).and_return http
+ end
+
+ it "builds XML request" do
+ xml_processor.should_receive(:build).with(:protocol => "XCP", :some => 'option')
+ server.call(:some => 'option')
+ end
+
+ it "posts to given path" do
+ server.server = URI.parse 'http://with-path.com/endpoint'
+ http.should_receive(:post).with('/endpoint', xml, header).and_return double.as_null_object
+ server.call
+ end
+
+ it "parses the response" do
+ xml_processor.should_receive(:parse).with(response.body)
+ server.call(:some => 'option')
+ end
+
+ it "posts to root path" do
+ server.server = URI.parse 'http://root-path.com/'
+ http.should_receive(:post).with('/', xml, header).and_return double.as_null_object
+ server.call
+ end
+
+ it "defaults path to '/'" do
+ server.server = URI.parse 'http://no-path.com'
+ http.should_receive(:post).with('/', xml, header).and_return double.as_null_object
+ server.call
+ end
+
+ it 'allows overriding of default (Net:HTTP) timeouts' do
+ server.timeout = 90
+
+ http.should_receive(:open_timeout=).with(90)
+ http.should_receive(:read_timeout=).with(90)
+
+ server.call( { :some => 'data' } )
+ end
+
+ it 'allows overriding of default (Net:HTTP) timeouts' do
+ server.timeout = 180
+ server.open_timeout = 30
+
+ http.should_receive(:read_timeout=).with(180)
+ http.should_receive(:open_timeout=).with(180)
+ http.should_receive(:open_timeout=).with(30)
+
+ server.call( { :some => 'data' } )
+ end
+
+ it 're-raises Net:HTTP timeouts' do
+ http.should_receive(:post).and_raise err = Timeout::Error.new('test')
+ expect { server.call }.to raise_exception OpenSRS::TimeoutError
+ end
end
describe "#test xml processor" do
context "on class initialization" do
- it { @server.xml_processor.should eql(OpenSRS::XmlProcessor::Nokogiri) }
+ it { server.xml_processor.should eql(OpenSRS::XmlProcessor::Libxml) }
end
context "on changing xml processor" do
before(:each) do
- OpenSRS::Server.xml_processor = :libxml
+ OpenSRS::Server.xml_processor = :nokogiri
end
- it { @server.xml_processor.should eql(OpenSRS::XmlProcessor::Libxml) }
+ it { server.xml_processor.should eql(OpenSRS::XmlProcessor::Nokogiri) }
end
end
end
diff --git a/spec/opensrs/version_spec.rb b/spec/opensrs/version_spec.rb
index dfa8268..fa40a60 100644
--- a/spec/opensrs/version_spec.rb
+++ b/spec/opensrs/version_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe OpenSRS::Version do
describe "VERSION" do
it "should return version string" do
- OpenSRS::Version::VERSION.should eql("0.3.2")
+ OpenSRS::Version::VERSION.should eql("0.3.4")
end
end
-end
\ No newline at end of file
+end
diff --git a/spec/opensrs/xml_processor/nokogiri_spec.rb b/spec/opensrs/xml_processor/nokogiri_spec.rb
index fa47d93..4323e09 100644
--- a/spec/opensrs/xml_processor/nokogiri_spec.rb
+++ b/spec/opensrs/xml_processor/nokogiri_spec.rb
@@ -1,9 +1,6 @@
require 'spec_helper'
require 'date'
-class OrderedHash < Hash
-end
-
describe OpenSRS::XmlProcessor::Nokogiri do
describe ".build" do
it "should create XML for a nested hash" do
@@ -51,22 +48,6 @@ describe OpenSRS::XmlProcessor::Nokogiri do
it { @e.children[0].attributes["key"].value.should eql('name') }
end
- context "on a hash subclass" do
- before(:each) do
- ohash = OrderedHash.new
- ohash[:name] = 'kitten'
- @e = OpenSRS::XmlProcessor::Nokogiri.encode_data(ohash, @doc)
- end
-
- it { @e.should be_an_instance_of(::Nokogiri::XML::Element) }
- it { @e.name.should eql('dt_assoc') }
-
- it { @e.should have(1).children }
- it { @e.children[0].name.should eql('item') }
- it { @e.children[0].attributes["key"].value.should eql('name') }
- end
-
-
context "on a nested hash" do
before(:each) do
@e = OpenSRS::XmlProcessor::Nokogiri.encode_data({:suggestion => {:maximum => "10"}}, @doc)
@@ -244,4 +225,4 @@ describe OpenSRS::XmlProcessor::Nokogiri do
end
end
-end
+end
\ No newline at end of file
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 7c6c8f2..65d02c8 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -2,4 +2,5 @@ require 'opensrs/xml_processor.rb'
require 'opensrs/xml_processor/libxml.rb'
require 'opensrs/xml_processor/nokogiri.rb'
require 'opensrs/server.rb'
-require 'opensrs/version.rb'
\ No newline at end of file
+require 'opensrs/version.rb'
+require 'opensrs/response.rb'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment