sndacs 0.0.1 → 0.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/Gemfile.lock +0 -2
- data/README.rdoc +21 -3
- data/lib/sndacs/bucket.rb +100 -52
- data/lib/sndacs/buckets_extension.rb +5 -0
- data/lib/sndacs/config.rb +59 -0
- data/lib/sndacs/connection.rb +38 -13
- data/lib/sndacs/exceptions.rb +6 -3
- data/lib/sndacs/object.rb +35 -24
- data/lib/sndacs/objects_extension.rb +2 -0
- data/lib/sndacs/parser.rb +31 -8
- data/lib/sndacs/request.rb +8 -1
- data/lib/sndacs/service.rb +38 -27
- data/lib/sndacs/signature.rb +6 -31
- data/lib/sndacs/version.rb +1 -1
- data/lib/sndacs.rb +28 -2
- data/sndacs.gemspec +5 -5
- data/spec/sndacs/bucket_spec.rb +180 -0
- data/spec/sndacs/object_spec.rb +167 -0
- data/spec/sndacs/service_spec.rb +30 -19
- data/spec/spec_helper.rb +19 -0
- metadata +90 -66
- data/test/bucket_test.rb +0 -215
- data/test/connection_test.rb +0 -214
- data/test/object_test.rb +0 -205
- data/test/service_test.rb +0 -111
- data/test/signature_test.rb +0 -205
- data/test/test_helper.rb +0 -3
data/lib/sndacs/object.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Sndacs
|
2
2
|
|
3
|
-
# Class responsible for handling objects stored in
|
3
|
+
# Class responsible for handling objects stored in CS buckets
|
4
4
|
class Object
|
5
5
|
include Parser
|
6
6
|
extend Forwardable
|
@@ -10,7 +10,7 @@ module Sndacs
|
|
10
10
|
attr_writer :content
|
11
11
|
|
12
12
|
def_instance_delegators :bucket, :name, :service, :bucket_request, :vhost?, :host, :path_prefix
|
13
|
-
def_instance_delegators :service, :protocol, :port, :secret_access_key
|
13
|
+
def_instance_delegators :service, :protocol, :port, :access_key_id, :secret_access_key
|
14
14
|
private_class_method :new
|
15
15
|
|
16
16
|
# Compares the object with other object. Returns true if the key
|
@@ -57,30 +57,24 @@ module Sndacs
|
|
57
57
|
# to do it).
|
58
58
|
def retrieve
|
59
59
|
object_headers
|
60
|
-
self
|
61
|
-
end
|
62
60
|
|
63
|
-
|
64
|
-
# exists or false otherwise. Uses #retrieve method, but catches
|
65
|
-
# S3::Error::NoSuchKey exception and returns false when it happens
|
66
|
-
def exists?
|
67
|
-
retrieve
|
68
|
-
true
|
69
|
-
rescue Error::NoSuchKey
|
70
|
-
false
|
61
|
+
self
|
71
62
|
end
|
72
63
|
|
73
64
|
# Downloads the content of the object, and caches it. Pass true to
|
74
65
|
# clear the cache and download the object again.
|
75
66
|
def content(reload = false)
|
76
67
|
return @content if defined?(@content) and not reload
|
68
|
+
|
77
69
|
get_object
|
70
|
+
|
78
71
|
@content
|
79
72
|
end
|
80
73
|
|
81
74
|
# Saves the object, returns true if successfull.
|
82
75
|
def save
|
83
76
|
put_object
|
77
|
+
|
84
78
|
true
|
85
79
|
end
|
86
80
|
|
@@ -89,7 +83,7 @@ module Sndacs
|
|
89
83
|
# ==== Options
|
90
84
|
# * <tt>:key</tt> - New key to store object in
|
91
85
|
# * <tt>:bucket</tt> - New bucket to store object in (instance of
|
92
|
-
#
|
86
|
+
# Sndacs::Bucket)
|
93
87
|
# * <tt>:acl</tt> - ACL of the copied object (default:
|
94
88
|
# "public-read")
|
95
89
|
# * <tt>:content_type</tt> - Content type of the copied object
|
@@ -101,40 +95,53 @@ module Sndacs
|
|
101
95
|
# Destroys the file on the server
|
102
96
|
def destroy
|
103
97
|
delete_object
|
98
|
+
|
104
99
|
true
|
105
100
|
end
|
106
101
|
|
107
102
|
# Returns Object's URL using protocol specified in service,
|
108
|
-
# e.g. <tt>http://
|
103
|
+
# e.g. <tt>http://storage.grandcloud.cn/bucket/key/file.extension</tt>
|
109
104
|
def url
|
110
105
|
URI.escape("#{protocol}#{host}/#{path_prefix}#{key}")
|
111
106
|
end
|
112
107
|
|
108
|
+
# Returns Object's CNAME URL (without <tt>storage.grandcloud.cn</tt>
|
109
|
+
# suffix) using protocol specified in Service,
|
110
|
+
# e.g. <tt>http://domain.com/key/with/path.extension</tt>. (you
|
111
|
+
# have to set the CNAME in your DNS before using the CNAME URL
|
112
|
+
# schema).
|
113
|
+
def cname_url
|
114
|
+
URI.escape("#{protocol}#{name}/#{key}") if bucket.vhost?
|
115
|
+
end
|
116
|
+
|
113
117
|
# Returns a temporary url to the object that expires on the
|
114
|
-
# timestamp given. Defaults to
|
118
|
+
# timestamp given. Defaults to 5min expire time.
|
115
119
|
def temporary_url(expires_at = Time.now + 3600)
|
120
|
+
url = URI.escape("#{protocol}#{host(true)}/#{path_prefix}#{key}")
|
116
121
|
signature = Signature.generate_temporary_url_signature(:bucket => name,
|
117
122
|
:resource => key,
|
118
123
|
:expires_at => expires_at,
|
119
124
|
:secret_access_key => secret_access_key)
|
120
125
|
|
121
|
-
"#{url}?
|
126
|
+
"#{url}?SNDAAccessKeyId=#{access_key_id}&Expires=#{expires_at.to_i.to_s}&Signature=#{signature}"
|
122
127
|
end
|
123
128
|
|
124
|
-
#
|
125
|
-
#
|
126
|
-
#
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
129
|
+
# Retrieves the object from the server, returns true if the object
|
130
|
+
# exists or false otherwise. Uses #retrieve method, but catches
|
131
|
+
# Sndacs::Error::NoSuchKey exception and returns false when it happens
|
132
|
+
def exists?
|
133
|
+
retrieve
|
134
|
+
|
135
|
+
true
|
136
|
+
rescue Error::NoSuchKey
|
137
|
+
false
|
131
138
|
end
|
132
139
|
|
133
140
|
def inspect #:nodoc:
|
134
141
|
"#<#{self.class}:/#{name}/#{key}>"
|
135
142
|
end
|
136
143
|
|
137
|
-
|
144
|
+
private
|
138
145
|
|
139
146
|
attr_writer :last_modified, :etag, :size, :original_key, :bucket
|
140
147
|
|
@@ -171,11 +178,13 @@ module Sndacs
|
|
171
178
|
|
172
179
|
def get_object(options = {})
|
173
180
|
response = object_request(:get, options)
|
181
|
+
|
174
182
|
parse_headers(response)
|
175
183
|
end
|
176
184
|
|
177
185
|
def object_headers(options = {})
|
178
186
|
response = object_request(:head, options)
|
187
|
+
|
179
188
|
parse_headers(response)
|
180
189
|
rescue Error::ResponseError => e
|
181
190
|
if e.response.code.to_i == 404
|
@@ -187,6 +196,7 @@ module Sndacs
|
|
187
196
|
|
188
197
|
def put_object
|
189
198
|
response = object_request(:put, :body => content, :headers => dump_headers)
|
199
|
+
|
190
200
|
parse_headers(response)
|
191
201
|
end
|
192
202
|
|
@@ -250,4 +260,5 @@ module Sndacs
|
|
250
260
|
end
|
251
261
|
end
|
252
262
|
end
|
263
|
+
|
253
264
|
end
|
data/lib/sndacs/parser.rb
CHANGED
@@ -1,25 +1,36 @@
|
|
1
1
|
require 'rexml/document'
|
2
2
|
|
3
3
|
module Sndacs
|
4
|
+
|
4
5
|
module Parser
|
5
6
|
include REXML
|
6
7
|
|
7
8
|
def rexml_document(xml)
|
8
9
|
xml.force_encoding(::Encoding::UTF_8) if xml.respond_to? :force_encoding
|
10
|
+
|
9
11
|
Document.new(xml)
|
10
12
|
end
|
11
13
|
|
12
|
-
def
|
13
|
-
|
14
|
-
rexml_document(xml).elements.each("ListAllMyBucketsResult/Buckets/Bucket
|
15
|
-
|
16
|
-
|
14
|
+
def parse_all_buckets_result(xml)
|
15
|
+
all_buckets = []
|
16
|
+
rexml_document(xml).elements.each("ListAllMyBucketsResult/Buckets/Bucket") do |e|
|
17
|
+
bucket_attributes = {}
|
18
|
+
bucket_attributes[:name] = e.elements["Name"].text
|
17
19
|
|
18
|
-
|
19
|
-
|
20
|
+
element_location = e.elements["Location"]
|
21
|
+
if element_location
|
22
|
+
bucket_attributes[:location] = element_location.text
|
23
|
+
else
|
24
|
+
bucket_attributes[:location] = REGION_DEFAULT
|
25
|
+
end
|
26
|
+
|
27
|
+
all_buckets << bucket_attributes
|
28
|
+
end
|
29
|
+
|
30
|
+
all_buckets
|
20
31
|
end
|
21
32
|
|
22
|
-
def
|
33
|
+
def parse_all_objects_result(xml)
|
23
34
|
objects_attributes = []
|
24
35
|
rexml_document(xml).elements.each("ListBucketResult/Contents") do |e|
|
25
36
|
object_attributes = {}
|
@@ -27,11 +38,22 @@ module Sndacs
|
|
27
38
|
object_attributes[:etag] = e.elements["ETag"].text
|
28
39
|
object_attributes[:last_modified] = e.elements["LastModified"].text
|
29
40
|
object_attributes[:size] = e.elements["Size"].text
|
41
|
+
|
30
42
|
objects_attributes << object_attributes
|
31
43
|
end
|
44
|
+
|
32
45
|
objects_attributes
|
33
46
|
end
|
34
47
|
|
48
|
+
def parse_location_constraint(xml)
|
49
|
+
location = rexml_document(xml).elements["LocationConstraint"].text
|
50
|
+
if location.nil? || location == ''
|
51
|
+
location = REGION_DEFAULT
|
52
|
+
end
|
53
|
+
|
54
|
+
location
|
55
|
+
end
|
56
|
+
|
35
57
|
def parse_copy_object_result(xml)
|
36
58
|
object_attributes = {}
|
37
59
|
document = rexml_document(xml)
|
@@ -51,4 +73,5 @@ module Sndacs
|
|
51
73
|
rexml_document(xml).elements["ListBucketResult/IsTruncated"].text =='true'
|
52
74
|
end
|
53
75
|
end
|
76
|
+
|
54
77
|
end
|
data/lib/sndacs/request.rb
CHANGED
@@ -1,25 +1,31 @@
|
|
1
1
|
module Sndacs
|
2
|
+
|
2
3
|
# Class responsible for sending chunked requests
|
3
4
|
# properly. Net::HTTPGenericRequest has hardcoded chunk_size, so we
|
4
5
|
# inherit the class and override chunk_size.
|
5
6
|
class Request < Net::HTTPGenericRequest
|
6
7
|
def initialize(chunk_size, m, reqbody, resbody, path, initheader = nil)
|
7
8
|
@chunk_size = chunk_size
|
9
|
+
|
8
10
|
super(m, reqbody, resbody, path, initheader)
|
9
11
|
end
|
10
12
|
|
11
|
-
|
13
|
+
private
|
12
14
|
|
13
15
|
def send_request_with_body_stream(sock, ver, path, f)
|
14
16
|
unless content_length() or chunked?
|
15
17
|
raise ArgumentError, "Content-Length not given and Transfer-Encoding is not `chunked'"
|
16
18
|
end
|
19
|
+
|
17
20
|
supply_default_content_type
|
21
|
+
|
18
22
|
write_header sock, ver, path
|
23
|
+
|
19
24
|
if chunked?
|
20
25
|
while s = f.read(@chunk_size)
|
21
26
|
sock.write(sprintf("%x\r\n", s.length) << s << "\r\n")
|
22
27
|
end
|
28
|
+
|
23
29
|
sock.write "0\r\n\r\n"
|
24
30
|
else
|
25
31
|
while s = f.read(@chunk_size)
|
@@ -28,4 +34,5 @@ module Sndacs
|
|
28
34
|
end
|
29
35
|
end
|
30
36
|
end
|
37
|
+
|
31
38
|
end
|
data/lib/sndacs/service.rb
CHANGED
@@ -3,15 +3,16 @@ require 'net/http'
|
|
3
3
|
require 'proxies'
|
4
4
|
|
5
5
|
require 'sndacs/parser'
|
6
|
-
require 'sndacs/buckets_extension'
|
7
6
|
require 'sndacs/connection'
|
7
|
+
require 'sndacs/buckets_extension'
|
8
8
|
|
9
9
|
module Sndacs
|
10
|
+
|
10
11
|
class Service
|
11
12
|
include Parser
|
12
13
|
include Proxies
|
13
14
|
|
14
|
-
attr_reader :access_key_id, :secret_access_key, :
|
15
|
+
attr_reader :access_key_id, :secret_access_key, :proxy , :use_ssl
|
15
16
|
|
16
17
|
# Compares service to other, by <tt>access_key_id</tt> and
|
17
18
|
# <tt>secret_access_key</tt>
|
@@ -30,28 +31,28 @@ module Sndacs
|
|
30
31
|
# (false by default)
|
31
32
|
# * <tt>:timeout</tt> - Timeout to use by the Net::HTTP object
|
32
33
|
# (60 by default)
|
33
|
-
def initialize(options)
|
34
|
-
@access_key_id = options.fetch(:access_key_id)
|
35
|
-
@secret_access_key = options.fetch(:secret_access_key)
|
36
|
-
@
|
37
|
-
@timeout = options.fetch(:timeout,
|
38
|
-
@
|
39
|
-
|
40
|
-
|
41
|
-
|
34
|
+
def initialize(options = {})
|
35
|
+
@access_key_id = options.fetch(:access_key_id, Config.access_key_id)
|
36
|
+
@secret_access_key = options.fetch(:secret_access_key, Config.secret_access_key)
|
37
|
+
@proxy = options.fetch(:proxy, Config.proxy)
|
38
|
+
@timeout = options.fetch(:timeout, Config.timeout)
|
39
|
+
@use_ssl = options.fetch(:use_ssl, Config.use_ssl)
|
40
|
+
@debug = options.fetch(:debug, Config.debug)
|
41
|
+
|
42
|
+
raise ArgumentError, "Wrong proxy settings. Must specify at least :host option." if @proxy && !@proxy[:host]
|
42
43
|
end
|
43
44
|
|
44
45
|
# Returns all buckets in the service and caches the result (see
|
45
46
|
# +reload+)
|
46
47
|
def buckets
|
47
|
-
Proxy.new(lambda {
|
48
|
+
Proxy.new(lambda { buckets_all }, :owner => self, :extend => BucketsExtension)
|
48
49
|
end
|
49
50
|
|
50
|
-
# Returns the bucket with the given name. Does not check whether the
|
51
|
+
# Returns the bucket with the given name and region. Does not check whether the
|
51
52
|
# bucket exists. But also does not issue any HTTP requests, so it's
|
52
53
|
# much faster than buckets.find
|
53
|
-
def bucket(name)
|
54
|
-
Bucket.send(:new, self, name)
|
54
|
+
def bucket(name, region = nil)
|
55
|
+
Bucket.send(:new, self, name, region || REGION_DEFAULT)
|
55
56
|
end
|
56
57
|
|
57
58
|
# Returns "http://" or "https://", depends on <tt>:use_ssl</tt>
|
@@ -70,26 +71,36 @@ module Sndacs
|
|
70
71
|
"#<#{self.class}:#@access_key_id>"
|
71
72
|
end
|
72
73
|
|
73
|
-
|
74
|
+
private
|
74
75
|
|
75
|
-
def
|
76
|
+
def buckets_all
|
76
77
|
response = service_request(:get)
|
77
|
-
|
78
|
-
|
78
|
+
|
79
|
+
all_buckets = parse_all_buckets_result(response.body)
|
80
|
+
all_buckets.map { |bucket| Bucket.send(:new, self, bucket[:name], bucket[:region]) }
|
79
81
|
end
|
80
82
|
|
81
83
|
def service_request(method, options = {})
|
82
|
-
|
84
|
+
unless options[:path]
|
85
|
+
options[:path] = '/'
|
86
|
+
end
|
87
|
+
|
88
|
+
req_path = options[:path]
|
89
|
+
if req_path[0,1] != '/'
|
90
|
+
req_path = "/#{req_path}"
|
91
|
+
end
|
92
|
+
|
93
|
+
connection.request(method, options.merge(:path => req_path))
|
83
94
|
end
|
84
95
|
|
85
96
|
def connection
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
:proxy => @proxy)
|
97
|
+
@connection ||= Connection.new(:access_key_id => @access_key_id,
|
98
|
+
:secret_access_key => @secret_access_key,
|
99
|
+
:use_ssl => @use_ssl,
|
100
|
+
:timeout => @timeout,
|
101
|
+
:proxy => @proxy,
|
102
|
+
:debug => @debug)
|
93
103
|
end
|
94
104
|
end
|
105
|
+
|
95
106
|
end
|
data/lib/sndacs/signature.rb
CHANGED
@@ -2,11 +2,11 @@ module Sndacs
|
|
2
2
|
|
3
3
|
# Class responsible for generating signatures to requests.
|
4
4
|
#
|
5
|
-
# Implements algorithm defined by
|
5
|
+
# Implements algorithm defined by GrandCloud Web Services to sign
|
6
6
|
# request with secret private credentials
|
7
7
|
#
|
8
8
|
# === See
|
9
|
-
#
|
9
|
+
# https://cs-console.grandcloud.cn/public/docs/GrandCloud_Storage_Developer_Guide.pdf
|
10
10
|
|
11
11
|
class Signature
|
12
12
|
|
@@ -62,34 +62,7 @@ module Sndacs
|
|
62
62
|
CGI.escape(signature)
|
63
63
|
end
|
64
64
|
|
65
|
-
|
66
|
-
#
|
67
|
-
# ==== Options
|
68
|
-
# * <tt>:bucket</tt> - Bucket in which the resource resides
|
69
|
-
# * <tt>:resource</tt> - Path to the resouce you want to create
|
70
|
-
# a temporary link to
|
71
|
-
# * <tt>:access_key</tt> - Access key
|
72
|
-
# * <tt>:secret_access_key</tt> - Secret access key
|
73
|
-
# * <tt>:expires_at</tt> - Unix time stamp of when the resouce
|
74
|
-
# link will expire
|
75
|
-
# * <tt>:method</tt> - HTTP request method you want to use on
|
76
|
-
# the resource, defaults to GET
|
77
|
-
# * <tt>:headers</tt> - Any additional HTTP headers you intend
|
78
|
-
# to use when requesting the resource
|
79
|
-
def self.generate_temporary_url(options)
|
80
|
-
bucket = options[:bucket]
|
81
|
-
resource = options[:resource]
|
82
|
-
access_key = options[:access_key]
|
83
|
-
expires = options[:expires_at].to_i
|
84
|
-
signature = generate_temporary_url_signature(options)
|
85
|
-
|
86
|
-
url = "http://#{S3::HOST}/#{bucket}/#{resource}"
|
87
|
-
url << "?AWSAccessKeyId=#{access_key}"
|
88
|
-
url << "&Expires=#{expires}"
|
89
|
-
url << "&Signature=#{signature}"
|
90
|
-
end
|
91
|
-
|
92
|
-
private
|
65
|
+
private
|
93
66
|
|
94
67
|
def self.canonicalized_signature(options)
|
95
68
|
headers = options[:headers] || {}
|
@@ -120,6 +93,7 @@ module Sndacs
|
|
120
93
|
digest = OpenSSL::Digest::Digest.new("sha1")
|
121
94
|
hmac = OpenSSL::HMAC.digest(digest, secret_access_key, string_to_sign)
|
122
95
|
base64 = Base64.encode64(hmac)
|
96
|
+
|
123
97
|
base64.chomp
|
124
98
|
end
|
125
99
|
|
@@ -209,7 +183,7 @@ module Sndacs
|
|
209
183
|
# requests that don't address a bucket, do nothing. For more
|
210
184
|
# information on virtual hosted-style requests, see Virtual
|
211
185
|
# Hosting of Buckets.
|
212
|
-
bucket_name = host.sub(/\.?storage
|
186
|
+
bucket_name = host.sub(/\.?storage[a-zA-Z0-9\-]*?\.grandcloud\.cn\Z/, "")
|
213
187
|
string << "/#{bucket_name}" unless bucket_name.empty?
|
214
188
|
|
215
189
|
# 3. Append the path part of the un-decoded HTTP Request-URI,
|
@@ -240,4 +214,5 @@ module Sndacs
|
|
240
214
|
string
|
241
215
|
end
|
242
216
|
end
|
217
|
+
|
243
218
|
end
|
data/lib/sndacs/version.rb
CHANGED
data/lib/sndacs.rb
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- encoding: utf-8 -*-
|
3
|
+
|
1
4
|
require "base64"
|
2
5
|
require "cgi"
|
3
6
|
require "digest/md5"
|
@@ -13,6 +16,7 @@ require "sndacs/objects_extension"
|
|
13
16
|
require "sndacs/buckets_extension"
|
14
17
|
require "sndacs/parser"
|
15
18
|
require "sndacs/bucket"
|
19
|
+
require "sndacs/config"
|
16
20
|
require "sndacs/connection"
|
17
21
|
require "sndacs/exceptions"
|
18
22
|
require "sndacs/object"
|
@@ -22,6 +26,28 @@ require "sndacs/signature"
|
|
22
26
|
require "sndacs/version"
|
23
27
|
|
24
28
|
module Sndacs
|
25
|
-
|
26
|
-
|
29
|
+
|
30
|
+
# Bucket default region
|
31
|
+
# NOTICE: DO NOT TOUCH THIS!!!
|
32
|
+
REGION_DEFAULT = 'huadong-1'
|
33
|
+
|
34
|
+
# Bucket region host template
|
35
|
+
# NOTICE: DO NOT TOUCH THIS!!!
|
36
|
+
REGION_HOST = 'storage-%s.grandcloud.cn'
|
37
|
+
|
38
|
+
# Object public access host template
|
39
|
+
# NOTICE: DO NOT TOUCH THIS!!!
|
40
|
+
REGION_CONTENT_HOST = 'storage-%s.sdcloud.cn'
|
41
|
+
|
42
|
+
# Default configurations, see Sndacs::Config for more info
|
43
|
+
#Config.access_key_id = ''
|
44
|
+
#Config.secret_access_key = ''
|
45
|
+
#Config.host = 'storage.grandcloud.cn'
|
46
|
+
#Config.content_host = 'storage.sdcloud.cn'
|
47
|
+
#Config.proxy = nil
|
48
|
+
#Config.timeout = 60
|
49
|
+
#Config.use_ssl = false
|
50
|
+
#Config.chunk_size = 1048576
|
51
|
+
#Config.debug = false
|
52
|
+
|
27
53
|
end
|
data/sndacs.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
|
3
|
-
# Load version requiring the canonical "
|
4
|
-
# is a different file and complaint about a double declaration of
|
3
|
+
# Load version requiring the canonical "sndacs/version", otherwise Ruby will think
|
4
|
+
# is a different file and complaint about a double declaration of Sndacs::VERSION.
|
5
5
|
$LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
|
6
6
|
require "sndacs/version"
|
7
7
|
|
@@ -12,16 +12,16 @@ Gem::Specification.new do |s|
|
|
12
12
|
s.authors = ["LI Daobing"]
|
13
13
|
s.email = ["lidaobing@snda.com"]
|
14
14
|
s.homepage = "https://github.com/grandcloud/sndacs-ruby"
|
15
|
-
s.summary = "Library for accessing SNDA Cloud Storage
|
15
|
+
s.summary = "Library for accessing SNDA Cloud Storage buckets and objects"
|
16
16
|
s.description = "sndacs library provides access to SNDA Cloud Storage."
|
17
17
|
|
18
18
|
s.required_rubygems_version = ">= 1.3.6"
|
19
19
|
|
20
20
|
s.add_dependency "proxies", "~> 0.2.0"
|
21
|
-
s.add_development_dependency "test-unit", ">= 2.0"
|
22
|
-
s.add_development_dependency "mocha"
|
23
21
|
s.add_development_dependency "bundler", ">= 1.0.0"
|
24
22
|
s.add_development_dependency "rspec", "~> 2.0"
|
23
|
+
s.add_development_dependency "mocha"
|
24
|
+
#s.add_development_dependency "test-unit", ">= 2.0"
|
25
25
|
|
26
26
|
s.files = `git ls-files`.split("\n")
|
27
27
|
s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
|