s3io 0.0.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -25,12 +25,13 @@ Or install it yourself as:
25
25
  ## Usage
26
26
 
27
27
  Once wrapped, S3 objects behave the way you'd expect from an ordinary IO object.
28
+ It can read:
28
29
 
29
30
  require 'aws-sdk'
30
31
  require 's3io'
31
32
 
32
33
  s3_object = S3.buckets['some-bucket'].objects['path/to/object']
33
- io = S3io.new(s3_object)
34
+ io = S3io.open(s3_object, 'r')
34
35
 
35
36
  first_100_bytes = io.read(100) # reading first 100 bytes
36
37
 
@@ -44,9 +45,22 @@ Once wrapped, S3 objects behave the way you'd expect from an ordinary IO object.
44
45
 
45
46
  puts io.read # and print everything from that byte to the end
46
47
 
48
+
49
+ It can write:
50
+
51
+ require 'aws-sdk'
52
+ require 's3io'
53
+
54
+ s3_object = S3.buckets['some-bucket'].objects['path/to/object']
55
+
56
+ S3io.open(s3_object, 'w') do |s3io|
57
+ io.write 'abc'
58
+ io.write 'def'
59
+ end
60
+
47
61
  ## To do
48
62
 
49
- * Write support
63
+ * Code documentation
50
64
 
51
65
  ## Contributing
52
66
 
@@ -1,5 +1,7 @@
1
1
  require "s3io/version"
2
2
  require "s3io/wrapper"
3
+ require "s3io/read_wrapper"
4
+ require "s3io/write_wrapper"
3
5
 
4
6
  require "aws-sdk"
5
7
 
@@ -11,7 +13,7 @@ module S3io
11
13
  # @param [Hash] options options hash
12
14
  # @option options [Integer] :line_buffer_size size of the buffer that is used for reading contents of S3 object when iterating over its lines
13
15
  # @return [S3io::Wrapper] a wrapped S3 object
14
- def self.new(s3object, options = {})
15
- Wrapper.new(s3object, options)
16
- end
16
+ #def self.new(s3object, options = {})
17
+ # Wrapper.new(s3object, options)
18
+ #end
17
19
  end
@@ -0,0 +1,86 @@
1
+ module S3io
2
+
3
+ def self.reader(s3object, options = {}, &block)
4
+ open(s3object, 'r', options, &block)
5
+ end
6
+
7
+ class ReadWrapper < Wrapper
8
+
9
+ # Default buffer size for line parser in bytes
10
+ LINE_BUFFER_SIZE = 5 * 1024 * 1024 # MiB
11
+
12
+ include Enumerable
13
+
14
+ # Current byte position in S3 object
15
+ attr_accessor :pos
16
+
17
+ def initialize(s3object, options = {})
18
+ super(s3object)
19
+
20
+ @options = {
21
+ :line_buffer_size => (options[:line_buffer_size] || LINE_BUFFER_SIZE)
22
+ }
23
+ end
24
+
25
+ # Reads data from S3 object.
26
+ #
27
+ # @param [Integer] bytes number of bytes to read
28
+ def read(bytes = nil)
29
+ content_length = @s3object.content_length
30
+
31
+ return '' if (@pos >= content_length) || (bytes == 0)
32
+
33
+ bytes ||= content_length
34
+
35
+ upper_bound = @pos + bytes - 1
36
+ upper_bound = (content_length - 1) if upper_bound >= content_length
37
+
38
+ data = @s3object.read :range => @pos..upper_bound
39
+ @pos = upper_bound + 1
40
+
41
+ return data
42
+ end
43
+
44
+ def eof?
45
+ @pos >= @s3object.content_length
46
+ end
47
+
48
+ # Rewinds position to the very beginning of S3 object.
49
+ def rewind
50
+ @pos = 0
51
+ end
52
+
53
+ # Iterates over S3 object lines.
54
+ #
55
+ # @param [String] separator line separator string
56
+ def each(separator = $/)
57
+ return enum_for(:each, separator) unless block_given?
58
+
59
+ line = ''
60
+ newline_pos = nil
61
+
62
+ # Either trying to parse the remainder or reading some more data
63
+ while newline_pos || !(buffer = read(@options[:line_buffer_size])).empty?
64
+ prev_newline_pos = newline_pos || 0
65
+ newline_pos = buffer.index(separator, prev_newline_pos)
66
+
67
+ if newline_pos
68
+ line << buffer[prev_newline_pos..newline_pos]
69
+ newline_pos += 1
70
+ yield line
71
+ line = ''
72
+ else
73
+ line << buffer[prev_newline_pos..-1]
74
+ end
75
+ end
76
+
77
+ # Flush the remainder if body doesn't end with separator
78
+ yield line unless line.empty?
79
+
80
+ return self
81
+ end
82
+ alias lines each
83
+ alias each_line each
84
+
85
+ end
86
+ end
@@ -1,3 +1,3 @@
1
1
  module S3io
2
- VERSION = "0.0.2"
2
+ VERSION = "1.0.0"
3
3
  end
@@ -1,88 +1,44 @@
1
1
  module S3io
2
- # This class wraps an AWS S3 object in order to provide IO-like API.
3
- # S3 objects wrapped this way can be used in methods that would otherwise expect an instance of File, StringIO etc.
4
- class Wrapper
5
2
 
6
- # Default buffer size for line parser in bytes
7
- LINE_BUFFER_SIZE = 5 * 1024 * 1024 # MiB
3
+ def self.open(s3object, mode_string = 'r', options = {}, &block)
4
+ wrapper_class = case mode_string
5
+ when 'r'
6
+ ReadWrapper
7
+ when 'w'
8
+ WriteWrapper
9
+ else
10
+ fail "S3IO only supports 'r' or 'w' as access modes"
11
+ end
8
12
 
9
- include Enumerable
13
+ wrapper = wrapper_class.new(s3object, options)
10
14
 
11
- # Current byte position in S3 object
12
- attr_accessor :pos
15
+ if block_given?
16
+ result = yield wrapper if block_given?
17
+ wrapper.close
18
+
19
+ return result
20
+ else
21
+ return wrapper
22
+ end
23
+ end
13
24
 
14
- # Options that were passed during initialization
15
- attr_reader :options
25
+ # This class wraps an AWS S3 object in order to provide IO-like API.
26
+ # S3 objects wrapped this way can be used in methods that would otherwise expect an instance of File, StringIO etc.
27
+ class Wrapper
16
28
 
17
29
  # Wraps an AWS::S3::S3Object into IO-like object.
18
30
  #
19
31
  # @param [AWS::S3::S3Object] s3object an object to wrap
20
- # @param [Hash] options options hash
21
- # @option options [Integer] :line_buffer_size size of the buffer that is used for reading contents of S3 object when iterating over its lines
22
- def initialize(s3object, options = {})
32
+ def initialize(s3object)
23
33
  @s3object = s3object
24
- @options = {
25
- :line_buffer_size => (options[:line_buffer_size] || LINE_BUFFER_SIZE)
26
- }
27
-
28
34
  @pos = 0
29
35
  end
30
36
 
31
- # Reads data from S3 object.
32
- #
33
- # @param [Integer] bytes number of bytes to read
34
- def read(bytes = nil)
35
- content_length = @s3object.content_length
36
-
37
- return '' if (@pos >= content_length) || (bytes == 0)
38
-
39
- bytes ||= content_length
40
-
41
- upper_bound = @pos + bytes - 1
42
- upper_bound = (content_length - 1) if upper_bound >= content_length
43
-
44
- data = @s3object.read :range => @pos..upper_bound
45
- @pos = upper_bound + 1
46
-
47
- return data
48
- end
49
-
50
- # Rewinds position to the very beginning of S3 object.
51
- def rewind
37
+ def close
38
+ @s3object = nil
52
39
  @pos = 0
53
- end
54
40
 
55
- # Iterates over S3 object lines.
56
- #
57
- # @param [String] separator line separator string
58
- def each(separator = $/)
59
- return enum_for(:each, separator) unless block_given?
60
-
61
- line = ''
62
- newline_pos = nil
63
-
64
- # Either trying to parse the remainder or reading some more data
65
- while newline_pos || !(buffer = read(@options[:line_buffer_size])).empty?
66
- prev_newline_pos = newline_pos || 0
67
- newline_pos = buffer.index(separator, prev_newline_pos)
68
-
69
- if newline_pos
70
- line << buffer[prev_newline_pos..newline_pos]
71
- newline_pos += 1
72
- yield line
73
- line = ''
74
- else
75
- line << buffer[prev_newline_pos..-1]
76
- end
77
- end
78
-
79
- # Flush the remainder if body doesn't end with separator
80
- yield line unless line.empty?
81
-
82
- return self
41
+ return nil
83
42
  end
84
- alias lines each
85
- alias each_line each
86
-
87
43
  end
88
44
  end
@@ -0,0 +1,64 @@
1
+ module S3io
2
+
3
+ def self.writer(s3object, options = {}, &block)
4
+ open(s3object, 'w', options, &block)
5
+ end
6
+
7
+ class WriteWrapper < Wrapper
8
+
9
+ # Default maximum file size
10
+ MAX_FILE_SIZE = 1 * 1024 * 1024 * 1024 * 1024 # TiB
11
+
12
+ # S3 only supports up to 10K multipart chunks
13
+ MAX_NUM_CHUNKS = 10000
14
+
15
+ # Minimum chunk size in S3 is 5MiB
16
+ MIN_CHUNK_SIZE = 5 * 1024 * 1024 # MiB
17
+
18
+ # Number of bytes written to S3
19
+ attr_reader :pos
20
+
21
+ def initialize(s3object, options = {})
22
+ super(s3object)
23
+
24
+ @options = {
25
+ :max_file_size => (options[:max_file_size] || MAX_FILE_SIZE),
26
+ :multipart_upload_options => (options[:multipart_upload_options] || {})
27
+ }
28
+
29
+ @min_chunk_size = [(@options[:max_file_size].to_f / MAX_NUM_CHUNKS).ceil, MIN_CHUNK_SIZE].max
30
+ @multipart_upload = @s3object.multipart_upload(@options[:multipart_upload_options])
31
+ @write_buffer = ''
32
+ end
33
+
34
+ def write(data)
35
+ fail "S3 Object is already closed" unless @s3object
36
+
37
+ data_str = data.to_s
38
+ data_size = data_str.size
39
+
40
+ @write_buffer << data_str
41
+ @pos += data_size
42
+ self.flush if @write_buffer.size >= @min_chunk_size
43
+
44
+ return data_size
45
+ end
46
+
47
+ def flush
48
+ return if @write_buffer.empty?
49
+
50
+ @multipart_upload.add_part(@write_buffer)
51
+ @write_buffer.replace '' # String#clear isn't available on 1.8.x
52
+
53
+ return nil
54
+ end
55
+
56
+ def close
57
+ self.flush
58
+ @multipart_upload.close
59
+ @multipart_upload = nil
60
+
61
+ super
62
+ end
63
+ end
64
+ end
@@ -3,7 +3,7 @@ require 's3io'
3
3
  require 'stringio'
4
4
 
5
5
  # Emulate S3Object in a way that allows us to check if its methods are being called properly
6
- class S3ObjectMock
6
+ class S3ObjectReadMock
7
7
  def initialize(body = '')
8
8
  @body = body
9
9
  end
@@ -20,35 +20,35 @@ class S3ObjectMock
20
20
  end
21
21
  end
22
22
 
23
- class S3ioWrapperTest < Test::Unit::TestCase
23
+ class S3ioReadWrapperTest < Test::Unit::TestCase
24
24
  S3_TEST_DATA = File.read('test/s3_test_data.csv')
25
25
 
26
26
  def setup
27
- @s3object = S3ObjectMock.new(S3_TEST_DATA)
27
+ @s3object = S3ObjectReadMock.new(S3_TEST_DATA)
28
28
  end
29
29
 
30
- def test_s3io_wrapper_full_read
31
- wrapper = S3io::Wrapper.new(@s3object)
30
+ def test_full_read
31
+ wrapper = S3io::ReadWrapper.new(@s3object)
32
32
 
33
33
  assert_equal(S3_TEST_DATA, wrapper.read)
34
34
  end
35
35
 
36
- def test_s3io_wrapper_zero_read
37
- wrapper = S3io::Wrapper.new(@s3object)
36
+ def test_zero_read
37
+ wrapper = S3io::ReadWrapper.new(@s3object)
38
38
 
39
39
  assert_equal('', wrapper.read(0))
40
40
  assert_equal(0, wrapper.pos)
41
41
  end
42
42
 
43
- def test_s3io_wrapper_partial_read
44
- wrapper = S3io::Wrapper.new(@s3object)
43
+ def test_partial_read
44
+ wrapper = S3io::ReadWrapper.new(@s3object)
45
45
 
46
46
  assert_equal(S3_TEST_DATA[0..99], wrapper.read(100))
47
47
  assert_equal(S3_TEST_DATA[100..100], wrapper.read(1))
48
48
  end
49
49
 
50
- def test_s3io_wrapper_each
51
- wrapper = S3io::Wrapper.new(@s3object)
50
+ def test_each
51
+ wrapper = S3io::ReadWrapper.new(@s3object)
52
52
 
53
53
  lines = []
54
54
  wrapper.each do |line|
@@ -58,15 +58,15 @@ class S3ioWrapperTest < Test::Unit::TestCase
58
58
  assert_equal(S3_TEST_DATA.lines.to_a, lines)
59
59
  end
60
60
 
61
- def test_s3io_wrapper_each_enum
62
- wrapper = S3io::Wrapper.new(@s3object)
61
+ def test_each_enum
62
+ wrapper = S3io::ReadWrapper.new(@s3object)
63
63
 
64
64
  assert_equal(S3_TEST_DATA.lines.to_a,
65
65
  wrapper.lines.to_a)
66
66
  end
67
67
 
68
- def test_s3io_wrapper_pos
69
- wrapper = S3io::Wrapper.new(@s3object)
68
+ def test_pos
69
+ wrapper = S3io::ReadWrapper.new(@s3object)
70
70
 
71
71
  assert_equal(0, wrapper.pos)
72
72
 
@@ -76,8 +76,8 @@ class S3ioWrapperTest < Test::Unit::TestCase
76
76
  assert_equal(S3_TEST_DATA[77, 32], wrapper.read(32))
77
77
  end
78
78
 
79
- def test_s3io_wrapper_pos_beyond
80
- wrapper = S3io::Wrapper.new(@s3object)
79
+ def test_pos_beyond
80
+ wrapper = S3io::ReadWrapper.new(@s3object)
81
81
 
82
82
  pos_beyond = @s3object.content_length + 100
83
83
  wrapper.pos = pos_beyond
@@ -86,8 +86,8 @@ class S3ioWrapperTest < Test::Unit::TestCase
86
86
  assert_equal(pos_beyond, wrapper.pos)
87
87
  end
88
88
 
89
- def test_s3io_wrapper_rewind
90
- wrapper = S3io::Wrapper.new(@s3object)
89
+ def test_rewind
90
+ wrapper = S3io::ReadWrapper.new(@s3object)
91
91
 
92
92
  wrapper.lines do |line|
93
93
  # iterate through all the lines
@@ -99,8 +99,31 @@ class S3ioWrapperTest < Test::Unit::TestCase
99
99
  assert_equal(S3_TEST_DATA[0..100], wrapper.read(101))
100
100
  end
101
101
 
102
- def test_s3io_wrapper_line_buffer_size
103
- wrapper = S3io::Wrapper.new(@s3object, :line_buffer_size => 25)
102
+ def test_lines_custom_separator
103
+ wrapper = S3io::ReadWrapper.new(@s3object)
104
+
105
+ assert_equal(S3_TEST_DATA.lines(",").to_a, wrapper.lines(",").to_a)
106
+ end
107
+
108
+ def test_eof
109
+ wrapper = S3io::ReadWrapper.new(@s3object)
110
+
111
+ assert_equal(false, wrapper.eof?)
112
+
113
+ wrapper.read(10)
114
+ assert_equal(false, wrapper.eof?)
115
+
116
+ wrapper.read
117
+ assert_equal(true, wrapper.eof?)
118
+
119
+ wrapper.rewind
120
+ assert_equal(false, wrapper.eof?)
121
+ end
122
+
123
+ # Custom options for wrapper
124
+
125
+ def test_line_buffer_size
126
+ wrapper = S3io::ReadWrapper.new(@s3object, :line_buffer_size => 25)
104
127
 
105
128
  wrapper.lines.each_with_index do |line, index|
106
129
  break if index == 1 # skip two buffered reads
@@ -110,14 +133,8 @@ class S3ioWrapperTest < Test::Unit::TestCase
110
133
  assert_equal(S3_TEST_DATA[50..-1], wrapper.read)
111
134
  end
112
135
 
113
- def test_s3io_wrapper_lines_custom_separator
114
- wrapper = S3io::Wrapper.new(@s3object)
115
-
116
- assert_equal(S3_TEST_DATA.lines(",").to_a, wrapper.lines(",").to_a)
117
- end
118
-
119
- def test_s3io_wrapper_empty_each
120
- wrapper = S3io::Wrapper.new(S3ObjectMock.new(''))
136
+ def test_empty_each
137
+ wrapper = S3io::ReadWrapper.new(S3ObjectReadMock.new(''))
121
138
 
122
139
  wrapper.each do |line|
123
140
  assert_equal(false, :never_gets_called)
@@ -0,0 +1,91 @@
1
+ require 'test/unit'
2
+ require 's3io'
3
+ require 'stringio'
4
+
5
+ class S3ObjectWriteMock
6
+ attr_reader :body
7
+ attr_accessor :uploaded
8
+ attr_accessor :multipart_upload_options
9
+
10
+ class MultiPartUploadMock
11
+ attr_reader :options
12
+
13
+ def initialize(body, options, mock)
14
+ @body = body
15
+ @mock = mock
16
+ @mock.multipart_upload_options = options
17
+ end
18
+
19
+ def add_part(part)
20
+ @body << part
21
+ end
22
+
23
+ def close
24
+ @mock.uploaded = @body
25
+ end
26
+ end
27
+
28
+ def initialize
29
+ @body = ''
30
+ end
31
+
32
+ def multipart_upload(options = {})
33
+ MultiPartUploadMock.new(@body, options, self)
34
+ end
35
+ end
36
+
37
+ class S3ioWriteWrapperTest < Test::Unit::TestCase
38
+ def setup
39
+ @s3object = S3ObjectWriteMock.new
40
+ end
41
+
42
+ def test_full_write
43
+ wrapper = S3io::WriteWrapper.new(@s3object)
44
+
45
+ test_string = 'This is a test.'
46
+
47
+ wrapper.write(test_string)
48
+ assert_equal(test_string.size, wrapper.pos)
49
+ assert_equal({}, @s3object.multipart_upload_options)
50
+
51
+ wrapper.close
52
+ assert_equal(test_string, @s3object.uploaded)
53
+ assert_equal(0, wrapper.pos)
54
+ end
55
+
56
+ def test_multipart_write
57
+ wrapper = S3io::WriteWrapper.new(@s3object, :max_file_size => 1)
58
+
59
+ chunk1 = 'z' * (S3io::WriteWrapper::MIN_CHUNK_SIZE + 100)
60
+ chunk2 = 'y' * (S3io::WriteWrapper::MIN_CHUNK_SIZE + 300)
61
+
62
+ full_body = chunk1 + chunk2
63
+
64
+ wrapper.write(chunk1)
65
+ assert_equal(chunk1, @s3object.body)
66
+ assert_equal(nil, @s3object.uploaded)
67
+
68
+ wrapper.write(chunk2)
69
+ assert_equal(full_body, @s3object.body)
70
+ assert_equal(nil, @s3object.uploaded)
71
+
72
+ wrapper.close
73
+ assert_equal(full_body, @s3object.uploaded)
74
+ end
75
+
76
+ def test_flush
77
+ wrapper = S3io::WriteWrapper.new(@s3object, :multipart_upload_options => {:metadata => {:yes => 'no'}})
78
+ test_string = '42'
79
+
80
+ assert_equal('', @s3object.body)
81
+ assert_equal({:metadata => {:yes => 'no'}}, @s3object.multipart_upload_options)
82
+
83
+ wrapper.write(test_string)
84
+ wrapper.flush
85
+ assert_equal(test_string, @s3object.body)
86
+
87
+ wrapper.close
88
+ assert_equal(test_string, @s3object.body)
89
+ assert_equal(test_string, @s3object.uploaded)
90
+ end
91
+ end
metadata CHANGED
@@ -1,39 +1,46 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: s3io
3
- version: !ruby/object:Gem::Version
4
- version: 0.0.2
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
5
  prerelease:
6
+ segments:
7
+ - 1
8
+ - 0
9
+ - 0
10
+ version: 1.0.0
6
11
  platform: ruby
7
- authors:
12
+ authors:
8
13
  - Arthur Pirogovski
9
14
  autorequire:
10
15
  bindir: bin
11
16
  cert_chain: []
12
- date: 2012-12-14 00:00:00.000000000 Z
13
- dependencies:
14
- - !ruby/object:Gem::Dependency
17
+
18
+ date: 2013-01-22 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
15
21
  name: aws-sdk
16
- requirement: !ruby/object:Gem::Requirement
17
- none: false
18
- requirements:
19
- - - ! '>='
20
- - !ruby/object:Gem::Version
21
- version: '0'
22
- type: :runtime
23
22
  prerelease: false
24
- version_requirements: !ruby/object:Gem::Requirement
23
+ requirement: &id001 !ruby/object:Gem::Requirement
25
24
  none: false
26
- requirements:
27
- - - ! '>='
28
- - !ruby/object:Gem::Version
29
- version: '0'
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 3
29
+ segments:
30
+ - 0
31
+ version: "0"
32
+ type: :runtime
33
+ version_requirements: *id001
30
34
  description: An IO-compatible wrapper for S3
31
- email:
35
+ email:
32
36
  - arthur@flyingtealeaf.com
33
37
  executables: []
38
+
34
39
  extensions: []
40
+
35
41
  extra_rdoc_files: []
36
- files:
42
+
43
+ files:
37
44
  - .gitignore
38
45
  - .travis.yml
39
46
  - Gemfile
@@ -41,41 +48,49 @@ files:
41
48
  - README.md
42
49
  - Rakefile
43
50
  - lib/s3io.rb
51
+ - lib/s3io/read_wrapper.rb
44
52
  - lib/s3io/version.rb
45
53
  - lib/s3io/wrapper.rb
54
+ - lib/s3io/write_wrapper.rb
46
55
  - s3io.gemspec
47
56
  - test/s3_test_data.csv
48
- - test/test_s3io.rb
49
- - test/test_s3io_wrapper.rb
57
+ - test/test_s3io_read_wrapper.rb
58
+ - test/test_s3io_write_wrapper.rb
50
59
  homepage: http://github.com/fiksu/s3io
51
60
  licenses: []
61
+
52
62
  post_install_message:
53
63
  rdoc_options: []
54
- require_paths:
64
+
65
+ require_paths:
55
66
  - lib
56
- required_ruby_version: !ruby/object:Gem::Requirement
67
+ required_ruby_version: !ruby/object:Gem::Requirement
57
68
  none: false
58
- requirements:
59
- - - ! '>='
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- required_rubygems_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ hash: 3
73
+ segments:
74
+ - 0
75
+ version: "0"
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
77
  none: false
64
- requirements:
65
- - - ! '>='
66
- - !ruby/object:Gem::Version
67
- version: '0'
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ hash: 3
82
+ segments:
83
+ - 0
84
+ version: "0"
68
85
  requirements: []
86
+
69
87
  rubyforge_project:
70
88
  rubygems_version: 1.8.24
71
89
  signing_key:
72
90
  specification_version: 3
73
- summary: Amazon's official AWS SDK provides an API for S3 that isn't compatible with
74
- Ruby's standard IO class and its derivatives. This gem provides a thin wrapper around
75
- AWS SDK that makes it possible to access objects stored on S3 as if they were instances
76
- of File or StringIO classes.
77
- test_files:
91
+ summary: Amazon's official AWS SDK provides an API for S3 that isn't compatible with Ruby's standard IO class and its derivatives. This gem provides a thin wrapper around AWS SDK that makes it possible to access objects stored on S3 as if they were instances of File or StringIO classes.
92
+ test_files:
78
93
  - test/s3_test_data.csv
79
- - test/test_s3io.rb
80
- - test/test_s3io_wrapper.rb
94
+ - test/test_s3io_read_wrapper.rb
95
+ - test/test_s3io_write_wrapper.rb
81
96
  has_rdoc:
@@ -1,16 +0,0 @@
1
- require 'test/unit'
2
- require 's3io'
3
-
4
- class S3ioTest < Test::Unit::TestCase
5
- def test_s3io_new
6
- s3object = Object.new
7
- wrapper = S3io.new(s3object)
8
- assert_equal(S3io::Wrapper, wrapper.class)
9
- end
10
-
11
- def test_s3io_new_with_options
12
- s3object = Object.new
13
- wrapper = S3io.new(s3object, :line_buffer_size => 128)
14
- assert_equal(128, wrapper.options[:line_buffer_size])
15
- end
16
- end