ro-crate 0.4.2 → 0.4.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 174513e7c0e8ec6ac0cf6c8bf1ca80dda57f4d95669681d15821a5e1290b5a70
4
- data.tar.gz: 835ad728feca6614b81368b3d3428ffe4f7ad8614863bfdbaf669597bc8abbc9
3
+ metadata.gz: 12ec7081b3540a664a8146c27c07ad1ab68f7c6dec49fda79560a4e81588c5d6
4
+ data.tar.gz: 6e367c3d7b299dbaa095cf74c3715cffa877fed5b1cd89f195e61758c47782b3
5
5
  SHA512:
6
- metadata.gz: c87db2e02ed875d80e1a5ef4a8c5a3e63fedeb67a20b3a94762f6e8a47f79430e970b525ada5510cd3b86d64b955691dde0e267c856ca53eb24e311017f4a59b
7
- data.tar.gz: bbd587d78f67f043917b128f78ad9a94e4044e7096bd9d1540a28e47313fb427a8196b8e531b7123ee7ba1dac686cb5a4de4114d9418ae415f384b3d27847f7e
6
+ metadata.gz: a659655a5e779cf9ee0f9c662809b82d06c25e57af67bde6954fdc08d6a58ce0b053495b939a764dbf47b91c4298644e23556e02f9ec23d04ce680e746d6ff5f
7
+ data.tar.gz: 70c036c6fd7692dfdedf466c962bf92d7e92bbe9fe4283fc74a39f8827540f0d828de727ba7b1dde1daa33ee5551554bb52ce87e0637d4d275e6f15574fc8eb9
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ro-crate (0.4.2)
4
+ ro-crate (0.4.7)
5
5
  addressable (~> 2.7.0)
6
6
  rubyzip (~> 2.0.0)
7
7
 
@@ -68,22 +68,23 @@ module ROCrate
68
68
  #
69
69
  # @param source_directory [String, Pathname, ::File,] The source directory that will be included in the crate.
70
70
  # @param create_entities [Boolean] Whether to create data entities for the added content, or just include them anonymously.
71
+ # @param include_hidden [Boolean] Whether to include hidden files, i.e. those prefixed by a `.` (period).
71
72
  #
72
73
  # @return [Array<DataEntity>] Any entities that were created from the directory contents. Will be empty if `create_entities` was false.
73
- def add_all(source_directory, create_entities = true)
74
+ def add_all(source_directory, create_entities = true, include_hidden: false)
74
75
  added = []
75
76
 
76
- Dir.chdir(source_directory) { Dir.glob('**/*') }.each do |rel_path|
77
- source_path = Pathname.new(::File.join(source_directory, rel_path)).expand_path
78
- if create_entities
77
+ if create_entities
78
+ list_all_files(source_directory, include_hidden: include_hidden).each do |rel_path|
79
+ source_path = Pathname.new(::File.join(source_directory, rel_path)).expand_path
79
80
  if source_path.directory?
80
81
  added << add_directory(source_path, rel_path)
81
82
  else
82
83
  added << add_file(source_path, rel_path)
83
84
  end
84
- else
85
- populate_entries(Pathname.new(::File.expand_path(source_directory)))
86
85
  end
86
+ else
87
+ populate_entries(Pathname.new(::File.expand_path(source_directory)), include_hidden: include_hidden)
87
88
  end
88
89
 
89
90
  added
@@ -216,16 +217,20 @@ module ROCrate
216
217
 
217
218
  alias_method :own_entries, :entries
218
219
  ##
219
- # A map of all the files/directories contained in the RO-Crate, where the key is the destination path within the crate
220
- # and the value is an Entry where the source data can be read.
220
+ # # The RO-Crate's "payload" of the crate - a map of all the files/directories contained in the RO-Crate, where the
221
+ # key is the destination path within the crate and the value is an Entry where the source data can be read.
221
222
  #
222
223
  # @return [Hash{String => Entry}>]
223
224
  def entries
224
- entries = {}
225
-
226
- (default_entities | data_entities).each do |entity|
227
- (entity == self ? own_entries : entity.entries).each do |path, io|
228
- entries[path] = io
225
+ # Gather a map of entries, starting from the crate itself, then any directory data entities, then finally any
226
+ # file data entities. This ensures in the case of a conflict, the more "specific" data entities take priority.
227
+ entries = own_entries
228
+ non_self_entities = default_entities.reject { |e| e == self }
229
+ sorted_entities = (non_self_entities | data_entities).sort_by { |e| e.is_a?(ROCrate::Directory) ? 0 : 1 }
230
+
231
+ sorted_entities.each do |entity|
232
+ entity.entries.each do |path, entry|
233
+ entries[path] = entry
229
234
  end
230
235
  end
231
236
 
@@ -235,5 +240,11 @@ module ROCrate
235
240
  def get_binding
236
241
  binding
237
242
  end
243
+
244
+ private
245
+
246
+ def full_entry_path(relative_path)
247
+ relative_path
248
+ end
238
249
  end
239
250
  end
@@ -21,6 +21,7 @@ module ROCrate
21
21
 
22
22
  if source_directory
23
23
  source_directory = Pathname.new(::File.expand_path(source_directory))
24
+ @entry = Entry.new(source_directory)
24
25
  populate_entries(source_directory)
25
26
  crate_path = source_directory.basename.to_s if crate_path.nil?
26
27
  end
@@ -29,15 +30,16 @@ module ROCrate
29
30
  end
30
31
 
31
32
  ##
32
- # A map of all the files/directories under this directory, where the key is the destination path within the crate
33
- # and the value is an Entry where the source data can be read.
33
+ # The "payload" of this directory - a map of all the files/directories, where the key is the destination path
34
+ # within the crate and the value is an Entry where the source data can be read.
34
35
  #
35
36
  # @return [Hash{String => Entry}>]
36
37
  def entries
37
38
  entries = {}
39
+ entries[filepath.chomp('/')] = @entry if @entry
38
40
 
39
41
  @directory_entries.each do |rel_path, entry|
40
- entries[::File.join(filepath, rel_path)] = entry
42
+ entries[full_entry_path(rel_path)] = entry
41
43
  end
42
44
 
43
45
  entries
@@ -49,13 +51,14 @@ module ROCrate
49
51
  # Populate this directory with files/directories from a given source directory on disk.
50
52
  #
51
53
  # @param source_directory [Pathname] The source directory to populate from.
54
+ # @param include_hidden [Boolean] Whether to include hidden files, i.e. those prefixed by a `.` (period).
52
55
  #
53
56
  # @return [Hash{String => Entry}>] The files/directories that were populated.
54
57
  # The key is the relative path of the file/directory, and the value is an Entry object where data can be read etc.
55
- def populate_entries(source_directory)
58
+ def populate_entries(source_directory, include_hidden: false)
56
59
  raise 'Not a directory' unless ::File.directory?(source_directory)
57
60
  @directory_entries = {}
58
- Dir.chdir(source_directory) { Dir.glob('**/*') }.each do |rel_path|
61
+ list_all_files(source_directory, include_hidden: include_hidden).each do |rel_path|
59
62
  source_path = Pathname.new(::File.join(source_directory, rel_path)).expand_path
60
63
  @directory_entries[rel_path] = Entry.new(source_path)
61
64
  end
@@ -63,6 +66,18 @@ module ROCrate
63
66
  @directory_entries
64
67
  end
65
68
 
69
+ def full_entry_path(relative_path)
70
+ ::File.join(filepath, relative_path)
71
+ end
72
+
73
+ def list_all_files(source_directory, include_hidden: false)
74
+ args = ['**/*']
75
+ args << ::File::FNM_DOTMATCH if include_hidden
76
+ Dir.chdir(source_directory) { Dir.glob(*args) }.reject do |path|
77
+ path == '.' || path == '..' || path.end_with?('/.')
78
+ end
79
+ end
80
+
66
81
  def default_properties
67
82
  super.merge(
68
83
  '@id' => "#{SecureRandom.uuid}/",
@@ -52,7 +52,9 @@ module ROCrate
52
52
  end
53
53
 
54
54
  ##
55
- # A map of all the files/directories associated with this File. Should only be a single key and value.
55
+ # The "payload". A map with a single key and value, of the relative filepath within the crate, to the source on disk
56
+ # where the actual bytes of the file can be read. Blank if remote.
57
+ #
56
58
  # (for compatibility with Directory#entries)
57
59
  #
58
60
  # @return [Hash{String => Entry}>] The key is the location within the crate, and the value is an Entry.
@@ -3,29 +3,67 @@ module ROCrate
3
3
  # A class to handle reading of RO-Crates from Zip files or directories.
4
4
  class Reader
5
5
  ##
6
- # Reads an RO-Crate from a directory of zip file.
6
+ # Reads an RO-Crate from a directory or zip file.
7
7
  #
8
- # @param source [String, ::File, Pathname] The source location for the crate.
8
+ # @param source [String, ::File, Pathname, #read] The location of the zip or directory, or an IO-like object containing a zip.
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
12
  raise "Not a directory!" unless ::File.directory?(target_dir)
13
- if ::File.directory?(source)
13
+ begin
14
+ is_dir = ::File.directory?(source)
15
+ rescue TypeError
16
+ is_dir = false
17
+ end
18
+
19
+ if is_dir
14
20
  read_directory(source)
15
21
  else
16
22
  read_zip(source, target_dir: target_dir)
17
23
  end
18
24
  end
19
25
 
26
+ ##
27
+ # Extract the contents of the given Zip file/data to the given directory.
28
+ #
29
+ # @param source [String, ::File, Pathname, #read] The location of the zip file, or an IO-like object.
30
+ # @param target [String, ::File, Pathname] The target directory where the file should be unzipped.
31
+ def self.unzip_to(source, target)
32
+ source = Pathname.new(::File.expand_path(source)) if source.is_a?(String)
33
+
34
+ if source.is_a?(Pathname) || source.is_a?(::File)
35
+ unzip_file_to(source, target)
36
+ else
37
+ unzip_io_to(source, target)
38
+ end
39
+ end
40
+
41
+ ##
42
+ # Extract the given Zip file data to the given directory.
43
+ #
44
+ # @param source [#read] An IO-like object containing a Zip file.
45
+ # @param target [String, ::File, Pathname] The target directory where the file should be unzipped.
46
+ def self.unzip_io_to(io, target)
47
+ Dir.chdir(target) do
48
+ Zip::InputStream.open(io) do |input|
49
+ while (entry = input.get_next_entry)
50
+ unless ::File.exist?(entry.name) || entry.name_is_directory?
51
+ FileUtils::mkdir_p(::File.dirname(entry.name))
52
+ ::File.write(entry.name, input.read)
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+
20
59
  ##
21
60
  # Extract the contents of the given Zip file to the given directory.
22
61
  #
23
62
  # @param source [String, ::File, Pathname] The location of the zip file.
24
63
  # @param target [String, ::File, Pathname] The target directory where the file should be unzipped.
25
- def self.unzip_to(source, target)
26
- source = ::File.expand_path(source)
64
+ def self.unzip_file_to(file_or_path, target)
27
65
  Dir.chdir(target) do
28
- Zip::File.open(source) do |zipfile|
66
+ Zip::File.open(file_or_path) do |zipfile|
29
67
  zipfile.each do |entry|
30
68
  unless ::File.exist?(entry.name)
31
69
  FileUtils::mkdir_p(::File.dirname(entry.name))
@@ -40,7 +78,7 @@ module ROCrate
40
78
  # Reads an RO-Crate from a zip file. It first extracts the Zip file to a temporary directory, and then calls
41
79
  # #read_directory.
42
80
  #
43
- # @param source [String, ::File, Pathname] The location of the zip file.
81
+ # @param source [String, ::File, Pathname, #read] The location of the zip file, or an IO-like object.
44
82
  # @param target_dir [String, ::File, Pathname] The target directory where the crate should be unzipped.
45
83
  # @return [Crate] The RO-Crate.
46
84
  def self.read_zip(source, target_dir: Dir.mktmpdir)
@@ -55,6 +93,8 @@ module ROCrate
55
93
  # @param source [String, ::File, Pathname] The location of the directory.
56
94
  # @return [Crate] The RO-Crate.
57
95
  def self.read_directory(source)
96
+ raise "Not a directory!" unless ::File.directory?(source)
97
+
58
98
  source = ::File.expand_path(source)
59
99
  metadata_file = Dir.entries(source).detect { |entry| entry == ROCrate::Metadata::IDENTIFIER ||
60
100
  entry == ROCrate::Metadata::IDENTIFIER_1_0 }
@@ -107,6 +147,7 @@ module ROCrate
107
147
  crate.metadata.properties = entity_hash.delete(ROCrate::Metadata::IDENTIFIER)
108
148
  preview_properties = entity_hash.delete(ROCrate::Preview::IDENTIFIER)
109
149
  crate.preview.properties = preview_properties if preview_properties
150
+ crate.add_all(source, false)
110
151
  extract_data_entities(crate, source, entity_hash).each do |entity|
111
152
  crate.add_data_entity(entity)
112
153
  end
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.2'
3
+ s.version = '0.4.7'
4
4
  s.summary = 'Create, manipulate, read RO-Crates.'
5
5
  s.authors = ['Finn Bacall']
6
6
  s.email = 'finn.bacall@manchester.ac.uk'
data/test/crate_test.rb CHANGED
@@ -201,25 +201,57 @@ class CrateTest < Test::Unit::TestCase
201
201
 
202
202
  test 'can add an entire directory tree as data entities' do
203
203
  crate = ROCrate::Crate.new
204
- entities = crate.add_all(fixture_file('directory').path)
205
-
206
- assert_equal 6, entities.length
204
+ entities = crate.add_all(fixture_file('directory').path, include_hidden: true)
205
+
206
+ paths = crate.entries.keys
207
+ assert_equal 11, paths.length
208
+ assert_includes paths, 'data'
209
+ assert_includes paths, 'root.txt'
210
+ assert_includes paths, 'info.txt'
211
+ assert_includes paths, 'data/binary.jpg'
212
+ assert_includes paths, 'data/info.txt'
213
+ assert_includes paths, 'data/nested.txt'
214
+ assert_includes paths, '.dotfile'
215
+ assert_includes paths, '.dir'
216
+ assert_includes paths, '.dir/test.txt'
217
+ assert_includes paths, 'ro-crate-metadata.json'
218
+ assert_includes paths, 'ro-crate-preview.html'
219
+
220
+ assert_equal 9, entities.length
207
221
  assert_equal 'ROCrate::Directory', crate.dereference('data/').class.name
208
222
  assert_equal 'ROCrate::File', crate.dereference('root.txt').class.name
209
223
  assert_equal 'ROCrate::File', crate.dereference('info.txt').class.name
210
224
  assert_equal 'ROCrate::File', crate.dereference('data/binary.jpg').class.name
211
225
  assert_equal 'ROCrate::File', crate.dereference('data/info.txt').class.name
212
226
  assert_equal 'ROCrate::File', crate.dereference('data/nested.txt').class.name
227
+ assert_equal 'ROCrate::File', crate.dereference('.dotfile').class.name
228
+ assert_equal 'ROCrate::Directory', crate.dereference('.dir/').class.name
229
+ assert_equal 'ROCrate::File', crate.dereference('.dir/test.txt').class.name
213
230
 
214
231
  assert_equal "5678\n", crate.dereference('data/info.txt').source.read
232
+ assert_equal "Am I included?\n", crate.dereference('.dotfile').source.read
215
233
  end
216
234
 
217
235
  test 'can create an RO-Crate using content from a given directory' do
218
236
  crate = ROCrate::Crate.new
219
- entities = crate.add_all(fixture_file('directory').path, false)
237
+ entities = crate.add_all(fixture_file('directory').path, false, include_hidden: true)
220
238
 
221
239
  assert_empty entities
222
240
 
241
+ paths = crate.entries.keys
242
+ assert_equal 11, paths.length
243
+ assert_includes paths, 'data'
244
+ assert_includes paths, 'root.txt'
245
+ assert_includes paths, 'info.txt'
246
+ assert_includes paths, 'data/binary.jpg'
247
+ assert_includes paths, 'data/info.txt'
248
+ assert_includes paths, 'data/nested.txt'
249
+ assert_includes paths, '.dotfile'
250
+ assert_includes paths, '.dir'
251
+ assert_includes paths, '.dir/test.txt'
252
+ assert_includes paths, 'ro-crate-metadata.json'
253
+ assert_includes paths, 'ro-crate-preview.html'
254
+
223
255
  # Should not create any data entities
224
256
  assert_nil crate.dereference('data/')
225
257
  assert_nil crate.dereference('root.txt')
@@ -227,5 +259,38 @@ class CrateTest < Test::Unit::TestCase
227
259
  assert_nil crate.dereference('data/binary.jpg')
228
260
  assert_nil crate.dereference('data/info.txt')
229
261
  assert_nil crate.dereference('data/nested.txt')
262
+ assert_nil crate.dereference('.dotfile')
263
+ end
264
+
265
+ test 'can create an RO-Crate using content from a given directory, excluding hidden files' do
266
+ crate = ROCrate::Crate.new
267
+ entities = crate.add_all(fixture_file('directory').path)
268
+
269
+ paths = crate.entries.keys
270
+ assert_equal 8, paths.length
271
+ assert_includes paths, 'data'
272
+ assert_includes paths, 'root.txt'
273
+ assert_includes paths, 'info.txt'
274
+ assert_includes paths, 'data/binary.jpg'
275
+ assert_includes paths, 'data/info.txt'
276
+ assert_includes paths, 'data/nested.txt'
277
+ assert_not_includes paths, '.dotfile'
278
+ assert_not_includes paths, '.dir'
279
+ assert_not_includes paths, '.dir/test.txt'
280
+ assert_includes paths, 'ro-crate-metadata.json'
281
+ assert_includes paths, 'ro-crate-preview.html'
282
+
283
+ assert_equal 6, entities.length
284
+ assert_equal 'ROCrate::Directory', crate.dereference('data/').class.name
285
+ assert_equal 'ROCrate::File', crate.dereference('root.txt').class.name
286
+ assert_equal 'ROCrate::File', crate.dereference('info.txt').class.name
287
+ assert_equal 'ROCrate::File', crate.dereference('data/binary.jpg').class.name
288
+ assert_equal 'ROCrate::File', crate.dereference('data/info.txt').class.name
289
+ assert_equal 'ROCrate::File', crate.dereference('data/nested.txt').class.name
290
+ assert_nil crate.dereference('.dotfile')
291
+ assert_nil crate.dereference('.dir/')
292
+ assert_nil crate.dereference('.dir/test.txt')
293
+
294
+ assert_equal "5678\n", crate.dereference('data/info.txt').source.read
230
295
  end
231
296
  end
@@ -0,0 +1 @@
1
+ 123
@@ -0,0 +1 @@
1
+ Am I included?
@@ -0,0 +1 @@
1
+ I'm at the root
@@ -0,0 +1,32 @@
1
+ {
2
+ "@context": "https://w3id.org/ro/crate/1.0/context",
3
+ "@graph": [
4
+ {
5
+ "@id": "ro-crate-metadata.jsonld",
6
+ "@type": "CreativeWork",
7
+ "about": {
8
+ "@id": "./"
9
+ }
10
+ },
11
+ {
12
+ "@id": "ro-crate-preview.html",
13
+ "@type": "CreativeWork",
14
+ "about": {
15
+ "@id": "./"
16
+ }
17
+ },
18
+ {
19
+ "@id": "./",
20
+ "@type": "Dataset",
21
+ "hasPart": [
22
+ {
23
+ "@id": "listed_file.txt"
24
+ }
25
+ ]
26
+ },
27
+ {
28
+ "@id": "listed_file.txt",
29
+ "@type": "File"
30
+ }
31
+ ]
32
+ }
@@ -0,0 +1,66 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>New RO-Crate</title>
5
+ <script type="application/ld+json">{
6
+ "@context": "https://w3id.org/ro/crate/1.1/context",
7
+ "@graph": [
8
+ {
9
+ "@id": "ro-crate-metadata.jsonld",
10
+ "@type": "CreativeWork",
11
+ "about": {
12
+ "@id": "./"
13
+ }
14
+ },
15
+ {
16
+ "@id": "ro-crate-preview.html",
17
+ "@type": "CreativeWork",
18
+ "about": {
19
+ "@id": "./"
20
+ }
21
+ },
22
+ {
23
+ "@id": "./",
24
+ "@type": "Dataset",
25
+ "hasPart": [
26
+ {
27
+ "@id": "fish/"
28
+ }
29
+ ]
30
+ },
31
+ {
32
+ "@id": "fish/",
33
+ "@type": "Dataset"
34
+ }
35
+ ]
36
+ }</script>
37
+ <meta name="generator" content="https://github.com/fbacall/ro-crate-ruby">
38
+ <meta name="keywords" content="RO-Crate">
39
+ </head>
40
+ <body>
41
+ <h1>New RO-Crate</h1>
42
+
43
+ <p>
44
+
45
+ </p>
46
+ <dl>
47
+
48
+
49
+
50
+
51
+ </dl>
52
+
53
+ <h2>Contents</h2>
54
+ <ul>
55
+
56
+ <li id="__data_entity_fish/">
57
+
58
+ <strong>fish/</strong>
59
+
60
+
61
+
62
+ </li>
63
+
64
+ </ul>
65
+ </body>
66
+ </html>
data/test/reader_test.rb CHANGED
@@ -109,11 +109,13 @@ class ReaderTest < Test::Unit::TestCase
109
109
  test 'reading from directory with directories' do
110
110
  crate = ROCrate::Reader.read_directory(fixture_file('directory_crate').path)
111
111
 
112
+ assert crate.entries.values.all? { |e| e.is_a?(ROCrate::Entry) }
112
113
  assert crate.entries['fish/info.txt']
113
114
  assert_equal '1234', crate.entries['fish/info.txt'].source.read.chomp
114
- assert crate.entries['fish/root.txt']
115
+ refute crate.entries['fish/root.txt'].directory?
116
+ assert crate.entries['fish/data'].directory?
115
117
  assert crate.entries['fish/data/info.txt']
116
- assert crate.entries['fish/data/nested.txt']
118
+ refute crate.entries['fish/data/nested.txt'].remote?
117
119
  assert crate.entries['fish/data/binary.jpg']
118
120
  assert_equal ['./', 'fish/', 'ro-crate-metadata.jsonld', 'ro-crate-preview.html'], crate.entities.map(&:id).sort
119
121
  end
@@ -161,4 +163,56 @@ class ReaderTest < Test::Unit::TestCase
161
163
  assert_equal 'http://example.com/external_ref.txt', ext_file.id
162
164
  assert_equal 'file contents', ext_file.source.read
163
165
  end
166
+
167
+ test 'reading from directory with unlisted files' do
168
+ crate = ROCrate::Reader.read_directory(fixture_file('sparse_directory_crate').path)
169
+
170
+ assert_equal 11, crate.entries.count
171
+ assert crate.entries['listed_file.txt']
172
+ assert crate.entries['unlisted_file.txt']
173
+ assert crate.entries['fish']
174
+ assert_equal '1234', crate.entries['fish/info.txt'].source.read.chomp
175
+ refute crate.entries['fish/root.txt'].directory?
176
+ assert crate.entries['fish/data'].directory?
177
+ assert crate.entries['fish/data/info.txt']
178
+ refute crate.entries['fish/data/nested.txt'].remote?
179
+ assert crate.entries['fish/data/binary.jpg']
180
+ assert_equal ['./', 'listed_file.txt', 'ro-crate-metadata.jsonld', 'ro-crate-preview.html'], crate.entities.map(&:id).sort
181
+ end
182
+
183
+ test 'reading from a zip with unlisted files' do
184
+ crate = ROCrate::Reader.read_zip(fixture_file('sparse_directory_crate.zip').path)
185
+
186
+ assert_equal 11, crate.entries.count
187
+ assert crate.entries['listed_file.txt']
188
+ assert crate.entries['unlisted_file.txt']
189
+ assert crate.entries['fish']
190
+ assert_equal '1234', crate.entries['fish/info.txt'].source.read.chomp
191
+ refute crate.entries['fish/root.txt'].directory?
192
+ assert crate.entries['fish/data'].directory?
193
+ assert crate.entries['fish/data/info.txt']
194
+ refute crate.entries['fish/data/nested.txt'].remote?
195
+ assert crate.entries['fish/data/binary.jpg']
196
+ assert_equal ['./', 'listed_file.txt', 'ro-crate-metadata.jsonld', 'ro-crate-preview.html'], crate.entities.map(&:id).sort
197
+ end
198
+
199
+ test 'reading a zip from various object types' do
200
+ string_io = StringIO.new
201
+ string_io.write(::File.read(fixture_file('sparse_directory_crate.zip').path))
202
+ string_io.rewind
203
+ assert string_io.is_a?(StringIO)
204
+ assert_equal 11, ROCrate::Reader.read_zip(string_io).entries.count
205
+
206
+ path = Pathname.new(fixture_file('sparse_directory_crate.zip').path)
207
+ assert path.is_a?(Pathname)
208
+ assert_equal 11, ROCrate::Reader.read_zip(path).entries.count
209
+
210
+ file = ::File.open(fixture_file('sparse_directory_crate.zip').path)
211
+ assert file.is_a?(::File)
212
+ assert_equal 11, ROCrate::Reader.read_zip(file).entries.count
213
+
214
+ string = fixture_file('sparse_directory_crate.zip').path
215
+ assert string.is_a?(String)
216
+ assert_equal 11, ROCrate::Reader.read_zip(string).entries.count
217
+ end
164
218
  end
data/test/writer_test.rb CHANGED
@@ -112,4 +112,24 @@ class WriterTest < Test::Unit::TestCase
112
112
  assert_equal 2529, ::File.size(::File.join(dir, 'data', 'binary.jpg'))
113
113
  end
114
114
  end
115
+
116
+ test 'reading and writing out a directory crate produces an identical crate' do
117
+ fixture = fixture_file('sparse_directory_crate').path
118
+ Dir.mktmpdir do |dir|
119
+ dir = ::File.join(dir, 'new_directory')
120
+ crate = ROCrate::Reader.read(fixture)
121
+
122
+ ROCrate::Writer.new(crate).write(dir)
123
+ expected_files = Dir.chdir(fixture) { Dir.glob('**/*') }
124
+ actual_files = Dir.chdir(dir) { Dir.glob('**/*') }
125
+ assert_equal expected_files, actual_files
126
+ expected_files.each do |file|
127
+ next if file == 'ro-crate-metadata.jsonld' # Expected context gets updated.
128
+ next if file == 'ro-crate-preview.html' # RO-Crate preview format changed
129
+ abs_file_path = ::File.join(fixture, file)
130
+ next if ::File.directory?(abs_file_path)
131
+ assert_equal ::File.read(abs_file_path), ::File.read(::File.join(dir, file)), "#{file} didn't match"
132
+ end
133
+ end
134
+ end
115
135
  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.4.2
4
+ version: 0.4.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Finn Bacall
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-02-19 00:00:00.000000000 Z
11
+ date: 2021-02-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: addressable
@@ -149,6 +149,8 @@ files:
149
149
  - test/fixtures/crate-spec1.1/ro-crate-metadata.json
150
150
  - test/fixtures/data.csv
151
151
  - test/fixtures/directory.zip
152
+ - test/fixtures/directory/.dir/test.txt
153
+ - test/fixtures/directory/.dotfile
152
154
  - test/fixtures/directory/data/binary.jpg
153
155
  - test/fixtures/directory/data/info.txt
154
156
  - test/fixtures/directory/data/nested.txt
@@ -165,6 +167,16 @@ files:
165
167
  - test/fixtures/info.txt
166
168
  - test/fixtures/spaces/file with spaces.txt
167
169
  - test/fixtures/spaces/ro-crate-metadata.jsonld
170
+ - test/fixtures/sparse_directory_crate.zip
171
+ - test/fixtures/sparse_directory_crate/fish/data/binary.jpg
172
+ - test/fixtures/sparse_directory_crate/fish/data/info.txt
173
+ - test/fixtures/sparse_directory_crate/fish/data/nested.txt
174
+ - test/fixtures/sparse_directory_crate/fish/info.txt
175
+ - test/fixtures/sparse_directory_crate/fish/root.txt
176
+ - test/fixtures/sparse_directory_crate/listed_file.txt
177
+ - test/fixtures/sparse_directory_crate/ro-crate-metadata.jsonld
178
+ - test/fixtures/sparse_directory_crate/ro-crate-preview.html
179
+ - test/fixtures/sparse_directory_crate/unlisted_file.txt
168
180
  - test/fixtures/workflow-0.2.0.zip
169
181
  - test/fixtures/workflow-0.2.0/Dockerfile
170
182
  - test/fixtures/workflow-0.2.0/README.md