ro-crate 0.4.10 → 0.4.14
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +13 -13
- data/README.md +39 -0
- data/lib/ro_crate/model/crate.rb +48 -6
- data/lib/ro_crate/model/data_entity.rb +21 -8
- data/lib/ro_crate/model/directory.rb +5 -7
- data/lib/ro_crate/model/entity.rb +41 -4
- data/lib/ro_crate/model/entry.rb +2 -2
- data/lib/ro_crate/model/file.rb +6 -4
- data/lib/ro_crate/model/metadata.rb +9 -1
- data/lib/ro_crate/model/organization.rb +1 -1
- data/lib/ro_crate/model/preview.rb +3 -15
- data/lib/ro_crate/model/preview_generator.rb +40 -0
- data/lib/ro_crate/model/remote_entry.rb +1 -12
- data/lib/ro_crate/reader.rb +61 -23
- data/lib/ro_crate/writer.rb +4 -4
- data/lib/ro_crate.rb +2 -1
- data/ro_crate.gemspec +3 -3
- data/test/crate_test.rb +58 -3
- data/test/directory_test.rb +21 -21
- data/test/entity_test.rb +117 -3
- data/test/fixtures/biobb_hpc_workflows-condapack.zip +0 -0
- data/test/fixtures/conflicting_data_directory/info.txt +1 -0
- data/test/fixtures/conflicting_data_directory/nested.txt +1 -0
- data/test/fixtures/misc_data_entity_crate/ro-crate-metadata.json +33 -0
- data/test/fixtures/ro-crate-galaxy-sortchangecase/LICENSE +176 -0
- data/test/fixtures/ro-crate-galaxy-sortchangecase/README.md +6 -0
- data/test/fixtures/ro-crate-galaxy-sortchangecase/ro-crate-metadata.json +140 -0
- data/test/fixtures/ro-crate-galaxy-sortchangecase/sort-and-change-case.ga +118 -0
- data/test/fixtures/ro-crate-galaxy-sortchangecase/test/test1/input.bed +3 -0
- data/test/fixtures/ro-crate-galaxy-sortchangecase/test/test1/output_exp.bed +3 -0
- data/test/fixtures/ro-crate-galaxy-sortchangecase/test/test1/sort-and-change-case-test.yml +8 -0
- data/test/fixtures/sparse_directory_crate/ro-crate-preview.html +60 -59
- data/test/fixtures/workflow-0.2.0/ro-crate-metadata.jsonld +5 -5
- data/test/fixtures/workflow-0.2.0.zip +0 -0
- data/test/reader_test.rb +110 -58
- data/test/test_helper.rb +5 -1
- data/test/writer_test.rb +70 -2
- metadata +26 -8
data/lib/ro_crate/reader.rb
CHANGED
@@ -103,8 +103,12 @@ module ROCrate
|
|
103
103
|
entry == ROCrate::Metadata::IDENTIFIER_1_0 }
|
104
104
|
|
105
105
|
if metadata_file
|
106
|
-
|
107
|
-
|
106
|
+
metadata_json = ::File.read(::File.join(source, metadata_file))
|
107
|
+
metadata = JSON.parse(metadata_json)
|
108
|
+
entities = entities_from_metadata(metadata)
|
109
|
+
context = metadata['@context']
|
110
|
+
|
111
|
+
build_crate(entities, source, context: context)
|
108
112
|
else
|
109
113
|
raise 'No metadata found!'
|
110
114
|
end
|
@@ -113,10 +117,9 @@ module ROCrate
|
|
113
117
|
##
|
114
118
|
# Extracts all the entities from the @graph of the RO-Crate Metadata.
|
115
119
|
#
|
116
|
-
# @param
|
120
|
+
# @param metadata [Hash] A Hash containing the parsed metadata JSON.
|
117
121
|
# @return [Hash{String => Hash}] A Hash of all the entities, mapped by their @id.
|
118
|
-
def self.entities_from_metadata(
|
119
|
-
metadata = JSON.parse(metadata_json)
|
122
|
+
def self.entities_from_metadata(metadata)
|
120
123
|
graph = metadata['@graph']
|
121
124
|
|
122
125
|
if graph
|
@@ -129,6 +132,7 @@ module ROCrate
|
|
129
132
|
# Do some normalization...
|
130
133
|
entities[ROCrate::Metadata::IDENTIFIER] = extract_metadata_entity(entities)
|
131
134
|
raise "No metadata entity found in @graph!" unless entities[ROCrate::Metadata::IDENTIFIER]
|
135
|
+
entities[ROCrate::Preview::IDENTIFIER] = extract_preview_entity(entities)
|
132
136
|
entities[ROCrate::Crate::IDENTIFIER] = extract_root_entity(entities)
|
133
137
|
raise "No root entity (with @id: #{entities[ROCrate::Metadata::IDENTIFIER].dig('about', '@id')}) found in @graph!" unless entities[ROCrate::Crate::IDENTIFIER]
|
134
138
|
|
@@ -139,25 +143,50 @@ module ROCrate
|
|
139
143
|
end
|
140
144
|
|
141
145
|
##
|
142
|
-
# Create
|
146
|
+
# Create and populate crate from the given set of entities.
|
143
147
|
#
|
144
148
|
# @param entity_hash [Hash{String => Hash}] A Hash containing all the entities in the @graph, mapped by their @id.
|
145
149
|
# @param source [String, ::File, Pathname] The location of the RO-Crate being read.
|
150
|
+
# @param crate_class [Class] The class to use to instantiate the crate,
|
151
|
+
# useful if you have created a subclass of ROCrate::Crate that you want to use. (defaults to ROCrate::Crate).
|
152
|
+
# @param context [nil, String, Array, Hash] A custom JSON-LD @context (parsed), or nil to use default.
|
146
153
|
# @return [Crate] The RO-Crate.
|
147
|
-
def self.build_crate(entity_hash, source)
|
148
|
-
|
154
|
+
def self.build_crate(entity_hash, source, crate_class: ROCrate::Crate, context:)
|
155
|
+
crate = initialize_crate(entity_hash, source, crate_class: crate_class, context: context)
|
156
|
+
|
157
|
+
extract_data_entities(crate, source, entity_hash).each do |entity|
|
158
|
+
crate.add_data_entity(entity)
|
159
|
+
end
|
160
|
+
|
161
|
+
# The remaining entities in the hash must be contextual.
|
162
|
+
extract_contextual_entities(crate, entity_hash).each do |entity|
|
163
|
+
crate.add_contextual_entity(entity)
|
164
|
+
end
|
165
|
+
|
166
|
+
crate
|
167
|
+
end
|
168
|
+
|
169
|
+
##
|
170
|
+
# Initialize a crate from the given set of entities.
|
171
|
+
#
|
172
|
+
# @param entity_hash [Hash{String => Hash}] A Hash containing all the entities in the @graph, mapped by their @id.
|
173
|
+
# @param source [String, ::File, Pathname] The location of the RO-Crate being read.
|
174
|
+
# @param crate_class [Class] The class to use to instantiate the crate,
|
175
|
+
# useful if you have created a subclass of ROCrate::Crate that you want to use. (defaults to ROCrate::Crate).
|
176
|
+
# @param context [nil, String, Array, Hash] A custom JSON-LD @context (parsed), or nil to use default.
|
177
|
+
# @return [Crate] The RO-Crate.
|
178
|
+
def self.initialize_crate(entity_hash, source, crate_class: ROCrate::Crate, context:)
|
179
|
+
crate_class.new.tap do |crate|
|
149
180
|
crate.properties = entity_hash.delete(ROCrate::Crate::IDENTIFIER)
|
150
181
|
crate.metadata.properties = entity_hash.delete(ROCrate::Metadata::IDENTIFIER)
|
182
|
+
crate.metadata.context = context
|
151
183
|
preview_properties = entity_hash.delete(ROCrate::Preview::IDENTIFIER)
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
crate.
|
156
|
-
end
|
157
|
-
# The remaining entities in the hash must be contextual.
|
158
|
-
extract_contextual_entities(crate, entity_hash).each do |entity|
|
159
|
-
crate.add_contextual_entity(entity)
|
184
|
+
preview_path = ::File.join(source, ROCrate::Preview::IDENTIFIER)
|
185
|
+
preview_path = ::File.exists?(preview_path) ? Pathname.new(preview_path) : nil
|
186
|
+
if preview_properties || preview_path
|
187
|
+
crate.preview = ROCrate::Preview.new(crate, preview_path, preview_properties || {})
|
160
188
|
end
|
189
|
+
crate.add_all(source, false)
|
161
190
|
end
|
162
191
|
end
|
163
192
|
|
@@ -216,10 +245,10 @@ module ROCrate
|
|
216
245
|
fullpath = ::File.join(source, i)
|
217
246
|
path = Pathname.new(fullpath) if ::File.exist?(fullpath)
|
218
247
|
end
|
219
|
-
unless path
|
220
|
-
|
221
|
-
|
222
|
-
end
|
248
|
+
# unless path
|
249
|
+
# warn "Missing file/directory: #{id}, skipping..."
|
250
|
+
# return nil
|
251
|
+
# end
|
223
252
|
end
|
224
253
|
|
225
254
|
entity_class.new(crate, path, decoded_id, entity_props)
|
@@ -229,11 +258,13 @@ module ROCrate
|
|
229
258
|
##
|
230
259
|
# Extract the metadata entity from the entity hash, according to the rules defined here:
|
231
260
|
# https://www.researchobject.org/ro-crate/1.1/root-data-entity.html#finding-the-root-data-entity
|
232
|
-
# @return [Hash{String => Hash}] A Hash containing (hopefully) one value, the metadata entity's properties
|
233
|
-
# mapped by its @id.
|
261
|
+
# @return [nil, Hash{String => Hash}] A Hash containing (hopefully) one value, the metadata entity's properties
|
262
|
+
# mapped by its @id, or nil if nothing is found.
|
234
263
|
def self.extract_metadata_entity(entities)
|
235
264
|
key = entities.detect do |_, props|
|
236
|
-
props
|
265
|
+
conforms = props['conformsTo']
|
266
|
+
conforms = [conforms] unless conforms.is_a?(Array)
|
267
|
+
conforms.compact.any? { |c| c['@id']&.start_with?(ROCrate::Metadata::RO_CRATE_BASE) }
|
237
268
|
end&.first
|
238
269
|
|
239
270
|
return entities.delete(key) if key
|
@@ -245,6 +276,13 @@ module ROCrate
|
|
245
276
|
entities.delete(ROCrate::Metadata::IDENTIFIER_1_0))
|
246
277
|
end
|
247
278
|
|
279
|
+
##
|
280
|
+
# Extract the ro-crate-preview entity from the entity hash.
|
281
|
+
# @return [Hash{String => Hash}] A Hash containing the preview entity's properties mapped by its @id, or nil if nothing is found.
|
282
|
+
def self.extract_preview_entity(entities)
|
283
|
+
entities.delete("./#{ROCrate::Preview::IDENTIFIER}") || entities.delete(ROCrate::Preview::IDENTIFIER)
|
284
|
+
end
|
285
|
+
|
248
286
|
##
|
249
287
|
# Extract the root entity from the entity hash, according to the rules defined here:
|
250
288
|
# https://www.researchobject.org/ro-crate/1.1/root-data-entity.html#finding-the-root-data-entity
|
data/lib/ro_crate/writer.rb
CHANGED
@@ -16,14 +16,14 @@ module ROCrate
|
|
16
16
|
# @param overwrite [Boolean] Whether or not to overwrite existing files.
|
17
17
|
def write(dir, overwrite: true)
|
18
18
|
FileUtils.mkdir_p(dir) # Make any parent directories
|
19
|
-
@crate.
|
19
|
+
@crate.payload.each do |path, entry|
|
20
20
|
fullpath = ::File.join(dir, path)
|
21
21
|
next if !overwrite && ::File.exist?(fullpath)
|
22
22
|
next if entry.directory?
|
23
23
|
FileUtils.mkdir_p(::File.dirname(fullpath))
|
24
24
|
temp = Tempfile.new('ro-crate-temp')
|
25
25
|
begin
|
26
|
-
entry.
|
26
|
+
entry.write_to(temp)
|
27
27
|
temp.close
|
28
28
|
FileUtils.mv(temp, fullpath)
|
29
29
|
ensure
|
@@ -38,9 +38,9 @@ module ROCrate
|
|
38
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
|
-
@crate.
|
41
|
+
@crate.payload.each do |path, entry|
|
42
42
|
next if entry.directory?
|
43
|
-
zip.get_output_stream(path) { |s| entry.
|
43
|
+
zip.get_output_stream(path) { |s| entry.write_to(s) }
|
44
44
|
end
|
45
45
|
end
|
46
46
|
end
|
data/lib/ro_crate.rb
CHANGED
@@ -10,10 +10,11 @@ require 'ro_crate/json_ld_hash'
|
|
10
10
|
require 'ro_crate/model/entity'
|
11
11
|
require 'ro_crate/model/data_entity'
|
12
12
|
require 'ro_crate/model/file'
|
13
|
-
require 'ro_crate/model/remote_entry'
|
14
13
|
require 'ro_crate/model/entry'
|
14
|
+
require 'ro_crate/model/remote_entry'
|
15
15
|
require 'ro_crate/model/directory'
|
16
16
|
require 'ro_crate/model/metadata'
|
17
|
+
require 'ro_crate/model/preview_generator'
|
17
18
|
require 'ro_crate/model/preview'
|
18
19
|
require 'ro_crate/model/crate'
|
19
20
|
require 'ro_crate/model/contextual_entity'
|
data/ro_crate.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'ro-crate'
|
3
|
-
s.version = '0.4.
|
3
|
+
s.version = '0.4.14'
|
4
4
|
s.summary = 'Create, manipulate, read RO-Crates.'
|
5
5
|
s.authors = ['Finn Bacall']
|
6
6
|
s.email = 'finn.bacall@manchester.ac.uk'
|
@@ -8,11 +8,11 @@ Gem::Specification.new do |s|
|
|
8
8
|
s.homepage = 'https://github.com/ResearchObject/ro-crate-ruby'
|
9
9
|
s.require_paths = ['lib']
|
10
10
|
s.licenses = ['MIT']
|
11
|
-
s.add_runtime_dependency 'addressable', '
|
11
|
+
s.add_runtime_dependency 'addressable', '>= 2.7', '< 2.9'
|
12
12
|
s.add_runtime_dependency 'rubyzip', '~> 2.0.0'
|
13
13
|
s.add_development_dependency 'rake', '~> 13.0.0'
|
14
14
|
s.add_development_dependency 'test-unit', '~> 3.2.3'
|
15
|
-
s.add_development_dependency 'simplecov', '~> 0.
|
15
|
+
s.add_development_dependency 'simplecov', '~> 0.21.2'
|
16
16
|
s.add_development_dependency 'yard', '~> 0.9.25'
|
17
17
|
s.add_development_dependency 'webmock', '~> 3.8.3'
|
18
18
|
end
|
data/test/crate_test.rb
CHANGED
@@ -164,6 +164,18 @@ class CrateTest < Test::Unit::TestCase
|
|
164
164
|
assert_equal 2, crate1.contextual_entities.first.properties['cats']
|
165
165
|
end
|
166
166
|
|
167
|
+
test 'sharing entities' do
|
168
|
+
crate = ROCrate::Crate.new
|
169
|
+
info = crate.add_file(fixture_file('info.txt'),'the_info.txt')
|
170
|
+
bob = crate.add_person('bob', name: 'Bob Jones')
|
171
|
+
crate.author = bob
|
172
|
+
info.author = bob
|
173
|
+
|
174
|
+
assert_equal [bob], crate.contextual_entities
|
175
|
+
assert_equal bob, info.author
|
176
|
+
assert_equal bob, crate.author
|
177
|
+
end
|
178
|
+
|
167
179
|
test 'external files' do
|
168
180
|
crate = ROCrate::Crate.new
|
169
181
|
local = crate.add_file(fixture_file('info.txt'))
|
@@ -203,7 +215,7 @@ class CrateTest < Test::Unit::TestCase
|
|
203
215
|
crate = ROCrate::Crate.new
|
204
216
|
entities = crate.add_all(fixture_file('directory').path, include_hidden: true)
|
205
217
|
|
206
|
-
paths = crate.
|
218
|
+
paths = crate.payload.keys
|
207
219
|
assert_equal 11, paths.length
|
208
220
|
assert_includes paths, 'data'
|
209
221
|
assert_includes paths, 'root.txt'
|
@@ -238,7 +250,7 @@ class CrateTest < Test::Unit::TestCase
|
|
238
250
|
|
239
251
|
assert_empty entities
|
240
252
|
|
241
|
-
paths = crate.
|
253
|
+
paths = crate.payload.keys
|
242
254
|
assert_equal 11, paths.length
|
243
255
|
assert_includes paths, 'data'
|
244
256
|
assert_includes paths, 'root.txt'
|
@@ -266,7 +278,7 @@ class CrateTest < Test::Unit::TestCase
|
|
266
278
|
crate = ROCrate::Crate.new
|
267
279
|
entities = crate.add_all(fixture_file('directory').path)
|
268
280
|
|
269
|
-
paths = crate.
|
281
|
+
paths = crate.payload.keys
|
270
282
|
assert_equal 8, paths.length
|
271
283
|
assert_includes paths, 'data'
|
272
284
|
assert_includes paths, 'root.txt'
|
@@ -293,4 +305,47 @@ class CrateTest < Test::Unit::TestCase
|
|
293
305
|
|
294
306
|
assert_equal "5678\n", crate.dereference('data/info.txt').source.read
|
295
307
|
end
|
308
|
+
|
309
|
+
test 'can delete entities' do
|
310
|
+
crate = ROCrate::Crate.new
|
311
|
+
file = crate.add_file(StringIO.new(''), 'file')
|
312
|
+
person = crate.add_person('#bob', { name: 'Bob' })
|
313
|
+
file.author = person
|
314
|
+
|
315
|
+
assert crate.delete(file)
|
316
|
+
assert_not_include crate.entities, file
|
317
|
+
assert_not_include crate.entities, person
|
318
|
+
end
|
319
|
+
|
320
|
+
test 'can delete entities by id' do
|
321
|
+
crate = ROCrate::Crate.new
|
322
|
+
file = crate.add_file(StringIO.new(''), 'file')
|
323
|
+
person = crate.add_person('#bob', { name: 'Bob' })
|
324
|
+
file.author = person
|
325
|
+
|
326
|
+
assert crate.delete('file')
|
327
|
+
assert_not_include crate.entities, file
|
328
|
+
assert_not_include crate.entities, person
|
329
|
+
end
|
330
|
+
|
331
|
+
test 'legacy entries method still returns same result as payload' do
|
332
|
+
crate = ROCrate::Crate.new
|
333
|
+
crate.add_all(fixture_file('directory').path)
|
334
|
+
|
335
|
+
paths = crate.entries.keys
|
336
|
+
assert_equal 8, paths.length
|
337
|
+
assert_includes paths, 'data'
|
338
|
+
assert_includes paths, 'root.txt'
|
339
|
+
assert_includes paths, 'info.txt'
|
340
|
+
assert_includes paths, 'data/binary.jpg'
|
341
|
+
assert_includes paths, 'data/info.txt'
|
342
|
+
assert_includes paths, 'data/nested.txt'
|
343
|
+
assert_not_includes paths, '.dotfile'
|
344
|
+
assert_not_includes paths, '.dir'
|
345
|
+
assert_not_includes paths, '.dir/test.txt'
|
346
|
+
assert_includes paths, 'ro-crate-metadata.json'
|
347
|
+
assert_includes paths, 'ro-crate-preview.html'
|
348
|
+
|
349
|
+
assert_equal crate.payload.keys, crate.entries.keys
|
350
|
+
end
|
296
351
|
end
|
data/test/directory_test.rb
CHANGED
@@ -5,41 +5,41 @@ class DirectoryTest < Test::Unit::TestCase
|
|
5
5
|
crate = ROCrate::Crate.new
|
6
6
|
crate.add_directory(fixture_file('directory'))
|
7
7
|
|
8
|
-
|
8
|
+
payload = crate.payload
|
9
9
|
base_path = ::File.dirname(fixture_file('directory'))
|
10
|
-
assert_equal ::File.expand_path(::File.join(base_path, 'directory/info.txt')),
|
11
|
-
assert_equal ::File.expand_path(::File.join(base_path, 'directory/root.txt')),
|
12
|
-
assert_equal ::File.expand_path(::File.join(base_path, 'directory/data')),
|
13
|
-
assert_equal ::File.expand_path(::File.join(base_path, 'directory/data/info.txt')),
|
14
|
-
assert_equal ::File.expand_path(::File.join(base_path, 'directory/data/nested.txt')),
|
15
|
-
assert_equal ::File.expand_path(::File.join(base_path, 'directory/data/binary.jpg')),
|
10
|
+
assert_equal ::File.expand_path(::File.join(base_path, 'directory/info.txt')), payload['directory/info.txt'].path
|
11
|
+
assert_equal ::File.expand_path(::File.join(base_path, 'directory/root.txt')), payload['directory/root.txt'].path
|
12
|
+
assert_equal ::File.expand_path(::File.join(base_path, 'directory/data')), payload['directory/data'].path
|
13
|
+
assert_equal ::File.expand_path(::File.join(base_path, 'directory/data/info.txt')), payload['directory/data/info.txt'].path
|
14
|
+
assert_equal ::File.expand_path(::File.join(base_path, 'directory/data/nested.txt')), payload['directory/data/nested.txt'].path
|
15
|
+
assert_equal ::File.expand_path(::File.join(base_path, 'directory/data/binary.jpg')), payload['directory/data/binary.jpg'].path
|
16
16
|
end
|
17
17
|
|
18
18
|
test 'adding directory via path' do
|
19
19
|
crate = ROCrate::Crate.new
|
20
20
|
crate.add_directory(fixture_file('directory').path.to_s)
|
21
21
|
|
22
|
-
|
22
|
+
payload = crate.payload
|
23
23
|
base_path = ::File.dirname(fixture_file('directory'))
|
24
|
-
assert_equal ::File.expand_path(::File.join(base_path, 'directory/info.txt')),
|
25
|
-
assert_equal ::File.expand_path(::File.join(base_path, 'directory/root.txt')),
|
26
|
-
assert_equal ::File.expand_path(::File.join(base_path, 'directory/data')),
|
27
|
-
assert_equal ::File.expand_path(::File.join(base_path, 'directory/data/info.txt')),
|
28
|
-
assert_equal ::File.expand_path(::File.join(base_path, 'directory/data/nested.txt')),
|
29
|
-
assert_equal ::File.expand_path(::File.join(base_path, 'directory/data/binary.jpg')),
|
24
|
+
assert_equal ::File.expand_path(::File.join(base_path, 'directory/info.txt')), payload['directory/info.txt'].path
|
25
|
+
assert_equal ::File.expand_path(::File.join(base_path, 'directory/root.txt')), payload['directory/root.txt'].path
|
26
|
+
assert_equal ::File.expand_path(::File.join(base_path, 'directory/data')), payload['directory/data'].path
|
27
|
+
assert_equal ::File.expand_path(::File.join(base_path, 'directory/data/info.txt')), payload['directory/data/info.txt'].path
|
28
|
+
assert_equal ::File.expand_path(::File.join(base_path, 'directory/data/nested.txt')), payload['directory/data/nested.txt'].path
|
29
|
+
assert_equal ::File.expand_path(::File.join(base_path, 'directory/data/binary.jpg')), payload['directory/data/binary.jpg'].path
|
30
30
|
end
|
31
31
|
|
32
32
|
test 'adding to given path' do
|
33
33
|
crate = ROCrate::Crate.new
|
34
34
|
crate.add_directory(fixture_file('directory').path.to_s, 'fish')
|
35
35
|
|
36
|
-
|
36
|
+
payload = crate.payload
|
37
37
|
base_path = ::File.dirname(fixture_file('directory'))
|
38
|
-
assert_equal ::File.expand_path(::File.join(base_path, 'directory/info.txt')),
|
39
|
-
assert_equal ::File.expand_path(::File.join(base_path, 'directory/root.txt')),
|
40
|
-
assert_equal ::File.expand_path(::File.join(base_path, 'directory/data')),
|
41
|
-
assert_equal ::File.expand_path(::File.join(base_path, 'directory/data/info.txt')),
|
42
|
-
assert_equal ::File.expand_path(::File.join(base_path, 'directory/data/nested.txt')),
|
43
|
-
assert_equal ::File.expand_path(::File.join(base_path, 'directory/data/binary.jpg')),
|
38
|
+
assert_equal ::File.expand_path(::File.join(base_path, 'directory/info.txt')), payload['fish/info.txt'].path
|
39
|
+
assert_equal ::File.expand_path(::File.join(base_path, 'directory/root.txt')), payload['fish/root.txt'].path
|
40
|
+
assert_equal ::File.expand_path(::File.join(base_path, 'directory/data')), payload['fish/data'].path
|
41
|
+
assert_equal ::File.expand_path(::File.join(base_path, 'directory/data/info.txt')), payload['fish/data/info.txt'].path
|
42
|
+
assert_equal ::File.expand_path(::File.join(base_path, 'directory/data/nested.txt')), payload['fish/data/nested.txt'].path
|
43
|
+
assert_equal ::File.expand_path(::File.join(base_path, 'directory/data/binary.jpg')), payload['fish/data/binary.jpg'].path
|
44
44
|
end
|
45
45
|
end
|
data/test/entity_test.rb
CHANGED
@@ -38,11 +38,11 @@ class EntityTest < Test::Unit::TestCase
|
|
38
38
|
test 'fetch appropriate class for type' do
|
39
39
|
assert_equal ROCrate::File, ROCrate::DataEntity.specialize({ '@type' => 'File' })
|
40
40
|
assert_equal ROCrate::File, ROCrate::DataEntity.specialize({ '@type' => ['File', 'Image'] })
|
41
|
-
assert_equal ROCrate::
|
42
|
-
assert_equal ROCrate::
|
41
|
+
assert_equal ROCrate::DataEntity, ROCrate::DataEntity.specialize({ '@type' => 'SoftwareSourceCode' })
|
42
|
+
assert_equal ROCrate::DataEntity, ROCrate::DataEntity.specialize({ '@type' => 'anything that isnt a directory' })
|
43
43
|
assert_equal ROCrate::Directory, ROCrate::DataEntity.specialize({ '@type' => 'Dataset' })
|
44
44
|
assert_equal ROCrate::Directory, ROCrate::DataEntity.specialize({ '@type' => ['Dataset', 'Image'] })
|
45
|
-
assert_equal ROCrate::
|
45
|
+
assert_equal ROCrate::DataEntity, ROCrate::DataEntity.specialize({ '@type' => 'Person' })
|
46
46
|
assert_equal ROCrate::File, ROCrate::DataEntity.specialize({ '@type' => ['File', 'Image'], '@id' => 'http://www.external.com' })
|
47
47
|
|
48
48
|
assert_equal ROCrate::Person, ROCrate::ContextualEntity.specialize({ '@type' => 'Person' })
|
@@ -91,4 +91,118 @@ class EntityTest < Test::Unit::TestCase
|
|
91
91
|
assert_equal "http://www.data.com/my%20crate/", ROCrate::Crate.format_id('http://www.data.com/my%20crate'), 'Crate ID should end with /'
|
92
92
|
assert_equal "http://www.data.com/my%20crate/", ROCrate::Crate.format_id('http://www.data.com/my%20crate/')
|
93
93
|
end
|
94
|
+
|
95
|
+
test 'linked entities' do
|
96
|
+
crate = ROCrate::Crate.new
|
97
|
+
file = crate.add_file(StringIO.new(''), 'file')
|
98
|
+
person = crate.add_person('#bob', { name: 'Bob' })
|
99
|
+
file.author = person
|
100
|
+
|
101
|
+
linked = file.linked_entities
|
102
|
+
assert_include linked, person
|
103
|
+
assert_equal 1, linked.length
|
104
|
+
|
105
|
+
linked = crate.linked_entities
|
106
|
+
assert_include linked, file
|
107
|
+
assert_equal 1, linked.length
|
108
|
+
|
109
|
+
linked = crate.linked_entities(deep: true)
|
110
|
+
assert_include linked, file
|
111
|
+
assert_include linked, person
|
112
|
+
assert_equal 2, linked.length
|
113
|
+
end
|
114
|
+
|
115
|
+
test 'deleting entities removes linked entities' do
|
116
|
+
crate = ROCrate::Crate.new
|
117
|
+
file = crate.add_file(StringIO.new(''), 'file')
|
118
|
+
person = crate.add_person('#bob', { name: 'Bob' })
|
119
|
+
file.author = person
|
120
|
+
|
121
|
+
assert file.delete
|
122
|
+
assert_not_include crate.entities, file
|
123
|
+
assert_not_include crate.entities, person
|
124
|
+
end
|
125
|
+
|
126
|
+
test 'deleting entities does not remove dangling entities if option set' do
|
127
|
+
crate = ROCrate::Crate.new
|
128
|
+
file = crate.add_file(StringIO.new(''), 'file')
|
129
|
+
person = crate.add_person('#bob', { name: 'Bob' })
|
130
|
+
file.author = person
|
131
|
+
|
132
|
+
assert file.delete(remove_orphaned: false)
|
133
|
+
assert_not_include crate.entities, file
|
134
|
+
assert_include crate.entities, person
|
135
|
+
end
|
136
|
+
|
137
|
+
test 'creating files in various ways' do
|
138
|
+
stub_request(:get, 'http://example.com/external_ref.txt').to_return(status: 200, body: 'file contents')
|
139
|
+
|
140
|
+
crate = ROCrate::Crate.new
|
141
|
+
|
142
|
+
f1 = nil
|
143
|
+
Dir.chdir(fixture_dir) { f1 = ROCrate::File.new(crate, 'data.csv') }
|
144
|
+
refute f1.source.remote?
|
145
|
+
refute f1.source.directory?
|
146
|
+
assert_equal 20, f1.source.read.length
|
147
|
+
t = Tempfile.new('tf1')
|
148
|
+
f1.source.write_to(t)
|
149
|
+
t.rewind
|
150
|
+
assert_equal 20, t.read.length
|
151
|
+
|
152
|
+
f2 = ROCrate::File.new(crate, fixture_file('info.txt'), { author: crate.add_person('bob', name: 'Bob').reference })
|
153
|
+
refute f2.source.remote?
|
154
|
+
refute f2.source.directory?
|
155
|
+
assert f2.source.read
|
156
|
+
assert_equal 6, f2.source.read.length
|
157
|
+
t = Tempfile.new('tf2')
|
158
|
+
f2.source.write_to(t)
|
159
|
+
t.rewind
|
160
|
+
assert_equal 6, t.read.length
|
161
|
+
|
162
|
+
f3 = ROCrate::File.new(crate, 'http://example.com/external_ref.txt')
|
163
|
+
assert f3.source.remote?
|
164
|
+
refute f3.source.directory?
|
165
|
+
assert f3.source.read
|
166
|
+
assert_equal 13, f3.source.read.length
|
167
|
+
t = Tempfile.new('tf3')
|
168
|
+
f3.source.write_to(t)
|
169
|
+
t.rewind
|
170
|
+
assert_equal 13, t.read.length
|
171
|
+
|
172
|
+
f3 = ROCrate::File.new(crate, 'http://example.com/external_ref.txt')
|
173
|
+
assert f3.source.remote?
|
174
|
+
refute f3.source.directory?
|
175
|
+
assert f3.source.read
|
176
|
+
assert_equal 13, f3.source.read.length
|
177
|
+
t = Tempfile.new('tf3')
|
178
|
+
f3.source.write_to(t)
|
179
|
+
t.rewind
|
180
|
+
assert_equal 13, t.read.length
|
181
|
+
end
|
182
|
+
|
183
|
+
test 'assigning and checking type' do
|
184
|
+
crate = ROCrate::Crate.new
|
185
|
+
file = ROCrate::File.new(crate, 'data.csv')
|
186
|
+
|
187
|
+
assert file.has_type?('File')
|
188
|
+
|
189
|
+
file.type = ['File', 'Workflow']
|
190
|
+
|
191
|
+
assert file.has_type?('Workflow')
|
192
|
+
assert file.has_type?('File')
|
193
|
+
refute file.has_type?('Banana')
|
194
|
+
end
|
195
|
+
|
196
|
+
test 'inspecting object truncates very long property list' do
|
197
|
+
crate = ROCrate::Crate.new
|
198
|
+
entity = ROCrate::ContextualEntity.new(crate, 'hello')
|
199
|
+
|
200
|
+
assert entity.inspect.start_with?("<#ROCrate::ContextualEntity arcp://uuid,")
|
201
|
+
|
202
|
+
entity['veryLong'] = ('123456789a' * 100)
|
203
|
+
|
204
|
+
ins = entity.inspect
|
205
|
+
assert ins.length < 1000
|
206
|
+
assert ins.end_with?('...>')
|
207
|
+
end
|
94
208
|
end
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
abcd
|
@@ -0,0 +1 @@
|
|
1
|
+
No, I am nested!
|
@@ -0,0 +1,33 @@
|
|
1
|
+
{
|
2
|
+
"@context": [
|
3
|
+
"https://w3id.org/ro/crate/1.1/context",
|
4
|
+
{
|
5
|
+
"@vocab": "http://schema.org/"
|
6
|
+
},
|
7
|
+
{
|
8
|
+
"@base": null
|
9
|
+
}
|
10
|
+
],
|
11
|
+
"@graph": [
|
12
|
+
{
|
13
|
+
"@id": "#collection",
|
14
|
+
"@type": "RepositoryCollection",
|
15
|
+
"name": "Test collection"
|
16
|
+
},
|
17
|
+
{
|
18
|
+
"@id": "./",
|
19
|
+
"@type": "Dataset",
|
20
|
+
"hasFile": [],
|
21
|
+
"hasPart": [{"@id": "#collection"}],
|
22
|
+
"name": "testing hasPart"
|
23
|
+
},
|
24
|
+
{
|
25
|
+
"@id": "ro-crate-metadata.json",
|
26
|
+
"@type": "CreativeWork",
|
27
|
+
"about": {
|
28
|
+
"@id": "./"
|
29
|
+
},
|
30
|
+
"identifier": "ro-crate-metadata.json"
|
31
|
+
}
|
32
|
+
]
|
33
|
+
}
|