ro-crate 0.4.8 → 0.4.12

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.
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