s3-rb 1.0.0 → 1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8da7974f1a862a8b59312aa1b2a14e62acb50e0c395a59cb0e9163c81ca6c1d9
4
- data.tar.gz: 271348a115ab248f843912064ce39ec87466165706304cbbfda8919f47e3d00b
3
+ metadata.gz: 85a4eeb57da7dbe4999bb438af9db19d367daf81350f784448e3f150a1e1fd70
4
+ data.tar.gz: a698dcb334a90ba430190bad1bbae206d4d0a4b5c7ab8ce7c49a4de8332367db
5
5
  SHA512:
6
- metadata.gz: 89d5da5bdae4ba11bf4fd3de8145d2f992a012b4d28f2cba73c9752af4d220f788fcefb8e45fe73aea16eb31ee3d6286fd989f83ba1768cb60e4950a9063ee8c
7
- data.tar.gz: a57ec119c7b94cc518a10869e95f58937df0ef553cf2d7e0aafab14341980c96fcb54e5bcf0885566b0d3cb268ecd24b9cfc9cbb793147311177ca0e4a1047b5
6
+ metadata.gz: 670b1933127338a97975c5950415bf397aa59892732dc8fa88d8e3467af908e7b343a051128d017c781f94a633956867424fa9cb319b46d73d79e5fc61f61ce6
7
+ data.tar.gz: ebc2090cef7c63ee6da0fc136e94f05a46cfd605971ba64e1c738026b6fa6762cddbb5259478528f4ee18cbbd8231b5716973fdadb430eb6bd57894bbdb01b56
data/CHANGELOG.md ADDED
@@ -0,0 +1,38 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ ## [1.1.0] - 2025-02-04
6
+
7
+ ### Added
8
+
9
+ - New options classes for all requests with optional parameters:
10
+ - `BucketCreateOptions` (region, acl)
11
+ - `MultipartCreateOptions` (metadata, content_type, acl, storage_class)
12
+ - `MultipartListOptions` (prefix, key_marker, upload_id_marker, max_uploads)
13
+ - `MultipartPartsOptions` (part_number_marker, max_parts)
14
+ - `ObjectListOptions` (prefix, delimiter, max_keys, continuation_token, start_after)
15
+ - `PresignGetOptions` (expires_in, response_content_type, response_content_disposition)
16
+ - `PresignPutOptions` (expires_in, content_type)
17
+
18
+ - Added `metadata` field to `ObjectPutOptions` and `ObjectCopyOptions`
19
+
20
+ - Flexible options passing for all requests and service methods:
21
+ - Pass options as keyword arguments (primary approach)
22
+ - Pass an options struct as the first positional argument
23
+ - Pass an options struct or hash via the `options:` keyword argument
24
+ - Combine any of the above (precedence: positional < `options:` kwarg < other kwargs)
25
+
26
+ ### Changed
27
+
28
+ - Refactored request classes to use shared `merge_options` helper method in base `Request` class
29
+ - Simplified service method signatures to use `**kwargs` passthrough
30
+
31
+ ### Notes
32
+
33
+ - Fully backwards compatible with 1.0.0
34
+ - All existing code continues to work without modification
35
+
36
+ ## [1.0.0] - 2025-02-04
37
+
38
+ - Initial release
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- s3-rb (0.1.0)
4
+ s3-rb (1.1.0)
5
5
  dynamicschema (~> 2.0)
6
6
  faraday (~> 2.0)
7
7
  faraday-net_http_persistent (~> 2.0)
data/README.md CHANGED
@@ -4,17 +4,12 @@ This is a lightweight, low dependency, high performance, high compatibility, 'ba
4
4
 
5
5
  I chose to make this implementation 'bare metal' in that there is minimal abstraction layer atop the S3 API - not even an iterator for the object list. You are then free to build your own abstraction best suited to the semantics of your application or gem.
6
6
 
7
- At its most basic the implementation provides a request class per operation which returns a result structure. In some cases, for operations with many parameters, there is an options structure you can build. The operation is executed by 'submitting' an instance of the request.
7
+ At its most basic the implementation provides a request class per operation which returns a result structure. The operation is executed by 'submitting' an instance of the request with required parameters and optional keyword arguments.
8
8
 
9
9
  ```ruby
10
10
  require 's3'
11
11
 
12
- # build the options for the put operation
13
- options = S3::ObjectPutOptions.build( content_type: 'text/plain',
14
- acl: :public_read,
15
- storage_class: :standard_ia )
16
-
17
- # create the request and submit it
12
+ # create the request and submit it with keyword arguments
18
13
  request = S3::ObjectPutRequest.new( access_key_id: 'AKIA...',
19
14
  secret_access_key: '...',
20
15
  region: 'us-east-1' )
@@ -22,7 +17,9 @@ request = S3::ObjectPutRequest.new( access_key_id: 'AKIA...',
22
17
  response = request.submit( bucket: 'my-bucket',
23
18
  key: 'hello.txt',
24
19
  body: 'Hello, World!',
25
- options: options )
20
+ content_type: 'text/plain',
21
+ acl: :public_read,
22
+ storage_class: :standard_ia )
26
23
 
27
24
  # check for success and read the result
28
25
  if response.success?
@@ -34,6 +31,32 @@ else
34
31
  end
35
32
  ```
36
33
 
34
+ Alternatively, you can build an options structure and pass it as the first positional argument or as the `options:` keyword argument:
35
+
36
+ ```ruby
37
+ # build the options for the put operation
38
+ options = S3::ObjectPutOptions.build( content_type: 'text/plain',
39
+ acl: :public_read,
40
+ storage_class: :standard_ia )
41
+
42
+ # as first positional argument
43
+ response = request.submit( options, bucket: 'my-bucket',
44
+ key: 'hello.txt',
45
+ body: 'Hello, World!' )
46
+
47
+ # or as keyword argument
48
+ response = request.submit( bucket: 'my-bucket',
49
+ key: 'hello.txt',
50
+ body: 'Hello, World!',
51
+ options: options )
52
+
53
+ # options can also be a Hash
54
+ response = request.submit( bucket: 'my-bucket',
55
+ key: 'hello.txt',
56
+ body: 'Hello, World!',
57
+ options: { content_type: 'text/plain', acl: :public_read } )
58
+ ```
59
+
37
60
  The operation methods - similar to those in the AWS gem - then create a matching request object with the given arguments and submit a request, typically returning the same result structure.
38
61
 
39
62
  ```ruby
@@ -0,0 +1,14 @@
1
+ module S3
2
+ class BucketCreateOptions
3
+ include SchemaOptions
4
+
5
+ CANNED_ACLS = %w[
6
+ private public-read public-read-write authenticated-read
7
+ ].freeze
8
+
9
+ schema do
10
+ region String
11
+ acl [ String, Symbol ], normalize: ->( v ) { v.to_s.downcase.tr( '_', '-' ) }
12
+ end
13
+ end
14
+ end
@@ -1,11 +1,13 @@
1
1
  module S3
2
2
  class BucketCreateRequest < Request
3
- def submit( bucket:, region: nil, acl: nil )
3
+ def submit( options = nil, bucket:, **kwargs )
4
+ options = merge_options( options, kwargs, BucketCreateOptions )
5
+
4
6
  headers = {}
5
- headers[ 'x-amz-acl' ] = acl if acl
7
+ headers[ 'x-amz-acl' ] = options[ :acl ] if options[ :acl ]
6
8
 
7
9
  body = nil
8
- location = region || @region
10
+ location = options[ :region ] || @region
9
11
 
10
12
  if location && location != 'us-east-1'
11
13
  body = <<~XML
@@ -9,9 +9,9 @@ module S3
9
9
  response.result
10
10
  end
11
11
 
12
- def bucket_create( bucket:, region: nil, acl: nil )
12
+ def bucket_create( options = nil, bucket:, **kwargs )
13
13
  request = BucketCreateRequest.new( **request_options )
14
- response = request.submit( bucket: bucket, region: region, acl: acl )
14
+ response = request.submit( options, bucket: bucket, **kwargs )
15
15
 
16
16
  raise_if_error( response )
17
17
 
@@ -0,0 +1,22 @@
1
+ module S3
2
+ class MultipartCreateOptions
3
+ include SchemaOptions
4
+
5
+ STORAGE_CLASSES = %w[
6
+ STANDARD REDUCED_REDUNDANCY STANDARD_IA ONEZONE_IA
7
+ INTELLIGENT_TIERING GLACIER DEEP_ARCHIVE GLACIER_IR
8
+ ].freeze
9
+
10
+ CANNED_ACLS = %w[
11
+ private public-read public-read-write authenticated-read
12
+ aws-exec-read bucket-owner-read bucket-owner-full-control
13
+ ].freeze
14
+
15
+ schema do
16
+ metadata Hash
17
+ content_type String
18
+ acl [ String, Symbol ], normalize: ->( v ) { v.to_s.downcase.tr( '_', '-' ) }
19
+ storage_class [ String, Symbol ], normalize: ->( v ) { v.to_s.upcase.tr( '-', '_' ) }
20
+ end
21
+ end
22
+ end
@@ -1,15 +1,17 @@
1
1
  module S3
2
2
  class MultipartCreateRequest < Request
3
- def submit( bucket:, key:, metadata: nil, content_type: nil, acl: nil, storage_class: nil )
3
+ def submit( options = nil, bucket:, key:, **kwargs )
4
4
  path = "/#{ bucket }/#{ Helpers.encode_key( key ) }"
5
5
  query = 'uploads='
6
6
 
7
+ options = merge_options( options, kwargs, MultipartCreateOptions )
8
+
7
9
  headers = {}
8
- headers[ 'Content-Type' ] = content_type if content_type
9
- headers[ 'x-amz-acl' ] = acl if acl
10
- headers[ 'x-amz-storage-class' ] = storage_class if storage_class
10
+ headers[ 'Content-Type' ] = options[ :content_type ] if options[ :content_type ]
11
+ headers[ 'x-amz-acl' ] = options[ :acl ] if options[ :acl ]
12
+ headers[ 'x-amz-storage-class' ] = options[ :storage_class ] if options[ :storage_class ]
11
13
 
12
- metadata&.each do | meta_key, value |
14
+ options[ :metadata ]&.each do | meta_key, value |
13
15
  headers[ "x-amz-meta-#{ meta_key }" ] = value.to_s
14
16
  end
15
17
 
@@ -0,0 +1,12 @@
1
+ module S3
2
+ class MultipartListOptions
3
+ include SchemaOptions
4
+
5
+ schema do
6
+ prefix String
7
+ key_marker String
8
+ upload_id_marker String
9
+ max_uploads Integer
10
+ end
11
+ end
12
+ end
@@ -1,13 +1,15 @@
1
1
  module S3
2
2
  class MultipartListRequest < Request
3
- def submit( bucket:, prefix: nil, key_marker: nil, upload_id_marker: nil, max_uploads: nil )
3
+ def submit( options = nil, bucket:, **kwargs )
4
4
  path = "/#{ bucket }"
5
5
 
6
+ options = merge_options( options, kwargs, MultipartListOptions )
7
+
6
8
  params = { 'uploads' => '' }
7
- params[ 'prefix' ] = prefix if prefix
8
- params[ 'key-marker' ] = key_marker if key_marker
9
- params[ 'upload-id-marker' ] = upload_id_marker if upload_id_marker
10
- params[ 'max-uploads' ] = max_uploads.to_s if max_uploads
9
+ params[ 'prefix' ] = options[ :prefix ] if options[ :prefix ]
10
+ params[ 'key-marker' ] = options[ :key_marker ] if options[ :key_marker ]
11
+ params[ 'upload-id-marker' ] = options[ :upload_id_marker ] if options[ :upload_id_marker ]
12
+ params[ 'max-uploads' ] = options[ :max_uploads ].to_s if options[ :max_uploads ]
11
13
 
12
14
  query = Helpers.build_query_string( params )
13
15
 
@@ -1,15 +1,8 @@
1
1
  module S3
2
2
  module MultipartMethods
3
- def multipart_create( bucket:, key:, metadata: nil, content_type: nil, acl: nil, storage_class: nil )
3
+ def multipart_create( options = nil, bucket:, key:, **kwargs )
4
4
  request = MultipartCreateRequest.new( **request_options )
5
- response = request.submit(
6
- bucket: bucket,
7
- key: key,
8
- metadata: metadata,
9
- content_type: content_type,
10
- acl: acl,
11
- storage_class: storage_class
12
- )
5
+ response = request.submit( options, bucket: bucket, key: key, **kwargs )
13
6
 
14
7
  raise_if_error( response )
15
8
 
@@ -54,30 +47,18 @@ module S3
54
47
  response.result
55
48
  end
56
49
 
57
- def multipart_list( bucket:, prefix: nil, key_marker: nil, upload_id_marker: nil, max_uploads: nil )
50
+ def multipart_list( options = nil, bucket:, **kwargs )
58
51
  request = MultipartListRequest.new( **request_options )
59
- response = request.submit(
60
- bucket: bucket,
61
- prefix: prefix,
62
- key_marker: key_marker,
63
- upload_id_marker: upload_id_marker,
64
- max_uploads: max_uploads
65
- )
52
+ response = request.submit( options, bucket: bucket, **kwargs )
66
53
 
67
54
  raise_if_error( response )
68
55
 
69
56
  response.result
70
57
  end
71
58
 
72
- def multipart_parts( bucket:, key:, upload_id:, part_number_marker: nil, max_parts: nil )
59
+ def multipart_parts( options = nil, bucket:, key:, upload_id:, **kwargs )
73
60
  request = MultipartPartsRequest.new( **request_options )
74
- response = request.submit(
75
- bucket: bucket,
76
- key: key,
77
- upload_id: upload_id,
78
- part_number_marker: part_number_marker,
79
- max_parts: max_parts
80
- )
61
+ response = request.submit( options, bucket: bucket, key: key, upload_id: upload_id, **kwargs )
81
62
 
82
63
  raise_if_error( response )
83
64
 
@@ -0,0 +1,10 @@
1
+ module S3
2
+ class MultipartPartsOptions
3
+ include SchemaOptions
4
+
5
+ schema do
6
+ part_number_marker Integer
7
+ max_parts Integer
8
+ end
9
+ end
10
+ end
@@ -1,11 +1,13 @@
1
1
  module S3
2
2
  class MultipartPartsRequest < Request
3
- def submit( bucket:, key:, upload_id:, part_number_marker: nil, max_parts: nil )
3
+ def submit( options = nil, bucket:, key:, upload_id:, **kwargs )
4
4
  path = "/#{ bucket }/#{ Helpers.encode_key( key ) }"
5
5
 
6
+ options = merge_options( options, kwargs, MultipartPartsOptions )
7
+
6
8
  params = { 'uploadId' => upload_id }
7
- params[ 'part-number-marker' ] = part_number_marker.to_s if part_number_marker
8
- params[ 'max-parts' ] = max_parts.to_s if max_parts
9
+ params[ 'part-number-marker' ] = options[ :part_number_marker ].to_s if options[ :part_number_marker ]
10
+ params[ 'max-parts' ] = options[ :max_parts ].to_s if options[ :max_parts ]
9
11
 
10
12
  query = Helpers.build_query_string( params )
11
13
 
@@ -15,6 +15,7 @@ module S3
15
15
  ].freeze
16
16
 
17
17
  schema do
18
+ metadata Hash
18
19
  metadata_directive [ String, Symbol ], normalize: ->( v ) { v.to_s.upcase }
19
20
  storage_class [ String, Symbol ], normalize: ->( v ) { v.to_s.upcase.tr( '-', '_' ) }
20
21
  acl [ String, Symbol ], normalize: ->( v ) { v.to_s.downcase.tr( '_', '-' ) }
@@ -1,20 +1,19 @@
1
1
  module S3
2
2
  class ObjectCopyRequest < Request
3
- def submit( source_bucket:, source_key:, bucket:, key:, metadata: nil, options: nil )
3
+ def submit( options = nil, source_bucket:, source_key:, bucket:, key:, **kwargs )
4
4
  path = "/#{ bucket }/#{ Helpers.encode_key( key ) }"
5
5
 
6
6
  source = "/#{ source_bucket }/#{ Helpers.encode_key( source_key ) }"
7
7
 
8
- headers = { 'x-amz-copy-source' => source }
8
+ options = merge_options( options, kwargs, ObjectCopyOptions )
9
9
 
10
- if options
11
- headers[ 'x-amz-metadata-directive' ] = options[ :metadata_directive ] if options[ :metadata_directive ]
12
- headers[ 'x-amz-storage-class' ] = options[ :storage_class ] if options[ :storage_class ]
13
- headers[ 'x-amz-acl' ] = options[ :acl ] if options[ :acl ]
14
- headers[ 'Content-Type' ] = options[ :content_type ] if options[ :content_type ]
15
- end
10
+ headers = { 'x-amz-copy-source' => source }
11
+ headers[ 'x-amz-metadata-directive' ] = options[ :metadata_directive ] if options[ :metadata_directive ]
12
+ headers[ 'x-amz-storage-class' ] = options[ :storage_class ] if options[ :storage_class ]
13
+ headers[ 'x-amz-acl' ] = options[ :acl ] if options[ :acl ]
14
+ headers[ 'Content-Type' ] = options[ :content_type ] if options[ :content_type ]
16
15
 
17
- metadata&.each do | meta_key, value |
16
+ options[ :metadata ]&.each do | meta_key, value |
18
17
  headers[ "x-amz-meta-#{ meta_key }" ] = value.to_s
19
18
  end
20
19
 
@@ -0,0 +1,13 @@
1
+ module S3
2
+ class ObjectListOptions
3
+ include SchemaOptions
4
+
5
+ schema do
6
+ prefix String
7
+ delimiter String
8
+ max_keys Integer
9
+ continuation_token String
10
+ start_after String
11
+ end
12
+ end
13
+ end
@@ -1,13 +1,14 @@
1
1
  module S3
2
2
  class ObjectListRequest < Request
3
- def submit( bucket:, prefix: nil, delimiter: nil, max_keys: nil,
4
- continuation_token: nil, start_after: nil )
3
+ def submit( options = nil, bucket:, **kwargs )
4
+ options = merge_options( options, kwargs, ObjectListOptions )
5
+
5
6
  params = { 'list-type' => '2' }
6
- params[ 'prefix' ] = prefix if prefix
7
- params[ 'delimiter' ] = delimiter if delimiter
8
- params[ 'max-keys' ] = max_keys.to_s if max_keys
9
- params[ 'continuation-token' ] = continuation_token if continuation_token
10
- params[ 'start-after' ] = start_after if start_after
7
+ params[ 'prefix' ] = options[ :prefix ] if options[ :prefix ]
8
+ params[ 'delimiter' ] = options[ :delimiter ] if options[ :delimiter ]
9
+ params[ 'max-keys' ] = options[ :max_keys ].to_s if options[ :max_keys ]
10
+ params[ 'continuation-token' ] = options[ :continuation_token ] if options[ :continuation_token ]
11
+ params[ 'start-after' ] = options[ :start_after ] if options[ :start_after ]
11
12
 
12
13
  query = Helpers.build_query_string( params )
13
14
 
@@ -1,16 +1,8 @@
1
1
  module S3
2
2
  module ObjectMethods
3
- def object_list( bucket:, prefix: nil, delimiter: nil, max_keys: nil,
4
- continuation_token: nil, start_after: nil )
3
+ def object_list( options = nil, bucket:, **kwargs )
5
4
  request = ObjectListRequest.new( **request_options )
6
- response = request.submit(
7
- bucket: bucket,
8
- prefix: prefix,
9
- delimiter: delimiter,
10
- max_keys: max_keys,
11
- continuation_token: continuation_token,
12
- start_after: start_after
13
- )
5
+ response = request.submit( options, bucket: bucket, **kwargs )
14
6
 
15
7
  raise_if_error( response )
16
8
 
@@ -31,29 +23,9 @@ module S3
31
23
  end
32
24
  end
33
25
 
34
- def object_put( bucket:, key:, body:, metadata: nil, content_type: nil,
35
- acl: nil, storage_class: nil, cache_control: nil,
36
- content_disposition: nil, content_encoding: nil,
37
- content_language: nil, expires: nil )
38
- options = ObjectPutOptions.build(
39
- content_type: content_type,
40
- acl: acl,
41
- storage_class: storage_class,
42
- cache_control: cache_control,
43
- content_disposition: content_disposition,
44
- content_encoding: content_encoding,
45
- content_language: content_language,
46
- expires: expires
47
- )
48
-
26
+ def object_put( options = nil, bucket:, key:, body:, **kwargs )
49
27
  request = ObjectPutRequest.new( **request_options )
50
- response = request.submit(
51
- bucket: bucket,
52
- key: key,
53
- body: body,
54
- metadata: metadata,
55
- options: options
56
- )
28
+ response = request.submit( options, bucket: bucket, key: key, body: body, **kwargs )
57
29
 
58
30
  raise_if_error( response )
59
31
 
@@ -93,24 +65,15 @@ module S3
93
65
  !object_head( bucket: bucket, key: key ).nil?
94
66
  end
95
67
 
96
- def object_copy( source_bucket:, source_key:, bucket:, key:,
97
- metadata: nil, metadata_directive: nil,
98
- storage_class: nil, acl: nil, content_type: nil )
99
- options = ObjectCopyOptions.build(
100
- metadata_directive: metadata_directive,
101
- storage_class: storage_class,
102
- acl: acl,
103
- content_type: content_type
104
- )
105
-
68
+ def object_copy( options = nil, source_bucket:, source_key:, bucket:, key:, **kwargs )
106
69
  request = ObjectCopyRequest.new( **request_options )
107
70
  response = request.submit(
71
+ options,
108
72
  source_bucket: source_bucket,
109
73
  source_key: source_key,
110
74
  bucket: bucket,
111
75
  key: key,
112
- metadata: metadata,
113
- options: options
76
+ **kwargs
114
77
  )
115
78
 
116
79
  raise_if_error( response )
@@ -13,6 +13,7 @@ module S3
13
13
  ].freeze
14
14
 
15
15
  schema do
16
+ metadata Hash
16
17
  content_type String
17
18
  acl [ String, Symbol ], normalize: ->( v ) { v.to_s.downcase.tr( '_', '-' ) }
18
19
  storage_class [ String, Symbol ], normalize: ->( v ) { v.to_s.upcase.tr( '-', '_' ) }
@@ -1,21 +1,21 @@
1
1
  module S3
2
2
  class ObjectPutRequest < Request
3
- def submit( bucket:, key:, body:, metadata: nil, options: nil )
3
+ def submit( options = nil, bucket:, key:, body:, **kwargs )
4
4
  path = "/#{ bucket }/#{ Helpers.encode_key( key ) }"
5
5
 
6
+ options = merge_options( options, kwargs, ObjectPutOptions )
7
+
6
8
  headers = {}
7
- if options
8
- headers[ 'Content-Type' ] = options[ :content_type ] if options[ :content_type ]
9
- headers[ 'x-amz-acl' ] = options[ :acl ] if options[ :acl ]
10
- headers[ 'x-amz-storage-class' ] = options[ :storage_class ] if options[ :storage_class ]
11
- headers[ 'Cache-Control' ] = options[ :cache_control ] if options[ :cache_control ]
12
- headers[ 'Content-Disposition' ] = options[ :content_disposition ] if options[ :content_disposition ]
13
- headers[ 'Content-Encoding' ] = options[ :content_encoding ] if options[ :content_encoding ]
14
- headers[ 'Content-Language' ] = options[ :content_language ] if options[ :content_language ]
15
- headers[ 'Expires' ] = options[ :expires ].httpdate if options[ :expires ]
16
- end
9
+ headers[ 'Content-Type' ] = options[ :content_type ] if options[ :content_type ]
10
+ headers[ 'x-amz-acl' ] = options[ :acl ] if options[ :acl ]
11
+ headers[ 'x-amz-storage-class' ] = options[ :storage_class ] if options[ :storage_class ]
12
+ headers[ 'Cache-Control' ] = options[ :cache_control ] if options[ :cache_control ]
13
+ headers[ 'Content-Disposition' ] = options[ :content_disposition ] if options[ :content_disposition ]
14
+ headers[ 'Content-Encoding' ] = options[ :content_encoding ] if options[ :content_encoding ]
15
+ headers[ 'Content-Language' ] = options[ :content_language ] if options[ :content_language ]
16
+ headers[ 'Expires' ] = options[ :expires ].httpdate if options[ :expires ]
17
17
 
18
- metadata&.each do | meta_key, value |
18
+ options[ :metadata ]&.each do | meta_key, value |
19
19
  headers[ "x-amz-meta-#{ meta_key }" ] = value.to_s
20
20
  end
21
21
 
@@ -0,0 +1,11 @@
1
+ module S3
2
+ class PresignGetOptions
3
+ include SchemaOptions
4
+
5
+ schema do
6
+ expires_in Integer
7
+ response_content_type String
8
+ response_content_disposition String
9
+ end
10
+ end
11
+ end
@@ -2,13 +2,15 @@ module S3
2
2
  class PresignGetRequest < Request
3
3
  DEFAULT_EXPIRES_IN = 3600
4
4
 
5
- def submit( bucket:, key:, expires_in: nil, response_content_type: nil, response_content_disposition: nil )
6
- expires_in ||= DEFAULT_EXPIRES_IN
5
+ def submit( options = nil, bucket:, key:, **kwargs )
6
+ options = merge_options( options, kwargs, PresignGetOptions )
7
+
8
+ expires_in = options[ :expires_in ] || DEFAULT_EXPIRES_IN
7
9
  path = "/#{ bucket }/#{ Helpers.encode_key( key ) }"
8
10
 
9
11
  generate_presigned_url( :get, path, expires_in: expires_in,
10
- response_content_type: response_content_type,
11
- response_content_disposition: response_content_disposition )
12
+ response_content_type: options[ :response_content_type ],
13
+ response_content_disposition: options[ :response_content_disposition ] )
12
14
  end
13
15
 
14
16
  private
@@ -1,24 +1,13 @@
1
1
  module S3
2
2
  module PresignMethods
3
- def presign_get( bucket:, key:, expires_in: nil, response_content_type: nil, response_content_disposition: nil )
3
+ def presign_get( options = nil, bucket:, key:, **kwargs )
4
4
  request = PresignGetRequest.new( **request_options )
5
- request.submit(
6
- bucket: bucket,
7
- key: key,
8
- expires_in: expires_in,
9
- response_content_type: response_content_type,
10
- response_content_disposition: response_content_disposition
11
- )
5
+ request.submit( options, bucket: bucket, key: key, **kwargs )
12
6
  end
13
7
 
14
- def presign_put( bucket:, key:, expires_in: nil, content_type: nil )
8
+ def presign_put( options = nil, bucket:, key:, **kwargs )
15
9
  request = PresignPutRequest.new( **request_options )
16
- request.submit(
17
- bucket: bucket,
18
- key: key,
19
- expires_in: expires_in,
20
- content_type: content_type
21
- )
10
+ request.submit( options, bucket: bucket, key: key, **kwargs )
22
11
  end
23
12
  end
24
13
  end
@@ -0,0 +1,10 @@
1
+ module S3
2
+ class PresignPutOptions
3
+ include SchemaOptions
4
+
5
+ schema do
6
+ expires_in Integer
7
+ content_type String
8
+ end
9
+ end
10
+ end
@@ -2,11 +2,13 @@ module S3
2
2
  class PresignPutRequest < Request
3
3
  DEFAULT_EXPIRES_IN = 3600
4
4
 
5
- def submit( bucket:, key:, expires_in: nil, content_type: nil )
6
- expires_in ||= DEFAULT_EXPIRES_IN
5
+ def submit( options = nil, bucket:, key:, **kwargs )
6
+ options = merge_options( options, kwargs, PresignPutOptions )
7
+
8
+ expires_in = options[ :expires_in ] || DEFAULT_EXPIRES_IN
7
9
  path = "/#{ bucket }/#{ Helpers.encode_key( key ) }"
8
10
 
9
- generate_presigned_url( :put, path, expires_in: expires_in, content_type: content_type )
11
+ generate_presigned_url( :put, path, expires_in: expires_in, content_type: options[ :content_type ] )
10
12
  end
11
13
 
12
14
  private
data/lib/s3/request.rb CHANGED
@@ -163,5 +163,16 @@ module S3
163
163
  faraday.options.timeout = 300
164
164
  end
165
165
  end
166
+
167
+ def merge_options( options, kwargs, options_class )
168
+ # support options as positional arg, keyword arg, or both (merged)
169
+ # precedence: positional < options: kwarg < other kwargs
170
+ kwargs_options = kwargs.delete( :options )
171
+ options = options.is_a?( Hash ) ? options_class.build( options ) : options
172
+ kwargs_options = kwargs_options.is_a?( Hash ) ? options_class.build( kwargs_options ) : kwargs_options
173
+ ( options&.to_h || {} )
174
+ .merge( kwargs_options&.to_h || {} )
175
+ .merge( options_class.build( kwargs ).to_h )
176
+ end
166
177
  end
167
178
  end
data/lib/s3/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module S3
2
- VERSION = '1.0.0'
2
+ VERSION = '1.1.0'
3
3
  end
data/lib/s3.rb CHANGED
@@ -15,17 +15,20 @@ require_relative 's3/response_methods'
15
15
  require_relative 's3/error_result'
16
16
  require_relative 's3/request'
17
17
 
18
+ require_relative 's3/schema_options'
19
+
18
20
  require_relative 's3/bucket_list_request'
19
21
  require_relative 's3/bucket_list_result'
22
+ require_relative 's3/bucket_create_options'
20
23
  require_relative 's3/bucket_create_request'
21
24
  require_relative 's3/bucket_delete_request'
22
25
  require_relative 's3/bucket_head_request'
23
26
  require_relative 's3/bucket_head_result'
24
27
 
28
+ require_relative 's3/object_list_options'
25
29
  require_relative 's3/object_list_request'
26
30
  require_relative 's3/object_list_result'
27
31
  require_relative 's3/object_get_request'
28
- require_relative 's3/schema_options'
29
32
  require_relative 's3/object_put_options'
30
33
  require_relative 's3/object_put_request'
31
34
  require_relative 's3/object_put_result'
@@ -38,6 +41,7 @@ require_relative 's3/object_copy_options'
38
41
  require_relative 's3/object_copy_request'
39
42
  require_relative 's3/object_copy_result'
40
43
 
44
+ require_relative 's3/multipart_create_options'
41
45
  require_relative 's3/multipart_create_request'
42
46
  require_relative 's3/multipart_create_result'
43
47
  require_relative 's3/multipart_upload_request'
@@ -46,12 +50,16 @@ require_relative 's3/multipart_complete_options'
46
50
  require_relative 's3/multipart_complete_request'
47
51
  require_relative 's3/multipart_complete_result'
48
52
  require_relative 's3/multipart_abort_request'
53
+ require_relative 's3/multipart_list_options'
49
54
  require_relative 's3/multipart_list_request'
50
55
  require_relative 's3/multipart_list_result'
56
+ require_relative 's3/multipart_parts_options'
51
57
  require_relative 's3/multipart_parts_request'
52
58
  require_relative 's3/multipart_parts_result'
53
59
 
60
+ require_relative 's3/presign_get_options'
54
61
  require_relative 's3/presign_get_request'
62
+ require_relative 's3/presign_put_options'
55
63
  require_relative 's3/presign_put_request'
56
64
 
57
65
  require_relative 's3/bucket_methods'
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: s3-rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kristoph Cichocki-Romanov
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2026-02-02 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: faraday
@@ -158,12 +157,14 @@ executables: []
158
157
  extensions: []
159
158
  extra_rdoc_files: []
160
159
  files:
160
+ - CHANGELOG.md
161
161
  - Gemfile
162
162
  - Gemfile.lock
163
163
  - README.md
164
164
  - Rakefile
165
165
  - lib/s3-rb.rb
166
166
  - lib/s3.rb
167
+ - lib/s3/bucket_create_options.rb
167
168
  - lib/s3/bucket_create_request.rb
168
169
  - lib/s3/bucket_delete_request.rb
169
170
  - lib/s3/bucket_head_request.rb
@@ -179,11 +180,14 @@ files:
179
180
  - lib/s3/multipart_complete_options.rb
180
181
  - lib/s3/multipart_complete_request.rb
181
182
  - lib/s3/multipart_complete_result.rb
183
+ - lib/s3/multipart_create_options.rb
182
184
  - lib/s3/multipart_create_request.rb
183
185
  - lib/s3/multipart_create_result.rb
186
+ - lib/s3/multipart_list_options.rb
184
187
  - lib/s3/multipart_list_request.rb
185
188
  - lib/s3/multipart_list_result.rb
186
189
  - lib/s3/multipart_methods.rb
190
+ - lib/s3/multipart_parts_options.rb
187
191
  - lib/s3/multipart_parts_request.rb
188
192
  - lib/s3/multipart_parts_result.rb
189
193
  - lib/s3/multipart_upload_request.rb
@@ -197,14 +201,17 @@ files:
197
201
  - lib/s3/object_get_request.rb
198
202
  - lib/s3/object_head_request.rb
199
203
  - lib/s3/object_head_result.rb
204
+ - lib/s3/object_list_options.rb
200
205
  - lib/s3/object_list_request.rb
201
206
  - lib/s3/object_list_result.rb
202
207
  - lib/s3/object_methods.rb
203
208
  - lib/s3/object_put_options.rb
204
209
  - lib/s3/object_put_request.rb
205
210
  - lib/s3/object_put_result.rb
211
+ - lib/s3/presign_get_options.rb
206
212
  - lib/s3/presign_get_request.rb
207
213
  - lib/s3/presign_methods.rb
214
+ - lib/s3/presign_put_options.rb
208
215
  - lib/s3/presign_put_request.rb
209
216
  - lib/s3/request.rb
210
217
  - lib/s3/response_methods.rb
@@ -223,7 +230,6 @@ metadata:
223
230
  homepage_uri: https://github.com/EndlessInternational/s3-rb
224
231
  source_code_uri: https://github.com/EndlessInternational/s3-rb
225
232
  changelog_uri: https://github.com/EndlessInternational/s3-rb/blob/main/CHANGELOG.md
226
- post_install_message:
227
233
  rdoc_options: []
228
234
  require_paths:
229
235
  - lib
@@ -238,8 +244,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
238
244
  - !ruby/object:Gem::Version
239
245
  version: '0'
240
246
  requirements: []
241
- rubygems_version: 3.5.22
242
- signing_key:
247
+ rubygems_version: 3.6.7
243
248
  specification_version: 4
244
249
  summary: A lightweight, low dependency, high performance, 'bare metal' S3 API gem.
245
250
  test_files: []