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.
- checksums.yaml +4 -4
- data/Gemfile.lock +13 -13
- data/README.md +39 -0
- data/lib/ro_crate/model/contextual_entity.rb +2 -14
- data/lib/ro_crate/model/crate.rb +52 -6
- data/lib/ro_crate/model/data_entity.rb +6 -5
- data/lib/ro_crate/model/directory.rb +3 -5
- data/lib/ro_crate/model/entity.rb +65 -6
- data/lib/ro_crate/model/entry.rb +2 -2
- data/lib/ro_crate/model/file.rb +2 -4
- data/lib/ro_crate/model/metadata.rb +9 -1
- data/lib/ro_crate/model/organization.rb +1 -1
- data/lib/ro_crate/model/preview.rb +3 -15
- data/lib/ro_crate/model/preview_generator.rb +40 -0
- data/lib/ro_crate/model/remote_entry.rb +1 -12
- data/lib/ro_crate/reader.rb +77 -20
- data/lib/ro_crate/writer.rb +4 -4
- data/lib/ro_crate.rb +2 -1
- data/ro_crate.gemspec +3 -3
- data/test/crate_test.rb +37 -3
- data/test/directory_test.rb +21 -21
- data/test/entity_test.rb +135 -0
- data/test/fixtures/biobb_hpc_workflows-condapack.zip +0 -0
- data/test/fixtures/conflicting_data_directory/info.txt +1 -0
- data/test/fixtures/conflicting_data_directory/nested.txt +1 -0
- data/test/fixtures/nested_directory.zip +0 -0
- data/test/fixtures/ro-crate-galaxy-sortchangecase/LICENSE +176 -0
- data/test/fixtures/ro-crate-galaxy-sortchangecase/README.md +6 -0
- data/test/fixtures/ro-crate-galaxy-sortchangecase/ro-crate-metadata.json +133 -0
- data/test/fixtures/ro-crate-galaxy-sortchangecase/sort-and-change-case.ga +118 -0
- data/test/fixtures/ro-crate-galaxy-sortchangecase/test/test1/input.bed +3 -0
- data/test/fixtures/ro-crate-galaxy-sortchangecase/test/test1/output_exp.bed +3 -0
- data/test/fixtures/ro-crate-galaxy-sortchangecase/test/test1/sort-and-change-case-test.yml +8 -0
- data/test/fixtures/sparse_directory_crate/ro-crate-preview.html +60 -59
- data/test/reader_test.rb +83 -40
- data/test/test_helper.rb +5 -1
- data/test/writer_test.rb +59 -2
- metadata +26 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d9f081110d1e5b5e94674cb53d07262fbce50ec3f63437d5c4c1ecda8b04f835
|
4
|
+
data.tar.gz: 0cd710a9cd86063e706fd9cf338e5fdf55f5bc6993f306af4f50d6f9191a0d87
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8ce573fbd259108edbb528e24f0d9647cfee4454378d57a4b3392aaeb0dea80385b2828221a0979caa4733be0e2108a4a535725846f576c9ac97866f46911e47
|
7
|
+
data.tar.gz: ffc7aafbdccb3f4897ad2acae726714d7a313f02fd87e5c96173da2b12860dfa1318b9b323dde751e3ac10c9a66cf29effea383037bc4622eaf5113dd01bd426
|
data/Gemfile.lock
CHANGED
@@ -1,31 +1,31 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
ro-crate (0.4.
|
5
|
-
addressable (
|
4
|
+
ro-crate (0.4.12)
|
5
|
+
addressable (>= 2.7, < 2.9)
|
6
6
|
rubyzip (~> 2.0.0)
|
7
7
|
|
8
8
|
GEM
|
9
9
|
remote: https://rubygems.org/
|
10
10
|
specs:
|
11
|
-
addressable (2.
|
11
|
+
addressable (2.8.0)
|
12
12
|
public_suffix (>= 2.0.2, < 5.0)
|
13
13
|
crack (0.4.3)
|
14
14
|
safe_yaml (~> 1.0.0)
|
15
|
-
docile (1.3.
|
15
|
+
docile (1.3.5)
|
16
16
|
hashdiff (1.0.1)
|
17
|
-
|
18
|
-
|
19
|
-
public_suffix (4.0.3)
|
17
|
+
power_assert (1.1.3)
|
18
|
+
public_suffix (4.0.6)
|
20
19
|
rake (13.0.0)
|
21
20
|
rubyzip (2.0.0)
|
22
21
|
safe_yaml (1.0.5)
|
23
|
-
simplecov (0.
|
22
|
+
simplecov (0.21.2)
|
24
23
|
docile (~> 1.1)
|
25
|
-
|
26
|
-
|
27
|
-
simplecov-html (0.
|
28
|
-
|
24
|
+
simplecov-html (~> 0.11)
|
25
|
+
simplecov_json_formatter (~> 0.1)
|
26
|
+
simplecov-html (0.12.3)
|
27
|
+
simplecov_json_formatter (0.1.2)
|
28
|
+
test-unit (3.2.9)
|
29
29
|
power_assert
|
30
30
|
webmock (3.8.3)
|
31
31
|
addressable (>= 2.3.6)
|
@@ -39,7 +39,7 @@ PLATFORMS
|
|
39
39
|
DEPENDENCIES
|
40
40
|
rake (~> 13.0.0)
|
41
41
|
ro-crate!
|
42
|
-
simplecov (~> 0.
|
42
|
+
simplecov (~> 0.21.2)
|
43
43
|
test-unit (~> 3.2.3)
|
44
44
|
webmock (~> 3.8.3)
|
45
45
|
yard (~> 0.9.25)
|
data/README.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# ro-crate-ruby
|
2
2
|
|
3
|
+

|
4
|
+
|
3
5
|
This is a WIP gem for creating, manipulating and reading RO-Crates (conforming to version 1.1 of the specification).
|
4
6
|
|
5
7
|
* RO-Crate - https://researchobject.github.io/ro-crate/
|
@@ -17,6 +19,43 @@ and run `bundle install`.
|
|
17
19
|
|
18
20
|
## Usage
|
19
21
|
|
22
|
+
This gem consists a hierarchy of classes to model RO-Crate "entities": the crate itself, data entities
|
23
|
+
(files and directory) and contextual entities (with a limited set of specializations, such as `ROCrate::Person`).
|
24
|
+
They are all descendents of the `ROCrate::Entity` class, with the `ROCrate::Crate` class representing the crate itself.
|
25
|
+
|
26
|
+
The `ROCrate::Reader` class handles reading of RO-Crates into the above model, from a Zip file or directory.
|
27
|
+
|
28
|
+
The `ROCrate::Writer` class can write out an `ROCrate::Crate` instance into a Zip file or directory.
|
29
|
+
|
30
|
+
**Note:** for performance reasons, the gem is currently not linked-data aware and will allow you to set properties that
|
31
|
+
are not semantically valid.
|
32
|
+
|
33
|
+
### Entities
|
34
|
+
Entities correspond to entries in the `@graph` of the RO-Crate's metadata JSON-LD file. Each entity class is
|
35
|
+
basically a wrapper around a set of JSON properties, with some convenience methods for getting/setting some
|
36
|
+
commonly used properties (`crate.name = "My first crate"`).
|
37
|
+
|
38
|
+
These convenience getter/setter methods will automatically handle turning objects into references and adding them to the
|
39
|
+
`@graph` if necessary.
|
40
|
+
|
41
|
+
##### Getting/Setting Arbitrary Properties of Entities
|
42
|
+
As well as using the pre-defined getter/setter methods, you can get/set arbitrary properties like so.
|
43
|
+
|
44
|
+
To set the "creativeWorkStatus" property of the RO-Crate itself to a string literal:
|
45
|
+
```ruby
|
46
|
+
crate['creativeWorkStatus'] = 'work-in-progress'
|
47
|
+
```
|
48
|
+
|
49
|
+
If you want to reference other entities in the crate, you can get a JSON-LD reference from an entity object by using the `reference` method:
|
50
|
+
```ruby
|
51
|
+
joe = crate.add_person('joe', { name: 'Joe Bloggs' }) # Add the entity to the @graph
|
52
|
+
crate['copyrightHolder'] = joe.reference # Reference the entity from the "copyrightHolder" property
|
53
|
+
```
|
54
|
+
and to resolve those references back to the object, use the `dereference` method:
|
55
|
+
```ruby
|
56
|
+
joe = crate['copyrightHolder'].dereference
|
57
|
+
```
|
58
|
+
|
20
59
|
### Documentation
|
21
60
|
|
22
61
|
[Click here for API documentation](https://www.researchobject.org/ro-crate-ruby/).
|
@@ -3,21 +3,9 @@ module ROCrate
|
|
3
3
|
# A class to represent a "Contextual Entity" within an RO-Crate.
|
4
4
|
# Contextual Entities are used to describe and provide context to the Data Entities within the crate.
|
5
5
|
class ContextualEntity < Entity
|
6
|
-
def self.
|
6
|
+
def self.format_local_id(id)
|
7
7
|
i = super
|
8
|
-
|
9
|
-
uri = URI(id)
|
10
|
-
rescue ArgumentError
|
11
|
-
uri = nil
|
12
|
-
end
|
13
|
-
|
14
|
-
if uri&.absolute?
|
15
|
-
i
|
16
|
-
elsif i.start_with?('#')
|
17
|
-
i
|
18
|
-
else
|
19
|
-
"##{i}"
|
20
|
-
end
|
8
|
+
i.start_with?('#') ? i : "##{i}"
|
21
9
|
end
|
22
10
|
|
23
11
|
##
|
data/lib/ro_crate/model/crate.rb
CHANGED
@@ -8,6 +8,11 @@ module ROCrate
|
|
8
8
|
properties(%w[name datePublished author license identifier distribution contactPoint publisher description url hasPart])
|
9
9
|
|
10
10
|
def self.format_id(id)
|
11
|
+
i = super(id)
|
12
|
+
i.end_with?('/') ? i : "#{i}/"
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.format_local_id(id)
|
11
16
|
return id if id == IDENTIFIER
|
12
17
|
super
|
13
18
|
end
|
@@ -20,6 +25,15 @@ module ROCrate
|
|
20
25
|
super(self, nil, id, properties)
|
21
26
|
end
|
22
27
|
|
28
|
+
##
|
29
|
+
# Lookup an Entity using the given ID (in this Entity's crate).
|
30
|
+
#
|
31
|
+
# @param id [String] The ID to query.
|
32
|
+
# @return [Entity, nil]
|
33
|
+
def dereference(id)
|
34
|
+
entities.detect { |e| e.canonical_id == crate.resolve_id(id) } if id
|
35
|
+
end
|
36
|
+
|
23
37
|
##
|
24
38
|
# Create a new file and add it to the crate.
|
25
39
|
#
|
@@ -163,6 +177,15 @@ module ROCrate
|
|
163
177
|
@preview ||= ROCrate::Preview.new(self)
|
164
178
|
end
|
165
179
|
|
180
|
+
##
|
181
|
+
# Set the RO-Crate preview file
|
182
|
+
# @param preview [Preview] the preview to set.
|
183
|
+
#
|
184
|
+
# @return [Preview]
|
185
|
+
def preview=(preview)
|
186
|
+
@preview = claim(preview)
|
187
|
+
end
|
188
|
+
|
166
189
|
##
|
167
190
|
# All the entities within the crate. Includes contextual entities, data entities, the crate itself and its metadata file.
|
168
191
|
#
|
@@ -215,21 +238,21 @@ module ROCrate
|
|
215
238
|
entity.class.new(crate, entity.id, entity.raw_properties)
|
216
239
|
end
|
217
240
|
|
218
|
-
alias_method :
|
241
|
+
alias_method :own_payload, :payload
|
219
242
|
##
|
220
|
-
#
|
221
|
-
# key is the
|
243
|
+
# The file payload of the RO-Crate - a map of all the files/directories contained in the RO-Crate, where the
|
244
|
+
# key is the path relative to the crate's root, and the value is an Entry where the source data can be read.
|
222
245
|
#
|
223
246
|
# @return [Hash{String => Entry}>]
|
224
|
-
def
|
247
|
+
def payload
|
225
248
|
# Gather a map of entries, starting from the crate itself, then any directory data entities, then finally any
|
226
249
|
# file data entities. This ensures in the case of a conflict, the more "specific" data entities take priority.
|
227
|
-
entries =
|
250
|
+
entries = own_payload
|
228
251
|
non_self_entities = default_entities.reject { |e| e == self }
|
229
252
|
sorted_entities = (non_self_entities | data_entities).sort_by { |e| e.is_a?(ROCrate::Directory) ? 0 : 1 }
|
230
253
|
|
231
254
|
sorted_entities.each do |entity|
|
232
|
-
entity.
|
255
|
+
entity.payload.each do |path, entry|
|
233
256
|
entries[path] = entry
|
234
257
|
end
|
235
258
|
end
|
@@ -241,6 +264,29 @@ module ROCrate
|
|
241
264
|
binding
|
242
265
|
end
|
243
266
|
|
267
|
+
##
|
268
|
+
# Remove the entity from the RO-Crate.
|
269
|
+
#
|
270
|
+
# @param entity [Entity, String] The entity or ID of an entity to remove from the crate.
|
271
|
+
# @param remove_orphaned [Boolean] Should linked contextual entities also be removed from the crate they are left
|
272
|
+
# dangling (nothing else is linked to them)?
|
273
|
+
#
|
274
|
+
# @return [Entity, nil] The entity that was deleted, or nil if nothing was deleted.
|
275
|
+
def delete(entity, remove_orphaned: true)
|
276
|
+
entity = dereference(entity) if entity.is_a?(String)
|
277
|
+
return unless entity
|
278
|
+
|
279
|
+
deleted = data_entities.delete(entity) || contextual_entities.delete(entity)
|
280
|
+
|
281
|
+
if deleted && remove_orphaned
|
282
|
+
crate_entities = crate.linked_entities(deep: true)
|
283
|
+
to_remove = (entity.linked_entities(deep: true) - crate_entities)
|
284
|
+
to_remove.each(&:delete)
|
285
|
+
end
|
286
|
+
|
287
|
+
deleted
|
288
|
+
end
|
289
|
+
|
244
290
|
private
|
245
291
|
|
246
292
|
def full_entry_path(relative_path)
|
@@ -3,7 +3,9 @@ module ROCrate
|
|
3
3
|
# A class to represent a "Data Entity" within an RO-Crate.
|
4
4
|
# Data Entities are the actual physical files and directories within the Crate.
|
5
5
|
class DataEntity < Entity
|
6
|
-
|
6
|
+
properties(%w[name contentSize dateModified encodingFormat identifier sameAs author])
|
7
|
+
|
8
|
+
def self.format_local_id(id)
|
7
9
|
super.chomp('/')
|
8
10
|
end
|
9
11
|
|
@@ -13,8 +15,6 @@ module ROCrate
|
|
13
15
|
# @return [Class]
|
14
16
|
def self.specialize(props)
|
15
17
|
type = props['@type']
|
16
|
-
id = props['@id']
|
17
|
-
abs = URI(id)&.absolute? rescue false
|
18
18
|
type = [type] unless type.is_a?(Array)
|
19
19
|
if type.include?('Dataset')
|
20
20
|
ROCrate::Directory
|
@@ -24,12 +24,13 @@ module ROCrate
|
|
24
24
|
end
|
25
25
|
|
26
26
|
##
|
27
|
-
#
|
27
|
+
# The payload of all the files/directories associated with this DataEntity, mapped by their relative file path.
|
28
28
|
#
|
29
29
|
# @return [Hash{String => Entry}>] The key is the location within the crate, and the value is an Entry.
|
30
|
-
def
|
30
|
+
def payload
|
31
31
|
{}
|
32
32
|
end
|
33
|
+
alias_method :entries, :payload
|
33
34
|
|
34
35
|
##
|
35
36
|
# A disk-safe filepath based on the ID of this DataEntity.
|
@@ -2,9 +2,7 @@ module ROCrate
|
|
2
2
|
##
|
3
3
|
# A data entity that represents a directory of potentially many files and subdirectories (or none).
|
4
4
|
class Directory < DataEntity
|
5
|
-
|
6
|
-
|
7
|
-
def self.format_id(id)
|
5
|
+
def self.format_local_id(id)
|
8
6
|
super + '/'
|
9
7
|
end
|
10
8
|
|
@@ -30,11 +28,11 @@ module ROCrate
|
|
30
28
|
end
|
31
29
|
|
32
30
|
##
|
33
|
-
# The
|
31
|
+
# The payload of this directory - a map of all the files/directories, where the key is the destination path
|
34
32
|
# within the crate and the value is an Entry where the source data can be read.
|
35
33
|
#
|
36
34
|
# @return [Hash{String => Entry}>]
|
37
|
-
def
|
35
|
+
def payload
|
38
36
|
entries = {}
|
39
37
|
entries[filepath.chomp('/')] = @entry if @entry
|
40
38
|
|
@@ -29,12 +29,34 @@ module ROCrate
|
|
29
29
|
end
|
30
30
|
|
31
31
|
##
|
32
|
-
# Format the given ID with rules appropriate for this type.
|
32
|
+
# Format the given ID with rules appropriate for this type if it is local/relative, leave as-is if absolute.
|
33
|
+
#
|
34
|
+
# @param id [String] The candidate ID to be formatted.
|
35
|
+
# @return [String] The formatted ID.
|
36
|
+
def self.format_id(id)
|
37
|
+
begin
|
38
|
+
uri = URI(id)
|
39
|
+
rescue ArgumentError, URI::InvalidURIError
|
40
|
+
uri = nil
|
41
|
+
end
|
42
|
+
|
43
|
+
if uri&.absolute?
|
44
|
+
id
|
45
|
+
else
|
46
|
+
format_local_id(id)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
##
|
51
|
+
# Format the given local ID with rules appropriate for this type.
|
33
52
|
# For example:
|
34
53
|
# * contextual entities MUST be absolute URIs, or begin with: #
|
35
54
|
# * files MUST NOT begin with ./
|
36
55
|
# * directories MUST NOT begin with ./ (except for the crate itself), and MUST end with /
|
37
|
-
|
56
|
+
#
|
57
|
+
# @param id [String] The candidate local ID to be formatted.
|
58
|
+
# @return [String] The formatted local ID.
|
59
|
+
def self.format_local_id(id)
|
38
60
|
Addressable::URI.escape(id.sub(/\A\.\//, '')) # Remove initial ./ if present
|
39
61
|
end
|
40
62
|
|
@@ -107,16 +129,26 @@ module ROCrate
|
|
107
129
|
# @param id [String] The ID to query.
|
108
130
|
# @return [Entity, nil]
|
109
131
|
def dereference(id)
|
110
|
-
crate.
|
132
|
+
crate.dereference(id)
|
111
133
|
end
|
112
|
-
|
113
134
|
alias_method :get, :dereference
|
114
135
|
|
136
|
+
##
|
137
|
+
# Remove this entity from the RO-Crate.
|
138
|
+
#
|
139
|
+
# @param remove_orphaned [Boolean] Should linked contextual entities also be removed from the crate (if nothing else is linked to them)?
|
140
|
+
#
|
141
|
+
# @return [Entity, nil] This entity, or nil if nothing was deleted.
|
142
|
+
def delete(remove_orphaned: true)
|
143
|
+
crate.delete(self, remove_orphaned: remove_orphaned)
|
144
|
+
end
|
145
|
+
|
115
146
|
def id
|
116
147
|
@properties['@id']
|
117
148
|
end
|
118
149
|
|
119
150
|
def id=(id)
|
151
|
+
@canonical_id = nil
|
120
152
|
@properties['@id'] = self.class.format_id(id)
|
121
153
|
end
|
122
154
|
|
@@ -168,13 +200,13 @@ module ROCrate
|
|
168
200
|
#
|
169
201
|
# @return [Addressable::URI]
|
170
202
|
def canonical_id
|
171
|
-
crate.resolve_id(id)
|
203
|
+
@canonical_id ||= crate.resolve_id(id)
|
172
204
|
end
|
173
205
|
|
174
206
|
##
|
175
207
|
# Is this entity local to the crate or an external reference?
|
176
208
|
#
|
177
|
-
# @return [
|
209
|
+
# @return [Boolean]
|
178
210
|
def external?
|
179
211
|
crate.canonical_id.host != canonical_id.host
|
180
212
|
end
|
@@ -204,6 +236,33 @@ module ROCrate
|
|
204
236
|
@properties.has_type?(type)
|
205
237
|
end
|
206
238
|
|
239
|
+
##
|
240
|
+
# Gather a list of entities linked to this one through its properties.
|
241
|
+
# @param deep [Boolean] If false, only consider direct links, otherwise consider transitive links.
|
242
|
+
# @param linked [Hash{String => Entity}] Discovered entities, mapped by their ID, to avoid loops when recursing.
|
243
|
+
# @return [Array<Entity>]
|
244
|
+
def linked_entities(deep: false, linked: {})
|
245
|
+
properties.each do |key, value|
|
246
|
+
value = [value] if value.is_a?(JSONLDHash)
|
247
|
+
|
248
|
+
if value.is_a?(Array)
|
249
|
+
value.each do |v|
|
250
|
+
if v.is_a?(JSONLDHash) && !linked.key?(v['@id'])
|
251
|
+
entity = v.dereference
|
252
|
+
linked[entity.id] = entity if entity
|
253
|
+
if deep
|
254
|
+
entity.linked_entities(deep: true, linked: linked).each do |e|
|
255
|
+
linked[e.id] = e
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
linked.values.compact
|
264
|
+
end
|
265
|
+
|
207
266
|
private
|
208
267
|
|
209
268
|
def default_properties
|
data/lib/ro_crate/model/entry.rb
CHANGED
@@ -14,10 +14,10 @@ module ROCrate
|
|
14
14
|
end
|
15
15
|
|
16
16
|
##
|
17
|
-
# Write the source to the destination via a buffer.
|
17
|
+
# Write the entry's source to the destination via a buffer.
|
18
18
|
#
|
19
19
|
# @param dest [#write] An IO-like destination to write to.
|
20
|
-
def
|
20
|
+
def write_to(dest)
|
21
21
|
input = source
|
22
22
|
input = input.open('rb') if input.is_a?(Pathname)
|
23
23
|
while (buff = input.read(4096))
|
data/lib/ro_crate/model/file.rb
CHANGED
@@ -2,14 +2,12 @@ module ROCrate
|
|
2
2
|
##
|
3
3
|
# A data entity that represents a single file.
|
4
4
|
class File < DataEntity
|
5
|
-
properties(%w[name contentSize dateModified encodingFormat identifier sameAs])
|
6
|
-
|
7
5
|
##
|
8
6
|
# Create a new ROCrate::File. PLEASE NOTE, the new file will not be added to the crate. To do this, call
|
9
7
|
# Crate#add_data_entity, or just use Crate#add_file.
|
10
8
|
#
|
11
9
|
# @param crate [Crate] The RO-Crate that owns this file.
|
12
|
-
# @param source [String, Pathname, ::File,
|
10
|
+
# @param source [String, Pathname, ::File, URI, nil, #read] The source on the disk (or on the internet if a URI) where this file will be read.
|
13
11
|
# @param crate_path [String] The relative path within the RO-Crate where this file will be written.
|
14
12
|
# @param properties [Hash{String => Object}] A hash of JSON-LD properties to associate with this file.
|
15
13
|
def initialize(crate, source, crate_path = nil, properties = {})
|
@@ -58,7 +56,7 @@ module ROCrate
|
|
58
56
|
# (for compatibility with Directory#entries)
|
59
57
|
#
|
60
58
|
# @return [Hash{String => Entry}>] The key is the location within the crate, and the value is an Entry.
|
61
|
-
def
|
59
|
+
def payload
|
62
60
|
remote? ? {} : { filepath => source }
|
63
61
|
end
|
64
62
|
|
@@ -17,7 +17,15 @@ module ROCrate
|
|
17
17
|
# @return [String] The rendered JSON-LD as a "prettified" string.
|
18
18
|
def generate
|
19
19
|
graph = crate.entities.map(&:properties).reject(&:empty?)
|
20
|
-
JSON.pretty_generate('@context' =>
|
20
|
+
JSON.pretty_generate('@context' => context, '@graph' => graph)
|
21
|
+
end
|
22
|
+
|
23
|
+
def context
|
24
|
+
@context || CONTEXT
|
25
|
+
end
|
26
|
+
|
27
|
+
def context= c
|
28
|
+
@context = c
|
21
29
|
end
|
22
30
|
|
23
31
|
private
|
@@ -12,26 +12,14 @@ module ROCrate
|
|
12
12
|
# @return [String]
|
13
13
|
attr_accessor :template
|
14
14
|
|
15
|
-
def initialize(crate, properties = {})
|
15
|
+
def initialize(crate, source = nil, properties = {})
|
16
|
+
source ||= PreviewGenerator.new(self)
|
16
17
|
@template = nil
|
17
|
-
super(crate,
|
18
|
-
end
|
19
|
-
|
20
|
-
##
|
21
|
-
# Generate the crate's `ro-crate-preview.html`.
|
22
|
-
# @return [String] The rendered HTML as a string.
|
23
|
-
def generate
|
24
|
-
b = crate.get_binding
|
25
|
-
renderer = ERB.new(template || ::File.read(DEFAULT_TEMPLATE))
|
26
|
-
renderer.result(b)
|
18
|
+
super(crate, source, IDENTIFIER, properties)
|
27
19
|
end
|
28
20
|
|
29
21
|
private
|
30
22
|
|
31
|
-
def source
|
32
|
-
Entry.new(StringIO.new(generate))
|
33
|
-
end
|
34
|
-
|
35
23
|
def default_properties
|
36
24
|
{
|
37
25
|
'@id' => IDENTIFIER,
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'erb'
|
2
|
+
|
3
|
+
module ROCrate
|
4
|
+
##
|
5
|
+
# A class to handle generation of an RO-Crate's preview HTML in an IO-like way (to fit into an Entry).
|
6
|
+
class PreviewGenerator
|
7
|
+
##
|
8
|
+
# @param preview [Preview] The RO-Crate preview object.
|
9
|
+
def initialize(preview)
|
10
|
+
@preview = preview
|
11
|
+
end
|
12
|
+
|
13
|
+
def read(*args)
|
14
|
+
io.read(*args)
|
15
|
+
end
|
16
|
+
|
17
|
+
##
|
18
|
+
# Generate the crate's `ro-crate-preview.html`.
|
19
|
+
# @return [String] The rendered HTML as a string.
|
20
|
+
def generate
|
21
|
+
b = crate.get_binding
|
22
|
+
renderer = ERB.new(template)
|
23
|
+
renderer.result(b)
|
24
|
+
end
|
25
|
+
|
26
|
+
def template
|
27
|
+
@preview.template || ::File.read(Preview::DEFAULT_TEMPLATE)
|
28
|
+
end
|
29
|
+
|
30
|
+
def crate
|
31
|
+
@preview.crate
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def io
|
37
|
+
@io ||= StringIO.new(generate)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -2,7 +2,7 @@ module ROCrate
|
|
2
2
|
##
|
3
3
|
# A class to represent a reference within an RO-Crate, to a remote file held on the internet somewhere.
|
4
4
|
# It handles the actual reading/writing of bytes.
|
5
|
-
class RemoteEntry
|
5
|
+
class RemoteEntry < Entry
|
6
6
|
attr_reader :uri
|
7
7
|
|
8
8
|
##
|
@@ -13,17 +13,6 @@ module ROCrate
|
|
13
13
|
@uri = uri
|
14
14
|
end
|
15
15
|
|
16
|
-
def write(dest)
|
17
|
-
raise 'Cannot write to a remote entry!'
|
18
|
-
end
|
19
|
-
|
20
|
-
##
|
21
|
-
# Read from the source.
|
22
|
-
#
|
23
|
-
def read
|
24
|
-
source.read
|
25
|
-
end
|
26
|
-
|
27
16
|
##
|
28
17
|
# @return [IO] An IO object for the remote resource.
|
29
18
|
#
|