ro-crate 0.5.2 → 0.5.3
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/.github/workflows/tests.yml +1 -1
- data/.ruby-version +1 -1
- data/lib/ro_crate/reader.rb +8 -2
- data/lib/ro_crate/ro-crate-preview.html.erb +28 -12
- data/lib/ro_crate/writer.rb +6 -2
- data/ro_crate.gemspec +1 -1
- data/test/fixtures/multi_metadata_crate.crate.zip +0 -0
- data/test/fixtures/singleton-haspart/a_file +1 -0
- data/test/fixtures/singleton-haspart/ro-crate-metadata.json +57 -0
- data/test/preview_test.rb +48 -0
- data/test/reader_test.rb +14 -0
- data/test/writer_test.rb +35 -0
- metadata +7 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 987f4bf5543890ca23264eaa771134f6ec2ba848a84ea32424cf951429141523
|
4
|
+
data.tar.gz: f05c5166d95be3cec706fbb5d550c5af916f5f4c444112575ec49d5fe961e12a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '0848a81d03d8cdf7b4809de8613d90b67950f4339ae20ab5ce4ba6fa8d9e9559033c4a53ca47391b99ed5287ba7a2f2be7976b87c7ea8479051b8e7dfc9da6e8'
|
7
|
+
data.tar.gz: c1fc1ffdadafd04c19d81c37befec9eed9bcf9e40db9c39158b20a2a8ec8b8368841c65211d31439ba585f637de9541e2b7d58673da4964c7b8afccbfb9bf6ff
|
data/.github/workflows/tests.yml
CHANGED
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
ruby-3.
|
1
|
+
ruby-3.2.5
|
data/lib/ro_crate/reader.rb
CHANGED
@@ -204,7 +204,9 @@ module ROCrate
|
|
204
204
|
# @param entity_hash [Hash] A Hash containing all the entities in the @graph, mapped by their @id.
|
205
205
|
# @return [Array<ROCrate::File, ROCrate::Directory>] The extracted DataEntity objects.
|
206
206
|
def self.extract_data_entities(crate, source, entity_hash)
|
207
|
-
|
207
|
+
parts = crate.raw_properties['hasPart'] || []
|
208
|
+
parts = [parts] unless parts.is_a?(Array)
|
209
|
+
parts.map do |ref|
|
208
210
|
entity_props = entity_hash.delete(ref['@id'])
|
209
211
|
next unless entity_props
|
210
212
|
entity_class = ROCrate::DataEntity.specialize(entity_props)
|
@@ -306,12 +308,16 @@ module ROCrate
|
|
306
308
|
# @param source [String, ::File, Pathname] The location of the directory.
|
307
309
|
# @return [Pathname, nil] The path to the root, or nil if not found.
|
308
310
|
def self.detect_root_directory(source)
|
309
|
-
|
311
|
+
queue = [source]
|
312
|
+
until queue.empty?
|
313
|
+
entry = Pathname(queue.shift)
|
310
314
|
if entry.file?
|
311
315
|
name = entry.basename.to_s
|
312
316
|
if name == ROCrate::Metadata::IDENTIFIER || name == ROCrate::Metadata::IDENTIFIER_1_0
|
313
317
|
return entry.parent
|
314
318
|
end
|
319
|
+
elsif entry.directory?
|
320
|
+
queue += entry.children
|
315
321
|
end
|
316
322
|
end
|
317
323
|
|
@@ -1,3 +1,23 @@
|
|
1
|
+
<%
|
2
|
+
def entity_to_html(entity)
|
3
|
+
if entity.is_a?(Array)
|
4
|
+
if entity.length == 1
|
5
|
+
entity_to_html(entity.first)
|
6
|
+
else
|
7
|
+
"<ul><li>#{entity.map { |e| entity_to_html(e) }.join('</li><li>')}</li></ul>"
|
8
|
+
end
|
9
|
+
elsif entity.is_a?(ROCrate::Entity)
|
10
|
+
label = entity['name'] || entity.id
|
11
|
+
if entity.external?
|
12
|
+
"<a href=\"#{entity.id}\" target=\"_blank\">#{label}</a>"
|
13
|
+
else
|
14
|
+
label
|
15
|
+
end
|
16
|
+
else
|
17
|
+
entity
|
18
|
+
end
|
19
|
+
end
|
20
|
+
%>
|
1
21
|
<!DOCTYPE html>
|
2
22
|
<html lang="en">
|
3
23
|
<head>
|
@@ -18,36 +38,32 @@
|
|
18
38
|
<dl>
|
19
39
|
<% if author %>
|
20
40
|
<dt>Author</dt>
|
21
|
-
<dd><%= author %></dd>
|
41
|
+
<dd><%= entity_to_html author %></dd>
|
22
42
|
<% end %>
|
23
43
|
<% if contact_point %>
|
24
44
|
<dt>Contact</dt>
|
25
|
-
<dd><%= contact_point %></dd>
|
45
|
+
<dd><%= entity_to_html contact_point %></dd>
|
26
46
|
<% end %>
|
27
47
|
<% if publisher %>
|
28
48
|
<dt>Publisher</dt>
|
29
|
-
<dd><%= publisher %></dd>
|
49
|
+
<dd><%= entity_to_html publisher %></dd>
|
30
50
|
<% end %>
|
31
51
|
<% if license %>
|
32
52
|
<dt>License</dt>
|
33
|
-
<dd><%= license %></dd>
|
53
|
+
<dd><%= entity_to_html license %></dd>
|
34
54
|
<% end %>
|
35
55
|
</dl>
|
36
56
|
|
37
57
|
<h2>Contents</h2>
|
38
58
|
<ul>
|
39
59
|
<% data_entities.each do |data_entity| %>
|
40
|
-
<li
|
41
|
-
|
42
|
-
<strong><a href="<%= data_entity.id %>" target="_blank"><%= data_entity.name || data_entity.id %></a></strong>
|
43
|
-
<% else %>
|
44
|
-
<strong><%= data_entity.name || data_entity.id %></strong>
|
45
|
-
<% end %>
|
60
|
+
<li>
|
61
|
+
<strong><%= entity_to_html data_entity %></strong>
|
46
62
|
<% if data_entity.content_size %>
|
47
|
-
<br/>Size: <%= data_entity.content_size %>
|
63
|
+
<br/>Size: <%= entity_to_html data_entity.content_size %>
|
48
64
|
<% end %>
|
49
65
|
<% if data_entity.encoding_format %>
|
50
|
-
<br/>Format: <%= data_entity.encoding_format %>
|
66
|
+
<br/>Format: <%= entity_to_html data_entity.encoding_format %>
|
51
67
|
<% end %>
|
52
68
|
</li>
|
53
69
|
<% end %>
|
data/lib/ro_crate/writer.rb
CHANGED
@@ -14,9 +14,11 @@ module ROCrate
|
|
14
14
|
#
|
15
15
|
# @param dir [String] A path for the directory for the crate to be written to. All parent directories will be created.
|
16
16
|
# @param overwrite [Boolean] Whether or not to overwrite existing files.
|
17
|
-
|
17
|
+
# @param skip_preview [Boolean] Whether or not to skip generation of the RO-Crate preview HTML file.
|
18
|
+
def write(dir, overwrite: true, skip_preview: false)
|
18
19
|
FileUtils.mkdir_p(dir) # Make any parent directories
|
19
20
|
@crate.payload.each do |path, entry|
|
21
|
+
next if skip_preview && entry&.source.is_a?(ROCrate::PreviewGenerator)
|
20
22
|
fullpath = ::File.join(dir, path)
|
21
23
|
next if !overwrite && ::File.exist?(fullpath)
|
22
24
|
next if entry.directory?
|
@@ -40,10 +42,12 @@ module ROCrate
|
|
40
42
|
# Write the crate to a zip file.
|
41
43
|
#
|
42
44
|
# @param destination [String, ::File] The destination where to write the RO-Crate zip.
|
43
|
-
|
45
|
+
# @param skip_preview [Boolean] Whether or not to skip generation of the RO-Crate preview HTML file.
|
46
|
+
def write_zip(destination, skip_preview: false)
|
44
47
|
Zip::File.open(destination, Zip::File::CREATE) do |zip|
|
45
48
|
@crate.payload.each do |path, entry|
|
46
49
|
next if entry.directory?
|
50
|
+
next if skip_preview && entry&.source.is_a?(ROCrate::PreviewGenerator)
|
47
51
|
if entry.symlink?
|
48
52
|
zip.add(path, entry.path) if entry.path
|
49
53
|
else
|
data/ro_crate.gemspec
CHANGED
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
123
|
@@ -0,0 +1,57 @@
|
|
1
|
+
{
|
2
|
+
"@context": [
|
3
|
+
"https://w3id.org/ro/crate/1.1/context",
|
4
|
+
"https://w3id.org/ro/terms/workflow-run/context"
|
5
|
+
],
|
6
|
+
"@graph": [
|
7
|
+
{
|
8
|
+
"@id": "./",
|
9
|
+
"@type": "Dataset",
|
10
|
+
"datePublished": "2025-01-28T02:44:51.523Z",
|
11
|
+
"hasPart": {
|
12
|
+
"@id": "a_file"
|
13
|
+
},
|
14
|
+
"dateCreated": "2025-01-28T02:45:05.906Z",
|
15
|
+
"dateModified": "2025-01-28T02:44:51.523Z",
|
16
|
+
"description": "Something",
|
17
|
+
"license": {
|
18
|
+
"@id": "https://spdx.org/licenses/MIT"
|
19
|
+
},
|
20
|
+
"mainEntity": {
|
21
|
+
"@id": "a_file"
|
22
|
+
},
|
23
|
+
"name": "An RO-Crate containing just a single item"
|
24
|
+
},
|
25
|
+
{
|
26
|
+
"@id": "ro-crate-metadata.json",
|
27
|
+
"@type": "CreativeWork",
|
28
|
+
"conformsTo": [
|
29
|
+
{
|
30
|
+
"@id": "https://w3id.org/ro/crate/1.1"
|
31
|
+
},
|
32
|
+
{
|
33
|
+
"@id": "https://w3id.org/workflowhub/workflow-ro-crate/1.0"
|
34
|
+
}
|
35
|
+
],
|
36
|
+
"about": {
|
37
|
+
"@id": "./"
|
38
|
+
}
|
39
|
+
},
|
40
|
+
{
|
41
|
+
"@id": "a_file",
|
42
|
+
"@type": [
|
43
|
+
"File",
|
44
|
+
"ComputationalWorkflow",
|
45
|
+
"SoftwareSourceCode"
|
46
|
+
],
|
47
|
+
"contentSize": 4,
|
48
|
+
"description": "A workflow",
|
49
|
+
"encodingFormat": "text/plain",
|
50
|
+
"name": "a_file",
|
51
|
+
"programmingLanguage": {
|
52
|
+
"@id": "https://example.com/workflow_format"
|
53
|
+
}
|
54
|
+
}
|
55
|
+
]
|
56
|
+
}
|
57
|
+
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'test_helper'
|
3
|
+
|
4
|
+
class PreviewTest < Test::Unit::TestCase
|
5
|
+
test 'simple attributes' do
|
6
|
+
crate = ROCrate::Crate.new
|
7
|
+
crate.author = 'Finn'
|
8
|
+
|
9
|
+
html = crate.preview.source.read
|
10
|
+
assert_includes html, '<dd>Finn</dd>'
|
11
|
+
end
|
12
|
+
|
13
|
+
test 'list attributes' do
|
14
|
+
crate = ROCrate::Crate.new
|
15
|
+
crate.author = ['Finn', 'Josiah']
|
16
|
+
|
17
|
+
html = crate.preview.source.read
|
18
|
+
assert_includes html, '<dd><ul><li>Finn</li><li>Josiah</li></ul></dd>'
|
19
|
+
end
|
20
|
+
|
21
|
+
test 'entity attributes' do
|
22
|
+
crate = ROCrate::Crate.new
|
23
|
+
crate.author = crate.add_person('https://orcid.org/0000-0002-0048-3300', name: 'Finn')
|
24
|
+
|
25
|
+
html = crate.preview.source.read
|
26
|
+
assert_includes html, '<dd><a href="https://orcid.org/0000-0002-0048-3300" target="_blank">Finn</a></dd>'
|
27
|
+
end
|
28
|
+
|
29
|
+
test 'complex attributes' do
|
30
|
+
crate = ROCrate::Crate.new
|
31
|
+
crate.author = [crate.add_person('https://orcid.org/0000-0002-0048-3300', name: 'Finn'), 'Josiah']
|
32
|
+
|
33
|
+
html = crate.preview.source.read
|
34
|
+
|
35
|
+
assert_includes html, '<dd><ul><li><a href="https://orcid.org/0000-0002-0048-3300" target="_blank">Finn</a></li><li>Josiah</li></ul></dd>'
|
36
|
+
end
|
37
|
+
|
38
|
+
test 'files' do
|
39
|
+
crate = ROCrate::Crate.new
|
40
|
+
crate.add_file(fixture_file('info.txt'))
|
41
|
+
crate.add_external_file('https://raw.githubusercontent.com/ResearchObject/ro-crate-ruby/master/README.md')
|
42
|
+
|
43
|
+
html = crate.preview.source.read
|
44
|
+
|
45
|
+
assert_includes html, '<strong>info.txt</strong>'
|
46
|
+
assert_includes html, '<strong><a href="https://raw.githubusercontent.com/ResearchObject/ro-crate-ruby/master/README.md" target="_blank">https://raw.githubusercontent.com/ResearchObject/ro-crate-ruby/master/README.md</a></strong>'
|
47
|
+
end
|
48
|
+
end
|
data/test/reader_test.rb
CHANGED
@@ -367,6 +367,20 @@ class ReaderTest < Test::Unit::TestCase
|
|
367
367
|
assert_empty crate.data_entities
|
368
368
|
end
|
369
369
|
|
370
|
+
test 'reads first metadata file it encounters' do
|
371
|
+
crate = ROCrate::Reader.read(fixture_file('multi_metadata_crate.crate.zip').path)
|
372
|
+
|
373
|
+
assert_equal 'At the root', crate.name
|
374
|
+
end
|
375
|
+
|
376
|
+
test 'reads crate with singleton hasPart' do
|
377
|
+
crate = ROCrate::Reader.read(fixture_file('singleton-haspart').path)
|
378
|
+
|
379
|
+
data = crate.data_entities
|
380
|
+
assert_equal 1, data.length
|
381
|
+
assert_equal 'a_file', data.first.name
|
382
|
+
end
|
383
|
+
|
370
384
|
private
|
371
385
|
|
372
386
|
def check_exception(exception_class)
|
data/test/writer_test.rb
CHANGED
@@ -274,4 +274,39 @@ class WriterTest < Test::Unit::TestCase
|
|
274
274
|
end
|
275
275
|
end
|
276
276
|
end
|
277
|
+
|
278
|
+
test 'skip generating the preview in a directory' do
|
279
|
+
crate = ROCrate::Crate.new
|
280
|
+
crate.add_file(fixture_file('info.txt'))
|
281
|
+
crate.add_file(StringIO.new('just a string!'), 'notice.txt')
|
282
|
+
crate.add_file(fixture_file('data.csv'), 'directory/data.csv')
|
283
|
+
|
284
|
+
Dir.mktmpdir do |dir|
|
285
|
+
ROCrate::Writer.new(crate).write(dir, skip_preview: true)
|
286
|
+
assert ::File.exist?(::File.join(dir, ROCrate::Metadata::IDENTIFIER))
|
287
|
+
refute ::File.exist?(::File.join(dir, ROCrate::Preview::IDENTIFIER))
|
288
|
+
assert_equal 6, ::File.size(::File.join(dir, 'info.txt'))
|
289
|
+
assert_equal 14, ::File.size(::File.join(dir, 'notice.txt'))
|
290
|
+
assert_equal 20, ::File.size(::File.join(dir, 'directory', 'data.csv'))
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
test 'skip generating the preview in a zip file' do
|
295
|
+
crate = ROCrate::Crate.new
|
296
|
+
crate.add_directory(fixture_file('directory').path.to_s, 'fish')
|
297
|
+
|
298
|
+
Tempfile.create do |file|
|
299
|
+
ROCrate::Writer.new(crate).write_zip(file, skip_preview: true)
|
300
|
+
|
301
|
+
Zip::File.open(file) do |zipfile|
|
302
|
+
assert zipfile.file.exist?(ROCrate::Metadata::IDENTIFIER)
|
303
|
+
refute zipfile.file.exist?(ROCrate::Preview::IDENTIFIER)
|
304
|
+
assert zipfile.file.exist? 'fish/info.txt'
|
305
|
+
assert zipfile.file.exist? 'fish/root.txt'
|
306
|
+
assert zipfile.file.exist? 'fish/data/info.txt'
|
307
|
+
assert zipfile.file.exist? 'fish/data/nested.txt'
|
308
|
+
assert zipfile.file.exist? 'fish/data/binary.jpg'
|
309
|
+
end
|
310
|
+
end
|
311
|
+
end
|
277
312
|
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.5.
|
4
|
+
version: 0.5.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Finn Bacall
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-01-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: addressable
|
@@ -201,6 +201,7 @@ files:
|
|
201
201
|
- test/fixtures/file with spaces.txt
|
202
202
|
- test/fixtures/info.txt
|
203
203
|
- test/fixtures/misc_data_entity_crate/ro-crate-metadata.json
|
204
|
+
- test/fixtures/multi_metadata_crate.crate.zip
|
204
205
|
- test/fixtures/nested_directory.zip
|
205
206
|
- test/fixtures/ro-crate-galaxy-sortchangecase/LICENSE
|
206
207
|
- test/fixtures/ro-crate-galaxy-sortchangecase/README.md
|
@@ -209,6 +210,8 @@ files:
|
|
209
210
|
- test/fixtures/ro-crate-galaxy-sortchangecase/test/test1/input.bed
|
210
211
|
- test/fixtures/ro-crate-galaxy-sortchangecase/test/test1/output_exp.bed
|
211
212
|
- test/fixtures/ro-crate-galaxy-sortchangecase/test/test1/sort-and-change-case-test.yml
|
213
|
+
- test/fixtures/singleton-haspart/a_file
|
214
|
+
- test/fixtures/singleton-haspart/ro-crate-metadata.json
|
212
215
|
- test/fixtures/spaces/file with spaces.txt
|
213
216
|
- test/fixtures/spaces/ro-crate-metadata.jsonld
|
214
217
|
- test/fixtures/sparse_directory_crate.zip
|
@@ -2462,6 +2465,7 @@ files:
|
|
2462
2465
|
- test/fixtures/workflow-test-fixture-symlink/concat_two_files.ga
|
2463
2466
|
- test/fixtures/workflow-test-fixture-symlink/diagram.png
|
2464
2467
|
- test/fixtures/workflow-test-fixture-symlink/images/workflow-diagram.png
|
2468
|
+
- test/preview_test.rb
|
2465
2469
|
- test/reader_test.rb
|
2466
2470
|
- test/test_helper.rb
|
2467
2471
|
- test/writer_test.rb
|
@@ -2484,7 +2488,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
2484
2488
|
- !ruby/object:Gem::Version
|
2485
2489
|
version: '0'
|
2486
2490
|
requirements: []
|
2487
|
-
rubygems_version: 3.
|
2491
|
+
rubygems_version: 3.4.19
|
2488
2492
|
signing_key:
|
2489
2493
|
specification_version: 4
|
2490
2494
|
summary: Create, manipulate, read RO-Crates.
|