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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f2462dcf00e2593cf8ea7108af9f9b6ef54ef773aea01be125f7c79ce67c2850
4
- data.tar.gz: 40955bc76cd0344b80b727a79f5888ddc99d3874ecf3f8ce4db64ac2a722d713
3
+ metadata.gz: 987f4bf5543890ca23264eaa771134f6ec2ba848a84ea32424cf951429141523
4
+ data.tar.gz: f05c5166d95be3cec706fbb5d550c5af916f5f4c444112575ec49d5fe961e12a
5
5
  SHA512:
6
- metadata.gz: 7bd16f57d802a39d378cbcfa663ecc55acfbc77256013a50d7490a652cf383186c99dbbd0c28d5747751c33aa79fe06033e1a90a15cb6f2052139045992afc76
7
- data.tar.gz: 8a6f755b6fa96e511ca1ff4c034f049c6148acd2fe4f1aa8e7a71ab231217dd2dfc4fdde7cc92cae0d6ab1d077aa36f2d13afe98ee7fbecfe0ccd532a0580325
6
+ metadata.gz: '0848a81d03d8cdf7b4809de8613d90b67950f4339ae20ab5ce4ba6fa8d9e9559033c4a53ca47391b99ed5287ba7a2f2be7976b87c7ea8479051b8e7dfc9da6e8'
7
+ data.tar.gz: c1fc1ffdadafd04c19d81c37befec9eed9bcf9e40db9c39158b20a2a8ec8b8368841c65211d31439ba585f637de9541e2b7d58673da4964c7b8afccbfb9bf6ff
@@ -5,7 +5,7 @@ jobs:
5
5
  runs-on: ubuntu-latest
6
6
  strategy:
7
7
  matrix:
8
- ruby: ['2.6', '2.7', '3.0', '3.1']
8
+ ruby: ['2.6', '2.7', '3.0', '3.1', '3.2', '3.3']
9
9
  fail-fast: false
10
10
  steps:
11
11
  - name: Checkout
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- ruby-3.0.4
1
+ ruby-3.2.5
@@ -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
- (crate.raw_properties['hasPart'] || []).map do |ref|
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
- Pathname(source).find do |entry|
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 id="__data_entity_<%= data_entity.id.gsub(/\s/, '-') %>">
41
- <% if data_entity.external? %>
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 %>
@@ -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
- def write(dir, overwrite: true)
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
- def write_zip(destination)
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
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'ro-crate'
3
- s.version = '0.5.2'
3
+ s.version = '0.5.3'
4
4
  s.summary = 'Create, manipulate, read RO-Crates.'
5
5
  s.authors = ['Finn Bacall']
6
6
  s.email = 'finn.bacall@manchester.ac.uk'
@@ -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.2
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: 2024-04-16 00:00:00.000000000 Z
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.2.33
2491
+ rubygems_version: 3.4.19
2488
2492
  signing_key:
2489
2493
  specification_version: 4
2490
2494
  summary: Create, manipulate, read RO-Crates.