snuggie 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +98 -0
- data/Rakefile +31 -0
- data/lib/snuggie.rb +17 -0
- data/lib/snuggie/config.rb +10 -0
- data/lib/snuggie/errors.rb +6 -0
- data/lib/snuggie/noc.rb +276 -0
- data/lib/snuggie/version.rb +3 -0
- data/test/fixtures/buy_license.txt +1 -0
- data/test/fixtures/cancel_license.txt +1 -0
- data/test/fixtures/edit_ips.txt +1 -0
- data/test/fixtures/invoice_details_unbilled.txt +1 -0
- data/test/fixtures/license_logs.txt +1 -0
- data/test/fixtures/list_licenses.txt +1 -0
- data/test/fixtures/refund.txt +1 -0
- data/test/snuggie/config_test.rb +15 -0
- data/test/snuggie/noc_test.rb +279 -0
- data/test/snuggie_test.rb +31 -0
- data/test/test_helper.rb +138 -0
- metadata +105 -0
data/README.markdown
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
# Snuggie [![Build Status](http://travis-ci.org/site5/snuggie.png)][Build Status]
|
2
|
+
|
3
|
+
Snuggie wraps the Softaculous API in a warm, loving ruby embrace.
|
4
|
+
|
5
|
+
Snuggie has been tested on on MRI 1.8.4, MRI 1.8.7, MRI 1.9.2,
|
6
|
+
Rubinius 2.0.0pre, and JRuby 1.6.2.
|
7
|
+
|
8
|
+
[Build Status]: http://travis-ci.org/site5/snuggie
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
|
12
|
+
gem install snuggie
|
13
|
+
|
14
|
+
## Usage
|
15
|
+
|
16
|
+
Create a new `Snuggie::NOC` object with your credentials:
|
17
|
+
|
18
|
+
noc = Snuggie::NOC.new(
|
19
|
+
:username => 'marty',
|
20
|
+
:password => 'mcSUPERfly'
|
21
|
+
)
|
22
|
+
|
23
|
+
Your Softaculous credentials can also be configured globally:
|
24
|
+
|
25
|
+
Snuggie.configure do |config|
|
26
|
+
config.username = 'marty'
|
27
|
+
config.password = 'mcSUPERfly'
|
28
|
+
end
|
29
|
+
|
30
|
+
noc = Snuggie::NOC.new
|
31
|
+
|
32
|
+
Buy/renew a license
|
33
|
+
|
34
|
+
noc.buy_license(
|
35
|
+
:ip => '127.0.0.1',
|
36
|
+
:months_to_add => 1,
|
37
|
+
:server_type => :dedicated,
|
38
|
+
:auth_email => 'marty@hilldale.edu',
|
39
|
+
:auto_renew => true
|
40
|
+
)
|
41
|
+
|
42
|
+
Refund a transaction
|
43
|
+
|
44
|
+
noc.refund :action_id => 99999
|
45
|
+
|
46
|
+
List all licenses
|
47
|
+
|
48
|
+
noc.list_licenses
|
49
|
+
|
50
|
+
List licenses by IP
|
51
|
+
|
52
|
+
noc.list_licenses :ip => '127.0.0.1'
|
53
|
+
|
54
|
+
List all expired licenses
|
55
|
+
|
56
|
+
noc.list_licenses :expired => 1
|
57
|
+
|
58
|
+
List licenses expiring in 7 days
|
59
|
+
|
60
|
+
noc.list_licenses :expired => 2
|
61
|
+
|
62
|
+
List licenses expiring in 15 days
|
63
|
+
|
64
|
+
noc.list_licenses :expired => 3
|
65
|
+
|
66
|
+
Get invoice details
|
67
|
+
|
68
|
+
noc.invoice_details :invoice_id => 99999
|
69
|
+
|
70
|
+
Get unbilled transactions for the current month:
|
71
|
+
|
72
|
+
noc.invoice_details
|
73
|
+
|
74
|
+
Cancel a license by key
|
75
|
+
|
76
|
+
noc.cancel_license :key => 'XXXXX-XXXXX-XXXXX-XXXXX-XXXXX'
|
77
|
+
|
78
|
+
Cancel a license by IP
|
79
|
+
|
80
|
+
noc.cancel_license :ip => '127.0.0.1'
|
81
|
+
|
82
|
+
Get Action/Activity logs for a license
|
83
|
+
|
84
|
+
noc.license_logs :key => 'XXXXX-XXXXX-XXXXX-XXXXX-XXXXX'
|
85
|
+
|
86
|
+
## Note on Patches/Pull Requests
|
87
|
+
|
88
|
+
* Fork the project.
|
89
|
+
* Make your feature addition or bug fix.
|
90
|
+
* Add tests for it. This is important so I don't break it in a future version
|
91
|
+
unintentionally.
|
92
|
+
* Commit, do not bump version. (If you want to have your own version, that is
|
93
|
+
fine but bump version in a commit by itself I can ignore when I pull.)
|
94
|
+
* Send me a pull request. Bonus points for topic branches.
|
95
|
+
|
96
|
+
## Copyright
|
97
|
+
|
98
|
+
Copyright (c) 2011 Site5 LLC. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
$:.unshift 'lib'
|
2
|
+
|
3
|
+
require 'rake/testtask'
|
4
|
+
|
5
|
+
Rake::TestTask.new do |test|
|
6
|
+
test.libs << "test"
|
7
|
+
test.test_files = FileList['test/**/*_test.rb']
|
8
|
+
end
|
9
|
+
|
10
|
+
task :default => :test
|
11
|
+
|
12
|
+
desc "Open an irb session preloaded with this library"
|
13
|
+
task :console do
|
14
|
+
sh "irb -rubygems -r ./lib/snuggie.rb -I ./lib"
|
15
|
+
end
|
16
|
+
|
17
|
+
desc "Push a new version to rubygems.org"
|
18
|
+
task :publish do
|
19
|
+
require 'snuggie/version'
|
20
|
+
|
21
|
+
ver = Snuggie::Version
|
22
|
+
|
23
|
+
mkdir("pkg") unless File.exists?("pkg")
|
24
|
+
|
25
|
+
sh "gem build snuggie.gemspec"
|
26
|
+
sh "gem push snuggie-#{ver}.gem"
|
27
|
+
sh "git tag -a -m 'Snuggie v#{ver}' v#{ver}"
|
28
|
+
sh "git push origin v#{ver}"
|
29
|
+
sh "git push origin master"
|
30
|
+
sh "mv snuggie-#{ver}.gem pkg"
|
31
|
+
end
|
data/lib/snuggie.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
module Snuggie
|
2
|
+
autoload :Version, "snuggie/version"
|
3
|
+
autoload :Errors, "snuggie/errors"
|
4
|
+
autoload :Config, "snuggie/config"
|
5
|
+
autoload :NOC, "snuggie/noc"
|
6
|
+
|
7
|
+
class << self
|
8
|
+
attr_accessor :config
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.configure
|
12
|
+
yield config if block_given?
|
13
|
+
config
|
14
|
+
end
|
15
|
+
|
16
|
+
self.config = Config.new
|
17
|
+
end
|
data/lib/snuggie/noc.rb
ADDED
@@ -0,0 +1,276 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
require 'net/http'
|
3
|
+
require 'php_serialize'
|
4
|
+
|
5
|
+
module Snuggie
|
6
|
+
# Snuggie::NOC is the main class for communicating with the
|
7
|
+
# Softaculous NOC API.
|
8
|
+
class NOC
|
9
|
+
|
10
|
+
# The Softaculous NOC API lives here
|
11
|
+
API_URL = 'http://www.softaculous.com/noc'
|
12
|
+
|
13
|
+
# Creates a new Snuggie::NOC instance
|
14
|
+
#
|
15
|
+
# Params
|
16
|
+
#
|
17
|
+
# * credentials - (Optional) a hash with :username, :password to
|
18
|
+
# be used to authenticate with Softaculous. If not
|
19
|
+
# provided, the Snuggie will try using those
|
20
|
+
# configured via `Snuggie#configure`
|
21
|
+
def initialize(credentials = {})
|
22
|
+
credentials = {
|
23
|
+
:username => Snuggie.config.username,
|
24
|
+
:password => Snuggie.config.password
|
25
|
+
} if credentials.empty? && Snuggie.config.username && Snuggie.config.password
|
26
|
+
|
27
|
+
@credentials = credentials
|
28
|
+
end
|
29
|
+
|
30
|
+
# Buy a license
|
31
|
+
#
|
32
|
+
# NOTE: You must specify either months_to_add or years_to_add
|
33
|
+
#
|
34
|
+
# Params
|
35
|
+
#
|
36
|
+
# * ip - The IP of the license to be Purchased or Renewed
|
37
|
+
# * months_to_add - Months to buy/renew the license for
|
38
|
+
# * years_to_add - Years to buy/renew the license for
|
39
|
+
# * server_type - Type of server used by this license, should be
|
40
|
+
# :dedicated or :vps
|
41
|
+
# * auth_email - When buying a new license, this is required to
|
42
|
+
# verify the owner of the License. This address will
|
43
|
+
# be used to send reminders when the license is
|
44
|
+
# expiring. Not required for renewals
|
45
|
+
# * auto_renew - Renew this license automatically before
|
46
|
+
# expiration. Set to true or false.
|
47
|
+
def buy_license(params = {})
|
48
|
+
params[:ips] = params.delete(:ip) if params[:ip]
|
49
|
+
params[:autorenew] = params.delete(:auto_renew) if params[:auto_renew]
|
50
|
+
params[:authemail] = params.delete(:auth_email) if params[:auth_email]
|
51
|
+
params[:servertype] = params.delete(:server_type) if params[:server_type]
|
52
|
+
|
53
|
+
if params[:months_to_add]
|
54
|
+
params[:toadd] = "#{params.delete(:months_to_add)}M"
|
55
|
+
elsif params[:years_to_add]
|
56
|
+
params[:toadd] = "#{params.delete(:years_to_add)}Y"
|
57
|
+
end
|
58
|
+
|
59
|
+
if [:dedicated, :vps].include?(params[:servertype])
|
60
|
+
params[:servertype] = params[:servertype] == :dedicated ? 1 : 2
|
61
|
+
end
|
62
|
+
|
63
|
+
if params.has_key?(:autorenew)
|
64
|
+
params[:autorenew] = params[:autorenew] === true ? 1 : 2
|
65
|
+
end
|
66
|
+
|
67
|
+
commit(params.merge!(:ca => :buy, :purchase => 1),
|
68
|
+
:require => [:purchase, :ips, :toadd, :servertype, :autorenew]
|
69
|
+
)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Refund a transaction
|
73
|
+
#
|
74
|
+
# NOTE: A refund can only be issued within 7 days of buying/renewing
|
75
|
+
# a license.
|
76
|
+
#
|
77
|
+
# Params
|
78
|
+
#
|
79
|
+
# * action_id - The Action ID to clain a refund for
|
80
|
+
def refund(params = {})
|
81
|
+
params[:actid] = params.delete(:action_id) if params[:action_id]
|
82
|
+
params[:ca] = :refund
|
83
|
+
commit(params, :require => [:actid])
|
84
|
+
end
|
85
|
+
|
86
|
+
# List licenses
|
87
|
+
#
|
88
|
+
# NOTE: All parameters are optional. If called without parameters, a
|
89
|
+
# list of all of your licenses will be returned.
|
90
|
+
#
|
91
|
+
# Params
|
92
|
+
#
|
93
|
+
# * key - (Optional) Search for a specific License by License Key
|
94
|
+
# * ip - (Optional) Search for a specific License by Primary IP
|
95
|
+
# * expiry - (Optional) Fetch a list of Licenses that are expiring
|
96
|
+
# Set to 1 to list all expired licenses on your account
|
97
|
+
# Set to 2 to list licenses expiring in the next 7 days
|
98
|
+
# Set to 3 to list licenses expiring in the next 15 days
|
99
|
+
# * start - (Optional) The starting point to return from
|
100
|
+
# Eg: specify 99 if you have 500 licenses and want to
|
101
|
+
# return licenses 100-500.
|
102
|
+
# * limit - (Optional) The length to limit the result set to
|
103
|
+
# Eg: specify 100 if you have 500 licenses and want to
|
104
|
+
# limit the result set to 100 items
|
105
|
+
def list_licenses(params = {})
|
106
|
+
params[:len] = params.delete(:limit) if params[:limit]
|
107
|
+
params[:ca] = :licenses
|
108
|
+
commit(params)
|
109
|
+
end
|
110
|
+
|
111
|
+
# Cancel license
|
112
|
+
#
|
113
|
+
# NOTES:
|
114
|
+
# * Either ip or key needs to be specified
|
115
|
+
# * Cancellations are not allowed on licenses expiring more than 1
|
116
|
+
# month in the future.
|
117
|
+
# * A refund is **NOT** applied when you cancel a license. You must
|
118
|
+
# claim the refund using Snuggie::NOC#refund
|
119
|
+
#
|
120
|
+
# Params
|
121
|
+
#
|
122
|
+
# * key - (Optional) The license key
|
123
|
+
# * ip - (Optional) The Primary IP of the license
|
124
|
+
def cancel_license(params = {})
|
125
|
+
params[:lickey] = params.delete(:key) if params[:key]
|
126
|
+
params[:licip] = params.delete(:ip) if params[:ip]
|
127
|
+
commit(params.merge!(:ca => :cancel, :cancel_license => 1),
|
128
|
+
:require_one => [:lickey, :licip]
|
129
|
+
)
|
130
|
+
end
|
131
|
+
|
132
|
+
# Edit IPs associated with a license
|
133
|
+
#
|
134
|
+
# Params
|
135
|
+
#
|
136
|
+
# * license_id - The license ID (**NOT** the license key)
|
137
|
+
# * ips - The list of IPs of the same VPS/Server. The first IP is
|
138
|
+
# the Primary IP. You may add up to 8 IPs
|
139
|
+
def edit_ips(params = {})
|
140
|
+
params[:'ips[]'] = params.delete(:ips)
|
141
|
+
params[:lid] = params.delete(:license_id) if params[:license_id]
|
142
|
+
commit(params.merge!(:ca => :showlicense, :editlicense => 1),
|
143
|
+
:require => [:lid, :'ips[]']
|
144
|
+
)
|
145
|
+
end
|
146
|
+
|
147
|
+
# Get details for an invoice
|
148
|
+
#
|
149
|
+
# NOTE: If invoid is 0 or not set, a list of **all** unbilled
|
150
|
+
# transactions for the current month will be returned
|
151
|
+
#
|
152
|
+
# Params
|
153
|
+
#
|
154
|
+
# * invoice_id - The invoice ID to getch details for.
|
155
|
+
def invoice_details(params = {})
|
156
|
+
params[:invoid] = params.delete(:invoice_id) if params[:invoice_id]
|
157
|
+
params[:ca] = :invoicedetails
|
158
|
+
commit(params)
|
159
|
+
end
|
160
|
+
|
161
|
+
# Get Action Logs for a license
|
162
|
+
#
|
163
|
+
# NOTE: The logs are returned in **DESCENDING ORDER**, meaning the
|
164
|
+
# latest logs will appear first.
|
165
|
+
#
|
166
|
+
# Params
|
167
|
+
#
|
168
|
+
# * key - The license key
|
169
|
+
# * limit - The number of action logs to return
|
170
|
+
def license_logs(params = {})
|
171
|
+
params[:ca] = :licenselogs
|
172
|
+
commit(params, :require => :key)
|
173
|
+
end
|
174
|
+
|
175
|
+
private
|
176
|
+
|
177
|
+
# Send a request upstream to Softaculous
|
178
|
+
#
|
179
|
+
# Params
|
180
|
+
#
|
181
|
+
# * params - a hash of parameters for the request
|
182
|
+
# * options - a hash of options, used to validate required params
|
183
|
+
def commit(params, options = {})
|
184
|
+
if options[:require]
|
185
|
+
unless require_params(params, options[:require])
|
186
|
+
raise Errors::MissingArgument
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
if options[:require_one]
|
191
|
+
unless require_one_of(params, options[:require_one])
|
192
|
+
raise Errors::MissingArgument
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
params.merge!(@credentials) unless @credentials.nil? || @credentials.empty?
|
197
|
+
|
198
|
+
uri = "#{API_URL}?#{query_string(params)}"
|
199
|
+
if res = fetch(uri)
|
200
|
+
@response = begin
|
201
|
+
PHP.unserialize(res.body)
|
202
|
+
rescue
|
203
|
+
res.body
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
# Returns true if params has all of the specified keys
|
209
|
+
#
|
210
|
+
# Params
|
211
|
+
#
|
212
|
+
# * params - hash of query parameters
|
213
|
+
# * keys - keys to search for in params
|
214
|
+
def require_params(params, keys)
|
215
|
+
Array(keys).each { |key| return false unless params[key] }
|
216
|
+
true
|
217
|
+
end
|
218
|
+
|
219
|
+
# Returns true if params has one of the specified keys
|
220
|
+
#
|
221
|
+
# Params
|
222
|
+
#
|
223
|
+
# * params - hash of query parameters
|
224
|
+
# * keys - keys to search for in params
|
225
|
+
def require_one_of(params, keys)
|
226
|
+
Array(keys).each { |key| return true if params[key] }
|
227
|
+
false
|
228
|
+
end
|
229
|
+
|
230
|
+
# Formats params into a query string for a GET request
|
231
|
+
#
|
232
|
+
# NOTE: For convenience, this converts the keys :username and
|
233
|
+
# :password to :nocname and :nocpass respectively.
|
234
|
+
#
|
235
|
+
# Params
|
236
|
+
#
|
237
|
+
# * params - hash of query parameters
|
238
|
+
def query_string(params)
|
239
|
+
params.map do |key, val|
|
240
|
+
case key.to_sym
|
241
|
+
when :username
|
242
|
+
key = :nocname
|
243
|
+
when :password
|
244
|
+
key = :nocpass
|
245
|
+
end
|
246
|
+
"#{key}=#{CGI.escape(val.to_s)}"
|
247
|
+
end.join('&')
|
248
|
+
end
|
249
|
+
|
250
|
+
# Performs a GET request on the given URI, redirects if needed
|
251
|
+
#
|
252
|
+
# See Following Redirection at
|
253
|
+
# http://ruby-doc.org/stdlib/libdoc/net/http/rdoc/classes/Net/HTTP.html
|
254
|
+
#
|
255
|
+
# Params
|
256
|
+
#
|
257
|
+
# * uri_str - the URL to fetch as a string
|
258
|
+
# * limit - number of redirects to allow
|
259
|
+
def fetch(uri_str, limit = 10)
|
260
|
+
# You should choose better exception.
|
261
|
+
raise ArgumentError, 'HTTP redirect too deep' if limit == 0
|
262
|
+
|
263
|
+
uri = URI.parse(uri_str)
|
264
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
265
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
266
|
+
response = http.start { |http| http.request(request) }
|
267
|
+
|
268
|
+
case response
|
269
|
+
when Net::HTTPSuccess then response
|
270
|
+
when Net::HTTPRedirection then fetch(response['location'], limit - 1)
|
271
|
+
else
|
272
|
+
response.error!
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
a:12:{s:3:"lid";i:99999;s:7:"license";s:29:"XXXXX-XXXXX-XXXXX-XXXXX-XXXXX";s:3:"bal";d:-48;s:2:"ip";s:9:"127.0.0.1";s:4:"time";i:1308062889;s:4:"rate";i:2;s:3:"amt";i:2;s:5:"added";s:2:"1M";s:6:"action";s:3:"new";s:9:"autorenew";s:3:"YES";s:5:"actid";i:99999;s:5:"error";N;}
|
@@ -0,0 +1 @@
|
|
1
|
+
a:2:{s:5:"error";N;s:17:"cancelled_license";a:15:{s:6:"apiuid";s:1:"0";s:5:"nocid";s:4:"XXXX";s:10:"servertype";s:1:"1";s:7:"license";s:29:"XXXXX-XXXXX-XXXXX-XXXXX-XXXXX";s:4:"time";s:10:"1308062889";s:7:"expires";s:8:"20110614";s:3:"env";s:0:"";s:4:"type";s:1:"1";s:9:"last_sync";s:1:"0";s:3:"lid";s:5:"99999";s:10:"soft_email";s:0:"";s:5:"panel";s:0:"";s:9:"authemail";s:18:"marty@hilldale.edu";s:6:"unique";s:0:"";s:6:"active";s:1:"1";}}
|
@@ -0,0 +1 @@
|
|
1
|
+
a:3:{s:5:"error";N;s:7:"new_ips";a:1:{i:0;s:9:"127.0.0.2";}s:3:"lid";i:99999;}
|
@@ -0,0 +1 @@
|
|
1
|
+
a:3:{s:7:"actions";a:2:{i:XXXXX;a:12:{s:5:"actid";s:5:"XXXXX";s:5:"nocid";s:4:"XXXX";s:6:"action";s:7:"advance";s:3:"lid";s:1:"0";s:6:"invoid";s:1:"0";s:4:"rate";s:5:"50.00";s:5:"added";s:0:"";s:3:"amt";s:6:"-50.00";s:4:"time";s:10:"1307554880";s:4:"date";s:8:"20110608";s:8:"refunded";s:1:"0";s:7:"license";N;}i:XXXXX;a:12:{s:5:"actid";s:5:"XXXXX";s:5:"nocid";s:4:"XXXX";s:6:"action";s:3:"new";s:3:"lid";s:5:"XXXXX";s:6:"invoid";s:1:"0";s:4:"rate";s:4:"2.00";s:5:"added";s:2:"1M";s:3:"amt";s:4:"2.00";s:4:"time";s:10:"1308062889";s:4:"date";s:8:"20110614";s:8:"refunded";s:1:"0";s:7:"license";s:29:"XXXXX-XXXXX-XXXXX-XXXXX-XXXXX";}}s:3:"amt";d:-48;s:6:"invoid";i:0;}
|
@@ -0,0 +1 @@
|
|
1
|
+
a:3:{s:7:"actions";a:1:{i:XXXXX;a:11:{s:5:"actid";s:5:"XXXXX";s:5:"nocid";s:4:"XXXX";s:6:"action";s:3:"new";s:3:"lid";s:5:"XXXXX";s:6:"invoid";s:1:"0";s:4:"rate";s:4:"2.00";s:5:"added";s:2:"1M";s:3:"amt";s:4:"2.00";s:4:"time";s:10:"1308062889";s:4:"date";s:8:"20110614";s:8:"refunded";s:1:"0";}}s:7:"license";a:15:{s:3:"lid";s:5:"XXXXX";s:7:"license";s:29:"XXXXX-XXXXX-XXXXX-XXXXX-XXXXX";s:4:"type";s:1:"1";s:6:"unique";s:0:"";s:6:"apiuid";s:1:"0";s:5:"nocid";s:4:"XXXX";s:9:"authemail";s:18:"marty@hilldale.edu";s:10:"soft_email";s:0:"";s:4:"time";s:10:"1308062889";s:7:"expires";s:8:"20110714";s:6:"active";s:1:"1";s:10:"servertype";s:1:"1";s:9:"last_sync";s:1:"0";s:5:"panel";s:0:"";s:3:"env";s:0:"";}s:5:"error";N;}
|
@@ -0,0 +1 @@
|
|
1
|
+
a:4:{s:8:"licenses";a:1:{i:99999;a:19:{s:3:"lid";s:5:"XXXXX";s:7:"license";s:29:"XXXXX-XXXXX-XXXXX-XXXXX-XXXXX";s:4:"type";s:1:"1";s:6:"unique";s:0:"";s:6:"apiuid";s:1:"0";s:5:"nocid";s:4:"XXXX";s:9:"authemail";s:18:"marty@hilldale.org";s:10:"soft_email";s:0:"";s:4:"time";s:10:"1308062889";s:7:"expires";s:8:"20110614";s:6:"active";s:1:"1";s:10:"servertype";s:1:"1";s:9:"last_sync";s:1:"0";s:5:"panel";s:0:"";s:3:"env";s:0:"";s:4:"ipid";s:5:"XXXXX";s:2:"ip";s:9:"127.0.0.1";s:7:"primary";s:1:"1";s:8:"hostname";s:12:"hilldale.org";}}s:10:"num_active";i:1;s:11:"num_results";i:1;s:5:"error";N;}
|
@@ -0,0 +1 @@
|
|
1
|
+
a:10:{s:3:"lid";s:5:"XXXXX";s:7:"license";s:29:"XXXXX-XXXXX-XXXXX-XXXXX-XXXXX";s:3:"bal";d:-50;s:4:"time";i:1308066592;s:4:"rate";s:4:"2.00";s:3:"amt";d:-2;s:5:"added";s:3:"-1M";s:6:"action";s:6:"refund";s:5:"actid";i:99999;s:5:"error";N;}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
context "Snuggie::Config" do
|
4
|
+
setup do
|
5
|
+
@config = Snuggie::Config.new
|
6
|
+
end
|
7
|
+
|
8
|
+
test "has attr_accessor :username" do
|
9
|
+
assert_attr_accessor @config, :username
|
10
|
+
end
|
11
|
+
|
12
|
+
test "has attr_accessor :password" do
|
13
|
+
assert_attr_accessor @config, :password
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,279 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
context "Snuggie::NOC" do
|
4
|
+
TEST_CREDENTIALS = { :username => 'marty', :password => 'mcSUPERfly' }
|
5
|
+
|
6
|
+
setup do
|
7
|
+
@noc = Snuggie::NOC.new(TEST_CREDENTIALS)
|
8
|
+
end
|
9
|
+
|
10
|
+
def mock_query_url(params = {})
|
11
|
+
@noc.class::API_URL + '?' + @noc.instance_eval { query_string(params) }
|
12
|
+
end
|
13
|
+
|
14
|
+
test "::API_URL has a valid format" do
|
15
|
+
assert_valid_url @noc.class::API_URL
|
16
|
+
end
|
17
|
+
|
18
|
+
test "#initialize sets @credentials" do
|
19
|
+
credentials = @noc.instance_variable_get(:@credentials)
|
20
|
+
assert credentials.is_a?(Hash)
|
21
|
+
TEST_CREDENTIALS.each do |key, val|
|
22
|
+
assert credentials.has_key?(key)
|
23
|
+
assert_equal val, credentials[key]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
test "#initialize uses Config to set @credentials" do
|
28
|
+
Snuggie.configure do |c|
|
29
|
+
c.username = 'doc'
|
30
|
+
c.password = 'clara'
|
31
|
+
end
|
32
|
+
credentials = @noc.class.new.instance_variable_get(:@credentials)
|
33
|
+
assert credentials.is_a?(Hash)
|
34
|
+
({ :username => 'doc', :password => 'clara' }).each do |key, val|
|
35
|
+
assert_not_nil credentials[key]
|
36
|
+
assert credentials.has_key?(key)
|
37
|
+
end
|
38
|
+
|
39
|
+
Snuggie.configure do |c|
|
40
|
+
c.username = nil
|
41
|
+
c.password = nil
|
42
|
+
end
|
43
|
+
assert_equal @noc.class.new.instance_variable_get(:@credentials), Hash.new
|
44
|
+
end
|
45
|
+
|
46
|
+
test "#require_params returns true if all params are set" do
|
47
|
+
a1 = @noc.instance_eval do
|
48
|
+
require_params({ :fuel => :plutonium, :date => 1955 }, [:fuel, :date])
|
49
|
+
end
|
50
|
+
assert a1
|
51
|
+
end
|
52
|
+
|
53
|
+
test "#require_one_of returns true if one param is set" do
|
54
|
+
a1 = @noc.instance_eval do
|
55
|
+
require_one_of({ :date => 1955, :fuel => :plutonium }, [:fusion, :fuel])
|
56
|
+
end
|
57
|
+
assert a1
|
58
|
+
end
|
59
|
+
|
60
|
+
test "#query_string" do
|
61
|
+
params = {
|
62
|
+
:date => 1955,
|
63
|
+
:fuel => :plutonium,
|
64
|
+
:username => 'marty',
|
65
|
+
:password => 'mcSUPERfly'
|
66
|
+
}
|
67
|
+
|
68
|
+
query = @noc.instance_eval do
|
69
|
+
query_string(params)
|
70
|
+
end
|
71
|
+
|
72
|
+
assert_match /date=1955/, query
|
73
|
+
assert_match /fuel=plutonium/, query
|
74
|
+
assert_match /nocname=marty/, query
|
75
|
+
assert_match /nocpass=mcSUPERfly/, query
|
76
|
+
|
77
|
+
assert_no_match /username/, query
|
78
|
+
assert_no_match /password/, query
|
79
|
+
end
|
80
|
+
|
81
|
+
test "#commit requires all :require params" do
|
82
|
+
mock_request(mock_query_url)
|
83
|
+
assert_raise(Snuggie::Errors::MissingArgument) do
|
84
|
+
@noc.instance_eval do
|
85
|
+
commit({}, :require => :fuel)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
params = { :fuel => :plutonium }
|
90
|
+
mock_request(mock_query_url(params))
|
91
|
+
assert_nothing_raised do
|
92
|
+
@noc.instance_eval do
|
93
|
+
commit(params, :require => :fuel)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
test "#commit requires one of :require_one params" do
|
99
|
+
p1 = { :date => 1955 }
|
100
|
+
mock_request(mock_query_url(p1))
|
101
|
+
assert_raise(Snuggie::Errors::MissingArgument) do
|
102
|
+
@noc.instance_eval do
|
103
|
+
commit(p1, :require_one => :fuel)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
p2 = { :date => 1955, :fuel => :plutonium }
|
108
|
+
mock_request(mock_query_url(p2))
|
109
|
+
assert_nothing_raised do
|
110
|
+
@noc.instance_eval do
|
111
|
+
commit(p2, :require_one => :fuel)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
test "#commit returns a hash if PHP.unserialize works" do
|
117
|
+
p1 = { :date => 1955 }
|
118
|
+
mock_request(mock_query_url(p1), :body => PHP.serialize(:status => :success))
|
119
|
+
res = @noc.instance_eval do
|
120
|
+
commit(p1, :require => :date)
|
121
|
+
end
|
122
|
+
assert res.has_key?('status')
|
123
|
+
assert_equal 'success', res['status']
|
124
|
+
end
|
125
|
+
|
126
|
+
test "#commit returns HTTP body if PHP.unserialize fails" do
|
127
|
+
p1 = { :date => 1955 }
|
128
|
+
mock_request(mock_query_url(p1), :body => "not a PHP serialized string")
|
129
|
+
res = @noc.instance_eval do
|
130
|
+
commit(p1, :require => :date)
|
131
|
+
end
|
132
|
+
assert_equal 'not a PHP serialized string', res
|
133
|
+
end
|
134
|
+
|
135
|
+
test "#buy_license required params" do
|
136
|
+
params = {
|
137
|
+
:ip => '127.0.0.1',
|
138
|
+
:months_to_add => 1,
|
139
|
+
:servertype => :dedicated,
|
140
|
+
:authemail => 'marty@hilldale.edu',
|
141
|
+
:autorenew => true
|
142
|
+
}
|
143
|
+
mock_request(:buy_license)
|
144
|
+
assert_raise(Snuggie::Errors::MissingArgument, "requires args") do
|
145
|
+
@noc.buy_license
|
146
|
+
end
|
147
|
+
|
148
|
+
res = @noc.buy_license(params)
|
149
|
+
assert res.is_a?(Hash)
|
150
|
+
assert_equal '1M', res['added']
|
151
|
+
assert_equal 'YES', res['autorenew']
|
152
|
+
assert_equal 'XXXXX-XXXXX-XXXXX-XXXXX-XXXXX', res['license']
|
153
|
+
assert_equal 1308062889, res['time']
|
154
|
+
assert_equal -48.0, res['bal']
|
155
|
+
assert_equal 2, res['rate']
|
156
|
+
assert_equal 99999, res['actid']
|
157
|
+
assert_equal '127.0.0.1', res['ip']
|
158
|
+
assert_equal 99999, res['lid']
|
159
|
+
assert_equal 2, res['amt']
|
160
|
+
end
|
161
|
+
|
162
|
+
test "#refund" do
|
163
|
+
mock_request(:refund)
|
164
|
+
assert_raise(Snuggie::Errors::MissingArgument, "requires actid") do
|
165
|
+
@noc.refund
|
166
|
+
end
|
167
|
+
|
168
|
+
res = @noc.refund :actid => 99999
|
169
|
+
assert res.is_a?(Hash)
|
170
|
+
assert_equal '-1M', res['added']
|
171
|
+
assert_equal 'XXXXX-XXXXX-XXXXX-XXXXX-XXXXX', res['license']
|
172
|
+
assert_equal 1308066592, res['time']
|
173
|
+
assert_equal -50.0, res['bal']
|
174
|
+
assert_equal 'refund', res['action']
|
175
|
+
assert_equal '2.00', res['rate']
|
176
|
+
assert_equal 99999, res['actid']
|
177
|
+
assert_equal 'XXXXX', res['lid']
|
178
|
+
assert_equal -2.0, res['amt']
|
179
|
+
end
|
180
|
+
|
181
|
+
test "#list_licenses" do
|
182
|
+
mock_request(:list_licenses)
|
183
|
+
res = @noc.list_licenses
|
184
|
+
assert res.is_a?(Hash)
|
185
|
+
assert_equal 1, res['num_results']
|
186
|
+
assert_equal 1, res['num_active']
|
187
|
+
assert_not_nil res['licenses']
|
188
|
+
end
|
189
|
+
|
190
|
+
test "#cancel_license" do
|
191
|
+
mock_request(:cancel_license)
|
192
|
+
assert_raise(Snuggie::Errors::MissingArgument, "requires lickey or licip") do
|
193
|
+
@noc.cancel_license
|
194
|
+
end
|
195
|
+
# TODO: fixture/test
|
196
|
+
res = @noc.cancel_license :key => 'XXXXX-XXXXX-XXXXX-XXXXX-XXXXX'
|
197
|
+
assert res.is_a?(Hash)
|
198
|
+
assert res['cancelled_license'].is_a?(Hash)
|
199
|
+
res = res['cancelled_license']
|
200
|
+
assert_equal '0', res['apiuid']
|
201
|
+
assert_equal 'XXXX', res['nocid']
|
202
|
+
assert_equal '1', res['servertype']
|
203
|
+
assert_equal 'XXXXX-XXXXX-XXXXX-XXXXX-XXXXX', res['license']
|
204
|
+
assert_equal '1308062889', res['time']
|
205
|
+
assert_equal '20110614', res['expires']
|
206
|
+
assert_equal '1', res['type']
|
207
|
+
assert_equal '0', res['last_sync']
|
208
|
+
assert_equal 'marty@hilldale.edu', res['authemail']
|
209
|
+
end
|
210
|
+
|
211
|
+
test "#invoice_details unbilled" do
|
212
|
+
mock_request(:invoice_details_unbilled)
|
213
|
+
res = @noc.invoice_details
|
214
|
+
assert res.is_a?(Hash)
|
215
|
+
assert res['actions'].is_a?(Hash)
|
216
|
+
act = res['actions'][0]
|
217
|
+
assert_equal '1M', act['added']
|
218
|
+
assert_equal 'XXXX', act['nocid']
|
219
|
+
assert_equal 'XXXXX-XXXXX-XXXXX-XXXXX-XXXXX', act['license']
|
220
|
+
assert_equal '0', act['refunded']
|
221
|
+
assert_equal '1308062889', act['time']
|
222
|
+
assert_equal '20110614', act['date']
|
223
|
+
assert_equal '2.00', act['rate']
|
224
|
+
assert_equal 'new', act['action']
|
225
|
+
assert_equal 'XXXXX', act['actid']
|
226
|
+
assert_equal '0', act['invoid']
|
227
|
+
assert_equal 'XXXXX', act['lid']
|
228
|
+
assert_equal '2.00', act['amt']
|
229
|
+
end
|
230
|
+
|
231
|
+
test "#license_logs" do
|
232
|
+
mock_request(:license_logs)
|
233
|
+
assert_raise(Snuggie::Errors::MissingArgument, "requires key") do
|
234
|
+
@noc.license_logs
|
235
|
+
end
|
236
|
+
res = @noc.license_logs :key => 'XXXXX-XXXXX-XXXXX-XXXXX'
|
237
|
+
|
238
|
+
assert res.is_a?(Hash)
|
239
|
+
assert res['actions'].is_a?(Array)
|
240
|
+
act = res['actions'].first
|
241
|
+
assert act.is_a?(Hash)
|
242
|
+
assert_equal '1M', act['added']
|
243
|
+
assert_equal 'XXXX', act['nocid']
|
244
|
+
assert_equal '0', act['refunded']
|
245
|
+
assert_equal '1308062889', act['time']
|
246
|
+
assert_equal '20110614', act['date']
|
247
|
+
assert_equal '2.00', act['rate']
|
248
|
+
assert_equal 'new', act['action']
|
249
|
+
assert_equal '0', act['invoid']
|
250
|
+
assert_equal 'XXXXX', act['lid']
|
251
|
+
assert_equal '2.00', act['amt']
|
252
|
+
lic = res['license']
|
253
|
+
assert lic.is_a?(Hash)
|
254
|
+
assert_equal '1', lic['servertype']
|
255
|
+
assert_equal 'XXXX', lic['nocid']
|
256
|
+
assert_equal '0', lic['apiuid']
|
257
|
+
assert_equal 'XXXXX-XXXXX-XXXXX-XXXXX-XXXXX', lic['license']
|
258
|
+
assert_equal '20110714', lic['expires']
|
259
|
+
assert_equal '1308062889', lic['time']
|
260
|
+
assert_equal '0', lic['last_sync']
|
261
|
+
assert_equal '1', lic['type']
|
262
|
+
assert_equal 'XXXXX', lic['lid']
|
263
|
+
assert_equal 'marty@hilldale.edu', lic['authemail']
|
264
|
+
assert_equal '1', lic['active']
|
265
|
+
end
|
266
|
+
|
267
|
+
test "#edit_ips" do
|
268
|
+
mock_request(:edit_ips)
|
269
|
+
assert_raise(Snuggie::Errors::MissingArgument, "requires ips and lid") do
|
270
|
+
@noc.edit_ips
|
271
|
+
end
|
272
|
+
res = @noc.edit_ips :ips => '127.0.0.2', :lid => 'XXXXX'
|
273
|
+
|
274
|
+
assert res.is_a?(Hash)
|
275
|
+
assert_equal 99999, res['lid']
|
276
|
+
assert res['new_ips'].is_a?(Array)
|
277
|
+
assert_equal '127.0.0.2', res['new_ips'].first
|
278
|
+
end
|
279
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
context "Snuggie" do
|
4
|
+
setup do
|
5
|
+
Snuggie.config = Snuggie::Config.new
|
6
|
+
end
|
7
|
+
|
8
|
+
test "::Version has a valid format" do
|
9
|
+
assert Snuggie::Version.match(/\d+\.\d+\.\d+/)
|
10
|
+
end
|
11
|
+
|
12
|
+
test "has class attr_accessor :config" do
|
13
|
+
assert_attr_accessor Snuggie, :config
|
14
|
+
end
|
15
|
+
|
16
|
+
test "::config defaults to Config.new" do
|
17
|
+
assert Snuggie.config.is_a?(Snuggie::Config)
|
18
|
+
end
|
19
|
+
|
20
|
+
test "::configure sets config with a block" do
|
21
|
+
Snuggie.configure do |c|
|
22
|
+
c.username = 'mcfly'
|
23
|
+
c.password = 'b4ck1nt1m3'
|
24
|
+
end
|
25
|
+
|
26
|
+
assert Snuggie.configure.is_a?(Snuggie::Config)
|
27
|
+
assert_equal Snuggie.config.username, 'mcfly'
|
28
|
+
assert_equal Snuggie.config.password, 'b4ck1nt1m3'
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'snuggie'
|
3
|
+
require 'test/unit'
|
4
|
+
require 'fakeweb'
|
5
|
+
require 'php_serialize'
|
6
|
+
|
7
|
+
begin
|
8
|
+
require 'turn'
|
9
|
+
rescue LoadError
|
10
|
+
puts "'gem install turn' for prettier test output"
|
11
|
+
end
|
12
|
+
|
13
|
+
FakeWeb.allow_net_connect = false
|
14
|
+
|
15
|
+
# test/spec/mini 3
|
16
|
+
# Based on http://gist.github.com/25455
|
17
|
+
def context(*args, &block)
|
18
|
+
return super unless (name = args.first) && block
|
19
|
+
klass = Class.new(Test::Unit::TestCase) do
|
20
|
+
def self.test(name, &block)
|
21
|
+
name = " #{name}" unless %w[: # .].include?(name[0].chr)
|
22
|
+
define_method("test: #{self.name}#{name}", &block) if block
|
23
|
+
end
|
24
|
+
def self.setup(&block) define_method(:setup, &block) end
|
25
|
+
def self.teardown(&block) define_method(:teardown, &block) end
|
26
|
+
end
|
27
|
+
(class << klass; self end).send(:define_method, :name) { name }
|
28
|
+
(class << klass; self end).send(:define_method, :to_s) { name }
|
29
|
+
klass.class_eval &block
|
30
|
+
end
|
31
|
+
|
32
|
+
def mock_request(method, options = {})
|
33
|
+
fixture = File.expand_path("../fixtures/#{method}.txt", __FILE__)
|
34
|
+
if File.exists?(fixture)
|
35
|
+
options[:body] = File.read(fixture)
|
36
|
+
end
|
37
|
+
FakeWeb.register_uri(:get, %r|^#{Snuggie::NOC::API_URL}\?.*|, options)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Asserts that the given object has an instance variable for var
|
41
|
+
#
|
42
|
+
# class Foo
|
43
|
+
# def initialize
|
44
|
+
# @bar = :bar
|
45
|
+
# end
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
# assert_instance_var(Foo.new, :bar) => passes
|
49
|
+
def assert_instance_var(obj, var)
|
50
|
+
assert_not_nil obj.instance_variable_get("@#{var}")
|
51
|
+
end
|
52
|
+
|
53
|
+
# Asserts that the given object has an attr_accessor for method
|
54
|
+
#
|
55
|
+
# class Foo
|
56
|
+
# attr_accessor :bar
|
57
|
+
# end
|
58
|
+
#
|
59
|
+
# assert_attr_accesor(Foo.new, :bar) => passes
|
60
|
+
def assert_attr_accessor(obj, method)
|
61
|
+
assert_attr_reader obj, method
|
62
|
+
assert_attr_writer obj, method
|
63
|
+
end
|
64
|
+
|
65
|
+
# Asserts that the given object has an attr_reader for method
|
66
|
+
#
|
67
|
+
# class Foo
|
68
|
+
# attr_writer :bar
|
69
|
+
# end
|
70
|
+
#
|
71
|
+
# assert_attr_reader(Foo.new, :bar) => passes
|
72
|
+
def assert_attr_reader(obj, method)
|
73
|
+
assert_respond_to obj, method
|
74
|
+
assert_equal obj.send(method), obj.instance_variable_get("@#{method}")
|
75
|
+
end
|
76
|
+
|
77
|
+
# Asserts that the given object has an attr_writer for method
|
78
|
+
#
|
79
|
+
# class Foo
|
80
|
+
# attr_writer :bar
|
81
|
+
# end
|
82
|
+
#
|
83
|
+
# assert_attr_writer(Foo.new, :bar) => passes
|
84
|
+
def assert_attr_writer(obj, method)
|
85
|
+
assert_respond_to obj, "#{method}="
|
86
|
+
end
|
87
|
+
|
88
|
+
# Asserts that the given string is a valid URL
|
89
|
+
#
|
90
|
+
# assert_valid_url('http://google.com') => passes
|
91
|
+
def assert_valid_url(string)
|
92
|
+
assert string.to_s.match(/https?:\/\/[\S]+/)
|
93
|
+
end
|
94
|
+
|
95
|
+
# From https://github.com/thoughtbot/shoulda-context/blob/master/lib/shoulda/context/assertions.rb
|
96
|
+
# Asserts that two arrays contain the same elements, the same number of times. Essentially ==, but unordered.
|
97
|
+
#
|
98
|
+
# assert_same_elements([:a, :b, :c], [:c, :a, :b]) => passes
|
99
|
+
def assert_same_elements(a1, a2, msg = nil)
|
100
|
+
[:select, :inject, :size].each do |m|
|
101
|
+
[a1, a2].each {|a| assert_respond_to(a, m, "Are you sure that #{a.inspect} is an array? It doesn't respond to #{m}.") }
|
102
|
+
end
|
103
|
+
|
104
|
+
assert a1h = a1.inject({}) { |h,e| h[e] ||= a1.select { |i| i == e }.size; h }
|
105
|
+
assert a2h = a2.inject({}) { |h,e| h[e] ||= a2.select { |i| i == e }.size; h }
|
106
|
+
|
107
|
+
assert_equal(a1h, a2h, msg)
|
108
|
+
end
|
109
|
+
|
110
|
+
# Asserts that the given collection contains item x. If x is a regular expression, ensure that
|
111
|
+
# at least one element from the collection matches x. +extra_msg+ is appended to the error message if the assertion fails.
|
112
|
+
#
|
113
|
+
# assert_contains(['a', '1'], /\d/) => passes
|
114
|
+
# assert_contains(['a', '1'], 'a') => passes
|
115
|
+
# assert_contains(['a', '1'], /not there/) => fails
|
116
|
+
def assert_contains(collection, x, extra_msg = "")
|
117
|
+
collection = Array(collection)
|
118
|
+
msg = "#{x.inspect} not found in #{collection.to_a.inspect} #{extra_msg}"
|
119
|
+
case x
|
120
|
+
when Regexp
|
121
|
+
assert(collection.detect { |e| e =~ x }, msg)
|
122
|
+
else
|
123
|
+
assert(collection.include?(x), msg)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# Asserts that the given collection does not contain item x. If x is a regular expression, ensure that
|
128
|
+
# none of the elements from the collection match x.
|
129
|
+
def assert_does_not_contain(collection, x, extra_msg = "")
|
130
|
+
collection = Array(collection)
|
131
|
+
msg = "#{x.inspect} found in #{collection.to_a.inspect} " + extra_msg
|
132
|
+
case x
|
133
|
+
when Regexp
|
134
|
+
assert(!collection.detect { |e| e =~ x }, msg)
|
135
|
+
else
|
136
|
+
assert(!collection.include?(x), msg)
|
137
|
+
end
|
138
|
+
end
|
metadata
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: snuggie
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.1.0
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Joshua Priddle
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-06-15 00:00:00 -04:00
|
14
|
+
default_executable:
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: php-serialize
|
18
|
+
prerelease: false
|
19
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
20
|
+
none: false
|
21
|
+
requirements:
|
22
|
+
- - ~>
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 1.1.0
|
25
|
+
type: :runtime
|
26
|
+
version_requirements: *id001
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
prerelease: false
|
30
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
31
|
+
none: false
|
32
|
+
requirements:
|
33
|
+
- - ~>
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: 0.8.7
|
36
|
+
type: :development
|
37
|
+
version_requirements: *id002
|
38
|
+
- !ruby/object:Gem::Dependency
|
39
|
+
name: fakeweb
|
40
|
+
prerelease: false
|
41
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ~>
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 1.3.0
|
47
|
+
type: :development
|
48
|
+
version_requirements: *id003
|
49
|
+
description: " Snuggie wraps the Softaculous API in a warm, loving ruby embrace.\n"
|
50
|
+
email: jpriddle@site5.com
|
51
|
+
executables: []
|
52
|
+
|
53
|
+
extensions: []
|
54
|
+
|
55
|
+
extra_rdoc_files:
|
56
|
+
- README.markdown
|
57
|
+
files:
|
58
|
+
- Rakefile
|
59
|
+
- README.markdown
|
60
|
+
- lib/snuggie/config.rb
|
61
|
+
- lib/snuggie/errors.rb
|
62
|
+
- lib/snuggie/noc.rb
|
63
|
+
- lib/snuggie/version.rb
|
64
|
+
- lib/snuggie.rb
|
65
|
+
- test/fixtures/buy_license.txt
|
66
|
+
- test/fixtures/cancel_license.txt
|
67
|
+
- test/fixtures/edit_ips.txt
|
68
|
+
- test/fixtures/invoice_details_unbilled.txt
|
69
|
+
- test/fixtures/license_logs.txt
|
70
|
+
- test/fixtures/list_licenses.txt
|
71
|
+
- test/fixtures/refund.txt
|
72
|
+
- test/snuggie/config_test.rb
|
73
|
+
- test/snuggie/noc_test.rb
|
74
|
+
- test/snuggie_test.rb
|
75
|
+
- test/test_helper.rb
|
76
|
+
has_rdoc: true
|
77
|
+
homepage: https://github.com/site5/snuggie
|
78
|
+
licenses: []
|
79
|
+
|
80
|
+
post_install_message:
|
81
|
+
rdoc_options:
|
82
|
+
- --charset=UTF-8
|
83
|
+
require_paths:
|
84
|
+
- lib
|
85
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
86
|
+
none: false
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: "0"
|
91
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
92
|
+
none: false
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: "0"
|
97
|
+
requirements: []
|
98
|
+
|
99
|
+
rubyforge_project:
|
100
|
+
rubygems_version: 1.6.2
|
101
|
+
signing_key:
|
102
|
+
specification_version: 3
|
103
|
+
summary: Snuggie wraps the Softaculous API in a warm, loving ruby embrace
|
104
|
+
test_files: []
|
105
|
+
|