ro-bundle 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -13
- data/.ruby-gemset +0 -1
- data/.ruby-version +1 -2
- data/.travis.yml +9 -1
- data/Licence.rdoc +1 -1
- data/ReadMe.rdoc +8 -7
- data/bin/dir2ro +3 -2
- data/bin/ro-bundle-info +2 -2
- data/bin/verify-ro-bundle +2 -2
- data/bin/zip2ro +2 -2
- data/lib/ro-bundle.rb +3 -2
- data/lib/ro-bundle/exceptions.rb +0 -14
- data/lib/ro-bundle/file.rb +28 -20
- data/lib/ro-bundle/ro/agent.rb +1 -1
- data/lib/ro-bundle/ro/aggregate.rb +46 -38
- data/lib/ro-bundle/ro/annotation.rb +58 -20
- data/lib/ro-bundle/ro/manifest-entry.rb +52 -0
- data/lib/ro-bundle/ro/manifest.rb +76 -38
- data/lib/ro-bundle/ro/provenance.rb +78 -11
- data/lib/ro-bundle/ro/proxy.rb +80 -0
- data/lib/ro-bundle/util.rb +1 -1
- data/lib/ro-bundle/version.rb +1 -1
- data/ro-bundle.gemspec +6 -5
- data/test/data/HelloAnyone.robundle +0 -0
- data/test/data/example3-manifest.json +7 -7
- data/test/data/example6-manifest.json +17 -0
- data/test/helpers/fake_provenance.rb +4 -1
- data/test/tc_add_annotation.rb +47 -44
- data/test/tc_aggregate.rb +70 -65
- data/test/tc_annotation.rb +70 -11
- data/test/tc_create.rb +30 -12
- data/test/tc_manifest.rb +25 -2
- data/test/tc_provenance.rb +75 -0
- data/test/tc_proxy.rb +56 -0
- data/test/tc_read.rb +4 -4
- data/test/tc_remove.rb +8 -5
- data/test/tc_util.rb +2 -1
- data/test/ts_ro_bundle.rb +3 -1
- metadata +51 -31
@@ -1,5 +1,5 @@
|
|
1
1
|
#------------------------------------------------------------------------------
|
2
|
-
# Copyright (c) 2014 The University of Manchester, UK.
|
2
|
+
# Copyright (c) 2014, 2015 The University of Manchester, UK.
|
3
3
|
#
|
4
4
|
# BSD Licenced. See LICENCE.rdoc for details.
|
5
5
|
#
|
@@ -10,8 +10,7 @@
|
|
10
10
|
module ROBundle
|
11
11
|
|
12
12
|
# A class to represent an Annotation in a Research Object.
|
13
|
-
class Annotation
|
14
|
-
include Provenance
|
13
|
+
class Annotation < ManifestEntry
|
15
14
|
|
16
15
|
# :call-seq:
|
17
16
|
# new(target, content = nil)
|
@@ -24,25 +23,67 @@ module ROBundle
|
|
24
23
|
# An annotation id is a UUID prefixed with "urn:uuid" as per
|
25
24
|
# {RFC4122}[http://www.ietf.org/rfc/rfc4122.txt].
|
26
25
|
def initialize(object, content = nil)
|
26
|
+
super()
|
27
|
+
|
27
28
|
if object.instance_of?(Hash)
|
28
29
|
@structure = object
|
30
|
+
@structure[:about] = [*@structure[:about]]
|
29
31
|
init_provenance_defaults(@structure)
|
30
32
|
else
|
31
33
|
@structure = {}
|
32
|
-
@structure[:about] = object
|
33
|
-
@structure[:
|
34
|
+
@structure[:about] = [*object]
|
35
|
+
@structure[:uri] = UUID.generate(:urn)
|
34
36
|
@structure[:content] = content
|
35
37
|
end
|
36
38
|
end
|
37
39
|
|
38
40
|
# :call-seq:
|
39
|
-
# target
|
41
|
+
# annotates?(target) -> true or false
|
42
|
+
#
|
43
|
+
# Does this annotation object annotate the supplied target?
|
44
|
+
def annotates?(target)
|
45
|
+
@structure[:about].include?(target)
|
46
|
+
end
|
47
|
+
|
48
|
+
# :call-seq:
|
49
|
+
# target -> String or Array
|
50
|
+
#
|
51
|
+
# The identifier(s) for the annotated resource. This is considered the
|
52
|
+
# target of the annotation, that is the resource (or resources) the
|
53
|
+
# annotation content is "somewhat about".
|
40
54
|
#
|
41
|
-
# The
|
42
|
-
# of the annotation, that is the resource the annotation content is
|
43
|
-
# "somewhat about".
|
55
|
+
# The target can either be a singleton or a list of targets.
|
44
56
|
def target
|
45
|
-
@structure[:about]
|
57
|
+
about = @structure[:about]
|
58
|
+
about.length == 1 ? about[0] : about.dup
|
59
|
+
end
|
60
|
+
|
61
|
+
# :call-seq:
|
62
|
+
# add_target(new_target, ...) -> added target(s)
|
63
|
+
#
|
64
|
+
# Add a new target, or targets, to this annotation.
|
65
|
+
#
|
66
|
+
# The target(s) added are returned.
|
67
|
+
def add_target(add)
|
68
|
+
@structure[:about] += [*add]
|
69
|
+
|
70
|
+
@edited = true
|
71
|
+
add
|
72
|
+
end
|
73
|
+
|
74
|
+
# :call-seq:
|
75
|
+
# remove_target(target) -> target or nil
|
76
|
+
#
|
77
|
+
# Remove a target from this annotation. An annotation must always have a
|
78
|
+
# target so this method will do nothing if it already has only one target.
|
79
|
+
#
|
80
|
+
# If the target can be removed then it is returned, otherwise nil is
|
81
|
+
# returned.
|
82
|
+
def remove_target(remove)
|
83
|
+
return if @structure[:about].length == 1
|
84
|
+
|
85
|
+
@edited = true
|
86
|
+
@structure[:about].delete(remove)
|
46
87
|
end
|
47
88
|
|
48
89
|
# :call-seq:
|
@@ -58,15 +99,16 @@ module ROBundle
|
|
58
99
|
#
|
59
100
|
# Set the content of this annotation.
|
60
101
|
def content=(new_content)
|
102
|
+
@edited = true
|
61
103
|
@structure[:content] = new_content
|
62
104
|
end
|
63
105
|
|
64
106
|
# :call-seq:
|
65
|
-
#
|
107
|
+
# uri -> String in the form of a urn:uuid URI.
|
66
108
|
#
|
67
109
|
# Return the annotation id of this Annotation.
|
68
|
-
def
|
69
|
-
@structure[:
|
110
|
+
def uri
|
111
|
+
@structure[:uri]
|
70
112
|
end
|
71
113
|
|
72
114
|
# :call-seq:
|
@@ -75,13 +117,9 @@ module ROBundle
|
|
75
117
|
# Write this Annotation out as a json string. Takes the same options as
|
76
118
|
# JSON#generate.
|
77
119
|
def to_json(*a)
|
78
|
-
Util.clean_json(@structure)
|
79
|
-
|
80
|
-
|
81
|
-
private
|
82
|
-
|
83
|
-
def structure
|
84
|
-
@structure
|
120
|
+
cleaned = Util.clean_json(@structure)
|
121
|
+
cleaned[:about] = target
|
122
|
+
JSON.generate(cleaned,*a)
|
85
123
|
end
|
86
124
|
|
87
125
|
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
#------------------------------------------------------------------------------
|
2
|
+
# Copyright (c) 2014 The University of Manchester, UK.
|
3
|
+
#
|
4
|
+
# BSD Licenced. See LICENCE.rdoc for details.
|
5
|
+
#
|
6
|
+
# Author: Robert Haines
|
7
|
+
#------------------------------------------------------------------------------
|
8
|
+
|
9
|
+
#
|
10
|
+
module ROBundle
|
11
|
+
|
12
|
+
# This is the bass class of things which can appear in the manifest:
|
13
|
+
# * Aggregate
|
14
|
+
# * Annotation
|
15
|
+
# * Proxy
|
16
|
+
class ManifestEntry
|
17
|
+
include Provenance
|
18
|
+
|
19
|
+
# :call-seq:
|
20
|
+
# new
|
21
|
+
#
|
22
|
+
# Create a new ManifestEntry with an empty structure and the +edited+ flag
|
23
|
+
# set to false.
|
24
|
+
def initialize
|
25
|
+
@structure = {}
|
26
|
+
@edited = false
|
27
|
+
end
|
28
|
+
|
29
|
+
# :call-seq:
|
30
|
+
# edited? -> true or false
|
31
|
+
#
|
32
|
+
# Has this ManifestEntry been edited?
|
33
|
+
def edited?
|
34
|
+
@edited
|
35
|
+
end
|
36
|
+
|
37
|
+
# :stopdoc:
|
38
|
+
# For internal use only!
|
39
|
+
def stored
|
40
|
+
@edited = false
|
41
|
+
end
|
42
|
+
# :startdoc:
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def structure
|
47
|
+
@structure
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
@@ -24,9 +24,19 @@ module ROBundle
|
|
24
24
|
def initialize
|
25
25
|
super(FILE_NAME, :required => true)
|
26
26
|
|
27
|
+
@structure = nil
|
28
|
+
@initialized = false
|
27
29
|
@edited = false
|
28
30
|
end
|
29
31
|
|
32
|
+
# :call-seq:
|
33
|
+
# initialized? -> true or false
|
34
|
+
#
|
35
|
+
# Has this manifest been initialized?
|
36
|
+
def initialized?
|
37
|
+
@initialized
|
38
|
+
end
|
39
|
+
|
30
40
|
# :call-seq:
|
31
41
|
# context -> List of context URIs
|
32
42
|
#
|
@@ -93,7 +103,7 @@ module ROBundle
|
|
93
103
|
#
|
94
104
|
# Return a list of all the aggregated resources in this Research Object.
|
95
105
|
def aggregates
|
96
|
-
structure[:aggregates]
|
106
|
+
structure[:aggregates]
|
97
107
|
end
|
98
108
|
|
99
109
|
# :call-seq:
|
@@ -134,12 +144,9 @@ module ROBundle
|
|
134
144
|
|
135
145
|
if object.is_a?(Aggregate)
|
136
146
|
removed = structure[:aggregates].delete(object)
|
137
|
-
|
138
|
-
unless removed.nil?
|
139
|
-
removed = removed.file.nil? ? removed.uri : removed.file
|
140
|
-
end
|
147
|
+
removed = removed.uri unless removed.nil?
|
141
148
|
else
|
142
|
-
removed =
|
149
|
+
removed = remove_aggregate_by_uri(object)
|
143
150
|
end
|
144
151
|
|
145
152
|
unless removed.nil?
|
@@ -165,7 +172,7 @@ module ROBundle
|
|
165
172
|
# If the supplied Annotation object is already registered then it is
|
166
173
|
# the annotation itself we are annotating!
|
167
174
|
if container.annotation?(object)
|
168
|
-
object = Annotation.new(object.
|
175
|
+
object = Annotation.new(object.uri, content)
|
169
176
|
end
|
170
177
|
else
|
171
178
|
object = Annotation.new(object, content)
|
@@ -200,7 +207,7 @@ module ROBundle
|
|
200
207
|
end
|
201
208
|
|
202
209
|
removed.each do |ann|
|
203
|
-
id = ann.
|
210
|
+
id = ann.uri
|
204
211
|
remove_annotation(id) unless id.nil?
|
205
212
|
end
|
206
213
|
|
@@ -212,7 +219,7 @@ module ROBundle
|
|
212
219
|
#
|
213
220
|
# Return a list of all the annotations in this Research Object.
|
214
221
|
def annotations
|
215
|
-
structure[:annotations]
|
222
|
+
structure[:annotations]
|
216
223
|
end
|
217
224
|
|
218
225
|
# :call-seq:
|
@@ -220,7 +227,11 @@ module ROBundle
|
|
220
227
|
#
|
221
228
|
# Has this manifest been altered in any way?
|
222
229
|
def edited?
|
223
|
-
@
|
230
|
+
if @structure.nil?
|
231
|
+
@edited
|
232
|
+
else
|
233
|
+
@edited || edited(aggregates) || edited(annotations)
|
234
|
+
end
|
224
235
|
end
|
225
236
|
|
226
237
|
# :call-seq:
|
@@ -229,8 +240,39 @@ module ROBundle
|
|
229
240
|
# Write this Manifest out as a json string. Takes the same options as
|
230
241
|
# JSON#generate.
|
231
242
|
def to_json(*a)
|
232
|
-
Util.clean_json(structure)
|
243
|
+
JSON.generate(Util.clean_json(structure),*a)
|
244
|
+
end
|
245
|
+
|
246
|
+
# :call-seq:
|
247
|
+
# write
|
248
|
+
#
|
249
|
+
# Write this manifest into the RO Bundle, overwriting the old version.
|
250
|
+
def write
|
251
|
+
container.file.open(full_name, "w") do |m|
|
252
|
+
m.puts JSON.pretty_generate(self)
|
253
|
+
end
|
254
|
+
|
255
|
+
stored
|
256
|
+
end
|
257
|
+
|
258
|
+
# :stopdoc:
|
259
|
+
# For internal use only!
|
260
|
+
def init(struct = {})
|
261
|
+
init_default_context(struct)
|
262
|
+
init_default_id(struct)
|
263
|
+
init_provenance_defaults(struct)
|
264
|
+
struct[:history] = [*struct.fetch(:history, [])]
|
265
|
+
struct[:aggregates] = [*struct.fetch(:aggregates, [])].map do |agg|
|
266
|
+
Aggregate.new(agg)
|
267
|
+
end
|
268
|
+
struct[:annotations] = [*struct.fetch(:annotations, [])].map do |ann|
|
269
|
+
Annotation.new(ann)
|
270
|
+
end
|
271
|
+
|
272
|
+
@initialized = true
|
273
|
+
@structure = struct
|
233
274
|
end
|
275
|
+
# :startdoc:
|
234
276
|
|
235
277
|
protected
|
236
278
|
|
@@ -250,12 +292,17 @@ module ROBundle
|
|
250
292
|
|
251
293
|
private
|
252
294
|
|
295
|
+
def stored
|
296
|
+
@edited = false
|
297
|
+
(aggregates + annotations).each { |a| a.stored }
|
298
|
+
end
|
299
|
+
|
253
300
|
# The internal structure of this class cannot be setup at construction
|
254
301
|
# time in the initializer as there is no route to its data on disk at that
|
255
302
|
# point. Once loaded, parts of the structure are converted to local
|
256
303
|
# objects where appropriate.
|
257
304
|
def structure
|
258
|
-
return @structure if
|
305
|
+
return @structure if initialized?
|
259
306
|
|
260
307
|
begin
|
261
308
|
struct ||= JSON.parse(contents, :symbolize_names => true)
|
@@ -263,22 +310,7 @@ module ROBundle
|
|
263
310
|
struct = {}
|
264
311
|
end
|
265
312
|
|
266
|
-
|
267
|
-
end
|
268
|
-
|
269
|
-
def init_defaults(struct)
|
270
|
-
init_default_context(struct)
|
271
|
-
init_default_id(struct)
|
272
|
-
init_provenance_defaults(struct)
|
273
|
-
struct[:history] = [*struct.fetch(:history, [])]
|
274
|
-
struct[:aggregates] = [*struct.fetch(:aggregates, [])].map do |agg|
|
275
|
-
Aggregate.new(agg)
|
276
|
-
end
|
277
|
-
struct[:annotations] = [*struct.fetch(:annotations, [])].map do |ann|
|
278
|
-
Annotation.new(ann)
|
279
|
-
end
|
280
|
-
|
281
|
-
struct
|
313
|
+
init(struct)
|
282
314
|
end
|
283
315
|
|
284
316
|
def init_default_context(struct)
|
@@ -303,14 +335,10 @@ module ROBundle
|
|
303
335
|
struct
|
304
336
|
end
|
305
337
|
|
306
|
-
def
|
307
|
-
aggregates.each do |agg|
|
308
|
-
if
|
309
|
-
return structure[:aggregates].delete(agg).uri
|
310
|
-
else
|
311
|
-
if object == agg.file || object == agg.file_entry
|
312
|
-
return structure[:aggregates].delete(agg).file
|
313
|
-
end
|
338
|
+
def remove_aggregate_by_uri(object)
|
339
|
+
structure[:aggregates].each do |agg|
|
340
|
+
if object == agg.uri || object == agg.file_entry
|
341
|
+
return structure[:aggregates].delete(agg).uri
|
314
342
|
end
|
315
343
|
end
|
316
344
|
|
@@ -321,8 +349,10 @@ module ROBundle
|
|
321
349
|
def remove_annotation_by_field(object)
|
322
350
|
removed = []
|
323
351
|
|
324
|
-
|
325
|
-
|
352
|
+
# Need to dup the list here so we don't break it when deleting things.
|
353
|
+
# We can't use delete_if because we want to know what we've deleted!
|
354
|
+
structure[:annotations].dup.each do |ann|
|
355
|
+
if ann.uri == object ||
|
326
356
|
ann.target == object ||
|
327
357
|
ann.content == object
|
328
358
|
|
@@ -333,6 +363,14 @@ module ROBundle
|
|
333
363
|
removed
|
334
364
|
end
|
335
365
|
|
366
|
+
def edited(resource)
|
367
|
+
resource.each do |res|
|
368
|
+
return true if res.edited?
|
369
|
+
end
|
370
|
+
|
371
|
+
false
|
372
|
+
end
|
373
|
+
|
336
374
|
end
|
337
375
|
|
338
376
|
end
|
@@ -10,8 +10,7 @@
|
|
10
10
|
module ROBundle
|
11
11
|
|
12
12
|
# This module is a mixin for Research Object
|
13
|
-
# {provenance}[
|
14
|
-
# information.
|
13
|
+
# {provenance}[https://w3id.org/bundle/#provenance] information.
|
15
14
|
#
|
16
15
|
# To use this module simply provide an (optionally private) method named
|
17
16
|
# 'structure' which returns the internal fields of the object as a Hash.
|
@@ -21,16 +20,19 @@ module ROBundle
|
|
21
20
|
# * <tt>:authoredOn</tt>
|
22
21
|
# * <tt>:createdBy</tt>
|
23
22
|
# * <tt>:createdOn</tt>
|
23
|
+
# * <tt>:retrievedBy</tt>
|
24
|
+
# * <tt>:retrievedFrom</tt>
|
25
|
+
# * <tt>:retrievedOn</tt>
|
24
26
|
module Provenance
|
25
27
|
|
26
28
|
# :call-seq:
|
27
29
|
# add_author(author) -> Agent
|
28
30
|
#
|
29
|
-
# Add an author to the list of authors for this
|
31
|
+
# Add an author to the list of authors for this resource. The
|
30
32
|
# supplied parameter can either be an Agent or the name of an author as a
|
31
33
|
# String.
|
32
34
|
#
|
33
|
-
# The Agent object
|
35
|
+
# The Agent object that is added is returned.
|
34
36
|
def add_author(author)
|
35
37
|
unless author.is_a?(Agent)
|
36
38
|
author = Agent.new(author.to_s)
|
@@ -44,7 +46,7 @@ module ROBundle
|
|
44
46
|
# :call-seq:
|
45
47
|
# authored_by -> Agents
|
46
48
|
#
|
47
|
-
# Return the list of Agents that authored this
|
49
|
+
# Return the list of Agents that authored this resource.
|
48
50
|
def authored_by
|
49
51
|
structure.fetch(:authoredBy, []).dup
|
50
52
|
end
|
@@ -52,7 +54,7 @@ module ROBundle
|
|
52
54
|
# :call-seq:
|
53
55
|
# authored_on -> Time
|
54
56
|
#
|
55
|
-
# Return the time that this
|
57
|
+
# Return the time that this resource was edited as a Time object, or
|
56
58
|
# +nil+ if not present in the manifest.
|
57
59
|
def authored_on
|
58
60
|
Util.parse_time(structure[:authoredOn])
|
@@ -61,7 +63,7 @@ module ROBundle
|
|
61
63
|
# :call-seq:
|
62
64
|
# authored_on = new_time
|
63
65
|
#
|
64
|
-
# Set a new authoredOn time for this
|
66
|
+
# Set a new authoredOn time for this resource. Anything that Ruby can
|
65
67
|
# interpret as a time is accepted and converted to ISO8601 format on
|
66
68
|
# serialization.
|
67
69
|
def authored_on=(new_time)
|
@@ -72,7 +74,7 @@ module ROBundle
|
|
72
74
|
# :call-seq:
|
73
75
|
# created_by -> Agent
|
74
76
|
#
|
75
|
-
# Return the Agent that created this
|
77
|
+
# Return the Agent that created this resource.
|
76
78
|
def created_by
|
77
79
|
structure[:createdBy]
|
78
80
|
end
|
@@ -80,7 +82,7 @@ module ROBundle
|
|
80
82
|
# :call-seq:
|
81
83
|
# created_by = new_creator
|
82
84
|
#
|
83
|
-
# Set the Agent that has created this
|
85
|
+
# Set the Agent that has created this resource. Anything passed to this
|
84
86
|
# method that is not an Agent will be converted to an Agent before setting
|
85
87
|
# the value.
|
86
88
|
def created_by=(new_creator)
|
@@ -95,7 +97,7 @@ module ROBundle
|
|
95
97
|
# :call-seq:
|
96
98
|
# created_on -> Time
|
97
99
|
#
|
98
|
-
# Return the time that this
|
100
|
+
# Return the time that this resource was created as a Time object, or
|
99
101
|
# +nil+ if not present in the manifest.
|
100
102
|
def created_on
|
101
103
|
Util.parse_time(structure[:createdOn])
|
@@ -104,7 +106,7 @@ module ROBundle
|
|
104
106
|
# :call-seq:
|
105
107
|
# created_on = new_time
|
106
108
|
#
|
107
|
-
# Set a new createdOn time for this
|
109
|
+
# Set a new createdOn time for this resource. Anything that Ruby can
|
108
110
|
# interpret as a time is accepted and converted to ISO8601 format on
|
109
111
|
# serialization.
|
110
112
|
def created_on=(new_time)
|
@@ -128,6 +130,69 @@ module ROBundle
|
|
128
130
|
end
|
129
131
|
end
|
130
132
|
|
133
|
+
# :call-seq:
|
134
|
+
# retrieved_by -> Agent
|
135
|
+
#
|
136
|
+
# Return the Agent that retrieved this resource.
|
137
|
+
def retrieved_by
|
138
|
+
structure[:retrievedBy]
|
139
|
+
end
|
140
|
+
|
141
|
+
# :call-seq:
|
142
|
+
# retrieved_by = new_retrievor
|
143
|
+
#
|
144
|
+
# Set the Agent that has retrieved this resource. Anything passed to this
|
145
|
+
# method that is not an Agent will be converted to an Agent before setting
|
146
|
+
# the value.
|
147
|
+
def retrieved_by=(new_retrievor)
|
148
|
+
unless new_retrievor.instance_of?(Agent)
|
149
|
+
new_retrievor = Agent.new(new_retrievor.to_s)
|
150
|
+
end
|
151
|
+
|
152
|
+
@edited = true
|
153
|
+
structure[:retrievedBy] = new_retrievor
|
154
|
+
end
|
155
|
+
|
156
|
+
# :call-seq:
|
157
|
+
# retrieved_from -> String URI
|
158
|
+
#
|
159
|
+
# Return the URI from which this resource was retrieved.
|
160
|
+
def retrieved_from
|
161
|
+
structure[:retrievedFrom]
|
162
|
+
end
|
163
|
+
|
164
|
+
# :call-seq:
|
165
|
+
# retrieved_from = uri
|
166
|
+
#
|
167
|
+
# Set the URI from which this resource was retrieved. If a URI object is
|
168
|
+
# given it is converted to a String first.
|
169
|
+
def retrieved_from=(uri)
|
170
|
+
return unless Util.is_absolute_uri?(uri)
|
171
|
+
|
172
|
+
@edited = true
|
173
|
+
structure[:retrievedFrom] = uri.to_s
|
174
|
+
end
|
175
|
+
|
176
|
+
# :call-seq:
|
177
|
+
# retrieved_on -> Time
|
178
|
+
#
|
179
|
+
# Return the time that this resource was retrieved as a Time object, or
|
180
|
+
# +nil+ if not present in the manifest.
|
181
|
+
def retrieved_on
|
182
|
+
Util.parse_time(structure[:retrievedOn])
|
183
|
+
end
|
184
|
+
|
185
|
+
# :call-seq:
|
186
|
+
# retrieved_on = new_time
|
187
|
+
#
|
188
|
+
# Set a new retrievedOn time for this resource. Anything that Ruby can
|
189
|
+
# interpret as a time is accepted and converted to ISO8601 format on
|
190
|
+
# serialization.
|
191
|
+
def retrieved_on=(new_time)
|
192
|
+
@edited = true
|
193
|
+
set_time(:retrievedOn, new_time)
|
194
|
+
end
|
195
|
+
|
131
196
|
private
|
132
197
|
|
133
198
|
def init_provenance_defaults(struct)
|
@@ -136,6 +201,8 @@ module ROBundle
|
|
136
201
|
struct[:authoredBy] = [*struct.fetch(:authoredBy, [])].map do |agent|
|
137
202
|
Agent.new(agent)
|
138
203
|
end
|
204
|
+
retrievor = struct[:retrievedBy]
|
205
|
+
struct[:retrievedBy] = Agent.new(retrievor) unless retrievor.nil?
|
139
206
|
|
140
207
|
struct
|
141
208
|
end
|