shrine-content_addressable 0.2.0 → 0.3.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 +4 -4
- data/CHANGELOG.md +5 -0
- data/README.md +4 -1
- data/lib/content_addressable_file.rb +59 -0
- data/shrine-content_addressable.gemspec +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 48b7c5d303fd33194e6bf893237f6116c6e79a1e
|
|
4
|
+
data.tar.gz: a5cd20d76d9136773685b54861050012c1195950
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f680433393ec5f045caff471e3fcdd89646f1c90bfdb0f3c4ed87ef5c4790e03e5b6b7d2b20347c8b8c47475f6006b9b581238a1338e580afefffdd1b5f44592
|
|
7
|
+
data.tar.gz: 81544f628c4899516449924a5f79aa70e426ab400b6bcac0c0c046bed5f3393c0172b4208c6399f8a3947690dad71a750d287d6b2050fc571fcdac79e0ab8967
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# shrine-content_addressable
|
|
2
2
|
[](https://travis-ci.com/SleeplessByte/content_addressable)
|
|
3
|
-
[](https://badge.fury.io/rb/content_addressable)
|
|
3
|
+
[](https://badge.fury.io/rb/shrine-content_addressable)
|
|
4
4
|
[](http://opensource.org/licenses/MIT)
|
|
5
5
|
|
|
6
6
|
Generate content addressable locations for shrine uploads.
|
|
@@ -55,6 +55,9 @@ require 'content_addressable_file'
|
|
|
55
55
|
# You currently need to register the storages
|
|
56
56
|
ContentAddressableFile.register_storage(lookup, lookup, lookup)
|
|
57
57
|
|
|
58
|
+
# You can disallow deletion using
|
|
59
|
+
ContentAddressableFile.register_read_only_storage(lookup, lookup, lookup)
|
|
60
|
+
|
|
58
61
|
file = ContentAddressableFile.new(content_addressable_hash)
|
|
59
62
|
|
|
60
63
|
# => file methods like open, rewind, read, close and eof? are available
|
|
@@ -1,17 +1,46 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'English'
|
|
4
|
+
require 'multihashes'
|
|
5
|
+
require 'forwardable'
|
|
6
|
+
|
|
7
|
+
class ReadOnlyStorage
|
|
8
|
+
extend Forwardable
|
|
9
|
+
def_delegators :@storage, :exists?, :download, :url
|
|
10
|
+
|
|
11
|
+
def initialize(storage)
|
|
12
|
+
@storage = storage
|
|
13
|
+
end
|
|
14
|
+
end
|
|
4
15
|
|
|
5
16
|
class ContentAddressableFile
|
|
6
17
|
|
|
7
18
|
class << self
|
|
8
19
|
attr_accessor :storages
|
|
9
20
|
|
|
21
|
+
# Registers a storage to be used with content-addressable file. All shrine
|
|
22
|
+
# storages are supported by default, as is any duck type that responds to
|
|
23
|
+
# Storage#open(content-addressable-hash) and Storage#exists?(hash).
|
|
24
|
+
#
|
|
25
|
+
# Additional functionality needs Storage#url(hash), Storage#delete(hash)
|
|
26
|
+
# and Storage#download(hash).
|
|
27
|
+
#
|
|
28
|
+
# When a content-addressable file is deleted, it's deleted from all
|
|
29
|
+
# registered storages. use #register_read_only_storage to prevent deletion.
|
|
30
|
+
#
|
|
10
31
|
def register_storage(*storage)
|
|
11
32
|
self.storages = Array(storages).push(*storage)
|
|
12
33
|
self
|
|
13
34
|
end
|
|
14
35
|
|
|
36
|
+
# Same as #register_storage, but only forwards read only methods.
|
|
37
|
+
def register_read_only_storage(*storage)
|
|
38
|
+
read_only = Array(storage).map { |s| ReadOnlyStorage.new(s) }
|
|
39
|
+
self.storages = Array(storages).push(*read_only)
|
|
40
|
+
self
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Removes all registered storages
|
|
15
44
|
def reset
|
|
16
45
|
self.storages = []
|
|
17
46
|
self
|
|
@@ -20,10 +49,38 @@ class ContentAddressableFile
|
|
|
20
49
|
|
|
21
50
|
attr_reader :id
|
|
22
51
|
|
|
52
|
+
# Creates a new content-addressable file wrapper that uses the given id as
|
|
53
|
+
# content hash, assuming that it is a content addressable multihash
|
|
54
|
+
#
|
|
55
|
+
# @param [String] id the multihash that is the content-addressable
|
|
56
|
+
#
|
|
23
57
|
def initialize(id)
|
|
24
58
|
self.id = id
|
|
25
59
|
end
|
|
26
60
|
|
|
61
|
+
# Tries to decode the multihash. This is a good check to see if the given id
|
|
62
|
+
# is actually a content-addressable, but also easy to "fake", as the only way
|
|
63
|
+
# to be certain that the id is a content addressable is actually getting the
|
|
64
|
+
# file and hashing it again.
|
|
65
|
+
def decode
|
|
66
|
+
@decode ||= Multihashes.decode id
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# The #deocode digest as a byte array
|
|
70
|
+
def digest
|
|
71
|
+
decode[:digest]
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# The #decode digest length
|
|
75
|
+
def digest_length
|
|
76
|
+
decode[:length]
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# The #decode hash function
|
|
80
|
+
def digest_hash_function
|
|
81
|
+
decode[:hash_function]
|
|
82
|
+
end
|
|
83
|
+
|
|
27
84
|
# Calls `#open` on the storages to open the uploaded file for reading.
|
|
28
85
|
# Most storages will return a lazy IO object which dynamically
|
|
29
86
|
# retrieves file content from the storage as the object is being read.
|
|
@@ -34,6 +91,8 @@ class ContentAddressableFile
|
|
|
34
91
|
#
|
|
35
92
|
# If no block is given, the opened IO object is returned.
|
|
36
93
|
#
|
|
94
|
+
# @example
|
|
95
|
+
#
|
|
37
96
|
# content_addressable.open #=> IO object returned by the storage
|
|
38
97
|
# content_addressable.read #=> "..."
|
|
39
98
|
# content_addressable.close
|
|
@@ -5,7 +5,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
|
5
5
|
|
|
6
6
|
Gem::Specification.new do |spec|
|
|
7
7
|
spec.name = 'shrine-content_addressable'
|
|
8
|
-
spec.version = '0.
|
|
8
|
+
spec.version = '0.3.0'
|
|
9
9
|
spec.authors = ['Derk-Jan Karrenbeld']
|
|
10
10
|
spec.email = ['derk-jan+github@karrenbeld.info']
|
|
11
11
|
|