opensrs 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,14 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem "libxml-ruby", "~> 1.0.0"
4
+
5
+ group :development do
6
+ gem "nokogiri"
7
+ gem "jeweler"
8
+ gem "git"
9
+ gem "rake"
10
+ gem "bundler"
11
+ gem "yard"
12
+ gem "shoulda"
13
+ gem "rspec", "~> 2.0"
14
+ end
@@ -0,0 +1,36 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ diff-lcs (1.1.2)
5
+ git (1.2.5)
6
+ jeweler (1.6.0)
7
+ bundler (~> 1.0.0)
8
+ git (>= 1.2.5)
9
+ rake
10
+ libxml-ruby (1.0.0)
11
+ nokogiri (1.4.4)
12
+ rake (0.8.7)
13
+ rspec (2.5.0)
14
+ rspec-core (~> 2.5.0)
15
+ rspec-expectations (~> 2.5.0)
16
+ rspec-mocks (~> 2.5.0)
17
+ rspec-core (2.5.2)
18
+ rspec-expectations (2.5.0)
19
+ diff-lcs (~> 1.1.2)
20
+ rspec-mocks (2.5.0)
21
+ shoulda (2.11.3)
22
+ yard (0.6.8)
23
+
24
+ PLATFORMS
25
+ ruby
26
+
27
+ DEPENDENCIES
28
+ bundler
29
+ git
30
+ jeweler
31
+ libxml-ruby (~> 1.0.0)
32
+ nokogiri
33
+ rake
34
+ rspec (~> 2.0)
35
+ shoulda
36
+ yard
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2010 Josh Delsman
1
+ Copyright (c) 2010-2011 Josh Delsman
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
@@ -1,7 +1,7 @@
1
1
  = OpenSRS
2
2
 
3
- Provides basic support to connect to, and utilise the OpenSRS API. This library has been well-tested in a high performance production
4
- environment. More information on the API can be located here:
3
+ 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
4
+ environments. More information on the API can be located here:
5
5
 
6
6
  http://opensrs.com/resources/documentation/opensrs_xmlapi.pdf
7
7
 
@@ -9,19 +9,19 @@ http://opensrs.com/resources/documentation/opensrs_xmlapi.pdf
9
9
 
10
10
  You can install this gem by doing the following:
11
11
 
12
- $ gem install opensrs
12
+ $ gem install opensrs
13
13
 
14
14
  You can then include it in a Ruby project, like so:
15
15
 
16
- require 'opensrs'
16
+ require 'opensrs'
17
17
 
18
18
  Alternatively, you can include it in a Rails 2.x project in the <tt>environment.rb</tt> file, like so:
19
19
 
20
- config.gem "opensrs"
20
+ config.gem "opensrs"
21
21
 
22
22
  For Rails 3.x, use the <tt>Gemfile</tt>:
23
23
 
24
- gem "opensrs"
24
+ gem "opensrs"
25
25
 
26
26
  == Usage
27
27
 
@@ -32,38 +32,43 @@ This library provides basic functionality for interacting with the OpenSRS XML A
32
32
  * XML encoding
33
33
  * XML decoding
34
34
 
35
- To connect, instantiate a new OpenSRS::Server object:
35
+ Currently, the library supports LibXML and Nokogiri as XML parsers. By default, it uses LibXML to parse and generate XML. If you'd like to use Nokogiri for parsing XML, then in one of your app initializers add the following line:
36
36
 
37
- server = OpenSRS::Server.new(
38
- :server => "https://rr-n1-tor.opensrs.net:55443/",
39
- :username => "testing",
40
- :password => "53cr3t",
41
- :key => "c633be3170c7fb3fb29e2f99b84be2410..."
37
+ OpenSRS::Server.xml_processor = :nokogiri
38
+
39
+ To connect, instantiate a new <tt>OpenSRS::Server</tt> object:
40
+
41
+ server = OpenSRS::Server.new(
42
+ :server => "https://rr-n1-tor.opensrs.net:55443/",
43
+ :username => "testing",
44
+ :password => "53cr3t",
45
+ :key => "c633be3170c7fb3fb29e2f99b84be2410..."
46
+ )
47
+
48
+ NOTE: Connecting to OpenSRS requires that you add the IP(s) you're connecting from to their whitelist. Login to the testing or production servers, and add your IP(s) under Profile Management > Add IPs for Script/API Access. IP changes take about one hour to take effect.
49
+
50
+ Once you have a server connection class, you can build from this to create the methods that you need. For instance, let's say we want to grab our account balance. The OpenSRS XML API takes a couple of attributes for all commands. You can include those here:
51
+
52
+ def get_balance
53
+ server.call(
54
+ :action => "GET_BALANCE",
55
+ :object => "BALANCE"
42
56
  )
43
-
44
- Once you have this, you can build from this to create the methods that you need. For instance, let's say we want to grab
45
- our account balance. The OpenSRS XML API takes a couple of attributes for all commands. You can include those here:
46
-
47
- def get_balance
48
- server.call(
49
- :action => "GET_BALANCE",
50
- :object => "BALANCE"
51
- )
52
- end
57
+ end
53
58
 
54
59
  Sometimes you might need to include attributes for the command, such as a cookie, or the data attributes themselves. You can do this, too:
55
60
 
56
- def create_nameserver(nameserver)
57
- server.call(
58
- :action => "CREATE",
59
- :object => "NAMESERVER",
60
- :cookie => "366828736:3210384",
61
- :attributes => {
62
- :name => nameserver.hostname,
63
- :ipaddress => "212.112.123.11"
64
- }
65
- )
66
- end
61
+ def create_nameserver(nameserver)
62
+ server.call(
63
+ :action => "CREATE",
64
+ :object => "NAMESERVER",
65
+ :cookie => "366828736:3210384",
66
+ :attributes => {
67
+ :name => nameserver.hostname,
68
+ :ipaddress => "212.112.123.11"
69
+ }
70
+ )
71
+ end
67
72
 
68
73
  Responses from OpenSRS are returned in an OpenSRS::Response object, which gives you access to a multitude of things.
69
74
 
@@ -80,14 +85,13 @@ If you have any bugs or feature requests for this gem, feel free to add them in
80
85
  http://github.com/voxxit/opensrs/issues
81
86
 
82
87
  == Note on Patches/Pull Requests
83
-
88
+
84
89
  * Fork the project.
85
90
  * Make your feature addition or bug fix.
86
- * Add tests for it. This is important so I don't break it in a
87
- future version unintentionally.
91
+ * Add tests for it. This is important so I don't break it in a future version unintentionally.
88
92
  * 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.
89
93
  * Send me a pull request. Bonus points for topic branches.
90
94
 
91
95
  == Copyright
92
96
 
93
- Copyright (c) 2010 Josh Delsman. See LICENSE for details.
97
+ Copyright (c) 2010-2011 Josh Delsman. Distributed under the MIT license. See LICENSE for details.
data/Rakefile CHANGED
@@ -1,56 +1,46 @@
1
1
  require 'rubygems'
2
+ require 'bundler'
3
+
4
+ begin
5
+ Bundler.setup(:default, :development)
6
+ rescue Bundler::BundlerError => e
7
+ $stderr.puts e.message
8
+ $stderr.puts "Run `bundle install` to install missing gems"
9
+ exit e.status_code
10
+ end
11
+
12
+ $LOAD_PATH.unshift("lib")
13
+
2
14
  require 'rake'
15
+ require 'opensrs'
3
16
 
4
17
  begin
5
18
  require 'jeweler'
19
+
6
20
  Jeweler::Tasks.new do |gem|
7
- gem.name = "opensrs"
8
- gem.summary = %Q{Provides support to utilise the OpenSRS API with Ruby/Rails.}
9
- gem.description = %Q{Provides support to utilise the OpenSRS API with Ruby/Rails.}
10
- gem.email = "josh@voxx.it"
11
- gem.homepage = "http://github.com/voxxit/opensrs"
12
- gem.authors = ["Josh Delsman"]
13
- gem.add_dependency "libxml-ruby"
14
- gem.add_development_dependency "rspec", "~> 2.0"
21
+ gem.name = "opensrs"
22
+ gem.version = OpenSRS::Version::VERSION
23
+ gem.summary = "Provides support to utilize the OpenSRS API with Ruby/Rails."
24
+ gem.description = "Provides support to utilize the OpenSRS API with Ruby/Rails."
25
+ gem.email = "josh@voxxit.com"
26
+ gem.homepage = "http://github.com/voxxit/opensrs"
27
+ gem.license = "MIT"
28
+ gem.authors = ["Josh Delsman"]
29
+
30
+ # Requirements are in Gemfile
15
31
  end
16
32
  rescue LoadError
17
33
  puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
18
34
  end
19
35
 
20
- require 'rake/testtask'
21
- Rake::TestTask.new(:test) do |test|
22
- test.libs << 'lib' << 'test'
23
- test.pattern = 'test/**/*_test.rb'
24
- test.verbose = true
25
- end
36
+ require 'rspec/core/rake_task'
26
37
 
27
- begin
28
- require 'rcov/rcovtask'
29
- Rcov::RcovTask.new do |test|
30
- test.libs << 'test'
31
- test.pattern = 'test/**/*_test.rb'
32
- test.verbose = true
33
- end
34
- rescue LoadError
35
- task :rcov do
36
- abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
37
- end
38
- end
39
-
40
- task :test => :check_dependencies
38
+ RSpec::Core::RakeTask.new(:spec)
41
39
 
42
- task :default => :test
40
+ task :default => :spec
43
41
 
44
- require 'rake/rdoctask'
45
- Rake::RDocTask.new do |rdoc|
46
- if File.exist?('VERSION')
47
- version = File.read('VERSION')
48
- else
49
- version = ""
50
- end
42
+ require 'yard'
51
43
 
52
- rdoc.rdoc_dir = 'rdoc'
53
- rdoc.title = "opensrs #{version}"
54
- rdoc.rdoc_files.include('README*')
55
- rdoc.rdoc_files.include('lib/**/*.rb')
44
+ YARD::Rake::YardocTask.new do |t|
45
+ t.files = FileList['lib/**/*.rb']
56
46
  end
@@ -1,6 +1,8 @@
1
+ require File.dirname(__FILE__) + '/opensrs/xml_processor'
2
+ require File.dirname(__FILE__) + '/opensrs/xml_processor/libxml.rb'
1
3
  require File.dirname(__FILE__) + '/opensrs/server.rb'
2
4
  require File.dirname(__FILE__) + '/opensrs/response.rb'
3
- require File.dirname(__FILE__) + '/opensrs/xml.rb'
5
+ require File.dirname(__FILE__) + '/opensrs/version.rb'
4
6
 
5
7
  module OpenSRS
6
8
  end
@@ -4,6 +4,8 @@ require "digest/md5"
4
4
  require "openssl"
5
5
 
6
6
  module OpenSRS
7
+ class BadResponse < StandardError; end
8
+
7
9
  class Server
8
10
  attr_accessor :server, :username, :password, :key
9
11
 
@@ -19,13 +21,26 @@ module OpenSRS
19
21
  :protocol => "XCP"
20
22
  }
21
23
 
22
- xml = OpenSRS::XML.build(attributes.merge!(options))
23
-
24
- response = http.post(server.path, xml, headers(xml))
25
- parsed_response = OpenSRS::XML.parse(response.body)
24
+ xml = xml_processor.build(attributes.merge!(options))
25
+
26
+ response = http.post(server.path, xml, headers(xml))
27
+ parsed_response = xml_processor.parse(response.body)
26
28
 
27
29
  return OpenSRS::Response.new(parsed_response, xml, response.body)
30
+ rescue Net::HTTPBadResponse
31
+ raise OpenSRS::BadResponse, "Received a bad response from OpenSRS. Please check that your IP address is added to the whitelist, and try again."
32
+ end
33
+
34
+ def xml_processor
35
+ @@xml_processor
28
36
  end
37
+
38
+ def self.xml_processor=(name)
39
+ require File.dirname(__FILE__) + "/xml_processor/#{name.to_s.downcase}"
40
+ @@xml_processor = OpenSRS::XmlProcessor.const_get("#{name.to_s.capitalize}")
41
+ end
42
+
43
+ OpenSRS::Server.xml_processor = :libxml
29
44
 
30
45
  private
31
46
 
@@ -53,4 +68,4 @@ module OpenSRS
53
68
  http
54
69
  end
55
70
  end
56
- end
71
+ end
@@ -0,0 +1,5 @@
1
+ module OpenSRS
2
+ class Version
3
+ VERSION = "0.3.0"
4
+ end
5
+ end
@@ -0,0 +1,77 @@
1
+ module OpenSRS
2
+
3
+ class XmlProcessor
4
+
5
+ # Parses the main data block from OpenSRS and discards
6
+ # the rest of the response.
7
+ def self.parse(response)
8
+ data_block = data_block_element(response)
9
+
10
+ raise ArgumentError.new("No data found in document") if !data_block
11
+
12
+ return decode_data(data_block)
13
+ end
14
+
15
+ protected
16
+
17
+ # Encodes individual elements, and their child elements, for the root XML document.
18
+ def self.encode_data(data, container = nil)
19
+ case data.class.to_s
20
+ when "Array" then return encode_dt_array(data, container)
21
+ when "Hash" then return encode_dt_assoc(data, container)
22
+ when "String", "Numeric", "Date", "Time", "Symbol", "NilClass"
23
+ return data.to_s
24
+ else
25
+ return data.inspect
26
+ end
27
+
28
+ return nil
29
+ end
30
+
31
+ def self.encode_dt_array(data, container)
32
+ dt_array = new_element(:dt_array, container)
33
+
34
+ data.each_with_index do |item, index|
35
+ item_node = new_element(:item, container)
36
+ item_node["key"] = index.to_s
37
+ item_node << encode_data(item, item_node)
38
+
39
+ dt_array << item_node
40
+ end
41
+
42
+ return dt_array
43
+ end
44
+
45
+ def self.encode_dt_assoc(data, container)
46
+ dt_assoc = new_element(:dt_assoc, container)
47
+
48
+ data.each do |key, value|
49
+ item_node = new_element(:item, container)
50
+ item_node["key"] = key.to_s
51
+ item_node << encode_data(value, item_node)
52
+
53
+ dt_assoc << item_node
54
+ end
55
+
56
+ return dt_assoc
57
+ end
58
+
59
+ # Recursively decodes individual data elements from OpenSRS
60
+ # server response.
61
+ def self.decode_data(data)
62
+ data.each do |element|
63
+ case element.name
64
+ when "dt_array"
65
+ return decode_dt_array_data(element)
66
+ when "dt_assoc"
67
+ return decode_dt_assoc_data(element)
68
+ when "text", "item", "dt_scalar"
69
+ next if element.content.strip.empty?
70
+ return element.content.strip
71
+ end
72
+ end
73
+ end
74
+
75
+ end
76
+
77
+ end
@@ -0,0 +1,60 @@
1
+ require "libxml"
2
+
3
+ module OpenSRS
4
+ class XmlProcessor::Libxml < OpenSRS::XmlProcessor
5
+ include ::LibXML::XML
6
+
7
+ # First, builds REXML elements for the inputted data. Then, it will
8
+ # go ahead and build the entire XML document to send to OpenSRS.
9
+ def self.build(data)
10
+ xml = Document.new
11
+ xml.root = envelope = Node.new("OPS_envelope")
12
+
13
+ envelope << header = Node.new("header")
14
+ envelope << body = Node.new("body")
15
+ header << Node.new("version", "0.9")
16
+ body << data_block = Node.new("data_block")
17
+
18
+ data_block << encode_data(data, data_block)
19
+
20
+ return xml.to_s
21
+ end
22
+
23
+ protected
24
+
25
+ def self.data_block_element(response)
26
+ doc = Parser.string(response).parse
27
+ return doc.find("//OPS_envelope/body/data_block/*")
28
+ end
29
+
30
+ def self.decode_dt_array_data(element)
31
+ dt_array = []
32
+
33
+ element.children.each do |item|
34
+ next if item.empty?
35
+ dt_array[item.attributes["key"].to_i] = decode_data(item)
36
+ end
37
+
38
+ return dt_array
39
+ end
40
+
41
+ def self.decode_dt_assoc_data(element)
42
+ dt_assoc = {}
43
+
44
+ element.children.each do |item|
45
+ next if item.content.strip.empty?
46
+ dt_assoc[item.attributes["key"]] = decode_data(item)
47
+ end
48
+
49
+ return dt_assoc
50
+ end
51
+
52
+ # Accepts two parameters but uses only one; to keep the interface same as other xml parser classes
53
+ # Is that a side effect of Template pattern?
54
+ #
55
+ def self.new_element(element_name, container)
56
+ return Node.new(element_name.to_s)
57
+ end
58
+
59
+ end
60
+ end