attachie 1.0.0 → 1.1.2

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: 2a6322baba1a72a9869ed2cb50a2f58a890fed49a5b1fbfb57c6e358dfcce4b2
4
- data.tar.gz: 7e95e247cf920af92fd51d32b21bf2d0a82a59af022cacc1343a2bb71612d5b7
3
+ metadata.gz: 1e46dfdb8f2b5d9b94594ca38b5d72b3164a7659ce165f6e5f328ee72275ee5a
4
+ data.tar.gz: d88df51754ce79dc3f716b0e5ccbd7fc4853bde2b92dbf75a85bc65dbb5b83ae
5
5
  SHA512:
6
- metadata.gz: ef797be58fb2573636f3cfc9de41fc1484cc8f6357488e7d1699ed5288a79b3c2ca0a51795ab825ce8941f05c69986dd84dd05b1861493ef74c8cc1afb5a1cd6
7
- data.tar.gz: e986a15bc1a7781d4d60f620949582ae455c0dc6374c818930c7990a430bc9cbc4740d14cb2b0a60865769c084b7bc5bbce9c55f5aa1cabb0a10790704767745
6
+ metadata.gz: 8f92ec31c86801736cdc8cd6c2cd7265ed6054d48e796d3961c00490b1e8a79cdfaeefddc4746c2d3d714e0659f95ab0e1873331b3d6835acf0eaf47ed9dca4f
7
+ data.tar.gz: 2495f460854161a8e241c67babb8bd7eb72bf63bbaabd04b867a195e106207e6fbd5701c687acf8909bac241adecc25e32e571660d904ccebc32b3edd287d327
@@ -0,0 +1,27 @@
1
+ name: test
2
+ on: [push, pull_request]
3
+ jobs:
4
+ build:
5
+ runs-on: ubuntu-latest
6
+ strategy:
7
+ matrix:
8
+ ruby: ['2.5', '2.6', '2.7']
9
+ services:
10
+ fake-s3:
11
+ image: lphoward/fake-s3
12
+ ports:
13
+ - 4569:4569
14
+ steps:
15
+ - uses: actions/checkout@v1
16
+ - uses: actions/setup-ruby@v1
17
+ with:
18
+ ruby-version: ${{ matrix.ruby }}
19
+ - uses: actions/cache@v1
20
+ id: cache
21
+ with:
22
+ path: vendor/bundler
23
+ key: ${{ hashFiles('Gemfile.lock') }}-${{ matrix.ruby }}
24
+ - run: |
25
+ gem install bundler
26
+ bundle install --path=vendor/bundler
27
+ bundle exec rspec
data/CHANGELOG.md ADDED
@@ -0,0 +1,18 @@
1
+ # CHANGELOG
2
+
3
+ ## 1.1.2
4
+ ### Fixed
5
+ * Make `FakeDriver` thread-safe
6
+ * Sort objects in `FakeDriver#list` by key
7
+
8
+ ## 1.1.1
9
+ ### Fixed
10
+ * Use `mkdir_p` in `FileDriver#download`
11
+
12
+ ## 1.1.0
13
+ ### Added
14
+ * Added a download method to download files to a specific path
15
+
16
+ ## 1.0.1
17
+ ### Fixed
18
+ * dup list result in FakeDriver before iterating
data/README.md CHANGED
@@ -70,6 +70,7 @@ user.avatar(:icon).delete
70
70
  user.avatar(:icon).exists?
71
71
  user.avatar(:icon).value
72
72
  user.avatar(:icon).temp_url(expires_in: 2.days) # Must be supported by the driver
73
+ user.avator(:icon).download("/path/to/destination")
73
74
  ```
74
75
 
75
76
  ## Drivers
data/lib/attachie.rb CHANGED
@@ -59,6 +59,10 @@ module Attachie
59
59
  option(:driver).store(path, data_or_io, container, opts)
60
60
  end
61
61
 
62
+ def download(dest_path)
63
+ option(:driver).download(path, container, dest_path)
64
+ end
65
+
62
66
  def info
63
67
  option(:driver).info(path, container)
64
68
  end
@@ -32,22 +32,28 @@ module Attachie
32
32
  end
33
33
 
34
34
  class FakeDriver
35
+ include MonitorMixin
36
+
35
37
  class ItemNotFound < StandardError; end
36
38
 
37
39
  def list(bucket, prefix: nil)
38
40
  return enum_for(:list, bucket, prefix: prefix) unless block_given?
39
41
 
40
- objects(bucket).each do |key, _|
41
- yield key if prefix.nil? || key.start_with?(prefix)
42
+ synchronize do
43
+ objects(bucket).sort { |a, b| a[0] <=> b[0] }.each do |key, _|
44
+ yield key if prefix.nil? || key.start_with?(prefix)
45
+ end
42
46
  end
43
47
  end
44
48
 
45
49
  def info(name, bucket)
46
- {
47
- last_modified: nil,
48
- content_length: objects(bucket)[name].size,
49
- content_type: MIME::Types.of(name).first&.to_s
50
- }
50
+ synchronize do
51
+ {
52
+ last_modified: nil,
53
+ content_length: objects(bucket)[name].size,
54
+ content_type: MIME::Types.of(name).first&.to_s
55
+ }
56
+ end
51
57
  end
52
58
 
53
59
  def presigned_post(name, bucket, options = {})
@@ -55,40 +61,60 @@ module Attachie
55
61
  end
56
62
 
57
63
  def store(name, data_or_io, bucket, options = {})
58
- objects(bucket)[name] = data_or_io.respond_to?(:read) ? data_or_io.read : data_or_io
64
+ synchronize do
65
+ objects(bucket)[name] = data_or_io.respond_to?(:read) ? data_or_io.read : data_or_io
66
+ end
59
67
  end
60
68
 
61
69
  def store_multipart(name, bucket, options = {}, &block)
62
- objects(bucket)[name] = FakeMultipartUpload.new(name, bucket, options, &block).data
70
+ synchronize do
71
+ objects(bucket)[name] = FakeMultipartUpload.new(name, bucket, options, &block).data
72
+ end
63
73
  end
64
74
 
65
75
  def exists?(name, bucket)
66
- objects(bucket).key?(name)
76
+ synchronize do
77
+ objects(bucket).key?(name)
78
+ end
67
79
  end
68
80
 
69
81
  def delete(name, bucket)
70
- objects(bucket).delete(name)
82
+ synchronize do
83
+ objects(bucket).delete(name)
84
+ end
71
85
  end
72
86
 
73
87
  def value(name, bucket)
74
- raise(ItemNotFound) unless objects(bucket).key?(name)
88
+ synchronize do
89
+ raise(ItemNotFound) unless objects(bucket).key?(name)
75
90
 
76
- objects(bucket)[name]
91
+ objects(bucket)[name]
92
+ end
77
93
  end
78
94
 
95
+ def download(name, bucket, path)
96
+ content = value(name, bucket)
97
+
98
+ open(path, "wb") { |stream| stream.write(content) }
99
+ end
100
+
79
101
  def temp_url(name, bucket, options = {})
80
102
  "https://example.com/#{bucket}/#{name}?signature=signature&expires=expires"
81
103
  end
82
104
 
83
105
  def flush
84
- @objects = {}
106
+ synchronize do
107
+ @objects = {}
108
+ end
85
109
  end
86
110
 
87
111
  private
88
112
 
89
113
  def objects(bucket)
90
- @objects ||= {}
91
- @objects[bucket] ||= {}
114
+ synchronize do
115
+ @objects ||= {}
116
+ @objects[bucket] ||= {}
117
+ end
92
118
  end
93
119
  end
94
120
  end
@@ -89,6 +89,14 @@ module Attachie
89
89
  File.binread path_for(name, bucket)
90
90
  end
91
91
 
92
+ def download(name, bucket, dest_path)
93
+ path = path_for(name, bucket)
94
+
95
+ FileUtils.mkdir_p File.dirname(path)
96
+
97
+ FileUtils.cp(path, dest_path)
98
+ end
99
+
92
100
  def delete(name, bucket)
93
101
  path = path_for(name, bucket)
94
102
 
@@ -114,6 +114,10 @@ module Attachie
114
114
  s3_resource.bucket(bucket).object(name).get.body.read.force_encoding(Encoding::BINARY)
115
115
  end
116
116
 
117
+ def download(name, bucket, path)
118
+ s3_resource.bucket(bucket).object(name).download_file(path)
119
+ end
120
+
117
121
  def delete(name, bucket)
118
122
  s3_resource.bucket(bucket).object(name).delete
119
123
  end
@@ -1,3 +1,3 @@
1
1
  module Attachie
2
- VERSION = "1.0.0"
2
+ VERSION = "1.1.2"
3
3
  end
@@ -21,6 +21,14 @@ RSpec.describe Attachie::FakeDriver do
21
21
 
22
22
  expect(driver.list("bucket1", prefix: "object").to_a).to eq(["object1", "object2"])
23
23
  end
24
+
25
+ it "sorts the objects by key" do
26
+ driver.store("object2", "blob", "bucket")
27
+ driver.store("object1", "blob", "bucket")
28
+ driver.store("object3", "blob", "bucket")
29
+
30
+ expect(driver.list("bucket").to_a).to eq(["object1", "object2", "object3"])
31
+ end
24
32
  end
25
33
 
26
34
  describe "#store" do
@@ -32,6 +40,21 @@ RSpec.describe Attachie::FakeDriver do
32
40
  end
33
41
  end
34
42
 
43
+ describe "#download" do
44
+ it "downloads the blob to the specified path" do
45
+ tempfile = Tempfile.new
46
+
47
+ begin
48
+ driver.store("name", "blob", "bucket")
49
+ driver.download("name", "bucket", tempfile.path)
50
+
51
+ expect(tempfile.read).to eq("blob")
52
+ ensure
53
+ tempfile.close(true)
54
+ end
55
+ end
56
+ end
57
+
35
58
  describe "#store_multipart" do
36
59
  it "stores a blob via multipart upload" do
37
60
  driver.store_multipart("name", "bucket") do |upload|
@@ -23,6 +23,22 @@ RSpec.describe Attachie::FileDriver do
23
23
  end
24
24
  end
25
25
 
26
+ describe "#download" do
27
+ it "downloads the blob to the specified path" do
28
+ tempfile = Tempfile.new
29
+
30
+ begin
31
+ driver.store("name", "blob", "bucket")
32
+ driver.download("name", "bucket", tempfile.path)
33
+
34
+ expect(tempfile.read).to eq("blob")
35
+ ensure
36
+ driver.delete("name", "bucket")
37
+ tempfile.close(true)
38
+ end
39
+ end
40
+ end
41
+
26
42
  describe" #store_multipart" do
27
43
  it "stores a blob via multipart upload" do
28
44
  begin
@@ -7,6 +7,7 @@ RSpec.describe Attachie::S3Driver do
7
7
  access_key_id: "access_key_id",
8
8
  secret_access_key: "secret_access_key",
9
9
  endpoint: "http://localhost:4569",
10
+ force_path_style: true,
10
11
  region: "us-east-1"
11
12
  ))
12
13
  end
@@ -40,6 +41,22 @@ RSpec.describe Attachie::S3Driver do
40
41
  end
41
42
  end
42
43
 
44
+ describe "#download" do
45
+ it "downloads the blob to the specified path" do
46
+ tempfile = Tempfile.new
47
+
48
+ begin
49
+ driver.store("name", "blob", "bucket")
50
+ driver.download("name", "bucket", tempfile.path)
51
+
52
+ expect(tempfile.read).to eq("blob")
53
+ ensure
54
+ driver.delete("name", "bucket")
55
+ tempfile.close(true)
56
+ end
57
+ end
58
+ end
59
+
43
60
  describe "#store_multipart" do
44
61
  it "stores a blob via multipart upload" do
45
62
  begin
@@ -82,7 +99,7 @@ RSpec.describe Attachie::S3Driver do
82
99
  fields: hash_including("key" => "path/to/object"),
83
100
  headers: {},
84
101
  method: "post",
85
- url: "http://bucket.localhost:4569"
102
+ url: "http://localhost:4569/bucket"
86
103
  )
87
104
  end
88
105
 
@@ -37,7 +37,7 @@ RSpec.describe TestModel do
37
37
 
38
38
  it "correctly uses the driver" do
39
39
  test_model = TestModel.new(filename: "blob.txt")
40
- test_model.file(:large).store "blob"
40
+ test_model.file(:large).store("blob")
41
41
 
42
42
  expect(test_model.file(:large).value).to eq("blob")
43
43
  end
@@ -54,6 +54,22 @@ RSpec.describe TestModel do
54
54
  expect(test_model.updated_at).to be_nil
55
55
  end
56
56
 
57
+ describe "#download" do
58
+ it "downloads the file to the specified path" do
59
+ tempfile = Tempfile.new
60
+
61
+ begin
62
+ test_model = TestModel.new(filename: "blob.txt")
63
+ test_model.file(:large).store("blob")
64
+ test_model.file(:large).download(tempfile.path)
65
+
66
+ expect(tempfile.read).to eq("blob")
67
+ ensure
68
+ tempfile.close(true)
69
+ end
70
+ end
71
+ end
72
+
57
73
  describe "#info" do
58
74
  it "returns info about the attachment" do
59
75
  test_model = TestModel.new(filename: "blob.txt")
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: attachie
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Benjamin Vetter
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-11-13 00:00:00.000000000 Z
11
+ date: 2021-08-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-s3
@@ -129,8 +129,9 @@ executables: []
129
129
  extensions: []
130
130
  extra_rdoc_files: []
131
131
  files:
132
+ - ".github/workflows/test.yml"
132
133
  - ".gitignore"
133
- - ".travis.yml"
134
+ - CHANGELOG.md
134
135
  - Gemfile
135
136
  - LICENSE.txt
136
137
  - README.md
@@ -168,8 +169,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
168
169
  - !ruby/object:Gem::Version
169
170
  version: '0'
170
171
  requirements: []
171
- rubyforge_project:
172
- rubygems_version: 2.7.3
172
+ rubygems_version: 3.0.3
173
173
  signing_key:
174
174
  specification_version: 4
175
175
  summary: Declarative and flexible attachments
data/.travis.yml DELETED
@@ -1,13 +0,0 @@
1
- sudo: false
2
- language: ruby
3
- rvm:
4
- - 2.3.3
5
- addons:
6
- hosts:
7
- - bucket.localhost
8
- before_install:
9
- - docker-compose up -d
10
- - sleep 10
11
- install:
12
- - travis_retry bundle install
13
- script: rspec