ro-crate 0.5.1 → 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/.gitignore +2 -0
- data/.ruby-version +1 -1
- data/lib/ro_crate/json_ld_hash.rb +0 -5
- data/lib/ro_crate/model/directory.rb +1 -1
- data/lib/ro_crate/model/exceptions/exception.rb +15 -0
- data/lib/ro_crate/model/exceptions/read_exception.rb +4 -0
- data/lib/ro_crate/reader.rb +27 -15
- data/lib/ro_crate/ro-crate-preview.html.erb +31 -14
- data/lib/ro_crate/writer.rb +6 -2
- data/lib/ro_crate.rb +2 -0
- data/ro_crate.gemspec +1 -1
- data/test/entity_test.rb +17 -0
- data/test/entry_test.rb +110 -0
- data/test/fixtures/arcp/ro-crate-metadata.json +21 -0
- data/test/fixtures/broken/missing_file/file2.txt +1 -0
- data/test/fixtures/broken/missing_file/ro-crate-metadata.json +32 -0
- data/test/fixtures/broken/no_graph/ro-crate-metadata.json +3 -0
- data/test/fixtures/broken/no_metadata_entity/ro-crate-metadata.json +6 -0
- data/test/fixtures/broken/no_metadata_file/test.txt +1 -0
- data/test/fixtures/broken/no_root_entity/ro-crate-metadata.json +12 -0
- data/test/fixtures/broken/not_json/ro-crate-metadata.json +9 -0
- data/test/fixtures/dir_symlink +1 -0
- 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/fixtures/symlink +1 -0
- data/test/preview_test.rb +48 -0
- data/test/reader_test.rb +92 -0
- data/test/writer_test.rb +75 -28
- metadata +20 -4
- data/Gemfile.lock +0 -50
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/.gitignore
CHANGED
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
ruby-3.
|
1
|
+
ruby-3.2.5
|
@@ -2,11 +2,6 @@ module ROCrate
|
|
2
2
|
##
|
3
3
|
# A wrapper class for Hash that adds methods to dereference Entities within an RO-Crate.
|
4
4
|
class JSONLDHash < ::Hash
|
5
|
-
def self.[](graph, content = {})
|
6
|
-
@graph = graph
|
7
|
-
super(stringified(content))
|
8
|
-
end
|
9
|
-
|
10
5
|
def initialize(graph, content = {})
|
11
6
|
@graph = graph
|
12
7
|
super()
|
@@ -59,7 +59,7 @@ module ROCrate
|
|
59
59
|
# @return [Hash{String => Entry}>] The files/directories that were populated.
|
60
60
|
# The key is the relative path of the file/directory, and the value is an Entry object where data can be read etc.
|
61
61
|
def populate_entries(source_directory, include_hidden: false)
|
62
|
-
raise 'Not a directory' unless ::File.directory?(source_directory)
|
62
|
+
raise TypeError, 'Not a directory' unless ::File.directory?(source_directory)
|
63
63
|
@directory_entries = {}
|
64
64
|
list_all_files(source_directory, include_hidden: include_hidden).each do |rel_path|
|
65
65
|
source_path = Pathname.new(::File.join(source_directory, rel_path)).expand_path
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module ROCrate
|
2
|
+
class Exception < StandardError
|
3
|
+
attr_reader :inner_exception
|
4
|
+
|
5
|
+
def initialize(message, _inner_exception = nil)
|
6
|
+
if _inner_exception
|
7
|
+
@inner_exception = _inner_exception
|
8
|
+
super("#{message}: #{@inner_exception.class.name} - #{@inner_exception.message}")
|
9
|
+
set_backtrace(@inner_exception.backtrace)
|
10
|
+
else
|
11
|
+
super(message)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/ro_crate/reader.rb
CHANGED
@@ -9,7 +9,6 @@ module ROCrate
|
|
9
9
|
# @param target_dir [String, ::File, Pathname] The target directory where the crate should be unzipped (if its a Zip file).
|
10
10
|
# @return [Crate] The RO-Crate.
|
11
11
|
def self.read(source, target_dir: Dir.mktmpdir)
|
12
|
-
raise "Not a directory!" unless ::File.directory?(target_dir)
|
13
12
|
begin
|
14
13
|
is_dir = ::File.directory?(source)
|
15
14
|
rescue TypeError
|
@@ -82,6 +81,8 @@ module ROCrate
|
|
82
81
|
# @param target_dir [String, ::File, Pathname] The target directory where the crate should be unzipped.
|
83
82
|
# @return [Crate] The RO-Crate.
|
84
83
|
def self.read_zip(source, target_dir: Dir.mktmpdir)
|
84
|
+
raise ROCrate::ReadException, "Target is not a directory!" unless ::File.directory?(target_dir)
|
85
|
+
|
85
86
|
unzip_to(source, target_dir)
|
86
87
|
|
87
88
|
# Traverse the unzipped directory to try and find the crate's root
|
@@ -96,7 +97,7 @@ module ROCrate
|
|
96
97
|
# @param source [String, ::File, Pathname] The location of the directory.
|
97
98
|
# @return [Crate] The RO-Crate.
|
98
99
|
def self.read_directory(source)
|
99
|
-
raise "
|
100
|
+
raise ROCrate::ReadException, "Source is not a directory!" unless ::File.directory?(source)
|
100
101
|
|
101
102
|
source = ::File.expand_path(source)
|
102
103
|
metadata_file = Dir.entries(source).detect { |entry| entry == ROCrate::Metadata::IDENTIFIER ||
|
@@ -104,13 +105,18 @@ module ROCrate
|
|
104
105
|
|
105
106
|
if metadata_file
|
106
107
|
metadata_json = ::File.read(::File.join(source, metadata_file))
|
107
|
-
|
108
|
+
begin
|
109
|
+
metadata = JSON.parse(metadata_json)
|
110
|
+
rescue JSON::ParserError => e
|
111
|
+
raise ROCrate::ReadException.new("Error parsing metadata", e)
|
112
|
+
end
|
113
|
+
|
108
114
|
entities = entities_from_metadata(metadata)
|
109
115
|
context = metadata['@context']
|
110
116
|
|
111
117
|
build_crate(entities, source, context: context)
|
112
118
|
else
|
113
|
-
raise
|
119
|
+
raise ROCrate::ReadException, "No metadata found!"
|
114
120
|
end
|
115
121
|
end
|
116
122
|
|
@@ -131,14 +137,14 @@ module ROCrate
|
|
131
137
|
|
132
138
|
# Do some normalization...
|
133
139
|
entities[ROCrate::Metadata::IDENTIFIER] = extract_metadata_entity(entities)
|
134
|
-
raise "No metadata entity found in @graph!" unless entities[ROCrate::Metadata::IDENTIFIER]
|
140
|
+
raise ROCrate::ReadException, "No metadata entity found in @graph!" unless entities[ROCrate::Metadata::IDENTIFIER]
|
135
141
|
entities[ROCrate::Preview::IDENTIFIER] = extract_preview_entity(entities)
|
136
142
|
entities[ROCrate::Crate::IDENTIFIER] = extract_root_entity(entities)
|
137
|
-
raise "No root entity (with @id: #{entities[ROCrate::Metadata::IDENTIFIER].dig('about', '@id')}) found in @graph!" unless entities[ROCrate::Crate::IDENTIFIER]
|
143
|
+
raise ROCrate::ReadException, "No root entity (with @id: #{entities[ROCrate::Metadata::IDENTIFIER].dig('about', '@id')}) found in @graph!" unless entities[ROCrate::Crate::IDENTIFIER]
|
138
144
|
|
139
145
|
entities
|
140
146
|
else
|
141
|
-
raise "No @graph found in metadata!"
|
147
|
+
raise ROCrate::ReadException, "No @graph found in metadata!"
|
142
148
|
end
|
143
149
|
end
|
144
150
|
|
@@ -198,7 +204,9 @@ module ROCrate
|
|
198
204
|
# @param entity_hash [Hash] A Hash containing all the entities in the @graph, mapped by their @id.
|
199
205
|
# @return [Array<ROCrate::File, ROCrate::Directory>] The extracted DataEntity objects.
|
200
206
|
def self.extract_data_entities(crate, source, entity_hash)
|
201
|
-
crate.raw_properties['hasPart']
|
207
|
+
parts = crate.raw_properties['hasPart'] || []
|
208
|
+
parts = [parts] unless parts.is_a?(Array)
|
209
|
+
parts.map do |ref|
|
202
210
|
entity_props = entity_hash.delete(ref['@id'])
|
203
211
|
next unless entity_props
|
204
212
|
entity_class = ROCrate::DataEntity.specialize(entity_props)
|
@@ -234,21 +242,21 @@ module ROCrate
|
|
234
242
|
# or nil if it referenced a local file that wasn't found.
|
235
243
|
def self.create_data_entity(crate, entity_class, source, entity_props)
|
236
244
|
id = entity_props.delete('@id')
|
245
|
+
raise ROCrate::ReadException, "Data Entity missing '@id': #{entity_props.inspect}" unless id
|
237
246
|
decoded_id = URI.decode_www_form_component(id)
|
238
247
|
path = nil
|
239
248
|
uri = URI(id) rescue nil
|
240
249
|
if uri&.absolute?
|
241
250
|
path = uri
|
242
251
|
decoded_id = nil
|
243
|
-
|
252
|
+
elsif !id.start_with?('#')
|
244
253
|
[id, decoded_id].each do |i|
|
245
254
|
fullpath = ::File.join(source, i)
|
246
255
|
path = Pathname.new(fullpath) if ::File.exist?(fullpath)
|
247
256
|
end
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
# end
|
257
|
+
if path.nil?
|
258
|
+
raise ROCrate::ReadException, "Local Data Entity not found in crate: #{id}"
|
259
|
+
end
|
252
260
|
end
|
253
261
|
|
254
262
|
entity_class.new(crate, path, decoded_id, entity_props)
|
@@ -290,7 +298,7 @@ module ROCrate
|
|
290
298
|
# mapped by its @id.
|
291
299
|
def self.extract_root_entity(entities)
|
292
300
|
root_id = entities[ROCrate::Metadata::IDENTIFIER].dig('about', '@id')
|
293
|
-
raise "Metadata entity does not reference any root entity" unless root_id
|
301
|
+
raise ROCrate::ReadException, "Metadata entity does not reference any root entity" unless root_id
|
294
302
|
entities.delete(root_id)
|
295
303
|
end
|
296
304
|
|
@@ -300,12 +308,16 @@ module ROCrate
|
|
300
308
|
# @param source [String, ::File, Pathname] The location of the directory.
|
301
309
|
# @return [Pathname, nil] The path to the root, or nil if not found.
|
302
310
|
def self.detect_root_directory(source)
|
303
|
-
|
311
|
+
queue = [source]
|
312
|
+
until queue.empty?
|
313
|
+
entry = Pathname(queue.shift)
|
304
314
|
if entry.file?
|
305
315
|
name = entry.basename.to_s
|
306
316
|
if name == ROCrate::Metadata::IDENTIFIER || name == ROCrate::Metadata::IDENTIFIER_1_0
|
307
317
|
return entry.parent
|
308
318
|
end
|
319
|
+
elsif entry.directory?
|
320
|
+
queue += entry.children
|
309
321
|
end
|
310
322
|
end
|
311
323
|
|
@@ -1,10 +1,31 @@
|
|
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
|
-
<html>
|
22
|
+
<html lang="en">
|
3
23
|
<head>
|
4
24
|
<title><%= name || "New RO-Crate" %></title>
|
5
25
|
<script type="application/ld+json"><%= metadata.generate %></script>
|
6
|
-
<meta name="generator" content="https://github.com/
|
26
|
+
<meta name="generator" content="https://github.com/ResearchObject/ro-crate-ruby">
|
7
27
|
<meta name="keywords" content="RO-Crate">
|
28
|
+
<meta charset="utf-8">
|
8
29
|
</head>
|
9
30
|
<body>
|
10
31
|
<h1><%= name || "New RO-Crate" %></h1>
|
@@ -17,36 +38,32 @@
|
|
17
38
|
<dl>
|
18
39
|
<% if author %>
|
19
40
|
<dt>Author</dt>
|
20
|
-
<dd><%= author %></dd>
|
41
|
+
<dd><%= entity_to_html author %></dd>
|
21
42
|
<% end %>
|
22
43
|
<% if contact_point %>
|
23
44
|
<dt>Contact</dt>
|
24
|
-
<dd><%= contact_point %></dd>
|
45
|
+
<dd><%= entity_to_html contact_point %></dd>
|
25
46
|
<% end %>
|
26
47
|
<% if publisher %>
|
27
48
|
<dt>Publisher</dt>
|
28
|
-
<dd><%= publisher %></dd>
|
49
|
+
<dd><%= entity_to_html publisher %></dd>
|
29
50
|
<% end %>
|
30
51
|
<% if license %>
|
31
52
|
<dt>License</dt>
|
32
|
-
<dd><%= license %></dd>
|
53
|
+
<dd><%= entity_to_html license %></dd>
|
33
54
|
<% end %>
|
34
55
|
</dl>
|
35
56
|
|
36
57
|
<h2>Contents</h2>
|
37
58
|
<ul>
|
38
59
|
<% data_entities.each do |data_entity| %>
|
39
|
-
<li
|
40
|
-
|
41
|
-
<strong><a href="<%= data_entity.id %>" target="_blank"><%= data_entity.name || data_entity.id %></a></strong>
|
42
|
-
<% else %>
|
43
|
-
<strong><%= data_entity.name || data_entity.id %></strong>
|
44
|
-
<% end %>
|
60
|
+
<li>
|
61
|
+
<strong><%= entity_to_html data_entity %></strong>
|
45
62
|
<% if data_entity.content_size %>
|
46
|
-
<br/>Size: <%= data_entity.content_size %>
|
63
|
+
<br/>Size: <%= entity_to_html data_entity.content_size %>
|
47
64
|
<% end %>
|
48
65
|
<% if data_entity.encoding_format %>
|
49
|
-
<br/>Format: <%= data_entity.encoding_format %>
|
66
|
+
<br/>Format: <%= entity_to_html data_entity.encoding_format %>
|
50
67
|
<% end %>
|
51
68
|
</li>
|
52
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/lib/ro_crate.rb
CHANGED
@@ -6,6 +6,8 @@ require 'zip/filesystem'
|
|
6
6
|
require 'addressable'
|
7
7
|
require 'open-uri'
|
8
8
|
|
9
|
+
require 'ro_crate/model/exceptions/exception'
|
10
|
+
require 'ro_crate/model/exceptions/read_exception'
|
9
11
|
require 'ro_crate/json_ld_hash'
|
10
12
|
require 'ro_crate/model/entity'
|
11
13
|
require 'ro_crate/model/data_entity'
|
data/ro_crate.gemspec
CHANGED
data/test/entity_test.rb
CHANGED
@@ -72,6 +72,23 @@ class EntityTest < Test::Unit::TestCase
|
|
72
72
|
assert_equal(person.canonical_id, crate.author.canonical_id)
|
73
73
|
end
|
74
74
|
|
75
|
+
test 'to_json' do
|
76
|
+
crate = ROCrate::Crate.new
|
77
|
+
|
78
|
+
crate['test'] = 'hello'
|
79
|
+
crate['test2'] = ['hello']
|
80
|
+
crate['test3'] = 123
|
81
|
+
crate['test4'] = { a: 'bc' }
|
82
|
+
|
83
|
+
json = crate.to_json
|
84
|
+
parsed = JSON.parse(json)
|
85
|
+
|
86
|
+
assert_equal 'hello', parsed['test']
|
87
|
+
assert_equal ['hello'], parsed['test2']
|
88
|
+
assert_equal 123, parsed['test3']
|
89
|
+
assert_equal({ 'a' => 'bc' }, parsed['test4'])
|
90
|
+
end
|
91
|
+
|
75
92
|
test 'format various IDs' do
|
76
93
|
assert_equal "#Hello%20World/Goodbye%20World", ROCrate::ContextualEntity.format_id('#Hello World/Goodbye World')
|
77
94
|
assert_equal "#Hello%20World/Goodbye%20World", ROCrate::ContextualEntity.format_id('Hello World/Goodbye World')
|
data/test/entry_test.rb
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'test_helper'
|
3
|
+
|
4
|
+
class EntryTest < Test::Unit::TestCase
|
5
|
+
setup do
|
6
|
+
stub_request(:get, 'http://example.com/dir/file.txt').to_return(status: 200, body: 'file contents')
|
7
|
+
stub_request(:get, 'http://example.com/dir/').to_return(status: 200, body: '<html>...')
|
8
|
+
|
9
|
+
@local_file = ROCrate::Entry.new(fixture_file('info.txt'))
|
10
|
+
@local_path = ROCrate::Entry.new(Pathname.new(fixture_dir).join('directory', 'info.txt'))
|
11
|
+
@local_io = ROCrate::Entry.new(StringIO.new('stringio'))
|
12
|
+
@local_dir = ROCrate::Entry.new(Pathname.new(fixture_dir).join('directory'))
|
13
|
+
@local_symlink = ROCrate::Entry.new(Pathname.new(fixture_dir).join('symlink'))
|
14
|
+
@local_dir_symlink = ROCrate::Entry.new(Pathname.new(fixture_dir).join('dir_symlink'))
|
15
|
+
@remote_file = ROCrate::RemoteEntry.new(URI('http://example.com/dir/file.txt'))
|
16
|
+
@remote_dir = ROCrate::RemoteEntry.new(URI('http://example.com/dir/'), directory: true)
|
17
|
+
end
|
18
|
+
|
19
|
+
test 'read' do
|
20
|
+
assert_equal "Hello\n", @local_file.read
|
21
|
+
assert_equal "1234\n", @local_path.read
|
22
|
+
assert_equal "stringio", @local_io.read
|
23
|
+
assert_raises(Errno::EISDIR) { @local_dir.read }
|
24
|
+
assert_raises(Errno::EISDIR) { @local_dir_symlink.read }
|
25
|
+
assert_equal "I have spaces in my name\n", @local_symlink.read
|
26
|
+
assert_equal "file contents", @remote_file.read
|
27
|
+
assert_equal "<html>...", @remote_dir.read
|
28
|
+
end
|
29
|
+
|
30
|
+
test 'write_to' do
|
31
|
+
dest = StringIO.new
|
32
|
+
@local_file.write_to(dest)
|
33
|
+
dest.rewind
|
34
|
+
assert_equal "Hello\n", dest.read
|
35
|
+
|
36
|
+
dest = StringIO.new
|
37
|
+
@local_path.write_to(dest)
|
38
|
+
dest.rewind
|
39
|
+
assert_equal "1234\n", dest.read
|
40
|
+
|
41
|
+
dest = StringIO.new
|
42
|
+
@local_io.write_to(dest)
|
43
|
+
dest.rewind
|
44
|
+
assert_equal "stringio", dest.read
|
45
|
+
|
46
|
+
assert_raises(Errno::EISDIR) { @local_dir.write_to(dest) }
|
47
|
+
|
48
|
+
assert_raises(Errno::EISDIR) { @local_dir_symlink.write_to(dest) }
|
49
|
+
|
50
|
+
dest = StringIO.new
|
51
|
+
@local_symlink.write_to(dest)
|
52
|
+
dest.rewind
|
53
|
+
assert_equal "I have spaces in my name\n", dest.read
|
54
|
+
|
55
|
+
dest = StringIO.new
|
56
|
+
@remote_file.write_to(dest)
|
57
|
+
dest.rewind
|
58
|
+
assert_equal "file contents", dest.read
|
59
|
+
|
60
|
+
dest = StringIO.new
|
61
|
+
@remote_dir.write_to(dest)
|
62
|
+
dest.rewind
|
63
|
+
assert_equal "<html>...", dest.read
|
64
|
+
end
|
65
|
+
|
66
|
+
test 'directory?' do
|
67
|
+
refute @local_file.directory?
|
68
|
+
refute @local_path.directory?
|
69
|
+
refute @local_io.directory?
|
70
|
+
assert @local_dir.directory?
|
71
|
+
refute @local_symlink.directory?
|
72
|
+
assert @local_dir_symlink.directory?
|
73
|
+
refute @remote_file.directory?
|
74
|
+
assert @remote_dir.directory?
|
75
|
+
end
|
76
|
+
|
77
|
+
test 'symlink?' do
|
78
|
+
refute @local_file.symlink?
|
79
|
+
refute @local_path.symlink?
|
80
|
+
refute @local_io.symlink?
|
81
|
+
refute @local_dir.symlink?
|
82
|
+
assert @local_symlink.symlink?
|
83
|
+
assert @local_dir_symlink.symlink?
|
84
|
+
refute @remote_file.symlink?
|
85
|
+
refute @remote_dir.symlink?
|
86
|
+
end
|
87
|
+
|
88
|
+
test 'remote?' do
|
89
|
+
refute @local_file.remote?
|
90
|
+
refute @local_path.remote?
|
91
|
+
refute @local_io.remote?
|
92
|
+
refute @local_dir.remote?
|
93
|
+
refute @local_symlink.remote?
|
94
|
+
refute @local_dir_symlink.remote?
|
95
|
+
assert @remote_file.remote?
|
96
|
+
assert @remote_dir.remote?
|
97
|
+
end
|
98
|
+
|
99
|
+
test 'path' do
|
100
|
+
base = Pathname.new(fixture_dir).expand_path.to_s
|
101
|
+
assert_equal "#{base}/info.txt", @local_file.path
|
102
|
+
assert_equal "#{base}/directory/info.txt", @local_path.path
|
103
|
+
assert_nil @local_io.path
|
104
|
+
assert_equal "#{base}/directory", @local_dir.path
|
105
|
+
assert_equal "#{base}/symlink", @local_symlink.path
|
106
|
+
assert_equal "#{base}/dir_symlink", @local_dir_symlink.path
|
107
|
+
assert_nil @remote_file.path
|
108
|
+
assert_nil @remote_dir.path
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
{
|
2
|
+
"@context": "https://w3id.org/ro/crate/1.1/context",
|
3
|
+
"@graph": [
|
4
|
+
{
|
5
|
+
"@id": "arcp://name,somethingsomething",
|
6
|
+
"@type": "Dataset",
|
7
|
+
"datePublished": "2024-01-31T10:47:17+00:00"
|
8
|
+
|
9
|
+
},
|
10
|
+
{
|
11
|
+
"@id": "ro-crate-metadata.json",
|
12
|
+
"@type": "CreativeWork",
|
13
|
+
"about": {
|
14
|
+
"@id": "arcp://name,somethingsomething"
|
15
|
+
},
|
16
|
+
"conformsTo": {
|
17
|
+
"@id": "https://w3id.org/ro/crate/1.1"
|
18
|
+
}
|
19
|
+
}
|
20
|
+
]
|
21
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
2
|
@@ -0,0 +1,32 @@
|
|
1
|
+
{
|
2
|
+
"@context": "https://w3id.org/ro/crate/1.1/context",
|
3
|
+
"@graph": [
|
4
|
+
{
|
5
|
+
"@id": "ro-crate-metadata.json",
|
6
|
+
"@type": "CreativeWork",
|
7
|
+
"about": {
|
8
|
+
"@id": "./"
|
9
|
+
}
|
10
|
+
},
|
11
|
+
{
|
12
|
+
"@id": "./",
|
13
|
+
"@type": "Dataset",
|
14
|
+
"hasPart": [
|
15
|
+
{
|
16
|
+
"@id": "file1.txt"
|
17
|
+
},
|
18
|
+
{
|
19
|
+
"@id": "file2.txt"
|
20
|
+
}
|
21
|
+
]
|
22
|
+
},
|
23
|
+
{
|
24
|
+
"@id": "file1.txt",
|
25
|
+
"@type": "File"
|
26
|
+
},
|
27
|
+
{
|
28
|
+
"@id": "file2.txt",
|
29
|
+
"@type": "File"
|
30
|
+
}
|
31
|
+
]
|
32
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
123
|
@@ -0,0 +1 @@
|
|
1
|
+
directory
|
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 @@
|
|
1
|
+
file with spaces.txt
|
@@ -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
@@ -116,6 +116,19 @@ class ReaderTest < Test::Unit::TestCase
|
|
116
116
|
end
|
117
117
|
end
|
118
118
|
|
119
|
+
test 'reading from zip IO' do
|
120
|
+
io = StringIO.new(fixture_file('directory.zip').read)
|
121
|
+
crate = ROCrate::Reader.read(io)
|
122
|
+
|
123
|
+
assert crate.payload['fish/info.txt']
|
124
|
+
assert_equal '1234', crate.payload['fish/info.txt'].source.read.chomp
|
125
|
+
assert crate.payload['fish/root.txt']
|
126
|
+
assert crate.payload['fish/data/info.txt']
|
127
|
+
assert crate.payload['fish/data/nested.txt']
|
128
|
+
assert crate.payload['fish/data/binary.jpg']
|
129
|
+
assert_equal ['./', 'fish/', 'ro-crate-metadata.jsonld', 'ro-crate-preview.html'], crate.entities.map(&:id).sort
|
130
|
+
end
|
131
|
+
|
119
132
|
test 'reading from directory with directories' do
|
120
133
|
crate = ROCrate::Reader.read_directory(fixture_file('directory_crate').path)
|
121
134
|
|
@@ -303,4 +316,83 @@ class ReaderTest < Test::Unit::TestCase
|
|
303
316
|
refute real_file.payload.values.first.remote?
|
304
317
|
refute real_file.payload.values.first.directory?
|
305
318
|
end
|
319
|
+
|
320
|
+
test 'handles exceptions' do
|
321
|
+
e = check_exception(ROCrate::ReadException) do
|
322
|
+
ROCrate::Reader.read(fixture_file('broken/no_graph'))
|
323
|
+
end
|
324
|
+
assert_include e.message, 'No @graph'
|
325
|
+
|
326
|
+
e = check_exception(ROCrate::ReadException) do
|
327
|
+
ROCrate::Reader.read(fixture_file('broken/no_metadata_entity'))
|
328
|
+
end
|
329
|
+
assert_include e.message, 'No metadata entity'
|
330
|
+
|
331
|
+
e = check_exception(ROCrate::ReadException) do
|
332
|
+
ROCrate::Reader.read(fixture_file('broken/no_metadata_file'))
|
333
|
+
end
|
334
|
+
assert_include e.message, 'No metadata found'
|
335
|
+
|
336
|
+
e = check_exception(ROCrate::ReadException) do
|
337
|
+
ROCrate::Reader.read(fixture_file('broken/no_root_entity'))
|
338
|
+
end
|
339
|
+
assert_include e.message, 'No root'
|
340
|
+
|
341
|
+
e = check_exception(ROCrate::ReadException) do
|
342
|
+
ROCrate::Reader.read(fixture_file('broken/not_json'))
|
343
|
+
end
|
344
|
+
assert_include e.message, 'Error parsing metadata: JSON::ParserError'
|
345
|
+
assert_equal JSON::ParserError, e.inner_exception.class
|
346
|
+
|
347
|
+
e = check_exception(ROCrate::ReadException) do
|
348
|
+
ROCrate::Reader.read(fixture_file('workflow-0.2.0.zip'), target_dir: fixture_file('workflow-0.2.0.zip'))
|
349
|
+
end
|
350
|
+
assert_include e.message, 'Target is not a directory!'
|
351
|
+
|
352
|
+
e = check_exception(ROCrate::ReadException) do
|
353
|
+
ROCrate::Reader.read_directory(fixture_file('workflow-0.2.0.zip'))
|
354
|
+
end
|
355
|
+
assert_include e.message, 'Source is not a directory!'
|
356
|
+
|
357
|
+
e = check_exception(ROCrate::ReadException) do
|
358
|
+
ROCrate::Reader.read(fixture_file('broken/missing_file'))
|
359
|
+
end
|
360
|
+
assert_include e.message, 'not found in crate: file1.txt'
|
361
|
+
end
|
362
|
+
|
363
|
+
test 'tolerates arcp identifier on root data entity (and missing hasPart)' do
|
364
|
+
crate = ROCrate::Reader.read(fixture_file('arcp').path)
|
365
|
+
|
366
|
+
assert_equal 'arcp://name,somethingsomething', crate.id
|
367
|
+
assert_empty crate.data_entities
|
368
|
+
end
|
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
|
+
|
384
|
+
private
|
385
|
+
|
386
|
+
def check_exception(exception_class)
|
387
|
+
e = nil
|
388
|
+
assert_raise(exception_class) do
|
389
|
+
begin
|
390
|
+
yield
|
391
|
+
rescue exception_class => e
|
392
|
+
raise e
|
393
|
+
end
|
394
|
+
end
|
395
|
+
|
396
|
+
e
|
397
|
+
end
|
306
398
|
end
|
data/test/writer_test.rb
CHANGED
@@ -230,36 +230,83 @@ class WriterTest < Test::Unit::TestCase
|
|
230
230
|
|
231
231
|
test 'write crate with remote files and directories' do
|
232
232
|
orig = ROCrate::Reader.read(fixture_file('uri_heavy_crate').path)
|
233
|
-
|
234
|
-
|
233
|
+
Tempfile.create do |file|
|
234
|
+
ROCrate::Writer.new(orig).write_zip(file)
|
235
235
|
|
236
|
-
|
237
|
-
|
238
|
-
|
236
|
+
Zip::File.open(file) do |zipfile|
|
237
|
+
refute zipfile.find_entry('nih:sha-256;3a2c-8d14-a40b-3755-4abc-5af8-a56d-ba3a-e159-d688-c9b3-f169-6751-4b88-fbd2-6a9f;7')
|
238
|
+
end
|
239
239
|
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
240
|
+
file.rewind
|
241
|
+
|
242
|
+
crate = ROCrate::Reader.read(file)
|
243
|
+
|
244
|
+
dir = crate.get('nih:sha-256;f70e-eb2e-89d0-b3dc-5c99-8541-fa4b-6e64-a194-cf9d-ebd8-ca58-24e7-c47a-553f-86fa;c/')
|
245
|
+
assert dir
|
246
|
+
assert dir.is_a?(ROCrate::Directory)
|
247
|
+
assert dir.remote?
|
248
|
+
assert_empty dir.payload
|
249
|
+
|
250
|
+
file = crate.get('nih:sha-256;3a2c-8d14-a40b-3755-4abc-5af8-a56d-ba3a-e159-d688-c9b3-f169-6751-4b88-fbd2-6a9f;7')
|
251
|
+
assert file
|
252
|
+
assert file.is_a?(ROCrate::File)
|
253
|
+
assert file.remote?
|
254
|
+
assert_empty file.payload
|
255
|
+
|
256
|
+
real_file = crate.get('main.nf')
|
257
|
+
assert real_file
|
258
|
+
assert real_file.is_a?(ROCrate::File)
|
259
|
+
refute real_file.remote?
|
260
|
+
assert_not_empty real_file.payload
|
261
|
+
refute real_file.payload.values.first.remote?
|
262
|
+
refute real_file.payload.values.first.directory?
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
test 'write crate with arcp root identifier' do
|
267
|
+
crate = ROCrate::Reader.read(fixture_file('arcp').path)
|
268
|
+
|
269
|
+
assert_equal 'arcp://name,somethingsomething', crate.id
|
270
|
+
Dir.mktmpdir do |dir|
|
271
|
+
ROCrate::Writer.new(crate).write(dir)
|
272
|
+
Dir.chdir(dir) do
|
273
|
+
assert File.exist?('ro-crate-metadata.json')
|
263
274
|
end
|
275
|
+
end
|
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
|
264
311
|
end
|
265
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
|
@@ -139,7 +139,6 @@ files:
|
|
139
139
|
- ".gitignore"
|
140
140
|
- ".ruby-version"
|
141
141
|
- Gemfile
|
142
|
-
- Gemfile.lock
|
143
142
|
- LICENSE
|
144
143
|
- README.md
|
145
144
|
- Rakefile
|
@@ -152,6 +151,8 @@ files:
|
|
152
151
|
- lib/ro_crate/model/directory.rb
|
153
152
|
- lib/ro_crate/model/entity.rb
|
154
153
|
- lib/ro_crate/model/entry.rb
|
154
|
+
- lib/ro_crate/model/exceptions/exception.rb
|
155
|
+
- lib/ro_crate/model/exceptions/read_exception.rb
|
155
156
|
- lib/ro_crate/model/file.rb
|
156
157
|
- lib/ro_crate/model/metadata.rb
|
157
158
|
- lib/ro_crate/model/organization.rb
|
@@ -166,12 +167,22 @@ files:
|
|
166
167
|
- test/crate_test.rb
|
167
168
|
- test/directory_test.rb
|
168
169
|
- test/entity_test.rb
|
170
|
+
- test/entry_test.rb
|
171
|
+
- test/fixtures/arcp/ro-crate-metadata.json
|
169
172
|
- test/fixtures/biobb_hpc_workflows-condapack.zip
|
173
|
+
- test/fixtures/broken/missing_file/file2.txt
|
174
|
+
- test/fixtures/broken/missing_file/ro-crate-metadata.json
|
175
|
+
- test/fixtures/broken/no_graph/ro-crate-metadata.json
|
176
|
+
- test/fixtures/broken/no_metadata_entity/ro-crate-metadata.json
|
177
|
+
- test/fixtures/broken/no_metadata_file/test.txt
|
178
|
+
- test/fixtures/broken/no_root_entity/ro-crate-metadata.json
|
179
|
+
- test/fixtures/broken/not_json/ro-crate-metadata.json
|
170
180
|
- test/fixtures/conflicting_data_directory/info.txt
|
171
181
|
- test/fixtures/conflicting_data_directory/nested.txt
|
172
182
|
- test/fixtures/crate-spec1.1/file with spaces.txt
|
173
183
|
- test/fixtures/crate-spec1.1/ro-crate-metadata.json
|
174
184
|
- test/fixtures/data.csv
|
185
|
+
- test/fixtures/dir_symlink
|
175
186
|
- test/fixtures/directory.zip
|
176
187
|
- test/fixtures/directory/.dir/test.txt
|
177
188
|
- test/fixtures/directory/.dotfile
|
@@ -190,6 +201,7 @@ files:
|
|
190
201
|
- test/fixtures/file with spaces.txt
|
191
202
|
- test/fixtures/info.txt
|
192
203
|
- test/fixtures/misc_data_entity_crate/ro-crate-metadata.json
|
204
|
+
- test/fixtures/multi_metadata_crate.crate.zip
|
193
205
|
- test/fixtures/nested_directory.zip
|
194
206
|
- test/fixtures/ro-crate-galaxy-sortchangecase/LICENSE
|
195
207
|
- test/fixtures/ro-crate-galaxy-sortchangecase/README.md
|
@@ -198,6 +210,8 @@ files:
|
|
198
210
|
- test/fixtures/ro-crate-galaxy-sortchangecase/test/test1/input.bed
|
199
211
|
- test/fixtures/ro-crate-galaxy-sortchangecase/test/test1/output_exp.bed
|
200
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
|
201
215
|
- test/fixtures/spaces/file with spaces.txt
|
202
216
|
- test/fixtures/spaces/ro-crate-metadata.jsonld
|
203
217
|
- test/fixtures/sparse_directory_crate.zip
|
@@ -210,6 +224,7 @@ files:
|
|
210
224
|
- test/fixtures/sparse_directory_crate/ro-crate-metadata.jsonld
|
211
225
|
- test/fixtures/sparse_directory_crate/ro-crate-preview.html
|
212
226
|
- test/fixtures/sparse_directory_crate/unlisted_file.txt
|
227
|
+
- test/fixtures/symlink
|
213
228
|
- test/fixtures/unlinked_entity_crate/LICENSE
|
214
229
|
- test/fixtures/unlinked_entity_crate/README.md
|
215
230
|
- test/fixtures/unlinked_entity_crate/ro-crate-metadata.json
|
@@ -2450,6 +2465,7 @@ files:
|
|
2450
2465
|
- test/fixtures/workflow-test-fixture-symlink/concat_two_files.ga
|
2451
2466
|
- test/fixtures/workflow-test-fixture-symlink/diagram.png
|
2452
2467
|
- test/fixtures/workflow-test-fixture-symlink/images/workflow-diagram.png
|
2468
|
+
- test/preview_test.rb
|
2453
2469
|
- test/reader_test.rb
|
2454
2470
|
- test/test_helper.rb
|
2455
2471
|
- test/writer_test.rb
|
@@ -2472,7 +2488,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
2472
2488
|
- !ruby/object:Gem::Version
|
2473
2489
|
version: '0'
|
2474
2490
|
requirements: []
|
2475
|
-
rubygems_version: 3.
|
2491
|
+
rubygems_version: 3.4.19
|
2476
2492
|
signing_key:
|
2477
2493
|
specification_version: 4
|
2478
2494
|
summary: Create, manipulate, read RO-Crates.
|
data/Gemfile.lock
DELETED
@@ -1,50 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
ro-crate (0.5.1)
|
5
|
-
addressable (>= 2.7, < 2.9)
|
6
|
-
rubyzip (~> 2.0.0)
|
7
|
-
|
8
|
-
GEM
|
9
|
-
remote: https://rubygems.org/
|
10
|
-
specs:
|
11
|
-
addressable (2.8.0)
|
12
|
-
public_suffix (>= 2.0.2, < 5.0)
|
13
|
-
crack (0.4.3)
|
14
|
-
safe_yaml (~> 1.0.0)
|
15
|
-
docile (1.3.5)
|
16
|
-
hashdiff (1.0.1)
|
17
|
-
power_assert (2.0.1)
|
18
|
-
public_suffix (4.0.6)
|
19
|
-
rake (13.0.0)
|
20
|
-
rexml (3.2.5)
|
21
|
-
rubyzip (2.0.0)
|
22
|
-
safe_yaml (1.0.5)
|
23
|
-
simplecov (0.21.2)
|
24
|
-
docile (~> 1.1)
|
25
|
-
simplecov-html (~> 0.11)
|
26
|
-
simplecov_json_formatter (~> 0.1)
|
27
|
-
simplecov-html (0.12.3)
|
28
|
-
simplecov_json_formatter (0.1.2)
|
29
|
-
test-unit (3.5.3)
|
30
|
-
power_assert
|
31
|
-
webmock (3.8.3)
|
32
|
-
addressable (>= 2.3.6)
|
33
|
-
crack (>= 0.3.2)
|
34
|
-
hashdiff (>= 0.4.0, < 2.0.0)
|
35
|
-
yard (0.9.25)
|
36
|
-
|
37
|
-
PLATFORMS
|
38
|
-
ruby
|
39
|
-
|
40
|
-
DEPENDENCIES
|
41
|
-
rake (~> 13.0.0)
|
42
|
-
rexml (~> 3.2.5)
|
43
|
-
ro-crate!
|
44
|
-
simplecov (~> 0.21.2)
|
45
|
-
test-unit (~> 3.5.3)
|
46
|
-
webmock (~> 3.8.3)
|
47
|
-
yard (~> 0.9.25)
|
48
|
-
|
49
|
-
BUNDLED WITH
|
50
|
-
2.3.6
|