s3 0.3.0 → 0.3.1

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.
@@ -0,0 +1,7 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ rdoc
5
+ pkg
6
+ *.gem
7
+ .bundle
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source :gemcutter
2
+
3
+ # Specify your gem's dependencies in s3.gemspec
4
+ gemspec
@@ -0,0 +1,27 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ s3 (0.3.1)
5
+ proxies
6
+ trollop
7
+
8
+ GEM
9
+ remote: http://rubygems.org/
10
+ specs:
11
+ mocha (0.9.8)
12
+ rake
13
+ proxies (0.1.1)
14
+ rake (0.8.7)
15
+ test-unit (2.1.1)
16
+ trollop (1.16.2)
17
+
18
+ PLATFORMS
19
+ ruby
20
+
21
+ DEPENDENCIES
22
+ bundler (>= 1.0.0)
23
+ mocha
24
+ proxies
25
+ s3!
26
+ test-unit (>= 2.0)
27
+ trollop
@@ -0,0 +1,20 @@
1
+ require "bundler"
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require "rake/testtask"
5
+ require "rake/rdoctask"
6
+
7
+ Rake::TestTask.new(:test) do |test|
8
+ test.libs << "lib" << "test"
9
+ test.pattern = "test/**/*_test.rb"
10
+ test.verbose = true
11
+ end
12
+
13
+ Rake::RDocTask.new do |rdoc|
14
+ rdoc.rdoc_dir = "rdoc"
15
+ rdoc.title = "s3 #{S3::VERSION}"
16
+ rdoc.rdoc_files.include("README.rdoc")
17
+ rdoc.rdoc_files.include("lib/**/*.rb")
18
+ end
19
+
20
+ task :default => :test
@@ -4,7 +4,7 @@ module S3
4
4
  class Connection
5
5
  include Parser
6
6
 
7
- attr_accessor :access_key_id, :secret_access_key, :use_ssl, :timeout, :debug
7
+ attr_accessor :access_key_id, :secret_access_key, :use_ssl, :timeout, :debug, :proxy
8
8
  alias :use_ssl? :use_ssl
9
9
 
10
10
  # Creates new connection object.
@@ -18,12 +18,15 @@ module S3
18
18
  # (false by default)
19
19
  # * <tt>:timeout</tt> - Timeout to use by the Net::HTTP object
20
20
  # (60 by default)
21
+ # * <tt>:proxy</tt> - Hash for Net::HTTP Proxy settings
22
+ # { :host => "proxy.mydomain.com", :port => "80, :user => "user_a", :password => "secret" }
21
23
  def initialize(options = {})
22
24
  @access_key_id = options.fetch(:access_key_id)
23
25
  @secret_access_key = options.fetch(:secret_access_key)
24
26
  @use_ssl = options.fetch(:use_ssl, false)
25
27
  @debug = options.fetch(:debug, false)
26
28
  @timeout = options.fetch(:timeout, 60)
29
+ @proxy = options.fetch(:proxy, nil)
27
30
  end
28
31
 
29
32
  # Makes request with given HTTP method, sets missing parameters,
@@ -157,8 +160,12 @@ module S3
157
160
  use_ssl ? 443 : 80
158
161
  end
159
162
 
163
+ def proxy_settings
164
+ @proxy.values_at(:host, :port, :user, :password) unless @proxy.blank?
165
+ end
166
+
160
167
  def http(host)
161
- http = Net::HTTP.new(host, port)
168
+ http = Net::HTTP.new(host, port, *proxy_settings)
162
169
  http.set_debug_output(STDOUT) if @debug
163
170
  http.use_ssl = @use_ssl
164
171
  http.verify_mode = OpenSSL::SSL::VERIFY_NONE if @use_ssl
@@ -17,7 +17,7 @@ module S3
17
17
  # of the objects are the same, and both have the same buckets (see
18
18
  # Bucket equality)
19
19
  def ==(other)
20
- self.key == other.key and self.bucket == other.bucket
20
+ other.equal?(self) || (other.instance_of?(self.class) && self.key == other.key && self.bucket == other.bucket)
21
21
  end
22
22
 
23
23
  # Returns full key of the object: e.g. <tt>bucket-name/object/key.ext</tt>
@@ -3,7 +3,7 @@ module S3
3
3
  include Parser
4
4
  include Proxies
5
5
 
6
- attr_reader :access_key_id, :secret_access_key, :use_ssl
6
+ attr_reader :access_key_id, :secret_access_key, :use_ssl, :proxy
7
7
 
8
8
  # Compares service to other, by <tt>access_key_id</tt> and
9
9
  # <tt>secret_access_key</tt>
@@ -28,6 +28,9 @@ module S3
28
28
  @use_ssl = options.fetch(:use_ssl, false)
29
29
  @timeout = options.fetch(:timeout, 60)
30
30
  @debug = options.fetch(:debug, false)
31
+
32
+ raise ArgumentError, "Missing proxy settings. Must specify at least :host." if options[:proxy] && !options[:proxy][:host]
33
+ @proxy = options.fetch(:proxy, nil)
31
34
  end
32
35
 
33
36
  # Returns all buckets in the service and caches the result (see
@@ -70,7 +73,8 @@ module S3
70
73
  :secret_access_key => @secret_access_key,
71
74
  :use_ssl => @use_ssl,
72
75
  :timeout => @timeout,
73
- :debug => @debug)
76
+ :debug => @debug,
77
+ :proxy => @proxy)
74
78
  end
75
79
  @connection
76
80
  end
@@ -1,3 +1,3 @@
1
1
  module S3
2
- VERSION = "0.3.0"
2
+ VERSION = "0.3.1"
3
3
  end
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require File.expand_path("../lib/s3/version", __FILE__)
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "s3"
7
+ s.version = S3::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Jakub Kuźma"]
10
+ s.email = ["qoobaa@gmail.com"]
11
+ s.homepage = "http://jah.pl/projects/s3.html"
12
+ s.summary = "Library for accessing S3 objects and buckets, with command line tool"
13
+ s.description = "S3 library provides access to Amazon's Simple Storage Service. It supports both: European and US buckets through REST API."
14
+
15
+ s.required_rubygems_version = ">= 1.3.6"
16
+ s.rubyforge_project = "s3"
17
+
18
+ s.add_dependency "trollop"
19
+ s.add_dependency "proxies"
20
+ s.add_development_dependency "test-unit", ">= 2.0"
21
+ s.add_development_dependency "mocha"
22
+ s.add_development_dependency "bundler", ">= 1.0.0"
23
+
24
+ s.files = `git ls-files`.split("\n")
25
+ s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
26
+ s.require_path = "lib"
27
+ end
@@ -0,0 +1,215 @@
1
+ require "test_helper"
2
+
3
+ class BucketTest < Test::Unit::TestCase
4
+ def setup
5
+ @bucket_vhost = S3::Bucket.send(:new, nil, "Data-Bucket")
6
+ @bucket_path = S3::Bucket.send(:new, nil, "Data_Bucket")
7
+ @bucket = @bucket_vhost
8
+
9
+ @bucket_location = "EU"
10
+ @bucket_location_body = <<-EOLocation
11
+ <?xml version="1.0" encoding="UTF-8"?>\n<LocationConstraint xmlns="http://s3.amazonaws.com/doc/2006-03-01/">EU</LocationConstraint>
12
+ EOLocation
13
+
14
+ @response_location = Net::HTTPOK.new("1.1", "200", "OK")
15
+ @response_location.stubs(:body).returns(@bucket_location_body)
16
+
17
+ @bucket_owned_by_you_body = <<-EOOwnedByYou
18
+ <?xml version="1.0" encoding="UTF-8"?>\n<Error> <Code>BucketAlreadyOwnedByYou</Code> <Message>Your previous request to create the named bucket succeeded and you already own it.</Message> <BucketName>bucket</BucketName> <RequestId>117D08EA0EC6E860</RequestId> <HostId>4VpMSvmJ+G5+DLtVox6O5cZNgdPlYcjCu3l0n4HjDe01vPxxuk5eTAtcAkUynRyV</HostId> </Error>
19
+ EOOwnedByYou
20
+
21
+ @reponse_owned_by_you = Net::HTTPConflict.new("1.1", "409", "Conflict")
22
+ @reponse_owned_by_you.stubs(:body).returns(@bucket_owned_by_you_body)
23
+
24
+ @bucket_already_exists_body = <<-EOAlreadyExists
25
+ <?xml version="1.0" encoding="UTF-8"?>\n<Error> <Code>BucketAlreadyExists</Code> <Message>The requested bucket name is not available. The bucket namespace is shared by all users of the system. Please select a different name and try again.</Message> <BucketName>bucket</BucketName> <RequestId>4C154D32807C92BD</RequestId> <HostId>/xyHQgXcUXTZQhoO+NUBzbaxbFrIhKlyuaRHFnmcId0bMePvY9Zwg+dyk2LYE4g5</HostId> </Error>
26
+ EOAlreadyExists
27
+
28
+ @reponse_already_exists = Net::HTTPConflict.new("1.1", "409", "Conflict")
29
+ @response_already_exists.stubs(:body).returns(@bucket_already_exists_body)
30
+
31
+ @objects_list_empty = []
32
+ @objects_list = [
33
+ S3::Object.send(:new, @bucket, :key => "obj1"),
34
+ S3::Object.send(:new, @bucket, :key => "obj2")
35
+ ]
36
+
37
+ @response_objects_list_empty_body = <<-EOEmpty
38
+ <?xml version="1.0" encoding="UTF-8"?>\n<ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/"> <Name>bucket</Name> <Prefix></Prefix> <Marker></Marker> <MaxKeys>1000</MaxKeys> <IsTruncated>false</IsTruncated> </ListBucketResult>
39
+ EOEmpty
40
+
41
+ @response_objects_list_empty = Net::HTTPOK.new("1.1", "200", "OK")
42
+ @response_objects_list_empty.stubs(:body).returns(@response_objects_list_empty_body)
43
+
44
+ @response_objects_list_body = <<-EOObjects
45
+ <?xml version="1.0" encoding="UTF-8"?>\n<ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/"> <Name>bucket</Name> <Prefix></Prefix> <Marker></Marker> <MaxKeys>1000</MaxKeys> <IsTruncated>false</IsTruncated> <Contents> <Key>obj1</Key> <LastModified>2009-07-03T10:17:33.000Z</LastModified> <ETag>&quot;99519cdf14c255e580e1b7bca85a458c&quot;</ETag> <Size>1729</Size> <Owner> <ID>df864aeb6f42be43f1d9e60aaabe3f15e245b035a4b79d1cfe36c4deaec67205</ID> <DisplayName>owner</DisplayName> </Owner> <StorageClass>STANDARD</StorageClass> </Contents> <Contents> <Key>obj2</Key> <LastModified>2009-07-03T11:17:33.000Z</LastModified> <ETag>&quot;99519cdf14c255e586e1b12bca85a458c&quot;</ETag> <Size>179</Size> <Owner> <ID>df864aeb6f42be43f1d9e60aaabe3f17e247b037a4b79d1cfe36c4deaec67205</ID> <DisplayName>owner</DisplayName> </Owner> <StorageClass>STANDARD</StorageClass> </Contents> </ListBucketResult>
46
+ EOObjects
47
+
48
+ @response_objects_list = Net::HTTPOK.new("1.1", "200", "OK")
49
+ @response_objects_list.stubs(:body).returns(@response_objects_list_body)
50
+ end
51
+
52
+ test "name valid" do
53
+ assert_raise ArgumentError do S3::Bucket.send(:new, nil, "") end # should not be valid with empty name
54
+ assert_raise ArgumentError do S3::Bucket.send(:new, nil, "10.0.0.1") end # should not be valid with IP as name
55
+ assert_raise ArgumentError do S3::Bucket.send(:new, nil, "as") end # should not be valid with name shorter than 3 characters
56
+ assert_raise ArgumentError do S3::Bucket.send(:new, nil, "a" * 256) end # should not be valid with name longer than 255 characters
57
+ assert_raise ArgumentError do S3::Bucket.send(:new, nil, ".asdf") end # should not allow special characters as first character
58
+ assert_raise ArgumentError do S3::Bucket.send(:new, nil, "-asdf") end # should not allow special characters as first character
59
+ assert_raise ArgumentError do S3::Bucket.send(:new, nil, "_asdf") end # should not allow special characters as first character
60
+
61
+ assert_nothing_raised do
62
+ S3::Bucket.send(:new, nil, "a-a-")
63
+ S3::Bucket.send(:new, nil, "a.a.")
64
+ S3::Bucket.send(:new, nil, "a_a_")
65
+ end
66
+ end
67
+
68
+ test "path prefix" do
69
+ expected = ""
70
+ actual = @bucket_vhost.path_prefix
71
+ assert_equal expected, actual
72
+
73
+ expected = "Data_Bucket/"
74
+ actual = @bucket_path.path_prefix
75
+ assert_equal expected, actual
76
+ end
77
+
78
+ test "host" do
79
+ expected = "Data-Bucket.s3.amazonaws.com"
80
+ actual = @bucket_vhost.host
81
+ assert_equal expected, actual
82
+
83
+ expected = "s3.amazonaws.com"
84
+ actual = @bucket_path.host
85
+ assert_equal expected, actual
86
+ end
87
+
88
+ test "vhost" do
89
+ assert @bucket_vhost.vhost?
90
+ assert ! @bucket_path.vhost?
91
+ end
92
+
93
+ test "exists" do
94
+ @bucket.expects(:retrieve).returns(@bucket_vhost)
95
+ assert @bucket.exists?
96
+
97
+ @bucket.expects(:retrieve).raises(S3::Error::NoSuchBucket.new(nil, nil))
98
+ assert ! @bucket.exists?
99
+ end
100
+
101
+ test "location and parse location" do
102
+ @bucket.expects(:bucket_request).with(:get, { :params => { :location => nil } }).returns(@response_location)
103
+
104
+ expected = @bucket_location
105
+ actual = @bucket.location
106
+ assert_equal expected, actual
107
+
108
+ @bucket.stubs(:bucket_request).with(:get, { :params => { :location => nil } })
109
+ actual = @bucket.location
110
+ assert_equal expected, actual
111
+ end
112
+
113
+ test "save" do
114
+ @bucket.expects(:bucket_request).with(:put, { :headers => {} })
115
+ assert @bucket.save
116
+ # mock ensures that bucket_request was called
117
+ end
118
+
119
+ test "save failure owned by you" do
120
+ @bucket.expects(:bucket_request).with(:put, { :headers => {} }).raises(S3::Error::BucketAlreadyOwnedByYou.new(409, @response_owned_by_you))
121
+ assert_raise S3::Error::BucketAlreadyOwnedByYou do
122
+ @bucket.save
123
+ end
124
+
125
+ @bucket.expects(:bucket_request).with(:put, { :headers => {} }).raises(S3::Error::BucketAlreadyExists.new(409, @response_already_exists))
126
+ assert_raise S3::Error::BucketAlreadyExists do
127
+ @bucket.save
128
+ end
129
+ end
130
+
131
+ test "objects" do
132
+ @bucket.expects(:list_bucket).returns(@objects_list_empty)
133
+ expected = @objects_list_empty
134
+ actual = @bucket.objects
135
+ assert_equal expected, actual
136
+
137
+ @bucket.stubs(:list_bucket).returns(@objects_list_empty)
138
+ actual = @bucket.objects
139
+ assert_equal expected, actual
140
+
141
+ @bucket.stubs(:list_bucket).returns(@objects_list)
142
+
143
+ expected = @objects_list
144
+ actual = @bucket.objects
145
+ assert_equal expected, actual
146
+ end
147
+
148
+ test "list bucket and parse objects" do
149
+ @bucket.expects(:bucket_request).with(:get, :params => { :test=>true }).returns(@response_objects_list_empty)
150
+ expected = @objects_list_empty
151
+ actual = @bucket.objects.find_all(:test => true)
152
+ assert_equal expected, actual
153
+
154
+ @bucket.expects(:bucket_request).with(:get, :params => { :test => true }).returns(@response_objects_list)
155
+ expected = @objects_list
156
+ actual = @bucket.objects.find_all(:test => true)
157
+ assert_equal expected, actual
158
+ end
159
+
160
+ test "destroy" do
161
+ @bucket.expects(:bucket_request).with(:delete)
162
+ assert @bucket.destroy
163
+ end
164
+
165
+ test "objects build" do
166
+ @bucket.stubs(:bucket_request)
167
+
168
+ expected = "object_name"
169
+ actual = @bucket.objects.build("object_name")
170
+ assert_kind_of S3::Object, actual
171
+ assert_equal expected, actual.key
172
+ end
173
+
174
+ test "objects find first" do
175
+ assert_nothing_raised do
176
+ S3::Object.any_instance.stubs(:retrieve).returns(S3::Object.send(:new, nil, :key => "obj2"))
177
+ expected = "obj2"
178
+ actual = @bucket.objects.find_first("obj2")
179
+ assert_equal "obj2", actual.key
180
+ end
181
+ end
182
+
183
+ test "objects find first fail" do
184
+ assert_raise S3::Error::NoSuchKey do
185
+ S3::Object.any_instance.stubs(:retrieve).raises(S3::Error::NoSuchKey.new(404, nil))
186
+ @bucket.objects.find_first("obj3")
187
+ end
188
+ end
189
+
190
+ test "objects find all on empty list" do
191
+ @bucket.stubs(:list_bucket).returns(@objects_list_empty)
192
+ assert_nothing_raised do
193
+ expected = @objects_list_empty
194
+ actual = @bucket.objects.find_all
195
+ assert_equal expected, actual
196
+ end
197
+ end
198
+
199
+ test "objects find all" do
200
+ @bucket.stubs(:list_bucket).returns(@objects_list)
201
+ assert_nothing_raised do
202
+ expected = @objects_list
203
+ actual = @bucket.objects.find_all
204
+ assert_equal expected, actual
205
+ end
206
+ end
207
+
208
+ test "objects destroy all" do
209
+ @bucket.stubs(:list_bucket).returns(@objects_list)
210
+ @bucket.objects.each do |obj|
211
+ obj.expects(:destroy)
212
+ end
213
+ @bucket.objects.destroy_all
214
+ end
215
+ end
@@ -0,0 +1,210 @@
1
+ require "test_helper"
2
+
3
+ class ConnectionTest < Test::Unit::TestCase
4
+ def setup
5
+ @connection = S3::Connection.new(
6
+ :access_key_id => "12345678901234567890",
7
+ :secret_access_key => "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDF"
8
+ )
9
+ @http_request = Net::HTTP.new("")
10
+ @response_ok = Net::HTTPOK.new("1.1", "200", "OK")
11
+ @response_not_found = Net::HTTPNotFound.new("1.1", "404", "Not Found")
12
+ @response_error = Net::HTTPInternalServerError.new("1.1", "500", "Internal Server Error")
13
+ @response_temporary_redirect = Net::HTTPInternalServerError.new("1.1", "307", "Temporary Redirect")
14
+ @connection.stubs(:http).returns(@http_request)
15
+
16
+ @http_request.stubs(:start).returns(@response_ok)
17
+ end
18
+
19
+ test "handle response not modify response when ok" do
20
+ assert_nothing_raised do
21
+ response = @connection.request(
22
+ :get,
23
+ :host => "s3.amazonaws.com",
24
+ :path => "/"
25
+ )
26
+ assert_equal @response_ok, response
27
+ end
28
+ end
29
+
30
+ test "handle response throws exception when error" do
31
+ response_body = <<-EOFakeBody
32
+ <?xml version=\"1.0\" encoding=\"UTF-8\"?>
33
+ <Error>
34
+ <Code>NoSuchBucket</Code>
35
+ <Message>The specified bucket does not exist</Message>
36
+ </Error>
37
+ EOFakeBody
38
+
39
+ @http_request.stubs(:start).returns(@response_not_found)
40
+ @response_not_found.stubs(:body).returns(response_body)
41
+
42
+ assert_raise S3::Error::NoSuchBucket do
43
+ response = @connection.request(
44
+ :get,
45
+ :host => "data.example.com.s3.amazonaws.com",
46
+ :path => "/"
47
+ )
48
+ end
49
+ end
50
+
51
+ test "handle response throws standard exception when error" do
52
+ @http_request.stubs(:start).returns(@response_error)
53
+ @response_error.stubs(:body)
54
+ assert_raise S3::Error::ResponseError do
55
+ response = @connection.request(
56
+ :get,
57
+ :host => "data.example.com.s3.amazonaws.com",
58
+ :path => "/"
59
+ )
60
+ end
61
+
62
+ @response_error.stubs(:body).returns("")
63
+ assert_raise S3::Error::ResponseError do
64
+ response = @connection.request(
65
+ :get,
66
+ :host => "data.example.com.s3.amazonaws.com",
67
+ :path => "/"
68
+ )
69
+ end
70
+ end
71
+
72
+ test "parse params empty" do
73
+ expected = ""
74
+ actual = S3::Connection.parse_params({})
75
+ assert_equal expected, actual
76
+ end
77
+
78
+ test "parse params only interesting params" do
79
+ expected = ""
80
+ actual = S3::Connection.parse_params(:param1 => "1", :maxkeys => "2")
81
+ assert_equal expected, actual
82
+ end
83
+
84
+ test "parse params remove underscore" do
85
+ expected = "max-keys=100"
86
+ actual = S3::Connection.parse_params(:max_keys => 100)
87
+ assert_equal expected, actual
88
+ end
89
+
90
+ test "parse params with and without values" do
91
+ params = S3::Connection.parse_params(:max_keys => 100, :prefix => nil)
92
+
93
+ splitted_params = params.split("&")
94
+ assert_equal 2, splitted_params.length
95
+ assert splitted_params.include?("max-keys=100")
96
+ assert splitted_params.include?("prefix")
97
+ end
98
+
99
+ test "headers empty" do
100
+ expected = {}
101
+ actual = S3::Connection.parse_headers({})
102
+ assert_equal expected, actual
103
+ end
104
+
105
+ test "parse only interesting headers" do
106
+ expected = {}
107
+ actual = S3::Connection.parse_headers(
108
+ :accept => "text/*, text/html, text/html;level=1, */*",
109
+ :accept_charset => "iso-8859-2, unicode-1-1;q=0.8"
110
+ )
111
+ assert_equal expected, actual
112
+ end
113
+
114
+ test "parse headers remove underscore" do
115
+ expected = {
116
+ "content-type" => nil,
117
+ "x-amz-acl" => nil,
118
+ "if-modified-since" => nil,
119
+ "if-unmodified-since" => nil,
120
+ "if-match" => nil,
121
+ "if-none-match" => nil,
122
+ "content-disposition" => nil,
123
+ "content-encoding" => nil
124
+ }
125
+ actual = S3::Connection.parse_headers(
126
+ :content_type => nil,
127
+ :x_amz_acl => nil,
128
+ :if_modified_since => nil,
129
+ :if_unmodified_since => nil,
130
+ :if_match => nil,
131
+ :if_none_match => nil,
132
+ :content_disposition => nil,
133
+ :content_encoding => nil
134
+ )
135
+ assert_equal expected, actual
136
+ end
137
+
138
+ test "parse headers with values" do
139
+ expected = {
140
+ "content-type" => "text/html",
141
+ "x-amz-acl" => "public-read",
142
+ "if-modified-since" => "today",
143
+ "if-unmodified-since" => "tomorrow",
144
+ "if-match" => "1234",
145
+ "if-none-match" => "1243",
146
+ "content-disposition" => "inline",
147
+ "content-encoding" => "gzip"
148
+ }
149
+ actual = S3::Connection.parse_headers(
150
+ :content_type => "text/html",
151
+ :x_amz_acl => "public-read",
152
+ :if_modified_since => "today",
153
+ :if_unmodified_since => "tomorrow",
154
+ :if_match => "1234",
155
+ :if_none_match => "1243",
156
+ :content_disposition => "inline",
157
+ :content_encoding => "gzip"
158
+ )
159
+ assert_equal expected, actual
160
+ end
161
+
162
+ test "parse headers with range" do
163
+ expected = {
164
+ "range" => "bytes=0-100"
165
+ }
166
+ actual = S3::Connection.parse_headers(
167
+ :range => 0..100
168
+ )
169
+ assert_equal expected, actual
170
+ end
171
+
172
+ test "response.body is nil on TemporaryRedirect" do
173
+ @http_request.stubs(:start).returns(@response_temporary_redirect)
174
+ @response_temporary_redirect.stubs(:body).returns(nil)
175
+
176
+ assert_nothing_raised do
177
+ response = @connection.request(
178
+ :get,
179
+ :host => "data.example.com.s3.amazonaws.com",
180
+ :path => "/"
181
+ )
182
+ assert_equal nil, response
183
+ end
184
+ end
185
+
186
+ test "response body with new host on TemporaryRedirect" do
187
+ response_body = <<-EOFakeBody
188
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
189
+ <Error>
190
+ <Code>TemporaryRedirect</Code>
191
+ <Message>Please re-send this request to the specified temporary endpoint. Continue to use the original request endpoint for future requests.</Message>
192
+ <RequestId>24A0BB91158D470B</RequestId>
193
+ <Bucket>data.example.com</Bucket>
194
+ <HostId>DFcq9ktw5HvWZLduutz8fnVzqtXLwIZcAezc7mgyS7lJ2ux+RChY4qAJGa2fQDjV</HostId>
195
+ <Endpoint>data.example.com.s3-external-3.amazonaws.com</Endpoint>
196
+ </Error>"
197
+ EOFakeBody
198
+
199
+ @response_temporary_redirect.stubs(:body).returns(response_body)
200
+
201
+ assert_nothing_raised do
202
+ response = @connection.request(
203
+ :get,
204
+ :host => "data.example.com.s3.amazonaws.com",
205
+ :path => "/"
206
+ )
207
+ assert_equal @response_ok, response
208
+ end
209
+ end
210
+ end
@@ -0,0 +1,161 @@
1
+ # encoding: utf-8
2
+ require "test_helper"
3
+
4
+ class ObjectTest < Test::Unit::TestCase
5
+ def setup
6
+ @service = S3::Service.new(
7
+ :access_key_id => "1234",
8
+ :secret_access_key => "1337"
9
+ )
10
+ @bucket_images = S3::Bucket.send(:new, @service, "images")
11
+ @object_lena = S3::Object.send(:new, @bucket_images, :key => "Lena.png")
12
+ @object_lena.content = "test"
13
+ @object_carmen = S3::Object.send(:new, @bucket_images, :key => "Carmen.png")
14
+
15
+ @response_binary = Net::HTTPOK.new("1.1", "200", "OK")
16
+ @response_binary.stubs(:body).returns("test".respond_to?(:force_encoding) ? "test".force_encoding(Encoding::BINARY) : "test")
17
+ @response_binary["etag"] = ""
18
+ @response_binary["content-type"] = "image/png"
19
+ @response_binary["content-disposition"] = "inline"
20
+ @response_binary["content-encoding"] = nil
21
+ @response_binary["last-modified"] = Time.now.httpdate
22
+ @response_binary["content-length"] = 20
23
+
24
+ @xml_body = <<-EOXML
25
+ <?xml version="1.0" encoding="UTF-8"?>
26
+ <CopyObjectResult> <LastModified>#{Time.now.httpdate}</LastModified> <ETag>"etag"</ETag> </CopyObjectResult>
27
+ EOXML
28
+ @response_xml = Net::HTTPOK.new("1.1", "200", "OK")
29
+ @response_xml.stubs(:body).returns(@xml_body)
30
+ end
31
+
32
+ test "initializing" do
33
+ assert_raise ArgumentError do S3::Object.send(:new, nil, :key => "") end # should not allow empty key
34
+ assert_raise ArgumentError do S3::Object.send(:new, nil, :key => "//") end # should not allow key with double slash
35
+
36
+ assert_nothing_raised do
37
+ S3::Object.send(:new, nil, :key => "Lena.png")
38
+ S3::Object.send(:new, nil, :key => "Lena playboy.png")
39
+ S3::Object.send(:new, nil, :key => "Lena Söderberg.png")
40
+ S3::Object.send(:new, nil, :key => "/images/pictures/test images/Lena not full.png")
41
+ end
42
+ end
43
+
44
+ test "==" do
45
+ expected = false
46
+ actual = @object_lena == nil
47
+ assert_equal(expected, actual)
48
+ end
49
+
50
+ test "full key" do
51
+ expected = "images/Lena.png"
52
+ actual = @object_lena.full_key
53
+ assert_equal expected, actual
54
+ end
55
+
56
+ test "url" do
57
+ bucket1 = S3::Bucket.send(:new, @service, "images")
58
+
59
+ object11 = S3::Object.send(:new, bucket1, :key => "Lena.png")
60
+ expected = "http://images.s3.amazonaws.com/Lena.png"
61
+ actual = object11.url
62
+ assert_equal expected, actual
63
+
64
+ object12 = S3::Object.send(:new, bucket1, :key => "Lena Söderberg.png")
65
+ expected = "http://images.s3.amazonaws.com/Lena%20S%C3%B6derberg.png"
66
+ actual = object12.url
67
+ assert_equal expected, actual
68
+
69
+ bucket2 = S3::Bucket.send(:new, @service, "images_new")
70
+
71
+ object21 = S3::Object.send(:new, bucket2, :key => "Lena.png")
72
+ expected = "http://s3.amazonaws.com/images_new/Lena.png"
73
+ actual = object21.url
74
+ assert_equal expected, actual
75
+ end
76
+
77
+ test "cname url" do
78
+ bucket1 = S3::Bucket.send(:new, @service, "images.example.com")
79
+
80
+ object11 = S3::Object.send(:new, bucket1, :key => "Lena.png")
81
+ expected = "http://images.example.com/Lena.png"
82
+ actual = object11.cname_url
83
+ assert_equal expected, actual
84
+
85
+ object12 = S3::Object.send(:new, bucket1, :key => "Lena Söderberg.png")
86
+ expected = "http://images.example.com/Lena%20S%C3%B6derberg.png"
87
+ actual = object12.cname_url
88
+ assert_equal expected, actual
89
+
90
+ bucket2 = S3::Bucket.send(:new, @service, "images_new")
91
+
92
+ object21 = S3::Object.send(:new, bucket2, :key => "Lena.png")
93
+ expected = nil
94
+ actual = object21.cname_url
95
+ assert_equal expected, actual
96
+ end
97
+
98
+ test "destroy" do
99
+ @object_lena.expects(:object_request).with(:delete)
100
+ assert @object_lena.destroy
101
+ end
102
+
103
+ test "save" do
104
+ @object_lena.expects(:object_request).with(:put, :body=>"test", :headers=>{ :x_amz_acl=>"public-read", :content_type=>"application/octet-stream" }).returns(@response_binary)
105
+ assert @object_lena.save
106
+ end
107
+
108
+ test "content and parse headers" do
109
+ @object_lena.expects(:object_request).with(:get, {}).returns(@response_binary)
110
+
111
+ expected = /test/n
112
+ actual = @object_lena.content(true)
113
+ assert_match expected, actual
114
+ assert_equal "image/png", @object_lena.content_type
115
+
116
+ assert @object_lena.content
117
+
118
+ @object_lena.expects(:object_request).with(:get, {}).returns(@response_binary)
119
+ assert @object_lena.content(true)
120
+ end
121
+
122
+ test "retrieve" do
123
+ @object_lena.expects(:object_request).with(:head, {}).returns(@response_binary)
124
+ assert @object_lena.retrieve
125
+ end
126
+
127
+ test "exists" do
128
+ @object_lena.expects(:retrieve).returns(true)
129
+ assert @object_lena.exists?
130
+
131
+ @object_carmen.expects(:retrieve).raises(S3::Error::NoSuchKey.new(nil, nil))
132
+ assert ! @object_carmen.exists?
133
+ end
134
+
135
+ test "ACL writer" do
136
+ expected = nil
137
+ actual = @object_lena.acl
138
+ assert_equal expected, actual
139
+
140
+ assert @object_lena.acl = :public_read
141
+
142
+ expected = "public-read"
143
+ actual = @object_lena.acl
144
+ assert_equal expected, actual
145
+
146
+ assert @object_lena.acl = :private
147
+
148
+ expected = "private"
149
+ actual = @object_lena.acl
150
+ assert_equal expected, actual
151
+ end
152
+
153
+ test "copy" do
154
+ @bucket_images.expects(:bucket_request).with(:put, :path => "Lena-copy.png", :headers => { :x_amz_acl => "public-read", :content_type => "application/octet-stream", :x_amz_copy_source => "images/Lena.png", :x_amz_metadata_directive => "REPLACE" }).returns(@response_xml)
155
+
156
+ new_object = @object_lena.copy(:key => "Lena-copy.png")
157
+
158
+ assert_equal "Lena-copy.png", new_object.key
159
+ assert_equal "Lena.png", @object_lena.key
160
+ end
161
+ end
@@ -0,0 +1,111 @@
1
+ require "test_helper"
2
+
3
+ class ServiceTest < Test::Unit::TestCase
4
+ def setup
5
+ @buckets_list_body = <<-EOBuckets
6
+ <?xml version="1.0" encoding="UTF-8"?>\n<ListAllMyBucketsResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/"> <Owner> <ID>123u1odhkhfoadf</ID> <DisplayName>JohnDoe</DisplayName> </Owner> <Buckets> <Bucket> <Name>data.example.com</Name> <CreationDate>2009-07-02T11:56:58.000Z</CreationDate> </Bucket> <Bucket> <Name>images</Name> <CreationDate>2009-06-05T12:26:33.000Z</CreationDate> </Bucket> </Buckets> </ListAllMyBucketsResult>
7
+ EOBuckets
8
+
9
+ @bucket_not_exists = <<-EOBucketNoexists
10
+ <?xml version="1.0" encoding="UTF-8"?>\n<Error> <Code>NoSuchBucket</Code> <Message>The specified bucket does not exists</Message> <BucketName>data2.example.com</BucketName> <RequestId>8D7519AAE74E9E99</RequestId> <HostId>DvKnnNSMnPHd1oXukyRaFNv8Lg/bpwhuUtY8Kj7eDLbaIrIT8JebSnHwi89AK1P+</HostId> </Error>
11
+ EOBucketNoexists
12
+
13
+ @bucket_exists = <<-EOBucketexists
14
+ <?xml version="1.0" encoding="UTF-8"?>\n<ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/"> <Name>data.synergypeople.net</Name> <Prefix></Prefix> <Marker></Marker> <MaxKeys>1000</MaxKeys> <IsTruncated>false</IsTruncated> </ListBucketResult>
15
+ EOBucketexists
16
+
17
+ @service_empty_buckets_list = S3::Service.new(
18
+ :access_key_id => "12345678901234567890",
19
+ :secret_access_key => "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDF"
20
+ )
21
+ @response_empty_buckets_list = Net::HTTPOK.new("1.1", "200", "OK")
22
+ @service_empty_buckets_list.stubs(:service_request).returns(@response_empty_buckets_list)
23
+ @response_empty_buckets_list.stubs(:body).returns(@buckets_empty_list_body)
24
+
25
+ @service_buckets_list = S3::Service.new(
26
+ :access_key_id => "12345678901234567890",
27
+ :secret_access_key => "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDF"
28
+ )
29
+ @response_buckets_list = Net::HTTPOK.new("1.1", "200", "OK")
30
+ @service_buckets_list.stubs(:service_request).returns(@response_buckets_list)
31
+ @response_buckets_list.stubs(:body).returns(@buckets_list_body)
32
+
33
+ @service_bucket_exists = S3::Service.new(
34
+ :access_key_id => "12345678901234567890",
35
+ :secret_access_key => "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDF"
36
+ )
37
+ @response_bucket_exists = Net::HTTPNotFound.new("1.1", "200", "OK")
38
+ @service_bucket_exists.stubs(:service_request).returns(@response_bucket_exists)
39
+ @response_bucket_exists.stubs(:body).returns(@bucket_exists)
40
+
41
+ @service_bucket_not_exists = S3::Service.new(
42
+ :access_key_id => "12345678901234567890",
43
+ :secret_access_key => "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDF"
44
+ )
45
+ @response_bucket_not_exists = Net::HTTPNotFound.new("1.1", "404", "Not Found")
46
+ @service_bucket_not_exists.stubs(:service_request).raises(S3::Error::NoSuchBucket.new(404, @response_bucket_not_exists))
47
+ @response_bucket_not_exists.stubs(:body).returns(@bucket_not_exists)
48
+
49
+ @buckets_empty_list = []
50
+ @buckets_empty_list_body = <<-EOEmptyBuckets
51
+ <?xml version="1.0" encoding="UTF-8"?>\n<ListAllMyBucketsResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/"> <Owner> <ID>123u1odhkhfoadf</ID> <DisplayName>JohnDoe</DisplayName> </Owner> <Buckets> </Buckets> </ListAllMyBucketsResult>
52
+ EOEmptyBuckets
53
+
54
+ @buckets_list = [
55
+ S3::Bucket.send(:new, @service_buckets_list, "data.example.com"),
56
+ S3::Bucket.send(:new, @service_buckets_list, "images")
57
+ ]
58
+ end
59
+
60
+ test "buckets and parse buckets empty" do
61
+ expected = @buckets_empty_list
62
+ actual = @service_empty_buckets_list.buckets
63
+ assert_equal expected.length, actual.length
64
+ assert_equal expected, actual
65
+ end
66
+
67
+ test "buckets and parse buckets" do
68
+ expected = @buckets_list
69
+ # ugly hack
70
+ actual = @service_buckets_list.buckets.map { |obj| obj }
71
+ assert_equal expected, actual
72
+ end
73
+
74
+ test "buckets build" do
75
+ @service_empty_buckets_list.stubs(:service_request)
76
+
77
+ expected = "bucket_name"
78
+ actual = @service_empty_buckets_list.buckets.build("bucket_name")
79
+ assert_kind_of S3::Bucket, actual
80
+ assert_equal expected, actual.name
81
+ end
82
+
83
+ test "buckets find first" do
84
+ assert_nothing_raised do
85
+ actual = @service_buckets_list.buckets.find_first("data.example.com")
86
+ assert_equal "data.example.com", actual.name
87
+ end
88
+ end
89
+
90
+ test "buckets find first fail" do
91
+ assert_raise S3::Error::NoSuchBucket do
92
+ @service_bucket_not_exists.buckets.find_first("data2.example.com")
93
+ end
94
+ end
95
+
96
+ test "buckets find all on empty list" do
97
+ assert_nothing_raised do
98
+ expected = @buckets_empty_list
99
+ actual = @service_empty_buckets_list.buckets.find_all
100
+ assert_equal expected, actual
101
+ end
102
+ end
103
+
104
+ test "buckets find all" do
105
+ assert_nothing_raised do
106
+ expected = @buckets_list
107
+ actual = @service_buckets_list.buckets.find_all
108
+ assert_equal expected, actual
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,143 @@
1
+ require "test_helper"
2
+
3
+ class SignatureTest < Test::Unit::TestCase
4
+ # from http://docs.amazonwebservices.com/AmazonS3/latest/RESTAuthentication.html
5
+ test "signature for object get" do
6
+ request = Net::HTTP::Get.new("/photos/puppy.jpg")
7
+ request["host"] = "johnsmith.s3.amazonaws.com"
8
+ request["date"] = "Tue, 27 Mar 2007 19:36:42 +0000"
9
+
10
+ actual = S3::Signature.generate(
11
+ :host => request["host"],
12
+ :request => request,
13
+ :access_key_id => "0PN5J17HBGZHT7JJ3X82",
14
+ :secret_access_key => "uV3F3YluFJax1cknvbcGwgjvx4QpvB+leU8dUj2o"
15
+ )
16
+ expected = "AWS 0PN5J17HBGZHT7JJ3X82:xXjDGYUmKxnwqr5KXNPGldn5LbA="
17
+ assert_equal expected, actual
18
+ end
19
+
20
+ test "signature for object put" do
21
+ request = Net::HTTP::Put.new("/photos/puppy.jpg");
22
+ request["content-type"] = "image/jpeg"
23
+ request["content-length"] = "94328"
24
+ request["host"] = "johnsmith.s3.amazonaws.com"
25
+ request["date"] = "Tue, 27 Mar 2007 21:15:45 +0000"
26
+
27
+ actual = S3::Signature.generate(
28
+ :host => request["host"],
29
+ :request => request,
30
+ :access_key_id => "0PN5J17HBGZHT7JJ3X82",
31
+ :secret_access_key => "uV3F3YluFJax1cknvbcGwgjvx4QpvB+leU8dUj2o"
32
+ )
33
+ expected = "AWS 0PN5J17HBGZHT7JJ3X82:hcicpDDvL9SsO6AkvxqmIWkmOuQ="
34
+ assert_equal expected, actual
35
+ end
36
+
37
+ test "signature for list" do
38
+ request = Net::HTTP::Get.new("/?prefix=photos&max-keys=50&marker=puppy");
39
+ request["user-agent"] = "Mozilla/5.0"
40
+ request["host"] = "johnsmith.s3.amazonaws.com"
41
+ request["date"] = "Tue, 27 Mar 2007 19:42:41 +0000"
42
+
43
+ actual = S3::Signature.generate(
44
+ :host => request["host"],
45
+ :request => request,
46
+ :access_key_id => "0PN5J17HBGZHT7JJ3X82",
47
+ :secret_access_key => "uV3F3YluFJax1cknvbcGwgjvx4QpvB+leU8dUj2o"
48
+ )
49
+ expected = "AWS 0PN5J17HBGZHT7JJ3X82:jsRt/rhG+Vtp88HrYL706QhE4w4="
50
+ assert_equal expected, actual
51
+ end
52
+
53
+ test "signature for fetch" do
54
+ request = Net::HTTP::Get.new("/?acl");
55
+ request["host"] = "johnsmith.s3.amazonaws.com"
56
+ request["date"] = "Tue, 27 Mar 2007 19:44:46 +0000"
57
+
58
+ actual = S3::Signature.generate(
59
+ :host => request["host"],
60
+ :request => request,
61
+ :access_key_id => "0PN5J17HBGZHT7JJ3X82",
62
+ :secret_access_key => "uV3F3YluFJax1cknvbcGwgjvx4QpvB+leU8dUj2o"
63
+ )
64
+ expected = "AWS 0PN5J17HBGZHT7JJ3X82:thdUi9VAkzhkniLj96JIrOPGi0g="
65
+ assert_equal expected, actual
66
+ end
67
+
68
+ test "signature for delete" do
69
+ request = Net::HTTP::Delete.new("/johnsmith/photos/puppy.jpg");
70
+ request["user-agent"] = "dotnet"
71
+ request["host"] = "s3.amazonaws.com"
72
+ request["date"] = "Tue, 27 Mar 2007 21:20:27 +0000"
73
+ request["x-amz-date"] = "Tue, 27 Mar 2007 21:20:26 +0000"
74
+
75
+ actual = S3::Signature.generate(
76
+ :host => request["host"],
77
+ :request => request,
78
+ :access_key_id => "0PN5J17HBGZHT7JJ3X82",
79
+ :secret_access_key => "uV3F3YluFJax1cknvbcGwgjvx4QpvB+leU8dUj2o"
80
+ )
81
+ expected = "AWS 0PN5J17HBGZHT7JJ3X82:k3nL7gH3+PadhTEVn5Ip83xlYzk="
82
+ assert_equal expected, actual
83
+ end
84
+
85
+ test "signature for upload" do
86
+ request = Net::HTTP::Put.new("/db-backup.dat.gz");
87
+ request["user-agent"] = "curl/7.15.5"
88
+ request["host"] = "static.johnsmith.net:8080"
89
+ request["date"] = "Tue, 27 Mar 2007 21:06:08 +0000"
90
+ request["x-amz-acl"] = "public-read"
91
+ request["content-type"] = "application/x-download"
92
+ request["content-md5"] = "4gJE4saaMU4BqNR0kLY+lw=="
93
+ # FIXME: Net::HTTP doesn't allow to have multiple headers with the same name
94
+ # request.add_field add additional spaces (breaks signature)
95
+ #request["x-amz-meta-reviewedby"] = "joe@johnsmith.net"
96
+ #request["x-amz-meta-reviewedby"] = "jane@johnsmith.net"
97
+ request["x-amz-meta-reviewedby"] = "joe@johnsmith.net,jane@johnsmith.net"
98
+ request["x-amz-meta-filechecksum"] = "0x02661779"
99
+ request["x-amz-meta-checksumalgorithm"] = "crc32"
100
+ request["content-disposition"] = "attachment; filename=database.dat"
101
+ request["content-encoding"] = "gzip"
102
+ request["content-length"] = "5913339"
103
+
104
+ actual = S3::Signature.generate(
105
+ :host => "static.johnsmith.net",
106
+ :request => request,
107
+ :access_key_id => "0PN5J17HBGZHT7JJ3X82",
108
+ :secret_access_key => "uV3F3YluFJax1cknvbcGwgjvx4QpvB+leU8dUj2o"
109
+ )
110
+ expected = "AWS 0PN5J17HBGZHT7JJ3X82:C0FlOtU8Ylb9KDTpZqYkZPX91iI="
111
+ assert_equal expected, actual
112
+ end
113
+
114
+ test "signature for list all my buckets" do
115
+ request = Net::HTTP::Get.new("/");
116
+ request["host"] = "s3.amazonaws.com"
117
+ request["date"] = "Wed, 28 Mar 2007 01:29:59 +0000"
118
+
119
+ actual = S3::Signature.generate(
120
+ :host => request["host"],
121
+ :request => request,
122
+ :access_key_id => "0PN5J17HBGZHT7JJ3X82",
123
+ :secret_access_key => "uV3F3YluFJax1cknvbcGwgjvx4QpvB+leU8dUj2o"
124
+ )
125
+ expected = "AWS 0PN5J17HBGZHT7JJ3X82:Db+gepJSUbZKwpx1FR0DLtEYoZA="
126
+ assert_equal expected, actual
127
+ end
128
+
129
+ test "signature for unicode keys" do
130
+ request = Net::HTTP::Get.new("/dictionary/fran%C3%A7ais/pr%c3%a9f%c3%a8re");
131
+ request["host"] = "s3.amazonaws.com"
132
+ request["date"] = "Wed, 28 Mar 2007 01:49:49 +0000"
133
+
134
+ actual = S3::Signature.generate(
135
+ :host => request["host"],
136
+ :request => request,
137
+ :access_key_id => "0PN5J17HBGZHT7JJ3X82",
138
+ :secret_access_key => "uV3F3YluFJax1cknvbcGwgjvx4QpvB+leU8dUj2o"
139
+ )
140
+ expected = "AWS 0PN5J17HBGZHT7JJ3X82:dxhSBHoI6eVSPcXJqEghlUzZMnY="
141
+ assert_equal expected, actual
142
+ end
143
+ end
@@ -0,0 +1,7 @@
1
+ require "bundler"
2
+
3
+ Bundler.setup
4
+ Bundler.require
5
+
6
+ require "test/unit"
7
+ require "mocha"
metadata CHANGED
@@ -1,13 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: s3
3
3
  version: !ruby/object:Gem::Version
4
- hash: 19
5
4
  prerelease: false
6
5
  segments:
7
6
  - 0
8
7
  - 3
9
- - 0
10
- version: 0.3.0
8
+ - 1
9
+ version: 0.3.1
11
10
  platform: ruby
12
11
  authors:
13
12
  - "Jakub Ku\xC5\xBAma"
@@ -15,7 +14,7 @@ autorequire:
15
14
  bindir: bin
16
15
  cert_chain: []
17
16
 
18
- date: 2010-05-23 00:00:00 +02:00
17
+ date: 2010-09-04 00:00:00 +02:00
19
18
  default_executable:
20
19
  dependencies:
21
20
  - !ruby/object:Gem::Dependency
@@ -26,7 +25,6 @@ dependencies:
26
25
  requirements:
27
26
  - - ">="
28
27
  - !ruby/object:Gem::Version
29
- hash: 3
30
28
  segments:
31
29
  - 0
32
30
  version: "0"
@@ -40,7 +38,6 @@ dependencies:
40
38
  requirements:
41
39
  - - ">="
42
40
  - !ruby/object:Gem::Version
43
- hash: 3
44
41
  segments:
45
42
  - 0
46
43
  version: "0"
@@ -54,7 +51,6 @@ dependencies:
54
51
  requirements:
55
52
  - - ">="
56
53
  - !ruby/object:Gem::Version
57
- hash: 3
58
54
  segments:
59
55
  - 2
60
56
  - 0
@@ -69,14 +65,29 @@ dependencies:
69
65
  requirements:
70
66
  - - ">="
71
67
  - !ruby/object:Gem::Version
72
- hash: 3
73
68
  segments:
74
69
  - 0
75
70
  version: "0"
76
71
  type: :development
77
72
  version_requirements: *id004
73
+ - !ruby/object:Gem::Dependency
74
+ name: bundler
75
+ prerelease: false
76
+ requirement: &id005 !ruby/object:Gem::Requirement
77
+ none: false
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ segments:
82
+ - 1
83
+ - 0
84
+ - 0
85
+ version: 1.0.0
86
+ type: :development
87
+ version_requirements: *id005
78
88
  description: "S3 library provides access to Amazon's Simple Storage Service. It supports both: European and US buckets through REST API."
79
- email: qoobaa@gmail.com
89
+ email:
90
+ - qoobaa@gmail.com
80
91
  executables:
81
92
  - s3
82
93
  extensions: []
@@ -84,22 +95,33 @@ extensions: []
84
95
  extra_rdoc_files: []
85
96
 
86
97
  files:
98
+ - .gitignore
99
+ - Gemfile
100
+ - Gemfile.lock
101
+ - LICENSE
102
+ - README.rdoc
103
+ - Rakefile
87
104
  - bin/s3
88
105
  - extra/s3_attachment_fu.rb
89
106
  - extra/s3_paperclip.rb
90
107
  - lib/s3.rb
91
- - lib/s3/object.rb
92
- - lib/s3/parser.rb
93
- - lib/s3/signature.rb
94
108
  - lib/s3/bucket.rb
95
- - lib/s3/exceptions.rb
96
- - lib/s3/service.rb
97
- - lib/s3/version.rb
98
109
  - lib/s3/buckets_extension.rb
99
110
  - lib/s3/connection.rb
111
+ - lib/s3/exceptions.rb
112
+ - lib/s3/object.rb
100
113
  - lib/s3/objects_extension.rb
101
- - LICENSE
102
- - README.rdoc
114
+ - lib/s3/parser.rb
115
+ - lib/s3/service.rb
116
+ - lib/s3/signature.rb
117
+ - lib/s3/version.rb
118
+ - s3.gemspec
119
+ - test/bucket_test.rb
120
+ - test/connection_test.rb
121
+ - test/object_test.rb
122
+ - test/service_test.rb
123
+ - test/signature_test.rb
124
+ - test/test_helper.rb
103
125
  has_rdoc: true
104
126
  homepage: http://jah.pl/projects/s3.html
105
127
  licenses: []
@@ -114,7 +136,6 @@ required_ruby_version: !ruby/object:Gem::Requirement
114
136
  requirements:
115
137
  - - ">="
116
138
  - !ruby/object:Gem::Version
117
- hash: 3
118
139
  segments:
119
140
  - 0
120
141
  version: "0"
@@ -123,7 +144,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
123
144
  requirements:
124
145
  - - ">="
125
146
  - !ruby/object:Gem::Version
126
- hash: 23
127
147
  segments:
128
148
  - 1
129
149
  - 3
@@ -131,7 +151,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
131
151
  version: 1.3.6
132
152
  requirements: []
133
153
 
134
- rubyforge_project:
154
+ rubyforge_project: s3
135
155
  rubygems_version: 1.3.7
136
156
  signing_key:
137
157
  specification_version: 3