Class: ROCrate::Crate

Inherits:
Directory show all
Defined in:
lib/ro_crate/model/crate.rb

Overview

A Ruby abstraction of an RO-Crate.

Constant Summary collapse

IDENTIFIER =
'./'.freeze

Instance Attribute Summary collapse

Attributes inherited from Entity

#crate

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Directory

#remote?

Methods inherited from DataEntity

#filepath, specialize

Methods inherited from Entity

#==, #[], #[]=, #auto_dereference, #auto_reference, #eql?, #external?, #has_type?, #hash, #id, #id=, #inspect, #linked_entities, properties, #raw_properties, #reference, #to_json, #type, #type=

Constructor Details

#initialize(id = IDENTIFIER, properties = {}, version: ROCrate::Metadata::DEFAULT_VERSION) ⇒ Crate

Initialize an empty RO-Crate.

Parameters:

  • id (String) (defaults to: IDENTIFIER)

    The crate’s identifier.

  • properties (Hash) (defaults to: {})

    Initial properties for the root data entity.

  • version (String) (defaults to: ROCrate::Metadata::DEFAULT_VERSION)

    RO-Crate spec version to declare (default: ROCrate::Metadata::DEFAULT_VERSION). Must be one of ROCrate::Metadata::SUPPORTED_VERSIONS.



29
30
31
32
33
34
35
# File 'lib/ro_crate/model/crate.rb', line 29

def initialize(id = IDENTIFIER, properties = {}, version: ROCrate::Metadata::DEFAULT_VERSION)
  ROCrate::Metadata.warn_unrecognized_version(version)
  @data_entities = Set.new
  @contextual_entities = Set.new
  @metadata_version = version
  super(self, nil, id, properties)
end

Instance Attribute Details

#contextual_entitiesObject (readonly)

Returns the value of attribute contextual_entities.



9
10
11
# File 'lib/ro_crate/model/crate.rb', line 9

def contextual_entities
  @contextual_entities
end

#data_entitiesObject (readonly)

Returns the value of attribute data_entities.



8
9
10
# File 'lib/ro_crate/model/crate.rb', line 8

def data_entities
  @data_entities
end

Class Method Details

.format_id(id) ⇒ Object



12
13
14
15
# File 'lib/ro_crate/model/crate.rb', line 12

def self.format_id(id)
  i = super(id)
  i.end_with?('/') ? i : "#{i}/"
end

.format_local_id(id) ⇒ Object



17
18
19
20
# File 'lib/ro_crate/model/crate.rb', line 17

def self.format_local_id(id)
  return id if id == IDENTIFIER
  super
end

Instance Method Details

#add_all(source_directory, create_entities = true, include_hidden: false) ⇒ Array<DataEntity>

Recursively add the contents of the given source directory at the root of the crate. Useful for quickly RO-Crate-ifying a directory. Creates data entities for each file/directory discovered (excluding the top level directory itself) if ‘create_entities` is true.

Parameters:

  • source_directory (String, Pathname, ::File, )

    The source directory that will be included in the crate.

  • create_entities (Boolean) (defaults to: true)

    Whether to create data entities for the added content, or just include them anonymously.

  • include_hidden (Boolean) (defaults to: false)

    Whether to include hidden files, i.e. those prefixed by a ‘.` (period).

Returns:

  • (Array<DataEntity>)

    Any entities that were created from the directory contents. Will be empty if ‘create_entities` was false.



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/ro_crate/model/crate.rb', line 97

def add_all(source_directory, create_entities = true, include_hidden: false)
  added = []

  if create_entities
    list_all_files(source_directory, include_hidden: include_hidden).each do |rel_path|
      source_path = Pathname.new(::File.join(source_directory, rel_path)).expand_path
      if source_path.directory?
        added << add_directory(source_path, rel_path)
      else
        added << add_file(source_path, rel_path)
      end
    end
  else
    populate_entries(Pathname.new(::File.expand_path(source_directory)), include_hidden: include_hidden)
  end

  added
end

#add_contact_point(id, properties = {}) ⇒ ContactPoint

Create a new ROCrate::ContactPoint and add it to the crate

Parameters:

  • id (String, nil)

    An ID to identify this contact point, or blank to auto-generate an appropriate one, (or determine via the properties param)

  • properties (Hash{String => Object}) (defaults to: {})

    A hash of JSON-LD properties to associate with this contact point.

Returns:



134
135
136
# File 'lib/ro_crate/model/crate.rb', line 134

def add_contact_point(id, properties = {})
  add_contextual_entity(ROCrate::ContactPoint.new(self, id, properties))
end

#add_contextual_entity(entity) ⇒ Entity

Add a contextual entity to the crate

Parameters:

  • entity (Entity)

    the entity to add to the crate.

Returns:

  • (Entity)

    the entity itself, or a clone of the entity “owned” by this crate.



154
155
156
157
158
159
# File 'lib/ro_crate/model/crate.rb', line 154

def add_contextual_entity(entity)
  entity = claim(entity)
  contextual_entities.delete?(entity) # Remove (then re-add) the entity if it exists
  contextual_entities.add(entity)
  entity
end

#add_data_entity(entity) ⇒ Entity

Add a data entity to the crate

Parameters:

  • entity (Entity)

    the entity to add to the crate.

Returns:

  • (Entity)

    the entity itself, or a clone of the entity “owned” by this crate.



166
167
168
169
170
171
# File 'lib/ro_crate/model/crate.rb', line 166

def add_data_entity(entity)
  entity = claim(entity)
  data_entities.delete?(entity) # Remove (then re-add) the entity if it exists
  data_entities.add(entity)
  entity
end

#add_directory(source_directory, crate_path = nil, entity_class: ROCrate::Directory, **properties) ⇒ Entity

Create a new directory and add it to the crate.

Parameters:

  • source_directory (String, Pathname, ::File, #read, nil)

    The source directory that will be included in the crate.

  • crate_path (String) (defaults to: nil)

    The relative path within the RO-Crate where this directory will be written.

  • entity_class (Class) (defaults to: ROCrate::Directory)

    The class to use to instantiate the Entity, useful if you have created a subclass of ROCrate::Directory that you want to use. (defaults to ROCrate::Directory).

  • properties (Hash{String => Object})

    A hash of JSON-LD properties to associate with this directory.

Returns:



83
84
85
# File 'lib/ro_crate/model/crate.rb', line 83

def add_directory(source_directory, crate_path = nil, entity_class: ROCrate::Directory, **properties)
  entity_class.new(self, source_directory, crate_path, properties).tap { |e| add_data_entity(e) }
end

#add_external_file(source, entity_class: ROCrate::File, **properties) ⇒ Entity

Create a new file that references a remote URI and add it to the crate.

Parameters:

  • source (String, URI)

    The URI to add.

  • entity_class (Class) (defaults to: ROCrate::File)

    The class to use to instantiate the Entity, useful if you have created a subclass of ROCrate::File that you want to use. (defaults to ROCrate::File).

  • properties (Hash{String => Object})

    A hash of JSON-LD properties to associate with this file.

Returns:



69
70
71
# File 'lib/ro_crate/model/crate.rb', line 69

def add_external_file(source, entity_class: ROCrate::File, **properties)
  entity_class.new(self, source, nil, properties).tap { |e| add_data_entity(e) }
end

#add_file(source, crate_path = nil, entity_class: ROCrate::File, **properties) ⇒ Entity

Create a new file and add it to the crate.

Parameters:

  • source (String, Pathname, ::File, #read, nil)

    The source on the disk where this file will be read.

  • crate_path (String) (defaults to: nil)

    The relative path within the RO-Crate where this file will be written.

  • entity_class (Class) (defaults to: ROCrate::File)

    The class to use to instantiate the Entity, useful if you have created a subclass of ROCrate::File that you want to use. (defaults to ROCrate::File).

  • properties (Hash{String => Object})

    A hash of JSON-LD properties to associate with this file.

Returns:



56
57
58
# File 'lib/ro_crate/model/crate.rb', line 56

def add_file(source, crate_path = nil, entity_class: ROCrate::File, **properties)
  entity_class.new(self, source, crate_path, properties).tap { |e| add_data_entity(e) }
end

#add_organization(id, properties = {}) ⇒ Organization

Create a new ROCrate::Organization and add it to the crate

Parameters:

  • id (String, nil)

    An ID to identify this organization, or blank to auto-generate an appropriate one, (or determine via the properties param)

  • properties (Hash{String => Object}) (defaults to: {})

    A hash of JSON-LD properties to associate with this organization.

Returns:



145
146
147
# File 'lib/ro_crate/model/crate.rb', line 145

def add_organization(id, properties = {})
  add_contextual_entity(ROCrate::Organization.new(self, id, properties))
end

#add_person(id, properties = {}) ⇒ Person

Create a new ROCrate::Person and add it to the crate

Parameters:

  • id (String, nil)

    An ID to identify this person, or blank to auto-generate an appropriate one, (or determine via the properties param)

  • properties (Hash{String => Object}) (defaults to: {})

    A hash of JSON-LD properties to associate with this person.

Returns:



123
124
125
# File 'lib/ro_crate/model/crate.rb', line 123

def add_person(id, properties = {})
  add_contextual_entity(ROCrate::Person.new(self, id, properties))
end

#canonical_idAddressable::URI

The “canonical”, global ID of the crate. If the crate was not given an absolute URI as its ID, it will use an “Archive and Package” (ARCP) URI with the UUID of the crate, for example:

arcp://uuid,b3d6fa2b-4e49-43ba-bd89-464e948b7f0c/

Returns:

  • (Addressable::URI)


228
229
230
# File 'lib/ro_crate/model/crate.rb', line 228

def canonical_id
  @canonical_id ||= Addressable::URI.parse("arcp://uuid,#{uuid}").join(id)
end

#claim(entity) ⇒ Object

Copy the entity, but as if it was in this crate. (Or just return the entity if it was already included)



245
246
247
248
# File 'lib/ro_crate/model/crate.rb', line 245

def claim(entity)
  return entity if entity.crate == self
  entity.class.new(crate, entity.id, entity.raw_properties)
end

#default_entitiesSet<Entity>

Entities for the metadata file and crate itself, which should be present in all RO-Crates.

Returns:



210
211
212
# File 'lib/ro_crate/model/crate.rb', line 210

def default_entities
  Set.new([, preview, self])
end

#delete(entity, remove_orphaned: true) ⇒ Entity?

Remove the entity from the RO-Crate.

Parameters:

  • entity (Entity, String)

    The entity or ID of an entity to remove from the crate.

  • remove_orphaned (Boolean) (defaults to: true)

    Should linked contextual entities also be removed from the crate they are left dangling (nothing else is linked to them)?

Returns:

  • (Entity, nil)

    The entity that was deleted, or nil if nothing was deleted.



284
285
286
287
288
289
290
291
292
293
294
295
296
297
# File 'lib/ro_crate/model/crate.rb', line 284

def delete(entity, remove_orphaned: true)
  entity = dereference(entity) if entity.is_a?(String)
  return unless entity

  deleted = data_entities.delete?(entity) || contextual_entities.delete?(entity)

  if deleted && remove_orphaned
    crate_entities = crate.linked_entities(deep: true)
    to_remove = (entity.linked_entities(deep: true) - crate_entities)
    to_remove.each(&:delete)
  end

  deleted
end

#dereference(id) ⇒ Entity?

Lookup an Entity using the given ID (in this Entity’s crate).

Parameters:

  • id (String)

    The ID to query.

Returns:



42
43
44
# File 'lib/ro_crate/model/crate.rb', line 42

def dereference(id)
  entities.detect { |e| e.canonical_id == crate.resolve_id(id) } if id
end

#entitiesSet<Entity>

All the entities within the crate. Includes contextual entities, data entities, the crate itself and its metadata file.

Returns:



202
203
204
# File 'lib/ro_crate/model/crate.rb', line 202

def entities
  default_entities | data_entities | contextual_entities
end

#gc {|entity| ... } ⇒ Array<ContextualEntity>

Remove any contextual entities that are not linked from any other entity. Optionally takes a block to decide whether the given entity should be removed or not, otherwise removes all unlinked entities.

Yield Parameters:

Yield Returns:

  • (Boolean)

    remove Should this entity be removed?

Returns:



307
308
309
310
311
# File 'lib/ro_crate/model/crate.rb', line 307

def gc(&block)
  unlinked_entities = contextual_entities - .linked_entities(deep: true)

  unlinked_entities.select(&block).each { |e| e.delete(remove_orphaned: false) }
end

#get_bindingObject



272
273
274
# File 'lib/ro_crate/model/crate.rb', line 272

def get_binding
  binding
end

#metadataMetadata

The RO-Crate metadata file

Returns:



177
178
179
# File 'lib/ro_crate/model/crate.rb', line 177

def 
  @metadata ||= ROCrate::Metadata.new(self, {}, version: @metadata_version || ROCrate::Metadata::DEFAULT_VERSION)
end

#own_payloadObject



250
# File 'lib/ro_crate/model/crate.rb', line 250

alias_method :own_payload, :payload

#payloadHash{String => Entry} Also known as: entries

The file payload of the RO-Crate - a map of all the files/directories contained in the RO-Crate, where the key is the path relative to the crate’s root, and the value is an Entry where the source data can be read.

Returns:

  • (Hash{String => Entry})

    ]



256
257
258
259
260
261
262
263
264
265
266
267
268
269
# File 'lib/ro_crate/model/crate.rb', line 256

def payload
  # Gather a map of entries, starting from the crate itself, then any directory data entities, then finally any
  # file data entities. This ensures in the case of a conflict, the more "specific" data entities take priority.
  entries = own_payload
  sorted_entities = (default_entities.delete(self) | data_entities).sort_by { |e| e.is_a?(ROCrate::Directory) ? 0 : 1 }

  sorted_entities.each do |entity|
    entity.payload.each do |path, entry|
      entries[path] = entry
    end
  end

  entries
end

#previewPreview

The RO-Crate preview file

Returns:



185
186
187
# File 'lib/ro_crate/model/crate.rb', line 185

def preview
  @preview ||= ROCrate::Preview.new(self)
end

#preview=(preview) ⇒ Preview

Set the RO-Crate preview file

Parameters:

  • preview (Preview)

    the preview to set.

Returns:



194
195
196
# File 'lib/ro_crate/model/crate.rb', line 194

def preview=(preview)
  @preview = claim(preview)
end

#propertiesObject



214
215
216
# File 'lib/ro_crate/model/crate.rb', line 214

def properties
  super.merge('hasPart' => data_entities.map(&:reference))
end

#resolve_id(id) ⇒ Addressable::URI

Return an absolute URI for the given string ID, relative to the crate’s canonical ID.

Parameters:

  • id (String)

    The ID to “join” onto the crate’s base URI.

Returns:

  • (Addressable::URI)


238
239
240
# File 'lib/ro_crate/model/crate.rb', line 238

def resolve_id(id)
  canonical_id.join(id)
end

#uuidObject



218
219
220
# File 'lib/ro_crate/model/crate.rb', line 218

def uuid
  @uuid ||= SecureRandom.uuid
end