ro-crate 0.5.2 → 0.5.3

Sign up to get free protection for your applications and to get access to all the features.
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.