ro-crate 0.4.0 → 0.4.5
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/.ruby-version +1 -1
- data/Gemfile.lock +1 -1
- data/README.md +13 -9
- data/Rakefile +1 -1
- data/lib/{ro_crate_ruby.rb → ro_crate.rb} +0 -0
- data/lib/ro_crate/json_ld_hash.rb +1 -1
- data/lib/ro_crate/model/contextual_entity.rb +1 -1
- data/lib/ro_crate/model/crate.rb +46 -11
- data/lib/ro_crate/model/data_entity.rb +1 -1
- data/lib/ro_crate/model/directory.rb +37 -9
- data/lib/ro_crate/model/entity.rb +3 -3
- data/lib/ro_crate/model/entry.rb +1 -1
- data/lib/ro_crate/model/file.rb +2 -2
- data/lib/ro_crate/model/remote_entry.rb +1 -1
- data/lib/ro_crate/reader.rb +17 -15
- data/lib/ro_crate/ro-crate-preview.html.erb +3 -3
- data/lib/ro_crate/writer.rb +3 -3
- data/ro_crate.gemspec +2 -2
- data/test/crate_test.rb +95 -0
- data/test/fixtures/directory.zip +0 -0
- data/test/fixtures/directory/.dir/test.txt +1 -0
- data/test/fixtures/directory/.dotfile +1 -0
- data/test/fixtures/directory_crate/ro-crate-metadata.jsonld +7 -0
- data/test/fixtures/directory_crate/ro-crate-preview.html +66 -0
- data/test/reader_test.rb +4 -2
- data/test/test_helper.rb +1 -1
- data/test/writer_test.rb +13 -0
- metadata +7 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 78897fbce0fd01688c27516dceba600ed7cd984668fd16abde32a1713c0ba40f
|
4
|
+
data.tar.gz: 3194d882e4b7f6cd347d652d5da38cb2fe02cfb18e36d84f50e012193a538a69
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ddc2f5ffe217717299f2e5d76313b2a124fabfbc7b1e1800db18ca36d2f79c716ef249c6fcb8a6a8bfd4e0c5bba3b8a30d6ae3498ef8fd0068d7df08985c72f5
|
7
|
+
data.tar.gz: 802bf935d2e911ce771e962d6faaf0821f682049424cf5ac893ec780b8fc89d22f844156a83dd38adbe045a31faa7e527b4d8406bcabe937bdf8a2e8afafcd93
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
ruby-2.
|
1
|
+
ruby-2.6.6
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
# ro-crate-ruby
|
2
2
|
|
3
|
-
This is a WIP gem for creating, manipulating and reading RO
|
3
|
+
This is a WIP gem for creating, manipulating and reading RO-Crates (conforming to version 1.1 of the specification).
|
4
4
|
|
5
|
-
* RO
|
6
|
-
* RO
|
5
|
+
* RO-Crate - https://researchobject.github.io/ro-crate/
|
6
|
+
* RO-Crate spec (1.1) - https://researchobject.github.io/ro-crate/1.1/
|
7
7
|
|
8
8
|
## Installation
|
9
9
|
|
10
10
|
Using bundler, add the following to your Gemfile:
|
11
11
|
|
12
12
|
```
|
13
|
-
gem 'ro-crate
|
13
|
+
gem 'ro-crate'
|
14
14
|
```
|
15
15
|
|
16
16
|
and run `bundle install`.
|
@@ -24,20 +24,24 @@ and run `bundle install`.
|
|
24
24
|
### Examples
|
25
25
|
|
26
26
|
```ruby
|
27
|
-
require '
|
27
|
+
require 'ro_crate'
|
28
28
|
|
29
29
|
# Make a new crate
|
30
30
|
crate = ROCrate::Crate.new
|
31
31
|
crate.add_file(File.open('Gemfile')) # Using IO-like objects
|
32
32
|
crate.add_file('README.md') # or paths
|
33
33
|
|
34
|
+
# Quickly add everything from a directory into the crate
|
35
|
+
crate = ROCrate::Crate.new
|
36
|
+
crate.add_all('workspace/secret_project/dataset123')
|
37
|
+
|
34
38
|
# Write to a zip file
|
35
39
|
ROCrate::Writer.new(crate).write_zip(File.new('ro_crate.zip', 'w'))
|
36
40
|
|
37
41
|
# Write to a directory
|
38
42
|
ROCrate::Writer.new(crate).write('./ro_crate_stuff')
|
39
43
|
|
40
|
-
# Read an RO
|
44
|
+
# Read an RO-Crate
|
41
45
|
crate = ROCrate::Reader.read('./an_ro_crate_directory')
|
42
46
|
|
43
47
|
# Make some changes
|
@@ -55,9 +59,9 @@ ext_file = crate.add_external_file('https://example.com/my_file.txt')
|
|
55
59
|
ROCrate::Writer.new(crate).write('./an_ro_crate_directory')
|
56
60
|
```
|
57
61
|
|
58
|
-
### RO
|
59
|
-
A simple HTML preview page is generated when an RO
|
60
|
-
metadata. This preview is written to `ro-crate-preview.html` at the root of the RO
|
62
|
+
### RO-Crate Preview
|
63
|
+
A simple HTML preview page is generated when an RO-Crate is written, containing a list of the crate's contents and some
|
64
|
+
metadata. This preview is written to `ro-crate-preview.html` at the root of the RO-Crate.
|
61
65
|
|
62
66
|
The default template can be seen here [here](lib/ro_crate/ro-crate-preview.html.erb).
|
63
67
|
|
data/Rakefile
CHANGED
File without changes
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module ROCrate
|
2
2
|
##
|
3
|
-
# A wrapper class for Hash that adds methods to dereference Entities within an RO
|
3
|
+
# A wrapper class for Hash that adds methods to dereference Entities within an RO-Crate.
|
4
4
|
class JSONLDHash < ::Hash
|
5
5
|
def initialize(graph, content = {})
|
6
6
|
@graph = graph
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module ROCrate
|
2
2
|
##
|
3
|
-
# A class to represent a "Contextual Entity" within an RO
|
3
|
+
# A class to represent a "Contextual Entity" within an RO-Crate.
|
4
4
|
# Contextual Entities are used to describe and provide context to the Data Entities within the crate.
|
5
5
|
class ContextualEntity < Entity
|
6
6
|
def self.format_id(id)
|
data/lib/ro_crate/model/crate.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module ROCrate
|
2
2
|
##
|
3
|
-
# A Ruby abstraction of an RO
|
3
|
+
# A Ruby abstraction of an RO-Crate.
|
4
4
|
class Crate < Directory
|
5
5
|
IDENTIFIER = './'.freeze
|
6
6
|
attr_reader :data_entities
|
@@ -13,7 +13,7 @@ module ROCrate
|
|
13
13
|
end
|
14
14
|
|
15
15
|
##
|
16
|
-
# Initialize an empty RO
|
16
|
+
# Initialize an empty RO-Crate.
|
17
17
|
def initialize(id = IDENTIFIER, properties = {})
|
18
18
|
@data_entities = []
|
19
19
|
@contextual_entities = []
|
@@ -24,7 +24,7 @@ module ROCrate
|
|
24
24
|
# Create a new file and add it to the crate.
|
25
25
|
#
|
26
26
|
# @param source [String, Pathname, ::File, #read, nil] The source on the disk where this file will be read.
|
27
|
-
# @param crate_path [String] The relative path within the RO
|
27
|
+
# @param crate_path [String] The relative path within the RO-Crate where this file will be written.
|
28
28
|
# @param entity_class [Class] The class to use to instantiate the Entity,
|
29
29
|
# useful if you have created a subclass of ROCrate::File that you want to use. (defaults to ROCrate::File).
|
30
30
|
# @param properties [Hash{String => Object}] A hash of JSON-LD properties to associate with this file.
|
@@ -51,7 +51,7 @@ module ROCrate
|
|
51
51
|
# Create a new directory and add it to the crate.
|
52
52
|
#
|
53
53
|
# @param source_directory [String, Pathname, ::File, #read, nil] The source directory that will be included in the crate.
|
54
|
-
# @param crate_path [String] The relative path within the RO
|
54
|
+
# @param crate_path [String] The relative path within the RO-Crate where this directory will be written.
|
55
55
|
# @param entity_class [Class] The class to use to instantiate the Entity,
|
56
56
|
# useful if you have created a subclass of ROCrate::Directory that you want to use. (defaults to ROCrate::Directory).
|
57
57
|
# @param properties [Hash{String => Object}] A hash of JSON-LD properties to associate with this directory.
|
@@ -61,6 +61,35 @@ module ROCrate
|
|
61
61
|
entity_class.new(self, source_directory, crate_path, properties).tap { |e| add_data_entity(e) }
|
62
62
|
end
|
63
63
|
|
64
|
+
##
|
65
|
+
# Recursively add the contents of the given source directory at the root of the crate.
|
66
|
+
# Useful for quickly RO-Crate-ifying a directory.
|
67
|
+
# Creates data entities for each file/directory discovered (excluding the top level directory itself) if `create_entities` is true.
|
68
|
+
#
|
69
|
+
# @param source_directory [String, Pathname, ::File,] The source directory that will be included in the crate.
|
70
|
+
# @param create_entities [Boolean] Whether to create data entities for the added content, or just include them anonymously.
|
71
|
+
# @param include_hidden [Boolean] Whether to include hidden files, i.e. those prefixed by a `.` (period).
|
72
|
+
#
|
73
|
+
# @return [Array<DataEntity>] Any entities that were created from the directory contents. Will be empty if `create_entities` was false.
|
74
|
+
def add_all(source_directory, create_entities = true, include_hidden: false)
|
75
|
+
added = []
|
76
|
+
|
77
|
+
if create_entities
|
78
|
+
list_all_files(source_directory, include_hidden: include_hidden).each do |rel_path|
|
79
|
+
source_path = Pathname.new(::File.join(source_directory, rel_path)).expand_path
|
80
|
+
if source_path.directory?
|
81
|
+
added << add_directory(source_path, rel_path)
|
82
|
+
else
|
83
|
+
added << add_file(source_path, rel_path)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
else
|
87
|
+
populate_entries(Pathname.new(::File.expand_path(source_directory)), include_hidden: include_hidden)
|
88
|
+
end
|
89
|
+
|
90
|
+
added
|
91
|
+
end
|
92
|
+
|
64
93
|
##
|
65
94
|
# Create a new ROCrate::Person and add it to the crate
|
66
95
|
#
|
@@ -119,7 +148,7 @@ module ROCrate
|
|
119
148
|
end
|
120
149
|
|
121
150
|
##
|
122
|
-
# The RO
|
151
|
+
# The RO-Crate metadata file
|
123
152
|
#
|
124
153
|
# @return [Metadata]
|
125
154
|
def metadata
|
@@ -127,7 +156,7 @@ module ROCrate
|
|
127
156
|
end
|
128
157
|
|
129
158
|
##
|
130
|
-
# The RO
|
159
|
+
# The RO-Crate preview file
|
131
160
|
#
|
132
161
|
# @return [Preview]
|
133
162
|
def preview
|
@@ -143,7 +172,7 @@ module ROCrate
|
|
143
172
|
end
|
144
173
|
|
145
174
|
##
|
146
|
-
# Entities for the metadata file and crate itself, which should be present in all RO
|
175
|
+
# Entities for the metadata file and crate itself, which should be present in all RO-Crates.
|
147
176
|
#
|
148
177
|
# @return [Array<Entity>]
|
149
178
|
def default_entities
|
@@ -186,8 +215,9 @@ module ROCrate
|
|
186
215
|
entity.class.new(crate, entity.id, entity.raw_properties)
|
187
216
|
end
|
188
217
|
|
218
|
+
alias_method :own_entries, :entries
|
189
219
|
##
|
190
|
-
# A map of all the files/directories contained in the RO
|
220
|
+
# A map of all the files/directories contained in the RO-Crate, where the key is the destination path within the crate
|
191
221
|
# and the value is an Entry where the source data can be read.
|
192
222
|
#
|
193
223
|
# @return [Hash{String => Entry}>]
|
@@ -195,9 +225,8 @@ module ROCrate
|
|
195
225
|
entries = {}
|
196
226
|
|
197
227
|
(default_entities | data_entities).each do |entity|
|
198
|
-
|
199
|
-
|
200
|
-
entries[path] = io
|
228
|
+
(entity == self ? own_entries : entity.entries).each do |path, entry|
|
229
|
+
entries[path] = entry
|
201
230
|
end
|
202
231
|
end
|
203
232
|
|
@@ -207,5 +236,11 @@ module ROCrate
|
|
207
236
|
def get_binding
|
208
237
|
binding
|
209
238
|
end
|
239
|
+
|
240
|
+
private
|
241
|
+
|
242
|
+
def full_entry_path(relative_path)
|
243
|
+
relative_path
|
244
|
+
end
|
210
245
|
end
|
211
246
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module ROCrate
|
2
2
|
##
|
3
|
-
# A class to represent a "Data Entity" within an RO
|
3
|
+
# A class to represent a "Data Entity" within an RO-Crate.
|
4
4
|
# Data Entities are the actual physical files and directories within the Crate.
|
5
5
|
class DataEntity < Entity
|
6
6
|
def self.format_id(id)
|
@@ -12,22 +12,18 @@ module ROCrate
|
|
12
12
|
# Create a new Directory. PLEASE NOTE, the new directory will not be added to the crate. To do this, call
|
13
13
|
# Crate#add_data_entity, or just use Crate#add_directory.
|
14
14
|
#
|
15
|
-
# @param crate [Crate] The RO
|
15
|
+
# @param crate [Crate] The RO-Crate that owns this directory.
|
16
16
|
# @param source_directory [String, Pathname, ::File, nil] The source directory that will be included in the crate.
|
17
|
-
# @param crate_path [String] The relative path within the RO
|
17
|
+
# @param crate_path [String] The relative path within the RO-Crate where this directory will be written.
|
18
18
|
# @param properties [Hash{String => Object}] A hash of JSON-LD properties to associate with this directory.
|
19
19
|
def initialize(crate, source_directory = nil, crate_path = nil, properties = {})
|
20
20
|
@directory_entries = {}
|
21
21
|
|
22
22
|
if source_directory
|
23
|
-
raise 'Not a directory' unless ::File.directory?(source_directory)
|
24
23
|
source_directory = Pathname.new(::File.expand_path(source_directory))
|
24
|
+
@entry = Entry.new(source_directory)
|
25
|
+
populate_entries(source_directory)
|
25
26
|
crate_path = source_directory.basename.to_s if crate_path.nil?
|
26
|
-
|
27
|
-
Dir.chdir(source_directory) { Dir.glob('**/*') }.each do |rel_path|
|
28
|
-
source_path = Pathname.new(::File.join(source_directory, rel_path)).expand_path
|
29
|
-
@directory_entries[rel_path] = Entry.new(source_path)
|
30
|
-
end
|
31
27
|
end
|
32
28
|
|
33
29
|
super(crate, crate_path, properties)
|
@@ -40,9 +36,10 @@ module ROCrate
|
|
40
36
|
# @return [Hash{String => Entry}>]
|
41
37
|
def entries
|
42
38
|
entries = {}
|
39
|
+
entries[filepath.chomp('/')] = @entry if @entry
|
43
40
|
|
44
41
|
@directory_entries.each do |rel_path, entry|
|
45
|
-
entries[
|
42
|
+
entries[full_entry_path(rel_path)] = entry
|
46
43
|
end
|
47
44
|
|
48
45
|
entries
|
@@ -50,6 +47,37 @@ module ROCrate
|
|
50
47
|
|
51
48
|
private
|
52
49
|
|
50
|
+
##
|
51
|
+
# Populate this directory with files/directories from a given source directory on disk.
|
52
|
+
#
|
53
|
+
# @param source_directory [Pathname] The source directory to populate from.
|
54
|
+
# @param include_hidden [Boolean] Whether to include hidden files, i.e. those prefixed by a `.` (period).
|
55
|
+
#
|
56
|
+
# @return [Hash{String => Entry}>] The files/directories that were populated.
|
57
|
+
# The key is the relative path of the file/directory, and the value is an Entry object where data can be read etc.
|
58
|
+
def populate_entries(source_directory, include_hidden: false)
|
59
|
+
raise 'Not a directory' unless ::File.directory?(source_directory)
|
60
|
+
@directory_entries = {}
|
61
|
+
list_all_files(source_directory, include_hidden: include_hidden).each do |rel_path|
|
62
|
+
source_path = Pathname.new(::File.join(source_directory, rel_path)).expand_path
|
63
|
+
@directory_entries[rel_path] = Entry.new(source_path)
|
64
|
+
end
|
65
|
+
|
66
|
+
@directory_entries
|
67
|
+
end
|
68
|
+
|
69
|
+
def full_entry_path(relative_path)
|
70
|
+
::File.join(filepath, relative_path)
|
71
|
+
end
|
72
|
+
|
73
|
+
def list_all_files(source_directory, include_hidden: false)
|
74
|
+
args = ['**/*']
|
75
|
+
args << ::File::FNM_DOTMATCH if include_hidden
|
76
|
+
Dir.chdir(source_directory) { Dir.glob(*args) }.reject do |path|
|
77
|
+
path == '.' || path == '..' || path.end_with?('/.')
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
53
81
|
def default_properties
|
54
82
|
super.merge(
|
55
83
|
'@id' => "#{SecureRandom.uuid}/",
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module ROCrate
|
2
2
|
##
|
3
|
-
# A generic "Entity" within an RO
|
4
|
-
# RO
|
3
|
+
# A generic "Entity" within an RO-Crate. It has an identifier and a set of properties, and will be referenced in the
|
4
|
+
# RO-Crate Metadata's @graph.
|
5
5
|
class Entity
|
6
6
|
attr_reader :crate
|
7
7
|
attr_reader :properties
|
@@ -60,7 +60,7 @@ module ROCrate
|
|
60
60
|
##
|
61
61
|
# Automatically replace an Entity or Array of Entities with a reference or Array of references. Also associates
|
62
62
|
# the Entity/Entities with the current crate. This is useful for maintaining the flat @graph of entities that the
|
63
|
-
# RO
|
63
|
+
# RO-Crate metadata file requires.
|
64
64
|
#
|
65
65
|
# @param value [Entity, Array<Entity>, Object] A value that may be reference or array of references.
|
66
66
|
# @return [Hash, Array<Hash>, Object] Return a reference, Array of references, or just the object itself if
|
data/lib/ro_crate/model/entry.rb
CHANGED
data/lib/ro_crate/model/file.rb
CHANGED
@@ -8,9 +8,9 @@ module ROCrate
|
|
8
8
|
# Create a new ROCrate::File. PLEASE NOTE, the new file will not be added to the crate. To do this, call
|
9
9
|
# Crate#add_data_entity, or just use Crate#add_file.
|
10
10
|
#
|
11
|
-
# @param crate [Crate] The RO
|
11
|
+
# @param crate [Crate] The RO-Crate that owns this file.
|
12
12
|
# @param source [String, Pathname, ::File, #read, URI, nil] The source on the disk (or on the internet if a URI) where this file will be read.
|
13
|
-
# @param crate_path [String] The relative path within the RO
|
13
|
+
# @param crate_path [String] The relative path within the RO-Crate where this file will be written.
|
14
14
|
# @param properties [Hash{String => Object}] A hash of JSON-LD properties to associate with this file.
|
15
15
|
def initialize(crate, source, crate_path = nil, properties = {})
|
16
16
|
if crate_path.is_a?(Hash) && properties.empty?
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module ROCrate
|
2
2
|
##
|
3
|
-
# A class to represent a reference within an RO
|
3
|
+
# A class to represent a reference within an RO-Crate, to a remote file held on the internet somewhere.
|
4
4
|
# It handles the actual reading/writing of bytes.
|
5
5
|
class RemoteEntry
|
6
6
|
attr_reader :uri
|
data/lib/ro_crate/reader.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
module ROCrate
|
2
2
|
##
|
3
|
-
# A class to handle reading of RO
|
3
|
+
# A class to handle reading of RO-Crates from Zip files or directories.
|
4
4
|
class Reader
|
5
5
|
##
|
6
|
-
# Reads an RO
|
6
|
+
# Reads an RO-Crate from a directory of zip file.
|
7
7
|
#
|
8
8
|
# @param source [String, ::File, Pathname] The source location for the crate.
|
9
9
|
# @param target_dir [String, ::File, Pathname] The target directory where the crate should be unzipped (if its a Zip file).
|
10
|
-
# @return [Crate] The RO
|
10
|
+
# @return [Crate] The RO-Crate.
|
11
11
|
def self.read(source, target_dir: Dir.mktmpdir)
|
12
12
|
raise "Not a directory!" unless ::File.directory?(target_dir)
|
13
13
|
if ::File.directory?(source)
|
@@ -37,12 +37,12 @@ module ROCrate
|
|
37
37
|
end
|
38
38
|
|
39
39
|
##
|
40
|
-
# Reads an RO
|
40
|
+
# Reads an RO-Crate from a zip file. It first extracts the Zip file to a temporary directory, and then calls
|
41
41
|
# #read_directory.
|
42
42
|
#
|
43
43
|
# @param source [String, ::File, Pathname] The location of the zip file.
|
44
44
|
# @param target_dir [String, ::File, Pathname] The target directory where the crate should be unzipped.
|
45
|
-
# @return [Crate] The RO
|
45
|
+
# @return [Crate] The RO-Crate.
|
46
46
|
def self.read_zip(source, target_dir: Dir.mktmpdir)
|
47
47
|
unzip_to(source, target_dir)
|
48
48
|
|
@@ -50,10 +50,10 @@ module ROCrate
|
|
50
50
|
end
|
51
51
|
|
52
52
|
##
|
53
|
-
# Reads an RO
|
53
|
+
# Reads an RO-Crate from a directory.
|
54
54
|
#
|
55
55
|
# @param source [String, ::File, Pathname] The location of the directory.
|
56
|
-
# @return [Crate] The RO
|
56
|
+
# @return [Crate] The RO-Crate.
|
57
57
|
def self.read_directory(source)
|
58
58
|
source = ::File.expand_path(source)
|
59
59
|
metadata_file = Dir.entries(source).detect { |entry| entry == ROCrate::Metadata::IDENTIFIER ||
|
@@ -68,7 +68,7 @@ module ROCrate
|
|
68
68
|
end
|
69
69
|
|
70
70
|
##
|
71
|
-
# Extracts all the entities from the @graph of the RO
|
71
|
+
# Extracts all the entities from the @graph of the RO-Crate Metadata.
|
72
72
|
#
|
73
73
|
# @param metadata_json [String] A string containing the metadata JSON.
|
74
74
|
# @return [Hash{String => Hash}] A Hash of all the entities, mapped by their @id.
|
@@ -99,12 +99,14 @@ module ROCrate
|
|
99
99
|
# Create a crate from the given set of entities.
|
100
100
|
#
|
101
101
|
# @param entity_hash [Hash{String => Hash}] A Hash containing all the entities in the @graph, mapped by their @id.
|
102
|
-
# @param source [String, ::File, Pathname] The location of the RO
|
103
|
-
# @return [Crate] The RO
|
102
|
+
# @param source [String, ::File, Pathname] The location of the RO-Crate being read.
|
103
|
+
# @return [Crate] The RO-Crate.
|
104
104
|
def self.build_crate(entity_hash, source)
|
105
105
|
ROCrate::Crate.new.tap do |crate|
|
106
106
|
crate.properties = entity_hash.delete(ROCrate::Crate::IDENTIFIER)
|
107
107
|
crate.metadata.properties = entity_hash.delete(ROCrate::Metadata::IDENTIFIER)
|
108
|
+
preview_properties = entity_hash.delete(ROCrate::Preview::IDENTIFIER)
|
109
|
+
crate.preview.properties = preview_properties if preview_properties
|
108
110
|
extract_data_entities(crate, source, entity_hash).each do |entity|
|
109
111
|
crate.add_data_entity(entity)
|
110
112
|
end
|
@@ -118,8 +120,8 @@ module ROCrate
|
|
118
120
|
##
|
119
121
|
# Discover data entities from the `hasPart` property of a crate, and create DataEntity objects for them.
|
120
122
|
# Entities are looked up in the given `entity_hash` (and then removed from it).
|
121
|
-
# @param crate [Crate] The RO
|
122
|
-
# @param source [String, ::File, Pathname] The location of the RO
|
123
|
+
# @param crate [Crate] The RO-Crate being read.
|
124
|
+
# @param source [String, ::File, Pathname] The location of the RO-Crate being read.
|
123
125
|
# @param entity_hash [Hash] A Hash containing all the entities in the @graph, mapped by their @id.
|
124
126
|
# @return [Array<ROCrate::File, ROCrate::Directory>] The extracted DataEntity objects.
|
125
127
|
def self.extract_data_entities(crate, source, entity_hash)
|
@@ -135,7 +137,7 @@ module ROCrate
|
|
135
137
|
|
136
138
|
##
|
137
139
|
# Create appropriately specialized ContextualEntity objects from the given hash of entities and their properties.
|
138
|
-
# @param crate [Crate] The RO
|
140
|
+
# @param crate [Crate] The RO-Crate being read.
|
139
141
|
# @param entity_hash [Hash] A Hash containing all the entities in the @graph, mapped by their @id.
|
140
142
|
# @return [Array<ContextualEntity>] The extracted ContextualEntity objects.
|
141
143
|
def self.extract_contextual_entities(crate, entity_hash)
|
@@ -152,8 +154,8 @@ module ROCrate
|
|
152
154
|
|
153
155
|
##
|
154
156
|
# Create a DataEntity of the given class.
|
155
|
-
# @param crate [Crate] The RO
|
156
|
-
# @param source [String, ::File, Pathname] The location of the RO
|
157
|
+
# @param crate [Crate] The RO-Crate being read.
|
158
|
+
# @param source [String, ::File, Pathname] The location of the RO-Crate being read.
|
157
159
|
# @param entity_props [Hash] A Hash containing the entity's properties, including its @id.
|
158
160
|
# @return [ROCrate::File, ROCrate::Directory, nil] The DataEntity object,
|
159
161
|
# or nil if it referenced a local file that wasn't found.
|
@@ -1,13 +1,13 @@
|
|
1
1
|
<!DOCTYPE html>
|
2
2
|
<html>
|
3
3
|
<head>
|
4
|
-
<title><%= name || "New RO
|
4
|
+
<title><%= name || "New RO-Crate" %></title>
|
5
5
|
<script type="application/ld+json"><%= metadata.generate %></script>
|
6
6
|
<meta name="generator" content="https://github.com/fbacall/ro-crate-ruby">
|
7
|
-
<meta name="keywords" content="RO
|
7
|
+
<meta name="keywords" content="RO-Crate">
|
8
8
|
</head>
|
9
9
|
<body>
|
10
|
-
<h1><%= name || "New RO
|
10
|
+
<h1><%= name || "New RO-Crate" %></h1>
|
11
11
|
<% if url %>
|
12
12
|
<a href="<%= url %>" target="_blank"><%= url %></a>
|
13
13
|
<% end %>
|
data/lib/ro_crate/writer.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
module ROCrate
|
2
2
|
##
|
3
|
-
# A class to handle writing of RO
|
3
|
+
# A class to handle writing of RO-Crates to Zip files or directories.
|
4
4
|
class Writer
|
5
5
|
##
|
6
6
|
# Initialize a new Writer for the given Crate.
|
7
|
-
# @param crate [Crate] The RO
|
7
|
+
# @param crate [Crate] The RO-Crate to be written.
|
8
8
|
def initialize(crate)
|
9
9
|
@crate = crate
|
10
10
|
end
|
@@ -35,7 +35,7 @@ module ROCrate
|
|
35
35
|
##
|
36
36
|
# Write the crate to a zip file.
|
37
37
|
#
|
38
|
-
# @param destination [String, ::File] The destination where to write the RO
|
38
|
+
# @param destination [String, ::File] The destination where to write the RO-Crate zip.
|
39
39
|
def write_zip(destination)
|
40
40
|
Zip::File.open(destination, Zip::File::CREATE) do |zip|
|
41
41
|
@crate.entries.each do |path, entry|
|
data/ro_crate.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'ro-crate'
|
3
|
-
s.version = '0.4.
|
4
|
-
s.summary = 'Create, manipulate, read RO
|
3
|
+
s.version = '0.4.5'
|
4
|
+
s.summary = 'Create, manipulate, read RO-Crates.'
|
5
5
|
s.authors = ['Finn Bacall']
|
6
6
|
s.email = 'finn.bacall@manchester.ac.uk'
|
7
7
|
s.files = `git ls-files`.split("\n")
|
data/test/crate_test.rb
CHANGED
@@ -198,4 +198,99 @@ class CrateTest < Test::Unit::TestCase
|
|
198
198
|
assert_equal file, new_crate.get('some/file.txt')
|
199
199
|
assert_equal file, new_crate.get('http://mycoolwebsite.golf/ro_crate/some/file.txt')
|
200
200
|
end
|
201
|
+
|
202
|
+
test 'can add an entire directory tree as data entities' do
|
203
|
+
crate = ROCrate::Crate.new
|
204
|
+
entities = crate.add_all(fixture_file('directory').path, include_hidden: true)
|
205
|
+
|
206
|
+
paths = crate.entries.keys
|
207
|
+
assert_equal 11, paths.length
|
208
|
+
assert_includes paths, 'data'
|
209
|
+
assert_includes paths, 'root.txt'
|
210
|
+
assert_includes paths, 'info.txt'
|
211
|
+
assert_includes paths, 'data/binary.jpg'
|
212
|
+
assert_includes paths, 'data/info.txt'
|
213
|
+
assert_includes paths, 'data/nested.txt'
|
214
|
+
assert_includes paths, '.dotfile'
|
215
|
+
assert_includes paths, '.dir'
|
216
|
+
assert_includes paths, '.dir/test.txt'
|
217
|
+
assert_includes paths, 'ro-crate-metadata.json'
|
218
|
+
assert_includes paths, 'ro-crate-preview.html'
|
219
|
+
|
220
|
+
assert_equal 9, entities.length
|
221
|
+
assert_equal 'ROCrate::Directory', crate.dereference('data/').class.name
|
222
|
+
assert_equal 'ROCrate::File', crate.dereference('root.txt').class.name
|
223
|
+
assert_equal 'ROCrate::File', crate.dereference('info.txt').class.name
|
224
|
+
assert_equal 'ROCrate::File', crate.dereference('data/binary.jpg').class.name
|
225
|
+
assert_equal 'ROCrate::File', crate.dereference('data/info.txt').class.name
|
226
|
+
assert_equal 'ROCrate::File', crate.dereference('data/nested.txt').class.name
|
227
|
+
assert_equal 'ROCrate::File', crate.dereference('.dotfile').class.name
|
228
|
+
assert_equal 'ROCrate::Directory', crate.dereference('.dir/').class.name
|
229
|
+
assert_equal 'ROCrate::File', crate.dereference('.dir/test.txt').class.name
|
230
|
+
|
231
|
+
assert_equal "5678\n", crate.dereference('data/info.txt').source.read
|
232
|
+
assert_equal "Am I included?\n", crate.dereference('.dotfile').source.read
|
233
|
+
end
|
234
|
+
|
235
|
+
test 'can create an RO-Crate using content from a given directory' do
|
236
|
+
crate = ROCrate::Crate.new
|
237
|
+
entities = crate.add_all(fixture_file('directory').path, false, include_hidden: true)
|
238
|
+
|
239
|
+
assert_empty entities
|
240
|
+
|
241
|
+
paths = crate.entries.keys
|
242
|
+
assert_equal 11, paths.length
|
243
|
+
assert_includes paths, 'data'
|
244
|
+
assert_includes paths, 'root.txt'
|
245
|
+
assert_includes paths, 'info.txt'
|
246
|
+
assert_includes paths, 'data/binary.jpg'
|
247
|
+
assert_includes paths, 'data/info.txt'
|
248
|
+
assert_includes paths, 'data/nested.txt'
|
249
|
+
assert_includes paths, '.dotfile'
|
250
|
+
assert_includes paths, '.dir'
|
251
|
+
assert_includes paths, '.dir/test.txt'
|
252
|
+
assert_includes paths, 'ro-crate-metadata.json'
|
253
|
+
assert_includes paths, 'ro-crate-preview.html'
|
254
|
+
|
255
|
+
# Should not create any data entities
|
256
|
+
assert_nil crate.dereference('data/')
|
257
|
+
assert_nil crate.dereference('root.txt')
|
258
|
+
assert_nil crate.dereference('info.txt')
|
259
|
+
assert_nil crate.dereference('data/binary.jpg')
|
260
|
+
assert_nil crate.dereference('data/info.txt')
|
261
|
+
assert_nil crate.dereference('data/nested.txt')
|
262
|
+
assert_nil crate.dereference('.dotfile')
|
263
|
+
end
|
264
|
+
|
265
|
+
test 'can create an RO-Crate using content from a given directory, excluding hidden files' do
|
266
|
+
crate = ROCrate::Crate.new
|
267
|
+
entities = crate.add_all(fixture_file('directory').path)
|
268
|
+
|
269
|
+
paths = crate.entries.keys
|
270
|
+
assert_equal 8, paths.length
|
271
|
+
assert_includes paths, 'data'
|
272
|
+
assert_includes paths, 'root.txt'
|
273
|
+
assert_includes paths, 'info.txt'
|
274
|
+
assert_includes paths, 'data/binary.jpg'
|
275
|
+
assert_includes paths, 'data/info.txt'
|
276
|
+
assert_includes paths, 'data/nested.txt'
|
277
|
+
assert_not_includes paths, '.dotfile'
|
278
|
+
assert_not_includes paths, '.dir'
|
279
|
+
assert_not_includes paths, '.dir/test.txt'
|
280
|
+
assert_includes paths, 'ro-crate-metadata.json'
|
281
|
+
assert_includes paths, 'ro-crate-preview.html'
|
282
|
+
|
283
|
+
assert_equal 6, entities.length
|
284
|
+
assert_equal 'ROCrate::Directory', crate.dereference('data/').class.name
|
285
|
+
assert_equal 'ROCrate::File', crate.dereference('root.txt').class.name
|
286
|
+
assert_equal 'ROCrate::File', crate.dereference('info.txt').class.name
|
287
|
+
assert_equal 'ROCrate::File', crate.dereference('data/binary.jpg').class.name
|
288
|
+
assert_equal 'ROCrate::File', crate.dereference('data/info.txt').class.name
|
289
|
+
assert_equal 'ROCrate::File', crate.dereference('data/nested.txt').class.name
|
290
|
+
assert_nil crate.dereference('.dotfile')
|
291
|
+
assert_nil crate.dereference('.dir/')
|
292
|
+
assert_nil crate.dereference('.dir/test.txt')
|
293
|
+
|
294
|
+
assert_equal "5678\n", crate.dereference('data/info.txt').source.read
|
295
|
+
end
|
201
296
|
end
|
data/test/fixtures/directory.zip
CHANGED
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
123
|
@@ -0,0 +1 @@
|
|
1
|
+
Am I included?
|
@@ -0,0 +1,66 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>New RO-Crate</title>
|
5
|
+
<script type="application/ld+json">{
|
6
|
+
"@context": "https://w3id.org/ro/crate/1.1/context",
|
7
|
+
"@graph": [
|
8
|
+
{
|
9
|
+
"@id": "ro-crate-metadata.jsonld",
|
10
|
+
"@type": "CreativeWork",
|
11
|
+
"about": {
|
12
|
+
"@id": "./"
|
13
|
+
}
|
14
|
+
},
|
15
|
+
{
|
16
|
+
"@id": "ro-crate-preview.html",
|
17
|
+
"@type": "CreativeWork",
|
18
|
+
"about": {
|
19
|
+
"@id": "./"
|
20
|
+
}
|
21
|
+
},
|
22
|
+
{
|
23
|
+
"@id": "./",
|
24
|
+
"@type": "Dataset",
|
25
|
+
"hasPart": [
|
26
|
+
{
|
27
|
+
"@id": "fish/"
|
28
|
+
}
|
29
|
+
]
|
30
|
+
},
|
31
|
+
{
|
32
|
+
"@id": "fish/",
|
33
|
+
"@type": "Dataset"
|
34
|
+
}
|
35
|
+
]
|
36
|
+
}</script>
|
37
|
+
<meta name="generator" content="https://github.com/fbacall/ro-crate-ruby">
|
38
|
+
<meta name="keywords" content="RO-Crate">
|
39
|
+
</head>
|
40
|
+
<body>
|
41
|
+
<h1>New RO-Crate</h1>
|
42
|
+
|
43
|
+
<p>
|
44
|
+
|
45
|
+
</p>
|
46
|
+
<dl>
|
47
|
+
|
48
|
+
|
49
|
+
|
50
|
+
|
51
|
+
</dl>
|
52
|
+
|
53
|
+
<h2>Contents</h2>
|
54
|
+
<ul>
|
55
|
+
|
56
|
+
<li id="__data_entity_fish/">
|
57
|
+
|
58
|
+
<strong>fish/</strong>
|
59
|
+
|
60
|
+
|
61
|
+
|
62
|
+
</li>
|
63
|
+
|
64
|
+
</ul>
|
65
|
+
</body>
|
66
|
+
</html>
|
data/test/reader_test.rb
CHANGED
@@ -109,11 +109,13 @@ class ReaderTest < Test::Unit::TestCase
|
|
109
109
|
test 'reading from directory with directories' do
|
110
110
|
crate = ROCrate::Reader.read_directory(fixture_file('directory_crate').path)
|
111
111
|
|
112
|
+
assert crate.entries.values.all? { |e| e.is_a?(ROCrate::Entry) }
|
112
113
|
assert crate.entries['fish/info.txt']
|
113
114
|
assert_equal '1234', crate.entries['fish/info.txt'].source.read.chomp
|
114
|
-
|
115
|
+
refute crate.entries['fish/root.txt'].directory?
|
116
|
+
assert crate.entries['fish/data'].directory?
|
115
117
|
assert crate.entries['fish/data/info.txt']
|
116
|
-
|
118
|
+
refute crate.entries['fish/data/nested.txt'].remote?
|
117
119
|
assert crate.entries['fish/data/binary.jpg']
|
118
120
|
assert_equal ['./', 'fish/', 'ro-crate-metadata.jsonld', 'ro-crate-preview.html'], crate.entities.map(&:id).sort
|
119
121
|
end
|
data/test/test_helper.rb
CHANGED
data/test/writer_test.rb
CHANGED
@@ -99,4 +99,17 @@ class WriterTest < Test::Unit::TestCase
|
|
99
99
|
end
|
100
100
|
end
|
101
101
|
end
|
102
|
+
|
103
|
+
test 'should write out same contents that it was created with' do
|
104
|
+
crate = ROCrate::Crate.new
|
105
|
+
crate.add_all(fixture_file('directory').path, false)
|
106
|
+
|
107
|
+
Dir.mktmpdir do |dir|
|
108
|
+
ROCrate::Writer.new(crate).write(dir)
|
109
|
+
assert ::File.exist?(::File.join(dir, ROCrate::Metadata::IDENTIFIER))
|
110
|
+
assert ::File.exist?(::File.join(dir, ROCrate::Preview::IDENTIFIER))
|
111
|
+
assert_equal 5, ::File.size(::File.join(dir, 'info.txt'))
|
112
|
+
assert_equal 2529, ::File.size(::File.join(dir, 'data', 'binary.jpg'))
|
113
|
+
end
|
114
|
+
end
|
102
115
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ro-crate
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Finn Bacall
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-02-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: addressable
|
@@ -123,6 +123,7 @@ files:
|
|
123
123
|
- LICENSE
|
124
124
|
- README.md
|
125
125
|
- Rakefile
|
126
|
+
- lib/ro_crate.rb
|
126
127
|
- lib/ro_crate/json_ld_hash.rb
|
127
128
|
- lib/ro_crate/model/contact_point.rb
|
128
129
|
- lib/ro_crate/model/contextual_entity.rb
|
@@ -140,7 +141,6 @@ files:
|
|
140
141
|
- lib/ro_crate/reader.rb
|
141
142
|
- lib/ro_crate/ro-crate-preview.html.erb
|
142
143
|
- lib/ro_crate/writer.rb
|
143
|
-
- lib/ro_crate_ruby.rb
|
144
144
|
- ro_crate.gemspec
|
145
145
|
- test/crate_test.rb
|
146
146
|
- test/directory_test.rb
|
@@ -149,6 +149,8 @@ files:
|
|
149
149
|
- test/fixtures/crate-spec1.1/ro-crate-metadata.json
|
150
150
|
- test/fixtures/data.csv
|
151
151
|
- test/fixtures/directory.zip
|
152
|
+
- test/fixtures/directory/.dir/test.txt
|
153
|
+
- test/fixtures/directory/.dotfile
|
152
154
|
- test/fixtures/directory/data/binary.jpg
|
153
155
|
- test/fixtures/directory/data/info.txt
|
154
156
|
- test/fixtures/directory/data/nested.txt
|
@@ -160,6 +162,7 @@ files:
|
|
160
162
|
- test/fixtures/directory_crate/fish/info.txt
|
161
163
|
- test/fixtures/directory_crate/fish/root.txt
|
162
164
|
- test/fixtures/directory_crate/ro-crate-metadata.jsonld
|
165
|
+
- test/fixtures/directory_crate/ro-crate-preview.html
|
163
166
|
- test/fixtures/file with spaces.txt
|
164
167
|
- test/fixtures/info.txt
|
165
168
|
- test/fixtures/spaces/file with spaces.txt
|
@@ -2414,5 +2417,5 @@ requirements: []
|
|
2414
2417
|
rubygems_version: 3.0.8
|
2415
2418
|
signing_key:
|
2416
2419
|
specification_version: 4
|
2417
|
-
summary: Create, manipulate, read RO
|
2420
|
+
summary: Create, manipulate, read RO-Crates.
|
2418
2421
|
test_files: []
|