ro-crate 0.4.8 → 0.4.12
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/contextual_entity.rb +2 -14
- data/lib/ro_crate/model/crate.rb +52 -6
- data/lib/ro_crate/model/data_entity.rb +6 -5
- data/lib/ro_crate/model/directory.rb +3 -5
- data/lib/ro_crate/model/entity.rb +65 -6
- data/lib/ro_crate/model/entry.rb +2 -2
- data/lib/ro_crate/model/file.rb +2 -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 +77 -20
- 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 +37 -3
- data/test/directory_test.rb +21 -21
- data/test/entity_test.rb +135 -0
- 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/nested_directory.zip +0 -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 +133 -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/reader_test.rb +83 -40
- data/test/test_helper.rb +5 -1
- data/test/writer_test.rb +59 -2
- metadata +26 -8
data/lib/ro_crate/reader.rb
CHANGED
@@ -31,7 +31,7 @@ module ROCrate
|
|
31
31
|
def self.unzip_to(source, target)
|
32
32
|
source = Pathname.new(::File.expand_path(source)) if source.is_a?(String)
|
33
33
|
|
34
|
-
if source.is_a?(Pathname) || source.
|
34
|
+
if source.is_a?(Pathname) || source.respond_to?(:path)
|
35
35
|
unzip_file_to(source, target)
|
36
36
|
else
|
37
37
|
unzip_io_to(source, target)
|
@@ -84,7 +84,10 @@ module ROCrate
|
|
84
84
|
def self.read_zip(source, target_dir: Dir.mktmpdir)
|
85
85
|
unzip_to(source, target_dir)
|
86
86
|
|
87
|
-
|
87
|
+
# Traverse the unzipped directory to try and find the crate's root
|
88
|
+
root_dir = detect_root_directory(target_dir)
|
89
|
+
|
90
|
+
read_directory(root_dir)
|
88
91
|
end
|
89
92
|
|
90
93
|
##
|
@@ -100,8 +103,12 @@ module ROCrate
|
|
100
103
|
entry == ROCrate::Metadata::IDENTIFIER_1_0 }
|
101
104
|
|
102
105
|
if metadata_file
|
103
|
-
|
104
|
-
|
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)
|
105
112
|
else
|
106
113
|
raise 'No metadata found!'
|
107
114
|
end
|
@@ -110,10 +117,9 @@ module ROCrate
|
|
110
117
|
##
|
111
118
|
# Extracts all the entities from the @graph of the RO-Crate Metadata.
|
112
119
|
#
|
113
|
-
# @param
|
120
|
+
# @param metadata [Hash] A Hash containing the parsed metadata JSON.
|
114
121
|
# @return [Hash{String => Hash}] A Hash of all the entities, mapped by their @id.
|
115
|
-
def self.entities_from_metadata(
|
116
|
-
metadata = JSON.parse(metadata_json)
|
122
|
+
def self.entities_from_metadata(metadata)
|
117
123
|
graph = metadata['@graph']
|
118
124
|
|
119
125
|
if graph
|
@@ -126,6 +132,7 @@ module ROCrate
|
|
126
132
|
# Do some normalization...
|
127
133
|
entities[ROCrate::Metadata::IDENTIFIER] = extract_metadata_entity(entities)
|
128
134
|
raise "No metadata entity found in @graph!" unless entities[ROCrate::Metadata::IDENTIFIER]
|
135
|
+
entities[ROCrate::Preview::IDENTIFIER] = extract_preview_entity(entities)
|
129
136
|
entities[ROCrate::Crate::IDENTIFIER] = extract_root_entity(entities)
|
130
137
|
raise "No root entity (with @id: #{entities[ROCrate::Metadata::IDENTIFIER].dig('about', '@id')}) found in @graph!" unless entities[ROCrate::Crate::IDENTIFIER]
|
131
138
|
|
@@ -136,25 +143,50 @@ module ROCrate
|
|
136
143
|
end
|
137
144
|
|
138
145
|
##
|
139
|
-
# Create
|
146
|
+
# Create and populate crate from the given set of entities.
|
140
147
|
#
|
141
148
|
# @param entity_hash [Hash{String => Hash}] A Hash containing all the entities in the @graph, mapped by their @id.
|
142
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.
|
143
153
|
# @return [Crate] The RO-Crate.
|
144
|
-
def self.build_crate(entity_hash, source)
|
145
|
-
|
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|
|
146
180
|
crate.properties = entity_hash.delete(ROCrate::Crate::IDENTIFIER)
|
147
181
|
crate.metadata.properties = entity_hash.delete(ROCrate::Metadata::IDENTIFIER)
|
182
|
+
crate.metadata.context = context
|
148
183
|
preview_properties = entity_hash.delete(ROCrate::Preview::IDENTIFIER)
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
crate.
|
153
|
-
end
|
154
|
-
# The remaining entities in the hash must be contextual.
|
155
|
-
extract_contextual_entities(crate, entity_hash).each do |entity|
|
156
|
-
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 || {})
|
157
188
|
end
|
189
|
+
crate.add_all(source, false)
|
158
190
|
end
|
159
191
|
end
|
160
192
|
|
@@ -226,8 +258,8 @@ module ROCrate
|
|
226
258
|
##
|
227
259
|
# Extract the metadata entity from the entity hash, according to the rules defined here:
|
228
260
|
# https://www.researchobject.org/ro-crate/1.1/root-data-entity.html#finding-the-root-data-entity
|
229
|
-
# @return [Hash{String => Hash}] A Hash containing (hopefully) one value, the metadata entity's properties
|
230
|
-
# 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.
|
231
263
|
def self.extract_metadata_entity(entities)
|
232
264
|
key = entities.detect do |_, props|
|
233
265
|
props.dig('conformsTo', '@id')&.start_with?(ROCrate::Metadata::RO_CRATE_BASE)
|
@@ -242,6 +274,13 @@ module ROCrate
|
|
242
274
|
entities.delete(ROCrate::Metadata::IDENTIFIER_1_0))
|
243
275
|
end
|
244
276
|
|
277
|
+
##
|
278
|
+
# Extract the ro-crate-preview entity from the entity hash.
|
279
|
+
# @return [Hash{String => Hash}] A Hash containing the preview entity's properties mapped by its @id, or nil if nothing is found.
|
280
|
+
def self.extract_preview_entity(entities)
|
281
|
+
entities.delete("./#{ROCrate::Preview::IDENTIFIER}") || entities.delete(ROCrate::Preview::IDENTIFIER)
|
282
|
+
end
|
283
|
+
|
245
284
|
##
|
246
285
|
# Extract the root entity from the entity hash, according to the rules defined here:
|
247
286
|
# https://www.researchobject.org/ro-crate/1.1/root-data-entity.html#finding-the-root-data-entity
|
@@ -252,5 +291,23 @@ module ROCrate
|
|
252
291
|
raise "Metadata entity does not reference any root entity" unless root_id
|
253
292
|
entities.delete(root_id)
|
254
293
|
end
|
294
|
+
|
295
|
+
##
|
296
|
+
# Finds an RO-Crate's root directory (where `ro-crate-metdata.json` is located) within a given directory.
|
297
|
+
#
|
298
|
+
# @param source [String, ::File, Pathname] The location of the directory.
|
299
|
+
# @return [Pathname, nil] The path to the root, or nil if not found.
|
300
|
+
def self.detect_root_directory(source)
|
301
|
+
Pathname(source).find do |entry|
|
302
|
+
if entry.file?
|
303
|
+
name = entry.basename.to_s
|
304
|
+
if name == ROCrate::Metadata::IDENTIFIER || name == ROCrate::Metadata::IDENTIFIER_1_0
|
305
|
+
return entry.parent
|
306
|
+
end
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
nil
|
311
|
+
end
|
255
312
|
end
|
256
313
|
end
|
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.12'
|
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,26 @@ 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
|
296
330
|
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
@@ -70,4 +70,139 @@ class EntityTest < Test::Unit::TestCase
|
|
70
70
|
assert_equal({ '@id' => '#fred' }, person.reference)
|
71
71
|
assert_equal(person.canonical_id, crate.author.canonical_id)
|
72
72
|
end
|
73
|
+
|
74
|
+
test 'format various IDs' do
|
75
|
+
assert_equal "#Hello%20World/Goodbye%20World", ROCrate::ContextualEntity.format_id('#Hello World/Goodbye World')
|
76
|
+
assert_equal "#Hello%20World/Goodbye%20World", ROCrate::ContextualEntity.format_id('Hello World/Goodbye World')
|
77
|
+
assert_equal "#%F0%9F%98%8A", ROCrate::ContextualEntity.format_id("😊")
|
78
|
+
|
79
|
+
assert_equal "test123/hello.txt", ROCrate::File.format_id('./test123/hello.txt')
|
80
|
+
assert_equal "test123/hello.txt", ROCrate::File.format_id('./test123/hello.txt/')
|
81
|
+
assert_equal "http://www.data.com/my%20data.txt", ROCrate::File.format_id('http://www.data.com/my%20data.txt')
|
82
|
+
assert_equal "http://www.data.com/my%20data.txt/", ROCrate::File.format_id('http://www.data.com/my%20data.txt/'), 'Should not modify absolute URI for DataEntity'
|
83
|
+
|
84
|
+
assert_equal "my%20directory/", ROCrate::Directory.format_id('my directory')
|
85
|
+
assert_equal "my%20directory/", ROCrate::Directory.format_id('my directory/')
|
86
|
+
assert_equal 'http://www.data.com/my%20directory', ROCrate::Directory.format_id('http://www.data.com/my%20directory'), 'Should not modify absolute URI for DataEntity'
|
87
|
+
assert_equal 'http://www.data.com/my%20directory/', ROCrate::Directory.format_id('http://www.data.com/my%20directory/'), 'Should not modify absolute URI for DataEntity'
|
88
|
+
|
89
|
+
assert_equal "./", ROCrate::Crate.format_id('./')
|
90
|
+
assert_equal "cool%20crate/", ROCrate::Crate.format_id('./cool crate')
|
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
|
+
assert_equal "http://www.data.com/my%20crate/", ROCrate::Crate.format_id('http://www.data.com/my%20crate/')
|
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
|
73
208
|
end
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
abcd
|
@@ -0,0 +1 @@
|
|
1
|
+
No, I am nested!
|
Binary file
|