ro-crate 0.4.3 → 0.4.8

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 00f8d84d1776b3f8c51e68477fe665c5c703fb56a584e72f748cf10b1a80de14
4
- data.tar.gz: 6beefca605f5a5ab5da783510f3a8fe8cbcc795f595431a50eb2e6c47edf7999
3
+ metadata.gz: 7003f224766d4445498db499257b246ea2dbfb842f0f5e0c8d04471ccea4d299
4
+ data.tar.gz: f62e7c90a54f26aa6b18cf98310c998ada8c6836975c997f551b2b1ab7d85e29
5
5
  SHA512:
6
- metadata.gz: ba029b48b018565b89d5df2d6d4dd8e22a96d5d1949922985ebf564f6133a1b71495a41540a7e265cd3bc5871dda41940d400dea077c439ab23389ebc7e1c44b
7
- data.tar.gz: ba169bd9cf38fade168fada4a57ba3e29e0b70e1b181a753c09a2f39a21d13a17370376c6561b549041fc2e811c689f6db3a1fad616856f6b956c8528314004a
6
+ metadata.gz: f63fa2c3b9d88ec76f20e8986986d81878dc8bbb82bedd4c2c862ca6fca7f021ad84309678abb12ec6de7fb498a87711409f3f64809aba4c09c5b00676c60aac
7
+ data.tar.gz: 16616f82e91760e9a6ff3eff1199c327143401086b0f9c577908e28d023e27828b7e36eeffc65333ec3aa440697b8f18cddd9406185f116ccc59ff238c98b1e9
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ro-crate (0.4.3)
4
+ ro-crate (0.4.8)
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
 
@@ -21,7 +21,7 @@ module ROCrate
21
21
 
22
22
  if source_directory
23
23
  source_directory = Pathname.new(::File.expand_path(source_directory))
24
- @entry = source_directory
24
+ @entry = Entry.new(source_directory)
25
25
  populate_entries(source_directory)
26
26
  crate_path = source_directory.basename.to_s if crate_path.nil?
27
27
  end
@@ -30,8 +30,8 @@ module ROCrate
30
30
  end
31
31
 
32
32
  ##
33
- # A map of all the files/directories under this directory, where the key is the destination path within the crate
34
- # 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.
35
35
  #
36
36
  # @return [Hash{String => Entry}>]
37
37
  def entries
@@ -51,13 +51,14 @@ module ROCrate
51
51
  # Populate this directory with files/directories from a given source directory on disk.
52
52
  #
53
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).
54
55
  #
55
56
  # @return [Hash{String => Entry}>] The files/directories that were populated.
56
57
  # The key is the relative path of the file/directory, and the value is an Entry object where data can be read etc.
57
- def populate_entries(source_directory)
58
+ def populate_entries(source_directory, include_hidden: false)
58
59
  raise 'Not a directory' unless ::File.directory?(source_directory)
59
60
  @directory_entries = {}
60
- Dir.chdir(source_directory) { Dir.glob('**/*') }.each do |rel_path|
61
+ list_all_files(source_directory, include_hidden: include_hidden).each do |rel_path|
61
62
  source_path = Pathname.new(::File.join(source_directory, rel_path)).expand_path
62
63
  @directory_entries[rel_path] = Entry.new(source_path)
63
64
  end
@@ -69,6 +70,14 @@ module ROCrate
69
70
  ::File.join(filepath, relative_path)
70
71
  end
71
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
+
72
81
  def default_properties
73
82
  super.merge(
74
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.binwrite(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.3'
3
+ s.version = '0.4.8'
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,44 +201,54 @@ 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)
204
+ entities = crate.add_all(fixture_file('directory').path, include_hidden: true)
205
205
 
206
206
  paths = crate.entries.keys
207
- assert_equal 8, paths.length
207
+ assert_equal 11, paths.length
208
208
  assert_includes paths, 'data'
209
209
  assert_includes paths, 'root.txt'
210
210
  assert_includes paths, 'info.txt'
211
211
  assert_includes paths, 'data/binary.jpg'
212
212
  assert_includes paths, 'data/info.txt'
213
213
  assert_includes paths, 'data/nested.txt'
214
+ assert_includes paths, '.dotfile'
215
+ assert_includes paths, '.dir'
216
+ assert_includes paths, '.dir/test.txt'
214
217
  assert_includes paths, 'ro-crate-metadata.json'
215
218
  assert_includes paths, 'ro-crate-preview.html'
216
219
 
217
- assert_equal 6, entities.length
220
+ assert_equal 9, entities.length
218
221
  assert_equal 'ROCrate::Directory', crate.dereference('data/').class.name
219
222
  assert_equal 'ROCrate::File', crate.dereference('root.txt').class.name
220
223
  assert_equal 'ROCrate::File', crate.dereference('info.txt').class.name
221
224
  assert_equal 'ROCrate::File', crate.dereference('data/binary.jpg').class.name
222
225
  assert_equal 'ROCrate::File', crate.dereference('data/info.txt').class.name
223
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
224
230
 
225
231
  assert_equal "5678\n", crate.dereference('data/info.txt').source.read
232
+ assert_equal "Am I included?\n", crate.dereference('.dotfile').source.read
226
233
  end
227
234
 
228
235
  test 'can create an RO-Crate using content from a given directory' do
229
236
  crate = ROCrate::Crate.new
230
- entities = crate.add_all(fixture_file('directory').path, false)
237
+ entities = crate.add_all(fixture_file('directory').path, false, include_hidden: true)
231
238
 
232
239
  assert_empty entities
233
240
 
234
241
  paths = crate.entries.keys
235
- assert_equal 8, paths.length
242
+ assert_equal 11, paths.length
236
243
  assert_includes paths, 'data'
237
244
  assert_includes paths, 'root.txt'
238
245
  assert_includes paths, 'info.txt'
239
246
  assert_includes paths, 'data/binary.jpg'
240
247
  assert_includes paths, 'data/info.txt'
241
248
  assert_includes paths, 'data/nested.txt'
249
+ assert_includes paths, '.dotfile'
250
+ assert_includes paths, '.dir'
251
+ assert_includes paths, '.dir/test.txt'
242
252
  assert_includes paths, 'ro-crate-metadata.json'
243
253
  assert_includes paths, 'ro-crate-preview.html'
244
254
 
@@ -249,5 +259,38 @@ class CrateTest < Test::Unit::TestCase
249
259
  assert_nil crate.dereference('data/binary.jpg')
250
260
  assert_nil crate.dereference('data/info.txt')
251
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
252
295
  end
253
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.3
4
+ version: 0.4.8
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-24 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