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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +13 -13
  3. data/README.md +39 -0
  4. data/lib/ro_crate/model/contextual_entity.rb +2 -14
  5. data/lib/ro_crate/model/crate.rb +52 -6
  6. data/lib/ro_crate/model/data_entity.rb +6 -5
  7. data/lib/ro_crate/model/directory.rb +3 -5
  8. data/lib/ro_crate/model/entity.rb +65 -6
  9. data/lib/ro_crate/model/entry.rb +2 -2
  10. data/lib/ro_crate/model/file.rb +2 -4
  11. data/lib/ro_crate/model/metadata.rb +9 -1
  12. data/lib/ro_crate/model/organization.rb +1 -1
  13. data/lib/ro_crate/model/preview.rb +3 -15
  14. data/lib/ro_crate/model/preview_generator.rb +40 -0
  15. data/lib/ro_crate/model/remote_entry.rb +1 -12
  16. data/lib/ro_crate/reader.rb +77 -20
  17. data/lib/ro_crate/writer.rb +4 -4
  18. data/lib/ro_crate.rb +2 -1
  19. data/ro_crate.gemspec +3 -3
  20. data/test/crate_test.rb +37 -3
  21. data/test/directory_test.rb +21 -21
  22. data/test/entity_test.rb +135 -0
  23. data/test/fixtures/biobb_hpc_workflows-condapack.zip +0 -0
  24. data/test/fixtures/conflicting_data_directory/info.txt +1 -0
  25. data/test/fixtures/conflicting_data_directory/nested.txt +1 -0
  26. data/test/fixtures/nested_directory.zip +0 -0
  27. data/test/fixtures/ro-crate-galaxy-sortchangecase/LICENSE +176 -0
  28. data/test/fixtures/ro-crate-galaxy-sortchangecase/README.md +6 -0
  29. data/test/fixtures/ro-crate-galaxy-sortchangecase/ro-crate-metadata.json +133 -0
  30. data/test/fixtures/ro-crate-galaxy-sortchangecase/sort-and-change-case.ga +118 -0
  31. data/test/fixtures/ro-crate-galaxy-sortchangecase/test/test1/input.bed +3 -0
  32. data/test/fixtures/ro-crate-galaxy-sortchangecase/test/test1/output_exp.bed +3 -0
  33. data/test/fixtures/ro-crate-galaxy-sortchangecase/test/test1/sort-and-change-case-test.yml +8 -0
  34. data/test/fixtures/sparse_directory_crate/ro-crate-preview.html +60 -59
  35. data/test/reader_test.rb +83 -40
  36. data/test/test_helper.rb +5 -1
  37. data/test/writer_test.rb +59 -2
  38. metadata +26 -8
@@ -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.is_a?(::File)
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
- read_directory(target_dir)
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
- entities = entities_from_metadata(::File.read(::File.join(source, metadata_file)))
104
- build_crate(entities, source)
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 metadata_json [String] A string containing the metadata JSON.
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(metadata_json)
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 a crate from the given set of entities.
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
- ROCrate::Crate.new.tap do |crate|
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
- crate.preview.properties = preview_properties if preview_properties
150
- crate.add_all(source, false)
151
- extract_data_entities(crate, source, entity_hash).each do |entity|
152
- crate.add_data_entity(entity)
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
@@ -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.entries.each do |path, entry|
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.write(temp)
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.entries.each do |path, entry|
41
+ @crate.payload.each do |path, entry|
42
42
  next if entry.directory?
43
- zip.get_output_stream(path) { |s| entry.write(s) }
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.8'
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', '~> 2.7.0'
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.16.1'
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.entries.keys
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.entries.keys
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.entries.keys
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
@@ -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
- entries = crate.entries
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')), entries['directory/info.txt'].path
11
- assert_equal ::File.expand_path(::File.join(base_path, 'directory/root.txt')), entries['directory/root.txt'].path
12
- assert_equal ::File.expand_path(::File.join(base_path, 'directory/data')), entries['directory/data'].path
13
- assert_equal ::File.expand_path(::File.join(base_path, 'directory/data/info.txt')), entries['directory/data/info.txt'].path
14
- assert_equal ::File.expand_path(::File.join(base_path, 'directory/data/nested.txt')), entries['directory/data/nested.txt'].path
15
- assert_equal ::File.expand_path(::File.join(base_path, 'directory/data/binary.jpg')), entries['directory/data/binary.jpg'].path
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
- entries = crate.entries
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')), entries['directory/info.txt'].path
25
- assert_equal ::File.expand_path(::File.join(base_path, 'directory/root.txt')), entries['directory/root.txt'].path
26
- assert_equal ::File.expand_path(::File.join(base_path, 'directory/data')), entries['directory/data'].path
27
- assert_equal ::File.expand_path(::File.join(base_path, 'directory/data/info.txt')), entries['directory/data/info.txt'].path
28
- assert_equal ::File.expand_path(::File.join(base_path, 'directory/data/nested.txt')), entries['directory/data/nested.txt'].path
29
- assert_equal ::File.expand_path(::File.join(base_path, 'directory/data/binary.jpg')), entries['directory/data/binary.jpg'].path
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
- entries = crate.entries
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')), entries['fish/info.txt'].path
39
- assert_equal ::File.expand_path(::File.join(base_path, 'directory/root.txt')), entries['fish/root.txt'].path
40
- assert_equal ::File.expand_path(::File.join(base_path, 'directory/data')), entries['fish/data'].path
41
- assert_equal ::File.expand_path(::File.join(base_path, 'directory/data/info.txt')), entries['fish/data/info.txt'].path
42
- assert_equal ::File.expand_path(::File.join(base_path, 'directory/data/nested.txt')), entries['fish/data/nested.txt'].path
43
- assert_equal ::File.expand_path(::File.join(base_path, 'directory/data/binary.jpg')), entries['fish/data/binary.jpg'].path
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
@@ -0,0 +1 @@
1
+ No, I am nested!
Binary file