swirl 1.0
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/LICENSE +22 -0
- data/README.md +67 -0
- data/bin/swirl +11 -0
- data/lib/swirl.rb +1 -0
- data/lib/swirl/ec2.rb +114 -0
- data/lib/swirl/helpers.rb +108 -0
- data/list-types +36 -0
- data/test/compactor_test.rb +73 -0
- data/test/expander_test.rb +46 -0
- data/test/slop_test.rb +29 -0
- metadata +101 -0
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2007, 2008, 2009 Blake Mizerany
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person
|
4
|
+
obtaining a copy of this software and associated documentation
|
5
|
+
files (the "Software"), to deal in the Software without
|
6
|
+
restriction, including without limitation the rights to use,
|
7
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
copies of the Software, and to permit persons to whom the
|
9
|
+
Software is furnished to do so, subject to the following
|
10
|
+
conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
17
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
19
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
20
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
21
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
Swirl
|
2
|
+
=====
|
3
|
+
|
4
|
+
Swirl is an EC2 version agnostic client for EC2 writtin in Ruby. It gets
|
5
|
+
out of your way.
|
6
|
+
|
7
|
+
The secret is it's simple input extraction and output compacting. Your
|
8
|
+
input parameters and `expand`ed and EC2's (terrible) xml output is
|
9
|
+
`compact`ed.
|
10
|
+
|
11
|
+
|
12
|
+
Some simple examples:
|
13
|
+
|
14
|
+
# Input
|
15
|
+
{ "InstanceId" => ["i-123k2h1", "i-0234d3"] }
|
16
|
+
|
17
|
+
is `expand`ed to:
|
18
|
+
|
19
|
+
{ "InstanceId.0" => "i-123k2h1", "InstanceId.1" => "i-0234d3" }
|
20
|
+
|
21
|
+
and
|
22
|
+
|
23
|
+
# Output
|
24
|
+
{
|
25
|
+
"reservationSet" => {
|
26
|
+
"item" => {
|
27
|
+
"instancesSet" => { "item" => [ ... ] }
|
28
|
+
}
|
29
|
+
}
|
30
|
+
}
|
31
|
+
|
32
|
+
and it's varations are now `compact`ed to:
|
33
|
+
|
34
|
+
{
|
35
|
+
"reservationSet" => {
|
36
|
+
"instancesSet" => [ { ... }, { ... } ]
|
37
|
+
}
|
38
|
+
}
|
39
|
+
|
40
|
+
|
41
|
+
Some things worth noteing is that compact ignores Symbols. This
|
42
|
+
allows you to pass the params into `call` and use them later
|
43
|
+
without affecting the API call (i.e. chain of responsiblity); a
|
44
|
+
nifty trick we use in (Rack)[http://github.com/rack/rack]
|
45
|
+
|
46
|
+
Use
|
47
|
+
---
|
48
|
+
|
49
|
+
ec2 = Swirl::EC2.new
|
50
|
+
|
51
|
+
# Describe all instances
|
52
|
+
ec2.call "DescribeInstances"
|
53
|
+
|
54
|
+
# Describe specific instances
|
55
|
+
ec2.call "DescribeInstances", "InstanceId" => ["i-38hdk2f", "i-93nndch"]
|
56
|
+
|
57
|
+
|
58
|
+
Shell
|
59
|
+
---
|
60
|
+
|
61
|
+
$ swirl
|
62
|
+
>> c
|
63
|
+
<Swirl::EC2 ... >
|
64
|
+
>> c.call "DescribeInstances"
|
65
|
+
...
|
66
|
+
|
67
|
+
The shell respects your ~/.swirl file for configuration
|
data/bin/swirl
ADDED
data/lib/swirl.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'swirl/ec2'
|
data/lib/swirl/ec2.rb
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'cgi'
|
3
|
+
require 'base64'
|
4
|
+
require 'net/https'
|
5
|
+
|
6
|
+
require 'crack/xml'
|
7
|
+
require 'hmac-sha2'
|
8
|
+
|
9
|
+
require 'swirl/helpers'
|
10
|
+
|
11
|
+
module Swirl
|
12
|
+
|
13
|
+
## Errors
|
14
|
+
class InvalidRequest < StandardError ; end
|
15
|
+
|
16
|
+
|
17
|
+
class EC2
|
18
|
+
include Helpers::Compactor
|
19
|
+
include Helpers::Expander
|
20
|
+
|
21
|
+
|
22
|
+
def self.options(name=:default, file="~/.swirl")
|
23
|
+
YAML.load_file(File.expand_path(file))[name]
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize(options={}, file="~/.swirl")
|
27
|
+
account = options.fetch(:account) { :default }
|
28
|
+
options = self.class.options(account, file).merge(options)
|
29
|
+
|
30
|
+
@aws_access_key_id = options[:aws_access_key_id]
|
31
|
+
@aws_secret_access_key = options[:aws_secret_access_key]
|
32
|
+
@hmac = HMAC::SHA256.new(@aws_secret_access_key)
|
33
|
+
@version = options[:version] || "2009-11-30"
|
34
|
+
@url = URI(options[:url] || "https://ec2.amazonaws.com")
|
35
|
+
end
|
36
|
+
|
37
|
+
def escape(value)
|
38
|
+
CGI.escape(value).gsub(/\+/, "%20")
|
39
|
+
end
|
40
|
+
|
41
|
+
def compile_sorted_form_data(query)
|
42
|
+
valid = query.reject {|_, v| v.nil? }
|
43
|
+
valid.sort.map {|k,v| [k, escape(v)] * "=" } * "&"
|
44
|
+
end
|
45
|
+
|
46
|
+
def compile_signature(method, body)
|
47
|
+
string_to_sign = [method, @url.host, "/", body] * "\n"
|
48
|
+
hmac = @hmac.update(string_to_sign)
|
49
|
+
encoded_sig = Base64.encode64(hmac.digest).chomp
|
50
|
+
escape(encoded_sig)
|
51
|
+
end
|
52
|
+
|
53
|
+
##
|
54
|
+
# Execute an EC2 command, expand the input,
|
55
|
+
# and compact the output
|
56
|
+
#
|
57
|
+
# Examples:
|
58
|
+
# ec2.call("DescribeInstances")
|
59
|
+
# ec2.call("TerminateInstances", "InstanceId" => ["i-1234", "i-993j"]
|
60
|
+
#
|
61
|
+
def call(action, query={})
|
62
|
+
code, data = call!(action, expand(query))
|
63
|
+
|
64
|
+
case code
|
65
|
+
when 200
|
66
|
+
compact(data)
|
67
|
+
when 400...500
|
68
|
+
messages = Array(data["Response"]["Errors"]).map {|_, e| e["Message"] }
|
69
|
+
raise InvalidRequest, messages.join(",")
|
70
|
+
else
|
71
|
+
msg = "unexpected response #{response.code} -> #{data.inspect}"
|
72
|
+
raise InvalidRequest, msg
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def call!(action, query={})
|
77
|
+
# Hard coding this here until otherwise needed
|
78
|
+
method = "POST"
|
79
|
+
|
80
|
+
query["Action"] = action
|
81
|
+
query["AWSAccessKeyId"] = @aws_access_key_id
|
82
|
+
query["SignatureMethod"] = "HmacSHA256"
|
83
|
+
query["SignatureVersion"] = "2"
|
84
|
+
query["Timestamp"] = Time.now.utc.strftime("%Y-%m-%dT%H:%M:%SZ")
|
85
|
+
query["Version"] = @version
|
86
|
+
|
87
|
+
body = compile_sorted_form_data(query)
|
88
|
+
body += "&" + ["Signature", compile_signature(method, body)].join("=")
|
89
|
+
|
90
|
+
response = post(body)
|
91
|
+
data = Crack::XML.parse(response.body)
|
92
|
+
[response.code.to_i, data]
|
93
|
+
end
|
94
|
+
|
95
|
+
def post(body)
|
96
|
+
headers = { "Content-Type" => "application/x-www-form-urlencoded" }
|
97
|
+
|
98
|
+
http = Net::HTTP.new(@url.host, @url.port)
|
99
|
+
http.use_ssl = true
|
100
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
101
|
+
|
102
|
+
request = Net::HTTP::Post.new(@url.request_uri, headers)
|
103
|
+
request.body = body
|
104
|
+
|
105
|
+
http.request(request)
|
106
|
+
end
|
107
|
+
|
108
|
+
def inspect
|
109
|
+
"<#{self.class.name} version: #{@version} url: #{@url} aws_access_key_id: #{@aws_access_key_id}>"
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
module Swirl
|
2
|
+
|
3
|
+
module Helpers
|
4
|
+
|
5
|
+
module Compactor
|
6
|
+
|
7
|
+
Lists = [
|
8
|
+
"keySet",
|
9
|
+
"groupSet",
|
10
|
+
"blockDeviceMapping",
|
11
|
+
"instancesSet",
|
12
|
+
"reservationSet",
|
13
|
+
"imagesSet",
|
14
|
+
"ownersSet",
|
15
|
+
"executableBySet",
|
16
|
+
"securityGroupSet",
|
17
|
+
"ipPermissions",
|
18
|
+
"ipRanges",
|
19
|
+
"groups",
|
20
|
+
"securityGroupInfo",
|
21
|
+
"add",
|
22
|
+
"remove",
|
23
|
+
"launchPermission",
|
24
|
+
"productCodes",
|
25
|
+
"availabilityZoneSet",
|
26
|
+
"availabilityZoneInfo",
|
27
|
+
"publicIpsSet",
|
28
|
+
"addressesSet"
|
29
|
+
]
|
30
|
+
|
31
|
+
def compact(response)
|
32
|
+
root_key = response.keys.first
|
33
|
+
base = response[root_key]
|
34
|
+
compact!(base)
|
35
|
+
end
|
36
|
+
module_function :compact
|
37
|
+
|
38
|
+
def compact!(data)
|
39
|
+
data.inject({}) do |com, (key, value)|
|
40
|
+
if Lists.include?(key)
|
41
|
+
converted = if value && value.has_key?("item")
|
42
|
+
items = value["item"]
|
43
|
+
items ||= []
|
44
|
+
items = items.is_a?(Array) ? items : [items]
|
45
|
+
items.map {|item| compact!(item) }
|
46
|
+
else
|
47
|
+
[]
|
48
|
+
end
|
49
|
+
com[key] = converted
|
50
|
+
elsif key == "xmlns"
|
51
|
+
next(com)
|
52
|
+
else
|
53
|
+
com[key] = value
|
54
|
+
end
|
55
|
+
com
|
56
|
+
end
|
57
|
+
end
|
58
|
+
module_function :compact!
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
module Expander
|
63
|
+
def expand(request)
|
64
|
+
request.inject({}) do |exp, (key, value)|
|
65
|
+
next(exp) if !key.is_a?(String)
|
66
|
+
|
67
|
+
case value
|
68
|
+
when Array
|
69
|
+
value.each_with_index do |val, n|
|
70
|
+
exp["#{key}.#{n}"] = val
|
71
|
+
end
|
72
|
+
when Range
|
73
|
+
exp["From#{key}"] = value.min
|
74
|
+
exp["To#{key}"] = value.max
|
75
|
+
else
|
76
|
+
exp[key] = value
|
77
|
+
end
|
78
|
+
exp
|
79
|
+
end
|
80
|
+
end
|
81
|
+
module_function :expand
|
82
|
+
end
|
83
|
+
|
84
|
+
module Slop
|
85
|
+
class InvalidKey < StandardError ; end
|
86
|
+
|
87
|
+
def self.new(response)
|
88
|
+
sloppy = Hash.new do |hash, key|
|
89
|
+
camalized = Slop.camalize(key)
|
90
|
+
raise InvalidKey, key if !response.has_key?(camalized)
|
91
|
+
response[camalized]
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def self.camalize(stringish)
|
96
|
+
head, tail = stringish.to_s.split("_")
|
97
|
+
rest = Array(tail).map! {|part| part.capitalize }
|
98
|
+
[head, *rest].join
|
99
|
+
end
|
100
|
+
|
101
|
+
def slopify(response)
|
102
|
+
Slop.new(response)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
data/list-types
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'nokogiri'
|
5
|
+
rescue LoadError
|
6
|
+
abort <<-MSG
|
7
|
+
Unable to load nokogiri.
|
8
|
+
Ensure you have it installed and/or
|
9
|
+
export RUBYOPT=rubygems
|
10
|
+
MSG
|
11
|
+
end
|
12
|
+
|
13
|
+
require 'open-uri'
|
14
|
+
require 'stringio'
|
15
|
+
require 'pp'
|
16
|
+
|
17
|
+
DefaultWSDL = "http://s3.amazonaws.com/ec2-downloads/2008-02-01.ec2.wsdl"
|
18
|
+
|
19
|
+
wsdl_url = ARGV.shift || DefaultWSDL
|
20
|
+
Wsdl = Nokogiri::XML.parse(open(wsdl_url))
|
21
|
+
|
22
|
+
##__END__
|
23
|
+
|
24
|
+
list_keys = []
|
25
|
+
item_types = Wsdl.search(%Q|//xs:complexType//xs:element[@name="item"]|)
|
26
|
+
item_types.each do |item_type|
|
27
|
+
ns, name = item_type["type"].split(":")
|
28
|
+
next if ns != "tns"
|
29
|
+
complex = item_type.parent.parent
|
30
|
+
uses = Wsdl.search(%Q|//xs:element[@type="#{ns}:#{complex["name"]}"]|)
|
31
|
+
uses.each do |u|
|
32
|
+
list_keys << u["name"]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
pp list_keys.uniq
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'contest'
|
2
|
+
require 'swirl/helpers'
|
3
|
+
|
4
|
+
class CompactorTest < Test::Unit::TestCase
|
5
|
+
include Swirl::Helpers
|
6
|
+
|
7
|
+
test "pivots on root" do
|
8
|
+
response = { "Foo" => { "requestId" => "abc123" } }
|
9
|
+
expected = { "requestId" => "abc123" }
|
10
|
+
|
11
|
+
assert_equal expected, Compactor.compact(response)
|
12
|
+
end
|
13
|
+
|
14
|
+
test "ignores xmlns" do
|
15
|
+
response = { "Foo" => { "requestId" => "abc123", "xmlns" => "suckit" } }
|
16
|
+
expected = { "requestId" => "abc123" }
|
17
|
+
|
18
|
+
assert_equal expected, Compactor.compact(response)
|
19
|
+
end
|
20
|
+
|
21
|
+
test "pivots list keys on item" do
|
22
|
+
response = { "Foo" => { "groupSet" => { "item" => [{ "foo" => "bar" }] } } }
|
23
|
+
expected = { "groupSet" => [ { "foo" => "bar" } ] }
|
24
|
+
|
25
|
+
assert_equal expected, Compactor.compact(response)
|
26
|
+
end
|
27
|
+
|
28
|
+
test "pivots list keys item and converts to Array not already an Array" do
|
29
|
+
response = { "Foo" => { "groupSet" => { "item" => { "foo" => "bar" } } } }
|
30
|
+
expected = { "groupSet" => [ { "foo" => "bar" } ] }
|
31
|
+
|
32
|
+
assert_equal expected, Compactor.compact(response)
|
33
|
+
end
|
34
|
+
|
35
|
+
test "pivots list keys item and makes empty Array if nil" do
|
36
|
+
response = { "Foo" => { "groupSet" => { "item" => nil } } }
|
37
|
+
expected = { "groupSet" => [] }
|
38
|
+
|
39
|
+
assert_equal expected, Compactor.compact(response)
|
40
|
+
end
|
41
|
+
|
42
|
+
test "makes value empty Array if nil" do
|
43
|
+
response = { "Foo" => { "groupSet" => nil } }
|
44
|
+
expected = { "groupSet" => [] }
|
45
|
+
|
46
|
+
assert_equal expected, Compactor.compact(response)
|
47
|
+
end
|
48
|
+
|
49
|
+
test "traverses list values and compacts" do
|
50
|
+
response = {
|
51
|
+
"Foo" => {
|
52
|
+
"groupSet" => {
|
53
|
+
"item" => {
|
54
|
+
"ipPermissions" => {
|
55
|
+
"item" => {
|
56
|
+
"proto" => "tcp"
|
57
|
+
}
|
58
|
+
}
|
59
|
+
}
|
60
|
+
}
|
61
|
+
}
|
62
|
+
}
|
63
|
+
|
64
|
+
expected = {
|
65
|
+
"groupSet" => [
|
66
|
+
{ "ipPermissions" => [ { "proto" => "tcp" } ] }
|
67
|
+
]
|
68
|
+
}
|
69
|
+
|
70
|
+
assert_equal expected, Compactor.compact(response)
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'contest'
|
2
|
+
require 'swirl/helpers'
|
3
|
+
|
4
|
+
class ExpanderTest < Test::Unit::TestCase
|
5
|
+
include Swirl::Helpers
|
6
|
+
|
7
|
+
test "leaves params as is by default" do
|
8
|
+
request = { "foo" => "bar" }
|
9
|
+
|
10
|
+
assert_equal request, Expander.expand(request)
|
11
|
+
end
|
12
|
+
|
13
|
+
test "ignores non-String keys" do
|
14
|
+
request = { "foo" => "bar", :ignore => "test" }
|
15
|
+
expected = { "foo" => "bar" }
|
16
|
+
|
17
|
+
assert_equal expected, Expander.expand(request)
|
18
|
+
end
|
19
|
+
|
20
|
+
test "expands Array values to .n key-values" do
|
21
|
+
request = { "group" => ["foo", "bar", "baz"] }
|
22
|
+
|
23
|
+
expected = {
|
24
|
+
"group.0" => "foo",
|
25
|
+
"group.1" => "bar",
|
26
|
+
"group.2" => "baz"
|
27
|
+
}
|
28
|
+
|
29
|
+
assert_equal expected, Expander.expand(request)
|
30
|
+
end
|
31
|
+
|
32
|
+
test "ignores empty Array values" do
|
33
|
+
request = { "group" => [] }
|
34
|
+
expected = {}
|
35
|
+
|
36
|
+
assert_equal expected, Expander.expand(request)
|
37
|
+
end
|
38
|
+
|
39
|
+
test "converts Key of Range to FromKey ToKey" do
|
40
|
+
request = { "Port" => 1..3 }
|
41
|
+
expected = { "FromPort" => 1, "ToPort" => 3 }
|
42
|
+
|
43
|
+
assert_equal expected, Expander.expand(request)
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
data/test/slop_test.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'contest'
|
2
|
+
require 'swirl/helpers'
|
3
|
+
|
4
|
+
class SlopTest < Test::Unit::TestCase
|
5
|
+
include Swirl::Helpers
|
6
|
+
|
7
|
+
test "camalize" do
|
8
|
+
assert_equal "foo", Slop.camalize(:foo)
|
9
|
+
assert_equal "fooBar", Slop.camalize(:foo_bar)
|
10
|
+
end
|
11
|
+
|
12
|
+
test "gets sloppy" do
|
13
|
+
slop = Slop.new({"fooBar" => "baz"})
|
14
|
+
assert_equal "baz", slop[:foo_bar]
|
15
|
+
end
|
16
|
+
|
17
|
+
test "honors keys already camalized" do
|
18
|
+
slop = Slop.new({"fooBar" => "baz"})
|
19
|
+
assert_equal "baz", slop["fooBar"]
|
20
|
+
end
|
21
|
+
|
22
|
+
test "raise InvalidKey if key not found" do
|
23
|
+
slop = Slop.new({})
|
24
|
+
assert_raises Slop::InvalidKey do
|
25
|
+
slop[:not_here]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
metadata
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: swirl
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: "1.0"
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Blake Mizerany
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-01-26 00:00:00 -08:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: crack
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.1.4
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: ruby-hmac
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.3.2
|
34
|
+
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: contest
|
37
|
+
type: :development
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 0.1.2
|
44
|
+
version:
|
45
|
+
description: A version agnostic EC2 ruby driver
|
46
|
+
email:
|
47
|
+
executables:
|
48
|
+
- swirl
|
49
|
+
extensions: []
|
50
|
+
|
51
|
+
extra_rdoc_files:
|
52
|
+
- README.md
|
53
|
+
- LICENSE
|
54
|
+
files:
|
55
|
+
- LICENSE
|
56
|
+
- README.md
|
57
|
+
- list-types
|
58
|
+
- lib/swirl/ec2.rb
|
59
|
+
- lib/swirl/helpers.rb
|
60
|
+
- lib/swirl.rb
|
61
|
+
- test/compactor_test.rb
|
62
|
+
- test/expander_test.rb
|
63
|
+
- test/slop_test.rb
|
64
|
+
- bin/swirl
|
65
|
+
has_rdoc: true
|
66
|
+
homepage: http://github.com/bmizerany/swirl
|
67
|
+
licenses: []
|
68
|
+
|
69
|
+
post_install_message:
|
70
|
+
rdoc_options:
|
71
|
+
- --line-numbers
|
72
|
+
- --inline-source
|
73
|
+
- --title
|
74
|
+
- Sinatra
|
75
|
+
- --main
|
76
|
+
- README.rdoc
|
77
|
+
require_paths:
|
78
|
+
- lib
|
79
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: "0"
|
84
|
+
version:
|
85
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: "0"
|
90
|
+
version:
|
91
|
+
requirements: []
|
92
|
+
|
93
|
+
rubyforge_project: swirl
|
94
|
+
rubygems_version: 1.3.5
|
95
|
+
signing_key:
|
96
|
+
specification_version: 2
|
97
|
+
summary: A version agnostic EC2 ruby driver
|
98
|
+
test_files:
|
99
|
+
- test/compactor_test.rb
|
100
|
+
- test/expander_test.rb
|
101
|
+
- test/slop_test.rb
|