s3io 0.0.2 → 1.0.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/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