bfs 0.6.5 → 0.7.4

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: 42c7ec0b9c8599e48be9756f29d10f2f023cac4ed533567ce3e25f3b9ccdcbfc
4
- data.tar.gz: 2d63d874378606434e6311491c80b5993a21da95d465ec71c526e80faa2aa989
3
+ metadata.gz: c790272a036559149178dadb5932e424a90bbc535f842a298516457051912310
4
+ data.tar.gz: 9f673793872f84f34f4cd95fb396cac88d44d7fc338ac20888149303584790f1
5
5
  SHA512:
6
- metadata.gz: 05f54cb6d54163291b5c4ba7df49d3bb358aa9ac524d2b73492265a67635b864be8fd710a0f5a7eca10c7420d8060fe64483e28d5b135a4e1272bb11000ce8cf
7
- data.tar.gz: a4d43696270f615cd187952a88949b3e45fd3cfd0ad34a52d5cb2d8e52c1d50dba250d03a8bcb2f4ff85f1b12894ddcf464078555da98b0a13e3c8f962588a0d
6
+ metadata.gz: 53547ee9f745695a72196d8eb3d9b09054ea2d6cc106993bce0fe22d563e31cb67f450edc28424de2d9aa6b7f72126235dcd5a31c179b5c15c27ed739da21214
7
+ data.tar.gz: b6e0927840f82b058d2662e8b29e33fe9a6697b4219cf451c0ce49cb778e79070ce684ab8bc37e4f9dd2756898275fa872cd29d3dd20e175487649a216794f5b
@@ -15,5 +15,5 @@ Gem::Specification.new do |s|
15
15
  s.files = `git ls-files`.split("\n")
16
16
  s.test_files = `git ls-files -- spec/*`.split("\n")
17
17
  s.require_paths = ['lib']
18
- s.required_ruby_version = '>= 2.5.0'
18
+ s.required_ruby_version = '>= 2.6.0'
19
19
  end
data/lib/bfs.rb CHANGED
@@ -4,6 +4,8 @@ require 'cgi'
4
4
  module BFS
5
5
  class FileInfo < Hash
6
6
  def initialize(**attrs)
7
+ super(nil)
8
+
7
9
  update(size: 0, mtime: Time.at(0), mode: 0, metadata: {})
8
10
  update(attrs)
9
11
  end
@@ -36,11 +38,24 @@ module BFS
36
38
  def self.register(*schemes, &resolver)
37
39
  @registry ||= {}
38
40
  schemes.each do |scheme|
41
+ scheme = scheme.to_s
42
+ raise(ArgumentError, "scheme #{scheme} is already registered") if @registry.key?(scheme)
43
+
39
44
  @registry[scheme] = resolver
40
45
  end
41
46
  end
42
47
 
43
- def self.resolve(url)
48
+ def self.unregister(*schemes)
49
+ @registry ||= {}
50
+ schemes.each do |scheme|
51
+ scheme = scheme.to_s
52
+ raise(ArgumentError, "scheme #{scheme} is not registered") unless @registry.key?(scheme)
53
+
54
+ @registry.delete(scheme)
55
+ end
56
+ end
57
+
58
+ def self.resolve(url, &block)
44
59
  url = url.is_a?(::URI) ? url.dup : URI.parse(url)
45
60
  rsl = @registry[url.scheme]
46
61
  raise ArgumentError, "Unable to resolve #{url}, scheme #{url.scheme} is not registered" unless rsl
@@ -49,7 +64,7 @@ module BFS
49
64
  CGI.parse(url.query.to_s).each do |key, values|
50
65
  opts[key.to_sym] = values.first
51
66
  end
52
- rsl.call(url, opts)
67
+ rsl.call(url, opts, block)
53
68
  end
54
69
 
55
70
  def self.norm_path(path)
@@ -64,6 +79,11 @@ module BFS
64
79
  mode = mode.to_i(8) if mode.is_a?(String)
65
80
  mode & 0o000777
66
81
  end
82
+
83
+ def self.defer(obj, method)
84
+ owner = Process.pid
85
+ ObjectSpace.define_finalizer(obj, ->(*) { obj.send(method) if Process.pid == owner })
86
+ end
67
87
  end
68
88
 
69
89
  require 'bfs/helpers'
@@ -3,12 +3,27 @@ module BFS
3
3
  class Blob
4
4
  attr_reader :path
5
5
 
6
+ # Behaves like new, but accepts an optional block.
7
+ # If a block is given, blobs are automatically closed after the block is yielded.
8
+ def self.open(url)
9
+ blob = new(url)
10
+ return blob unless block_given?
11
+
12
+ begin
13
+ yield blob
14
+ ensure
15
+ blob.close
16
+ end
17
+ end
18
+
6
19
  def initialize(url)
7
20
  url = url.is_a?(::URI) ? url.dup : URI.parse(url)
8
21
  @path = BFS.norm_path(url.path)
9
22
 
10
23
  url.path = '/'
11
24
  @bucket = BFS.resolve(url)
25
+
26
+ BFS.defer(self, :close)
12
27
  end
13
28
 
14
29
  # Info returns the blob info.
@@ -34,7 +49,7 @@ module BFS
34
49
 
35
50
  # Shortcut method to read the contents of the blob.
36
51
  def read(**opts)
37
- open(**opts, &:read)
52
+ self.open(**opts, &:read)
38
53
  end
39
54
 
40
55
  # Shortcut method to write data to blob.
@@ -5,6 +5,19 @@ module BFS
5
5
  class Abstract
6
6
  attr_reader :encoding, :perm
7
7
 
8
+ # Behaves like new, but accepts an optional block.
9
+ # If a block is given, buckets are automatically closed after the block is yielded.
10
+ def self.open(*args, **opts)
11
+ bucket = new(*args, **opts)
12
+ return bucket unless block_given?
13
+
14
+ begin
15
+ yield bucket
16
+ ensure
17
+ bucket.close
18
+ end
19
+ end
20
+
8
21
  # Initializes a new bucket
9
22
  # @param [Hash] opts options
10
23
  # @option opts [String] :encoding Custom encoding. Default: Encoding.default_external.
@@ -18,6 +31,8 @@ module BFS
18
31
  when String
19
32
  @perm = perm.to_i(8)
20
33
  end
34
+
35
+ BFS.defer(self, :close)
21
36
  end
22
37
 
23
38
  # Lists the contents of a bucket using a glob pattern
@@ -51,7 +66,7 @@ module BFS
51
66
  # @param [String] path The path to read from.
52
67
  # @param [Hash] opts Additional options, see #open.
53
68
  def read(path, **opts)
54
- open(path, **opts, &:read)
69
+ self.open(path, **opts, &:read)
55
70
  end
56
71
 
57
72
  # Shortcut method to write data to path
@@ -68,7 +83,7 @@ module BFS
68
83
  # @param [String] src The source path.
69
84
  # @param [String] dst The destination path.
70
85
  def cp(src, dst, **opts)
71
- open(src, **opts) do |r|
86
+ self.open(src, **opts) do |r|
72
87
  create(dst, **opts) do |w|
73
88
  IO.copy_stream(r, w)
74
89
  end
@@ -102,7 +102,7 @@ module BFS
102
102
  end
103
103
  end
104
104
 
105
- BFS.register('file') do |url, opts|
105
+ BFS.register('file') do |url, opts, block|
106
106
  parts = [url.host, url.path].compact
107
- BFS::Bucket::FS.new File.join(*parts), **opts
107
+ BFS::Bucket::FS.open(File.join(*parts), **opts, &block)
108
108
  end
@@ -0,0 +1 @@
1
+ require 'bfs/bucket/fs'
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- RSpec.describe BFS::Blob do
3
+ RSpec.describe BFS::Blob, core: true do
4
4
  describe 'default' do
5
5
  let(:bucket) { BFS::Bucket::InMem.new }
6
6
  before { allow(BFS).to receive(:resolve).and_return(bucket) }
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe BFS::Bucket::Abstract, core: true do
4
+ it 'should open with a block' do
5
+ sub_class = Class.new(described_class) do
6
+ def close
7
+ @closed = true
8
+ end
9
+
10
+ def closed?
11
+ @closed == true
12
+ end
13
+ end
14
+
15
+ bucket = nil
16
+ result = sub_class.open do |bkt|
17
+ expect(bkt).not_to be_closed
18
+ bucket = bkt
19
+ 21
20
+ end
21
+ expect(result).to eq(21)
22
+ expect(bucket).to be_instance_of(sub_class)
23
+ expect(bucket).to be_closed
24
+ end
25
+ end
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- RSpec.describe BFS::Bucket::FS do
3
+ RSpec.describe BFS::Bucket::FS, core: true do
4
4
  let(:tmpdir) { Dir.mktmpdir }
5
5
  after { FileUtils.rm_rf tmpdir }
6
6
  subject { described_class.new(tmpdir) }
@@ -15,6 +15,7 @@ RSpec.describe BFS::Bucket::FS do
15
15
  bucket = BFS.resolve("file://#{tmpdir}")
16
16
  expect(bucket).to be_instance_of(described_class)
17
17
  expect(bucket.ls.to_a).to eq(['test.txt'])
18
+ bucket.close
18
19
  end
19
20
 
20
21
  it 'should support custom perms on #initialize' do
@@ -1,5 +1,5 @@
1
1
  require 'spec_helper'
2
2
 
3
- RSpec.describe BFS::Bucket::InMem do
3
+ RSpec.describe BFS::Bucket::InMem, core: true do
4
4
  it_behaves_like 'a bucket'
5
5
  end
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- RSpec.describe BFS::TempWriter do
3
+ RSpec.describe BFS::TempWriter, core: true do
4
4
  let(:closer) { proc {} }
5
5
  subject { described_class.new 'test', &closer }
6
6
 
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe BFS, core: true do
4
+ it 'should resolve' do
5
+ bucket = BFS.resolve("file://#{Dir.tmpdir}")
6
+ expect(bucket).to be_instance_of(BFS::Bucket::FS)
7
+ bucket.close
8
+ end
9
+
10
+ it 'should resolve with block' do
11
+ BFS.resolve("file://#{Dir.tmpdir}") do |bucket|
12
+ expect(bucket).to be_instance_of(BFS::Bucket::FS)
13
+ expect(bucket).to receive(:close)
14
+ end
15
+ end
16
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bfs
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.5
4
+ version: 0.7.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dimitrij Denissenko
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-02-17 00:00:00.000000000 Z
11
+ date: 2020-10-26 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Minimalist abstraction for bucket storage
14
14
  email: dimitrij@blacksquaremedia.com
@@ -24,11 +24,14 @@ files:
24
24
  - lib/bfs/bucket/fs.rb
25
25
  - lib/bfs/bucket/in_mem.rb
26
26
  - lib/bfs/errors.rb
27
+ - lib/bfs/fs.rb
27
28
  - lib/bfs/helpers.rb
28
29
  - spec/bfs/blob_spec.rb
30
+ - spec/bfs/bucket/abstract_spec.rb
29
31
  - spec/bfs/bucket/fs_spec.rb
30
32
  - spec/bfs/bucket/in_mem_spec.rb
31
33
  - spec/bfs/helpers_spec.rb
34
+ - spec/bfs_spec.rb
32
35
  homepage: https://github.com/bsm/bfs.rb
33
36
  licenses:
34
37
  - Apache-2.0
@@ -41,7 +44,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
41
44
  requirements:
42
45
  - - ">="
43
46
  - !ruby/object:Gem::Version
44
- version: 2.5.0
47
+ version: 2.6.0
45
48
  required_rubygems_version: !ruby/object:Gem::Requirement
46
49
  requirements:
47
50
  - - ">="
@@ -54,6 +57,8 @@ specification_version: 4
54
57
  summary: Multi-platform cloud bucket adapter
55
58
  test_files:
56
59
  - spec/bfs/blob_spec.rb
60
+ - spec/bfs/bucket/abstract_spec.rb
57
61
  - spec/bfs/bucket/fs_spec.rb
58
62
  - spec/bfs/bucket/in_mem_spec.rb
59
63
  - spec/bfs/helpers_spec.rb
64
+ - spec/bfs_spec.rb