dreamy 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +159 -0
- data/Rakefile +28 -0
- data/VERSION.yml +4 -0
- data/bin/dh +14 -0
- data/lib/dreamy.rb +27 -0
- data/lib/dreamy/announce_list.rb +19 -0
- data/lib/dreamy/base.rb +234 -0
- data/lib/dreamy/command.rb +57 -0
- data/lib/dreamy/commands/announce.rb +73 -0
- data/lib/dreamy/commands/base.rb +96 -0
- data/lib/dreamy/commands/dns.rb +48 -0
- data/lib/dreamy/commands/domains.rb +61 -0
- data/lib/dreamy/commands/help.rb +48 -0
- data/lib/dreamy/commands/mysql.rb +45 -0
- data/lib/dreamy/commands/ps.rb +136 -0
- data/lib/dreamy/commands/users.rb +32 -0
- data/lib/dreamy/core_extensions.rb +9 -0
- data/lib/dreamy/dns.rb +19 -0
- data/lib/dreamy/domain.rb +38 -0
- data/lib/dreamy/easy_class_maker.rb +43 -0
- data/lib/dreamy/mysql/db.rb +17 -0
- data/lib/dreamy/mysql/host.rb +15 -0
- data/lib/dreamy/mysql/user.rb +26 -0
- data/lib/dreamy/private_server.rb +53 -0
- data/lib/dreamy/subscriber.rb +17 -0
- data/lib/dreamy/user.rb +21 -0
- data/test/announce_test.rb +32 -0
- data/test/base_test.rb +235 -0
- data/test/dns_test.rb +32 -0
- data/test/domain_test.rb +74 -0
- data/test/mysql_db_test.rb +28 -0
- data/test/mysql_host_test.rb +24 -0
- data/test/mysql_user_test.rb +44 -0
- data/test/private_server_test.rb +147 -0
- data/test/subscriber_test.rb +28 -0
- data/test/test_helper.rb +10 -0
- data/test/user_test.rb +36 -0
- metadata +130 -0
data/README.md
ADDED
@@ -0,0 +1,159 @@
|
|
1
|
+
What is it?
|
2
|
+
===========
|
3
|
+
|
4
|
+
[Dreamy][1] is Ruby library and command line tool for interfacing with [DreamHost's API][2]. The API itself is still very young so this is by no means a comprehensive library. Please fork and contribute!
|
5
|
+
|
6
|
+
|
7
|
+
Install
|
8
|
+
=======
|
9
|
+
|
10
|
+
Grab the gem from GitHub
|
11
|
+
|
12
|
+
gem sources -a http://gems.github.com
|
13
|
+
gem install sant0sk1-dreamy
|
14
|
+
|
15
|
+
Library Usage
|
16
|
+
=============
|
17
|
+
|
18
|
+
DreamHost requires a username (email or webID) and API key (available from your DH Panel) to make API requests. When creating a Dreamy instance you'll need to provide this data. The Dreamy command line tool (dh) gathers the necessary info from a configuration file or environment variables, but you can do it however you'd like.
|
19
|
+
|
20
|
+
To get started with the library, just require the gem:
|
21
|
+
|
22
|
+
require 'rubygems'
|
23
|
+
require 'dreamy'
|
24
|
+
|
25
|
+
Create a new object using your username and API key.
|
26
|
+
|
27
|
+
account = Dreamy::Base.new(username,api_key)
|
28
|
+
|
29
|
+
Fetch an array of Dreamy::Domain objects:
|
30
|
+
|
31
|
+
account.domains
|
32
|
+
|
33
|
+
Now that you have an array you can have your way with the data:
|
34
|
+
|
35
|
+
account.domains.each do |d|
|
36
|
+
puts d.domain
|
37
|
+
puts d.type
|
38
|
+
puts d.home
|
39
|
+
end
|
40
|
+
|
41
|
+
Same goes with Users, DNS records, announcement list subscribers, MySQL databases, MySQL hosts, and MySQL users
|
42
|
+
|
43
|
+
# fetch an array of Dreamy::User objects
|
44
|
+
account.users
|
45
|
+
|
46
|
+
# fetch an array of Dreamy::Dns objects
|
47
|
+
account.dns
|
48
|
+
|
49
|
+
# fetch an array of Dreamy::AnnounceList objects
|
50
|
+
account.announce_lists
|
51
|
+
|
52
|
+
# fetch an array of Dreamy::Subscribers to an announcement list
|
53
|
+
account.announce_list(listname,domain)
|
54
|
+
|
55
|
+
# fetch an array of Dreamy::MysqlUser objects
|
56
|
+
account.mysql_users
|
57
|
+
|
58
|
+
You can interact with announcement lists by adding and removing subscribers
|
59
|
+
|
60
|
+
# add a new subscriber to an announcement list
|
61
|
+
account.announce_add(listname,domain,email)
|
62
|
+
|
63
|
+
# remove a subscriber from an announcement list
|
64
|
+
account.announce_remove(listname,domain,email)
|
65
|
+
|
66
|
+
You can interact with DNS by adding and removing records
|
67
|
+
|
68
|
+
# add a new A record for a subdomain of an hosted domain
|
69
|
+
account.dns_add(subdomain,"A","123.321.123.321")
|
70
|
+
|
71
|
+
# remove the A record just created
|
72
|
+
account.dns_remove(subdomain,"A","123.321.123.321")
|
73
|
+
|
74
|
+
You can interact with your Private Server in many different ways
|
75
|
+
|
76
|
+
# change a private server setting
|
77
|
+
account.ps_set(ps_name,setting,value)
|
78
|
+
|
79
|
+
# set the memory size (MB)
|
80
|
+
account.ps_size_set(ps_name,"200")
|
81
|
+
|
82
|
+
# reboot the server
|
83
|
+
account.ps_reboot!(ps_name)
|
84
|
+
|
85
|
+
Check the base class for all the different API calls.
|
86
|
+
|
87
|
+
More and more functions will be added as time allows. If there's something missing that you want in, please:
|
88
|
+
|
89
|
+
fork -> commit -> pull request
|
90
|
+
|
91
|
+
Command Line Usage
|
92
|
+
==================
|
93
|
+
|
94
|
+
The Dreamy gem will install an executable called "dh". In order to use it, you'll need to set your DreamHost account username and API key. You can acquire an API key from the DreamHost panel. "dh" will fetch your API credentials from 2 places, respectively:
|
95
|
+
|
96
|
+
1) A file called .dreamyrc in your $HOME directory with username on line 1, api key on line 2
|
97
|
+
|
98
|
+
An example ~/.dreamyrc would look like:
|
99
|
+
|
100
|
+
dh_user@gmail.com
|
101
|
+
34TGGGKBRG3YD1EA
|
102
|
+
|
103
|
+
2) Environment variables DH\_USER and DH\_KEY. You can set these by typing this in your shell:
|
104
|
+
|
105
|
+
export DH_USER=dh_user@gmail.com
|
106
|
+
export DH_KEY=34TGGGKBRG3YD1EA
|
107
|
+
|
108
|
+
If you want to make those environment variables permanent, add those 2 lines to the bottom of your ~/.bashrc
|
109
|
+
|
110
|
+
|
111
|
+
Run this from the command line to print the usage:
|
112
|
+
|
113
|
+
dh help
|
114
|
+
|
115
|
+
=== Commands
|
116
|
+
|
117
|
+
announce # list announce lists
|
118
|
+
announce:list <list> # list all subscribers to <name> list
|
119
|
+
announce:add <list> <email> # add subscriber with <email> to <list>
|
120
|
+
announce:remove <list> <email> # remove subscriber with <email> from <list>
|
121
|
+
|
122
|
+
dns # list DNS records
|
123
|
+
dns <name> # list DNS records for <name>
|
124
|
+
dns:add <record> <type> <value> # add DNS record
|
125
|
+
dns:remove <record> <type> <value> # remove DNS record
|
126
|
+
|
127
|
+
domains:http # list HTTP domain details
|
128
|
+
domains:mysql # list MySQL domains
|
129
|
+
domains:status # check availability of all domains (pingability)
|
130
|
+
|
131
|
+
mysql:dbs # list MySQL database details
|
132
|
+
mysql:hosts # list MySQL database hostnames
|
133
|
+
mysql:users # list MySQL user details
|
134
|
+
|
135
|
+
ps # list private servers
|
136
|
+
ps:add <web|mysql> <yes|no> # adds a private server of type <web|mysql>. Yes = move data
|
137
|
+
ps:pending # list private servers scheduled to be created
|
138
|
+
ps:reboots <name> # list historical reboots for <name>
|
139
|
+
ps:reboot <name> now! # reboot <name> now! (proceed with caution)
|
140
|
+
ps:remove # removes all pending private servers
|
141
|
+
ps:settings <name> # list settings for private server <name>
|
142
|
+
ps:set <name> <setting> <value> # change <setting> on <name> to <value>
|
143
|
+
ps:size <name> # list historical memory sizes for <name>
|
144
|
+
ps:size <name> <value> # set new memory <value> for <name>
|
145
|
+
ps:usage <name> # list historical memory & CPU usage for <name>
|
146
|
+
|
147
|
+
users # list user accounts: details
|
148
|
+
users:pw # list user accounts: usernames & passwords
|
149
|
+
|
150
|
+
|
151
|
+
That's it for now. New commands should be springing up as Dreamy and the DreamHost API mature!
|
152
|
+
|
153
|
+
TODO
|
154
|
+
====
|
155
|
+
|
156
|
+
* add real rdocs
|
157
|
+
|
158
|
+
[1]:http://github.com/sant0sk1/dreamy
|
159
|
+
[2]:http://wiki.Dreamy.com/API
|
data/Rakefile
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
|
4
|
+
task :default => [:test_units]
|
5
|
+
|
6
|
+
desc "Run basic tests"
|
7
|
+
Rake::TestTask.new("test_units") { |t|
|
8
|
+
t.pattern = 'test/*_test.rb'
|
9
|
+
t.verbose = true
|
10
|
+
t.warning = true
|
11
|
+
}
|
12
|
+
|
13
|
+
begin
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |gemspec|
|
16
|
+
gemspec.name = "dreamy"
|
17
|
+
gemspec.summary = "A Ruby library and command line tool for accessing DreamHost's API"
|
18
|
+
gemspec.email = "jerod.santo@gmail.com"
|
19
|
+
gemspec.homepage = "http://github.com/sant0sk1/dreamy"
|
20
|
+
gemspec.authors = ["Jerod Santo"]
|
21
|
+
gemspec.add_dependency('visionmedia-terminal-table', '>= 1.0.5')
|
22
|
+
gemspec.add_dependency('hpricot', '>= 0.7')
|
23
|
+
gemspec.add_dependency('uuid', '>= 2.0.1')
|
24
|
+
gemspec.files.exclude 'test/credentials.yml'
|
25
|
+
end
|
26
|
+
rescue LoadError
|
27
|
+
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
28
|
+
end
|
data/VERSION.yml
ADDED
data/bin/dh
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
|
5
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__) + '/../lib')
|
6
|
+
|
7
|
+
require 'dreamy'
|
8
|
+
require 'dreamy/command'
|
9
|
+
|
10
|
+
args = ARGV.dup
|
11
|
+
ARGV.clear
|
12
|
+
command = args.shift.strip rescue 'help'
|
13
|
+
|
14
|
+
Dreamy::Command.run(command, args)
|
data/lib/dreamy.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'net/https'
|
3
|
+
require 'yaml'
|
4
|
+
require 'rubygems'
|
5
|
+
require 'hpricot'
|
6
|
+
require 'uuid'
|
7
|
+
|
8
|
+
|
9
|
+
$:.unshift(File.dirname(__FILE__) + "/dreamy")
|
10
|
+
require 'dreamy/core_extensions'
|
11
|
+
require 'dreamy/easy_class_maker'
|
12
|
+
require 'dreamy/base'
|
13
|
+
require 'dreamy/domain'
|
14
|
+
require 'dreamy/dns'
|
15
|
+
require 'dreamy/announce_list'
|
16
|
+
require 'dreamy/private_server'
|
17
|
+
require 'dreamy/subscriber'
|
18
|
+
require 'dreamy/user'
|
19
|
+
require 'dreamy/mysql/db'
|
20
|
+
require 'dreamy/mysql/host'
|
21
|
+
require 'dreamy/mysql/user'
|
22
|
+
|
23
|
+
module Dreamy
|
24
|
+
class CantConnect < StandardError; end
|
25
|
+
class Unavailable < StandardError; end
|
26
|
+
class ApiError < StandardError; end
|
27
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Dreamy
|
2
|
+
class AnnounceList
|
3
|
+
include EasyClassMaker
|
4
|
+
|
5
|
+
attributes :account_id, :name, :domain, :short_name, :start_date, :max_bounces, :subscribers
|
6
|
+
|
7
|
+
def self.new_from_xml(xml)
|
8
|
+
l = new
|
9
|
+
l.account_id = (xml).at('account_id').innerHTML.to_i
|
10
|
+
l.short_name = (xml).at('listname').innerHTML
|
11
|
+
l.domain = (xml).at('domain').innerHTML
|
12
|
+
l.name = (xml).at('name').innerHTML
|
13
|
+
l.start_date = (xml).at('start_date').innerHTML
|
14
|
+
l.max_bounces = (xml).at('max_bounces').innerHTML.to_i
|
15
|
+
l.subscribers = (xml).at('num_subscribers').innerHTML.to_i
|
16
|
+
l
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/dreamy/base.rb
ADDED
@@ -0,0 +1,234 @@
|
|
1
|
+
module Dreamy
|
2
|
+
class Base
|
3
|
+
|
4
|
+
@@host = "api.dreamhost.com"
|
5
|
+
|
6
|
+
def initialize(username, key)
|
7
|
+
@username = username
|
8
|
+
@key = key
|
9
|
+
end
|
10
|
+
|
11
|
+
# returns an array of domain objects
|
12
|
+
def domains
|
13
|
+
doc = request("domain-list_domains")
|
14
|
+
api_error?(doc)
|
15
|
+
(doc/:data).inject([]) { |domains, domain| domains << Domain.new_from_xml(domain); domains }
|
16
|
+
end
|
17
|
+
|
18
|
+
# returns an array of user objects
|
19
|
+
def users(passwords=false)
|
20
|
+
if passwords
|
21
|
+
doc = request("user-list_users")
|
22
|
+
else
|
23
|
+
doc = request("user-list_users_no_pw")
|
24
|
+
end
|
25
|
+
api_error?(doc)
|
26
|
+
(doc/:data).inject([]) { |users, user| users << User.new_from_xml(user); users }
|
27
|
+
end
|
28
|
+
|
29
|
+
# returns an array of dns objects
|
30
|
+
def dns
|
31
|
+
doc = request("dns-list_records")
|
32
|
+
api_error?(doc)
|
33
|
+
(doc/:data).inject([]) { |records, dns| records << Dns.new_from_xml(dns); records }
|
34
|
+
end
|
35
|
+
|
36
|
+
def dns_add(record,type,value)
|
37
|
+
doc = request("dns-add_record", {"record" => record, "type" => type, "value" => value})
|
38
|
+
api_error?(doc)
|
39
|
+
true
|
40
|
+
end
|
41
|
+
|
42
|
+
def dns_remove(record,type,value)
|
43
|
+
doc = request("dns-remove_record", {"record" => record, "type" => type, "value" => value})
|
44
|
+
api_error?(doc)
|
45
|
+
true
|
46
|
+
end
|
47
|
+
|
48
|
+
def announce_lists
|
49
|
+
doc = request("announcement_list-list_lists")
|
50
|
+
api_error?(doc)
|
51
|
+
(doc/:data).inject([]) { |lists, list| lists << AnnounceList.new_from_xml(list); lists }
|
52
|
+
end
|
53
|
+
|
54
|
+
# returns an array of subscriber objects
|
55
|
+
def announce_list(listname,domain)
|
56
|
+
doc = request("announcement_list-list_subscribers",{ "listname" => listname, "domain" => domain})
|
57
|
+
api_error?(doc)
|
58
|
+
(doc/:data).inject([]) { |subs, sub| subs << Subscriber.new_from_xml(sub); subs }
|
59
|
+
end
|
60
|
+
|
61
|
+
# adds new subscriber to announce list
|
62
|
+
def announce_add(listname,domain,email,name="")
|
63
|
+
doc = request("announcement_list-add_subscriber",
|
64
|
+
{"listname" => listname, "domain" => domain, "email" => email, "name" => name})
|
65
|
+
api_error?(doc)
|
66
|
+
true
|
67
|
+
end
|
68
|
+
|
69
|
+
def announce_remove(listname,domain,email)
|
70
|
+
doc = request("announcement_list-remove_subscriber",
|
71
|
+
{"listname" => listname, "domain" => domain, "email" => email})
|
72
|
+
api_error?(doc)
|
73
|
+
true
|
74
|
+
end
|
75
|
+
|
76
|
+
# options:
|
77
|
+
# stamp - the time to send the message, like "2009-05-28" or "2009-05-28 14:24:36"
|
78
|
+
# charset - the character set in which the message is encoded
|
79
|
+
# type - the format of the message, either "text" or "html"
|
80
|
+
# duplicate_ok - whether to allow duplicate messages to be sent, like 1 or 0
|
81
|
+
def announce_post(listname,domain,subject,message,name,options={})
|
82
|
+
values = {
|
83
|
+
"listname" => listname,
|
84
|
+
"domain" => domain,
|
85
|
+
"subject" => subject,
|
86
|
+
"message" => message,
|
87
|
+
"name" => name
|
88
|
+
}.merge(options)
|
89
|
+
doc = request("announcement_list-post_announcement", values, true)
|
90
|
+
api_error?(doc)
|
91
|
+
true
|
92
|
+
end
|
93
|
+
|
94
|
+
def mysql_dbs
|
95
|
+
doc = request("mysql-list_dbs")
|
96
|
+
api_error?(doc)
|
97
|
+
(doc/:data).inject([]) { |dbs, db| dbs << MysqlDb.new_from_xml(db); dbs }
|
98
|
+
end
|
99
|
+
|
100
|
+
def mysql_hosts
|
101
|
+
doc = request("mysql-list_hostnames")
|
102
|
+
api_error?(doc)
|
103
|
+
(doc/:data).inject([]) { |hosts, host| hosts << MysqlHost.new_from_xml(host); hosts }
|
104
|
+
end
|
105
|
+
|
106
|
+
def mysql_users
|
107
|
+
doc = request("mysql-list_users")
|
108
|
+
api_error?(doc)
|
109
|
+
(doc/:data).inject([]) { |users, user| users << MysqlUser.new_from_xml(user); users }
|
110
|
+
end
|
111
|
+
|
112
|
+
def ps
|
113
|
+
doc = request("dreamhost_ps-list_ps")
|
114
|
+
api_error?(doc)
|
115
|
+
(doc/:data).inject([]) { |servers, server| servers << PrivateServer.new_from_xml(server); servers }
|
116
|
+
end
|
117
|
+
|
118
|
+
def ps_settings(name)
|
119
|
+
doc = request("dreamhost_ps-list_settings", {"ps" => name})
|
120
|
+
api_error?(doc)
|
121
|
+
PrivateServer.settings_from_xml(doc)
|
122
|
+
end
|
123
|
+
|
124
|
+
def ps_set(name,setting,value)
|
125
|
+
doc = request("dreamhost_ps-set_settings", {"ps" => name, setting => value})
|
126
|
+
api_error?(doc)
|
127
|
+
true
|
128
|
+
end
|
129
|
+
|
130
|
+
def ps_size_history(name)
|
131
|
+
doc = request("dreamhost_ps-list_size_history", {"ps" => name})
|
132
|
+
api_error?(doc)
|
133
|
+
(doc/:data).inject([]) { |sizes, size| sizes << PrivateServer.size_from_xml(size); sizes }
|
134
|
+
end
|
135
|
+
|
136
|
+
def ps_size_set(name,size)
|
137
|
+
doc = request("dreamhost_ps-set_size", {"ps" => name, "size" => size})
|
138
|
+
api_error?(doc)
|
139
|
+
true
|
140
|
+
end
|
141
|
+
|
142
|
+
def ps_reboot_history(name)
|
143
|
+
doc = request("dreamhost_ps-list_reboot_history", {"ps" => name})
|
144
|
+
api_error?(doc)
|
145
|
+
(doc/:data).inject([]) { |reboots,reboot| reboots << reboot.at('stamp').innerHTML; reboots }
|
146
|
+
end
|
147
|
+
|
148
|
+
def ps_reboot!(name)
|
149
|
+
doc = request("dreamhost_ps-reboot", {"ps" => name})
|
150
|
+
api_error?(doc)
|
151
|
+
true
|
152
|
+
end
|
153
|
+
|
154
|
+
def ps_usage(name)
|
155
|
+
doc = request("dreamhost_ps-list_usage", {"ps" => name})
|
156
|
+
api_error?(doc)
|
157
|
+
(doc/:data).inject([]) { |usages, usage| usages << PrivateServer.usage_from_xml(usage); usages }
|
158
|
+
end
|
159
|
+
|
160
|
+
def ps_add(type,movedata="no")
|
161
|
+
doc = request("dreamhost_ps-add_ps", {"type" => type, "movedata" => movedata})
|
162
|
+
api_error?(doc)
|
163
|
+
true
|
164
|
+
end
|
165
|
+
|
166
|
+
def ps_remove
|
167
|
+
doc = request("dreamhost_ps-remove_pending_ps")
|
168
|
+
api_error?(doc)
|
169
|
+
true
|
170
|
+
end
|
171
|
+
|
172
|
+
def ps_pending
|
173
|
+
doc = request("dreamhost_ps-list_pending_ps")
|
174
|
+
api_error?(doc)
|
175
|
+
(doc/:data).inject([]) { |pends, pend| pends << PrivateServer.pending_from_xml(pend); pends }
|
176
|
+
end
|
177
|
+
|
178
|
+
private
|
179
|
+
|
180
|
+
def api_error?(doc)
|
181
|
+
raise ApiError, (doc/:data).innerHTML if (doc/:result).innerHTML == "error"
|
182
|
+
end
|
183
|
+
|
184
|
+
def request(cmd,values={},use_post=false)
|
185
|
+
handle_response!(response(cmd,values,use_post))
|
186
|
+
end
|
187
|
+
|
188
|
+
def response(cmd,values={},use_post=false)
|
189
|
+
values = {
|
190
|
+
"username" => @username,
|
191
|
+
"key" => @key,
|
192
|
+
"cmd" => cmd,
|
193
|
+
"format" => "xml",
|
194
|
+
"unique_id" => UUID.new.generate
|
195
|
+
}.merge(values)
|
196
|
+
|
197
|
+
http = Net::HTTP.new(@@host, 443)
|
198
|
+
http.use_ssl = true
|
199
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
200
|
+
|
201
|
+
begin
|
202
|
+
# puts path
|
203
|
+
response = if use_post
|
204
|
+
request = Net::HTTP::Post.new("/")
|
205
|
+
request.form_data = values
|
206
|
+
http.request(request)
|
207
|
+
else
|
208
|
+
path = "/?#{values.to_param_array.join("&")}"
|
209
|
+
http.get(path)
|
210
|
+
end
|
211
|
+
rescue => error
|
212
|
+
raise CantConnect, error.message
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
def handle_response!(response)
|
217
|
+
if %w[200 304].include?(response.code)
|
218
|
+
response = parse(response.body)
|
219
|
+
elsif response.code == '503'
|
220
|
+
raise Unavailable, response.message
|
221
|
+
elsif response.code == '401'
|
222
|
+
raise CantConnect, 'Authentication failed. Check your username and password'
|
223
|
+
else
|
224
|
+
raise CantConnect, "Dreamy is returning a #{response.code}: #{response.message}"
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
# Converts a string response into an Hpricot xml element.
|
229
|
+
def parse(response)
|
230
|
+
Hpricot.XML(response || '')
|
231
|
+
end
|
232
|
+
|
233
|
+
end
|
234
|
+
end
|