shanesveller-webbynode-api 0.0.5 → 0.0.6

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/README.rdoc CHANGED
@@ -4,13 +4,19 @@ This gem wraps the API available for the VPS hosting company
4
4
  {WebbyNode}[http://www.webbynode.com]. Details and a preliminary
5
5
  design document for the API itself are available
6
6
  {here}[http://howto.webbynode.com/topic.php?id=25]. Functionality
7
- is currently based on the API guide version 1.
7
+ is currently based on the API guide version 2.
8
+
9
+ == Notice
10
+ All previous methods/initializers used named/ordered arguments. New API
11
+ interactions are designed to use hashes of arguments instead. Older API
12
+ models will be converted to this new design pattern soon.
8
13
 
9
14
  == Currently Supported API functionality
10
15
  * Client information such as account status, contact/address info, credit
11
16
  * Webby information (status) and simple actions (start, shutdown, reboot)
12
17
  * List all webbies
13
18
  * DNS zone information such as domain name, TTL, and status
19
+ * Creation/deletion of DNS zones
14
20
 
15
21
  == In Development
16
22
  * DNS record information such as type, data, name, id, and TTL
@@ -52,6 +58,13 @@ is currently based on the API guide version 1.
52
58
  pp @dns.domain
53
59
  pp @dns.records
54
60
 
61
+ === DNS Zone Creation/Deletion
62
+ require 'webbynode-api'
63
+ email = "example@email.com"
64
+ api_key = "1234567890abcdef"
65
+ @new_zone = WebbyNode::DNS.new_zone(:email => email, :token => token, :domain => "mynewdomain.com.", :ttl => 86400)
66
+ pp @new_zone["id"]
67
+
55
68
  == Copyright
56
69
 
57
70
  Copyright (c) 2009 Shane Sveller. See LICENSE for details.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.5
1
+ 0.0.6
data/lib/webbynode-api.rb CHANGED
@@ -18,7 +18,7 @@ class WebbyNode
18
18
 
19
19
  # Uses HTTParty to submit a secure API request via email address and token
20
20
  def auth_get(url, options = {})
21
- raise ArgumentError, "No API information given" unless @email && @api_key
21
+ raise ArgumentError, "API information is missing or incomplete" unless @email && @api_key
22
22
  options[:query] ||= {}
23
23
  options[:query].merge!(:email => @email, :token => @api_key)
24
24
  results = self.class.get(url, options)
@@ -26,6 +26,18 @@ class WebbyNode
26
26
  return results
27
27
  end
28
28
 
29
+ def auth_post(url, options = {})
30
+ self.class.auth_post(url, options)
31
+ end
32
+
33
+ def self.auth_post(url, options = {})
34
+ options[:query] ||= {}
35
+ raise ArgumentError, "API information is missing or incomplete" unless options[:query][:email] && options[:query][:token]
36
+ results = self.post(url, options)
37
+ raise ArgumentError, "Probable bad API information given" if results == {}
38
+ return results
39
+ end
40
+
29
41
  # Catches simple requests for specific API data returned via a hash
30
42
  def method_missing(method)
31
43
  key = @data[method.to_s] if @data
@@ -34,4 +46,4 @@ class WebbyNode
34
46
  end
35
47
  end
36
48
 
37
- require File.join(File.dirname(__FILE__), 'webbynode-api', 'data')
49
+ require File.join(File.dirname(__FILE__), 'webbynode-api', 'data')
@@ -52,8 +52,31 @@ class WebbyNode
52
52
  end
53
53
 
54
54
  def records
55
- raise "This method should only be called on DNS instances with an id." unless @id
55
+ raise "This method should only be called on DNS instances with an id" unless @id
56
56
  auth_get("/api/xml/dns/#{@id}/records")["hash"]["records"]
57
57
  end
58
+
59
+ def self.new_zone(options = {})
60
+ raise ArgumentError, "API access information via :email and :token are required arguments" unless options[:email] && options[:token]
61
+ raise ArgumentError, ":domain and :ttl are required arguments" unless options[:domain] && options[:ttl]
62
+ if options[:status]
63
+ raise ArgumentError, ":status must be 'Active' or 'Inactive'" unless %w(Active Inactive).include? options[:status]
64
+ end
65
+ zone_data = auth_post("/api/xml/dns/new", :query =>
66
+ {
67
+ :email => options[:email],
68
+ :token => options[:token],
69
+ "zone[domain]" => options[:domain],
70
+ "zone[ttl]" => options[:ttl],
71
+ "zone[status]" => options[:status]
72
+ })
73
+ return zone_data["hash"]
74
+ end
75
+
76
+ def self.delete_zone(options = {})
77
+ raise ArgumentError, "API access information via :email and :token are required arguments" unless options[:email] && options[:token]
78
+ raise ArgumentError, ":id is a required argument" unless options[:id]
79
+ return auth_post("/api/xml/dns/#{options[:id]}/delete", :query => options)["hash"]["success"]
80
+ end
58
81
  end
59
- end
82
+ end
@@ -0,0 +1,4 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <hash>
3
+ <success type="boolean">true</success>
4
+ </hash>
@@ -0,0 +1,7 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <hash>
3
+ <status>Active</status>
4
+ <ttl type="integer">86400</ttl>
5
+ <domain>example.com.</domain>
6
+ <id type="integer">171</id>
7
+ </hash>
@@ -7,15 +7,23 @@ class WebbynodeApiTest < Test::Unit::TestCase
7
7
  @api_key = "123456"
8
8
  data_path = File.join(File.dirname(__FILE__), "data")
9
9
  FakeWeb.clean_registry
10
- FakeWeb.register_uri(:get, /https:\/\/manager\.webbynode\.com\/api\/xml\/client\?\w+/i, :body => File.read("#{data_path}/bad-auth.xml"))
10
+ FakeWeb.register_uri(:get, /^https:\/\/manager\.webbynode\.com\/api\/xml\/client\?\w+/i, :body => File.read("#{data_path}/bad-auth.xml"))
11
+ FakeWeb.register_uri(:post, /^https:\/\/manager\.webbynode\.com\/.+$/, :body => "")
11
12
  end
12
13
  should "raise ArgumentError if no API data given" do
13
- assert_raise(ArgumentError){ WebbyNode::Client.new(nil, nil) }
14
- assert_raise(ArgumentError){ WebbyNode::Client.new(@email, nil) }
15
- assert_raise(ArgumentError){ WebbyNode::Client.new(nil, @api_key) }
14
+ # for auth_get
15
+ assert_raise(ArgumentError, "API information is missing or incomplete"){ WebbyNode::Client.new(nil, nil) }
16
+ assert_raise(ArgumentError, "API information is missing or incomplete"){ WebbyNode::Client.new(@email, nil) }
17
+ assert_raise(ArgumentError, "API information is missing or incomplete"){ WebbyNode::Client.new(nil, @api_key) }
18
+ # for auth_post
19
+ assert_raise(ArgumentError, "API information is missing or incomplete"){ WebbyNode::APIObject.new(nil, nil).auth_post("",{}) }
20
+ assert_raise(ArgumentError, "API information is missing or incomplete"){ WebbyNode::APIObject.new(@email, nil).auth_post("",{}) }
21
+ assert_raise(ArgumentError, "API information is missing or incomplete"){ WebbyNode::APIObject.new(nil, @api_key).auth_post("",{}) }
16
22
  end
17
23
  should "raise ArgumentError if bad API data given" do
18
- assert_raise(ArgumentError){ WebbyNode::Client.new(@email, @api_key) }
24
+ assert_raise(ArgumentError, "Probable bad API information given"){ WebbyNode::Client.new(@email, @api_key) }
25
+ # TODO: Need XML fixture file for this
26
+ # assert_raise(ArgumentError, "Probable bad API information given"){ WebbyNode::APIObject.new(@email, @api_key).auth_post("",{}) }
19
27
  end
20
28
  end
21
29
  context "fetching client data from API" do
@@ -24,7 +32,7 @@ class WebbynodeApiTest < Test::Unit::TestCase
24
32
  api_key = "123456"
25
33
  data_path = File.join(File.dirname(__FILE__), "data")
26
34
  FakeWeb.clean_registry
27
- FakeWeb.register_uri(:get, /https:\/\/manager\.webbynode\.com\/api\/xml\/client\?.+/i, :body => File.read("#{data_path}/client.xml"))
35
+ FakeWeb.register_uri(:get, /^https:\/\/manager\.webbynode\.com\/api\/xml\/client\?.+/i, :body => File.read("#{data_path}/client.xml"))
28
36
  @api = WebbyNode::Client.new(email, api_key)
29
37
  end
30
38
 
@@ -60,19 +68,17 @@ class WebbynodeApiTest < Test::Unit::TestCase
60
68
  end
61
69
  end
62
70
 
63
- context "fetching webbies data from API" do
71
+ context "fetching webbies data from API with hostname" do
64
72
  setup do
65
73
  email = "example@email.com"
66
74
  api_key = "123456"
67
75
  hostname = "webby1"
68
76
  data_path = File.join(File.dirname(__FILE__), "data")
69
77
  FakeWeb.clean_registry
70
- FakeWeb.register_uri(:get, /https:\/\/manager\.webbynode\.com\/api\/xml\/webby\/\w+\/start\?.+/i, :body => File.read("#{data_path}/webby-start.xml"))
71
- FakeWeb.register_uri(:get, /https:\/\/manager\.webbynode\.com\/api\/xml\/webby\/\w+\/shutdown\?.+/i, :body => File.read("#{data_path}/webby-shutdown.xml"))
72
- FakeWeb.register_uri(:get, /https:\/\/manager\.webbynode\.com\/api\/xml\/webby\/\w+\/reboot\?.+/i, :body => File.read("#{data_path}/webby-reboot.xml"))
73
- FakeWeb.register_uri(:get, /https:\/\/manager\.webbynode\.com\/api\/xml\/webbies\?.+/i, :body => File.read("#{data_path}/webbies.xml"))
78
+ FakeWeb.register_uri(:get, /^https:\/\/manager\.webbynode\.com\/api\/xml\/webby\/\w+\/start\?.+/i, :body => File.read("#{data_path}/webby-start.xml"))
79
+ FakeWeb.register_uri(:get, /^https:\/\/manager\.webbynode\.com\/api\/xml\/webby\/\w+\/shutdown\?.+/i, :body => File.read("#{data_path}/webby-shutdown.xml"))
80
+ FakeWeb.register_uri(:get, /^https:\/\/manager\.webbynode\.com\/api\/xml\/webby\/\w+\/reboot\?.+/i, :body => File.read("#{data_path}/webby-reboot.xml"))
74
81
  @webby = WebbyNode::Webby.new(email, api_key, hostname)
75
- @webbies = WebbyNode::Webby.new(email, api_key)
76
82
  end
77
83
  should "return a job ID when starting, shutting down, or rebooting" do
78
84
  @webby.start.should == 2562
@@ -81,15 +87,25 @@ class WebbynodeApiTest < Test::Unit::TestCase
81
87
  end
82
88
  should "return a valid status" do
83
89
  data_path = File.join(File.dirname(__FILE__), "data")
84
- FakeWeb.register_uri(:get, /https:\/\/manager\.webbynode\.com\/api\/xml\/webby\/\w+\/status\?.+/i, :body => File.read("#{data_path}/webby-status.xml"))
90
+ FakeWeb.register_uri(:get, /^https:\/\/manager\.webbynode\.com\/api\/xml\/webby\/\w+\/status\?.+/i, :body => File.read("#{data_path}/webby-status.xml"))
85
91
  @webby.status.should == "on"
86
- FakeWeb.register_uri(:get, /https:\/\/manager\.webbynode\.com\/api\/xml\/webby\/\w+\/status\?.+/i, :body => File.read("#{data_path}/webby-status-shutdown.xml"))
92
+ FakeWeb.register_uri(:get, /^https:\/\/manager\.webbynode\.com\/api\/xml\/webby\/\w+\/status\?.+/i, :body => File.read("#{data_path}/webby-status-shutdown.xml"))
87
93
  @webby.status.should == "Shutting down"
88
- FakeWeb.register_uri(:get, /https:\/\/manager\.webbynode\.com\/api\/xml\/webby\/\w+\/status\?.+/i, :body => File.read("#{data_path}/webby-status-off.xml"))
94
+ FakeWeb.register_uri(:get, /^https:\/\/manager\.webbynode\.com\/api\/xml\/webby\/\w+\/status\?.+/i, :body => File.read("#{data_path}/webby-status-off.xml"))
89
95
  @webby.status.should == "off"
90
- FakeWeb.register_uri(:get, /https:\/\/manager\.webbynode\.com\/api\/xml\/webby\/\w+\/status\?.+/i, :body => File.read("#{data_path}/webby-status-reboot.xml"))
96
+ FakeWeb.register_uri(:get, /^https:\/\/manager\.webbynode\.com\/api\/xml\/webby\/\w+\/status\?.+/i, :body => File.read("#{data_path}/webby-status-reboot.xml"))
91
97
  @webby.status.should == "Rebooting"
92
98
  end
99
+ end
100
+ context "fetching webbies data from API without hostname" do
101
+ setup do
102
+ email = "example@email.com"
103
+ api_key = "123456"
104
+ data_path = File.join(File.dirname(__FILE__), "data")
105
+ FakeWeb.clean_registry
106
+ FakeWeb.register_uri(:get, /^https:\/\/manager\.webbynode\.com\/api\/xml\/webbies\?.+/i, :body => File.read("#{data_path}/webbies.xml"))
107
+ @webbies = WebbyNode::Webby.new(email, api_key)
108
+ end
93
109
  should "return a array of webbies" do
94
110
  @webbies.list.is_a?(Array).should be(true)
95
111
  webby = @webbies.list.first
@@ -108,8 +124,8 @@ class WebbynodeApiTest < Test::Unit::TestCase
108
124
  api_key = "123456"
109
125
  data_path = File.join(File.dirname(__FILE__), "data")
110
126
  FakeWeb.clean_registry
111
- FakeWeb.register_uri(:get, /https:\/\/manager\.webbynode\.com\/api\/xml\/dns\?.+/i, :body => File.read("#{data_path}/dns.xml"))
112
- FakeWeb.register_uri(:get, /https:\/\/manager\.webbynode\.com\/api\/xml\/dns\/\d+\?.+/i, :body => File.read("#{data_path}/dns-1.xml"))
127
+ FakeWeb.register_uri(:get, /^https:\/\/manager\.webbynode\.com\/api\/xml\/dns\?.+/i, :body => File.read("#{data_path}/dns.xml"))
128
+ FakeWeb.register_uri(:get, /^https:\/\/manager\.webbynode\.com\/api\/xml\/dns\/\d+\?.+/i, :body => File.read("#{data_path}/dns-1.xml"))
113
129
  @dns = WebbyNode::DNS.new(email, api_key)
114
130
  end
115
131
  should "return an array of zones with domain, status, id, and TTL" do
@@ -134,9 +150,9 @@ class WebbynodeApiTest < Test::Unit::TestCase
134
150
  id = 1
135
151
  data_path = File.join(File.dirname(__FILE__), "data")
136
152
  FakeWeb.clean_registry
137
- FakeWeb.register_uri(:get, /https:\/\/manager\.webbynode\.com\/api\/xml\/dns\?.+/i, :body => File.read("#{data_path}/dns.xml"))
138
- FakeWeb.register_uri(:get, /https:\/\/manager\.webbynode\.com\/api\/xml\/dns\/\d+\?.+/i, :body => File.read("#{data_path}/dns-1.xml"))
139
- FakeWeb.register_uri(:get, /https:\/\/manager\.webbynode\.com\/api\/xml\/dns\/\d+\/records\?.+/i, :body => File.read("#{data_path}/dns-records.xml"))
153
+ FakeWeb.register_uri(:get, /^https:\/\/manager\.webbynode\.com\/api\/xml\/dns\?.+/i, :body => File.read("#{data_path}/dns.xml"))
154
+ FakeWeb.register_uri(:get, /^https:\/\/manager\.webbynode\.com\/api\/xml\/dns\/\d+\?.+/i, :body => File.read("#{data_path}/dns-1.xml"))
155
+ FakeWeb.register_uri(:get, /^https:\/\/manager\.webbynode\.com\/api\/xml\/dns\/\d+\/records\?.+/i, :body => File.read("#{data_path}/dns-records.xml"))
140
156
  @dns = WebbyNode::DNS.new(email, api_key, id)
141
157
  end
142
158
  should "return domain name, status, id and TTL" do
@@ -147,6 +163,57 @@ class WebbynodeApiTest < Test::Unit::TestCase
147
163
  end
148
164
  should "return an array of records with id, type, name, data, auxiliary data, and TTL" do
149
165
  @dns.records.is_a?(Array).should be(true)
166
+ record = @dns.records.first
167
+ record["id"].should == 51
168
+ record["ttl"].should == 86400
169
+ record["data"].should == "200.100.200.100"
170
+ record["name"].should be(nil)
171
+ record["aux"].should == 0
172
+ record["type"].should == "A"
173
+ end
174
+ end
175
+ context "creating a new DNS zone" do
176
+ setup do
177
+ @email = "example@email.com"
178
+ @api_key = "123456"
179
+ @domain = "example.com."
180
+ @ttl = 86400
181
+ data_path = File.join(File.dirname(__FILE__), "data")
182
+ FakeWeb.clean_registry
183
+ FakeWeb.register_uri(:post, /^https:\/\/manager\.webbynode\.com\/api\/xml\/dns\/new\?.+/i, :body => File.read("#{data_path}/new-zone.xml"))
184
+ end
185
+ should "raise ArgumentError if API information isn't present" do
186
+ assert_raise(ArgumentError,"API access information via :email and :token are required arguments"){ WebbyNode::DNS.new_zone(:token => @api_key, :domain => @domain, :ttl => @ttl) }
187
+ assert_raise(ArgumentError,"API access information via :email and :token are required arguments"){ WebbyNode::DNS.new_zone(:email => @email, :domain => @domain, :ttl => @ttl) }
188
+ end
189
+ should "raise ArgumentError if :domain or :ttl aren't included in method call" do
190
+ assert_raise(ArgumentError, ":domain and :ttl are required arguments"){ WebbyNode::DNS.new_zone(:email => @email, :token => @api_key, :ttl => @ttl) }
191
+ assert_raise(ArgumentError, ":domain and :ttl are required arguments"){ WebbyNode::DNS.new_zone(:email => @email, :token => @api_key, :domain => @domain) }
192
+ end
193
+ should "raise ArgumentError if :status is not a valid option" do
194
+ assert_raise(ArgumentError, ":domain and :ttl are required arguments"){ WebbyNode::DNS.new_zone(:email => @email, :token => @api_key, :ttl => @ttl, :status => "Not active") }
195
+ assert_nothing_raised(ArgumentError){ WebbyNode::DNS.new_zone(:email => @email, :token => @api_key, :domain => @domain, :ttl => @ttl, :status => "Active") }
196
+ assert_nothing_raised(ArgumentError){ WebbyNode::DNS.new_zone(:email => @email, :token => @api_key, :domain => @domain, :ttl => @ttl, :status => "Inactive") }
197
+ assert_nothing_raised(ArgumentError){ WebbyNode::DNS.new_zone(:email => @email, :token => @api_key, :domain => @domain, :ttl => @ttl, :status => nil) }
198
+ end
199
+ should "return a Hash containing the new zone's information" do
200
+ @new_zone = WebbyNode::DNS.new_zone(:email => @email, :token => @api_key, :domain => @domain, :ttl => @ttl, :status => "Inactive")
201
+ @new_zone["id"].should == 171
202
+ @new_zone["domain"].should == "example.com."
203
+ @new_zone["ttl"].should == 86400
204
+ end
205
+ end
206
+ context "deleting a DNS zone" do
207
+ setup do
208
+ @email = "example@email.com"
209
+ @api_key = "123456"
210
+ @id = 171
211
+ data_path = File.join(File.dirname(__FILE__), "data")
212
+ FakeWeb.clean_registry
213
+ FakeWeb.register_uri(:post, /^https:\/\/manager\.webbynode\.com\/api\/xml\/dns\/\d+\/delete\?.+/i, :body => File.read("#{data_path}/delete-zone.xml"))
214
+ end
215
+ should "return a boolean true for succesful deletion" do
216
+ WebbyNode::DNS.delete_zone(:email => @email, :token => @api_key, :id => @id)
150
217
  end
151
218
  end
152
219
  end
@@ -2,11 +2,11 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{webbynode-api}
5
- s.version = "0.0.5"
5
+ s.version = "0.0.6"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Shane Sveller"]
9
- s.date = %q{2009-07-11}
9
+ s.date = %q{2009-07-12}
10
10
  s.email = %q{shanesveller@gmail.com}
11
11
  s.extra_rdoc_files = [
12
12
  "LICENSE",
@@ -23,9 +23,11 @@ Gem::Specification.new do |s|
23
23
  "lib/webbynode-api/data.rb",
24
24
  "test/data/bad-auth.xml",
25
25
  "test/data/client.xml",
26
+ "test/data/delete-zone.xml",
26
27
  "test/data/dns-1.xml",
27
28
  "test/data/dns-records.xml",
28
29
  "test/data/dns.xml",
30
+ "test/data/new-zone.xml",
29
31
  "test/data/webbies.xml",
30
32
  "test/data/webby-reboot.xml",
31
33
  "test/data/webby-shutdown.xml",
@@ -38,11 +40,10 @@ Gem::Specification.new do |s|
38
40
  "test/webbynode-api_test.rb",
39
41
  "webbynode-api.gemspec"
40
42
  ]
41
- s.has_rdoc = true
42
43
  s.homepage = %q{http://github.com/shanesveller/webbynode-api}
43
44
  s.rdoc_options = ["--charset=UTF-8"]
44
45
  s.require_paths = ["lib"]
45
- s.rubygems_version = %q{1.3.1}
46
+ s.rubygems_version = %q{1.3.4}
46
47
  s.summary = %q{wraps the WebbyNode API into nice Ruby objects}
47
48
  s.test_files = [
48
49
  "test/test_helper.rb",
@@ -51,7 +52,7 @@ Gem::Specification.new do |s|
51
52
 
52
53
  if s.respond_to? :specification_version then
53
54
  current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
54
- s.specification_version = 2
55
+ s.specification_version = 3
55
56
 
56
57
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
57
58
  else
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shanesveller-webbynode-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shane Sveller
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-07-11 00:00:00 -07:00
12
+ date: 2009-07-12 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -33,9 +33,11 @@ files:
33
33
  - lib/webbynode-api/data.rb
34
34
  - test/data/bad-auth.xml
35
35
  - test/data/client.xml
36
+ - test/data/delete-zone.xml
36
37
  - test/data/dns-1.xml
37
38
  - test/data/dns-records.xml
38
39
  - test/data/dns.xml
40
+ - test/data/new-zone.xml
39
41
  - test/data/webbies.xml
40
42
  - test/data/webby-reboot.xml
41
43
  - test/data/webby-shutdown.xml
@@ -47,7 +49,7 @@ files:
47
49
  - test/test_helper.rb
48
50
  - test/webbynode-api_test.rb
49
51
  - webbynode-api.gemspec
50
- has_rdoc: true
52
+ has_rdoc: false
51
53
  homepage: http://github.com/shanesveller/webbynode-api
52
54
  post_install_message:
53
55
  rdoc_options:
@@ -71,7 +73,7 @@ requirements: []
71
73
  rubyforge_project:
72
74
  rubygems_version: 1.2.0
73
75
  signing_key:
74
- specification_version: 2
76
+ specification_version: 3
75
77
  summary: wraps the WebbyNode API into nice Ruby objects
76
78
  test_files:
77
79
  - test/test_helper.rb