Class: ROCrate::Entity

Inherits:
Object
  • Object
show all
Defined in:
lib/ro_crate/model/entity.rb

Overview

A generic “Entity” within an RO-Crate. It has an identifier and a set of properties, and will be referenced in the RO-Crate Metadata’s @graph.

Direct Known Subclasses

ContextualEntity, DataEntity

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(crate, id = nil, properties = {}) ⇒ Entity

Create a new Entity.

Parameters:

  • crate (Crate)

    The crate that owns this Entity.

  • id (String, nil) (defaults to: nil)

    An ID to identify this Entity, 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 entity.



117
118
119
120
121
# File 'lib/ro_crate/model/entity.rb', line 117

def initialize(crate, id = nil, properties = {})
  @crate = crate
  @properties = ROCrate::JSONLDHash.new(crate, default_properties.merge(properties))
  self.id = id if id
end

Instance Attribute Details

#crateObject (readonly)

Returns the value of attribute crate.



6
7
8
# File 'lib/ro_crate/model/entity.rb', line 6

def crate
  @crate
end

#propertiesObject

Returns the value of attribute properties.



7
8
9
# File 'lib/ro_crate/model/entity.rb', line 7

def properties
  @properties
end

Class Method Details

.format_id(id) ⇒ String

Format the given ID with rules appropriate for this type if it is local/relative, leave as-is if absolute.

Parameters:

  • id (String)

    The candidate ID to be formatted.

Returns:

  • (String)

    The formatted ID.



36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/ro_crate/model/entity.rb', line 36

def self.format_id(id)
  begin
    uri = URI(id)
  rescue ArgumentError, URI::InvalidURIError
    uri = nil
  end

  if uri&.absolute?
    id
  else
    format_local_id(id)
  end
end

.format_local_id(id) ⇒ String

Format the given local ID with rules appropriate for this type. For example:

* contextual entities MUST be absolute URIs, or begin with: #
* files MUST NOT begin with ./
* directories MUST NOT begin with ./ (except for the crate itself), and MUST end with /

Parameters:

  • id (String)

    The candidate local ID to be formatted.

Returns:

  • (String)

    The formatted local ID.



59
60
61
62
63
64
65
66
# File 'lib/ro_crate/model/entity.rb', line 59

def self.format_local_id(id)
  if id.start_with?('#')
    '#' + Addressable::URI.encode_component(id[1..-1], Addressable::URI::CharacterClasses::QUERY)
  else
    # Remove initial ./ if present
    Addressable::URI.encode_component(id.sub(/\A\.\//, ''), Addressable::URI::CharacterClasses::PATH)
  end
end

.properties(props) ⇒ Object

Define Ruby-style getters/setters for the given list of properties. The getters/setters will have underscored names, and will automatically reference/dereference entities within the crate using their ‘@id`.



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/ro_crate/model/entity.rb', line 13

def self.properties(props)
  props.each do |prop|
    # Convert camelCase to under_score
    underscored = prop.gsub(/([[:upper:]]*)([[:upper:]])([[:lower:]])/) do
      m = Regexp.last_match
      "#{m[1].downcase}_#{m[2].downcase}#{m[3]}"
    end

    define_method(underscored) do
      auto_dereference(@properties[prop])
    end

    define_method("#{underscored}=") do |value|
      @properties[prop] = auto_reference(value)
    end
  end
end

Instance Method Details

#==(other) ⇒ Object



182
183
184
185
# File 'lib/ro_crate/model/entity.rb', line 182

def ==(other)
  return super unless other.is_a?(Entity)
  canonical_id == other.canonical_id
end

#[](key) ⇒ Object



223
224
225
# File 'lib/ro_crate/model/entity.rb', line 223

def [](key)
  @properties[key]
end

#[]=(key, value) ⇒ Object



227
228
229
# File 'lib/ro_crate/model/entity.rb', line 227

def []=(key, value)
  @properties[key] = value
end

#auto_dereference(value) ⇒ Entity, ...

Automatically replace references to entities (e.g. ‘{ ’@id’ : ‘#something’ }‘) with the Entity object itself.

Parameters:

  • value (Hash, Array<Hash>, Object)

    A value that may be reference or array of references.

Returns:

  • (Entity, Array<Entity>, Object)

    Return an Entity, Array of Entities, or just the object itself if it wasn’t a reference after all.



74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/ro_crate/model/entity.rb', line 74

def auto_dereference(value)
  if value.is_a?(Array)
    return value.map { |v| auto_dereference(v) }
  end

  if value.is_a?(Hash) && value['@id']
    obj = dereference(value['@id'])
    return obj if obj
  end

  value
end

#auto_reference(value) ⇒ Hash, ...

Automatically replace an Entity or Array of Entities with a reference or Array of references. Also associates the Entity/Entities with the current crate. This is useful for maintaining the flat @graph of entities that the RO-Crate metadata file requires.

Parameters:

  • value (Entity, Array<Entity>, Object)

    A value that may be reference or array of references.

Returns:

  • (Hash, Array<Hash>, Object)

    Return a reference, Array of references, or just the object itself if it wasn’t an Entity after all.



95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/ro_crate/model/entity.rb', line 95

def auto_reference(value)
  if value.is_a?(Array)
    return value.map { |v| auto_reference(v) }
  end

  if value.is_a?(Entity)
    # If it's from another crate, need to add it to this one.
    crate.add_contextual_entity(value)

    return value.reference
  end

  value
end

#canonical_idAddressable::URI

The “canonical”, global ID of this entity relative to the canonical ID of the crate.

In the case that the crate does not have an absolute URI as its ID, it will appear something like this:

arcp://uuid,b3d6fa2b-4e49-43ba-bd89-464e948b7f0c/foo - where `foo` is the local ID of this entity.

If the crate does have an absolute URI, it will appear relative to that e.g.:

http://mycoolcrate.info/foo - where `foo` is the local ID of this entity.

If the entity itself has an absolute URI, that will be used e.g.:

http://website.com/foo.txt - where `http://website.com/foo.txt ` is the local ID of this entity.

This is used, for example, to compare equality of two entities.

Returns:

  • (Addressable::URI)


207
208
209
# File 'lib/ro_crate/model/entity.rb', line 207

def canonical_id
  @canonical_id ||= crate.resolve_id(id)
end

#delete(remove_orphaned: true) ⇒ Entity?

Remove this entity from the RO-Crate.

Parameters:

  • remove_orphaned (Boolean) (defaults to: true)

    Should linked contextual entities also be removed from the crate (if nothing else is linked to them)?

Returns:

  • (Entity, nil)

    This entity, or nil if nothing was deleted.



147
148
149
# File 'lib/ro_crate/model/entity.rb', line 147

def delete(remove_orphaned: true)
  crate.delete(self, remove_orphaned: remove_orphaned)
end

#dereference(id) ⇒ Entity? Also known as: get

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

Parameters:

  • id (String)

    The ID to query.

Returns:



136
137
138
# File 'lib/ro_crate/model/entity.rb', line 136

def dereference(id)
  crate.dereference(id)
end

#eql?(other) ⇒ Boolean

Returns:

  • (Boolean)


187
188
189
190
# File 'lib/ro_crate/model/entity.rb', line 187

def eql?(other)
  return super unless other.is_a?(Entity)
  canonical_id == other.canonical_id
end

#external?Boolean

Is this entity local to the crate or an external reference?

Returns:

  • (Boolean)


215
216
217
# File 'lib/ro_crate/model/entity.rb', line 215

def external?
  crate.canonical_id.host != canonical_id.host
end

#has_type?(type) ⇒ Boolean

A safe way of checking if the Entity has the given type, regardless of whether the Entity has a single, or Array of types. Does not check superclasses etc.

Parameters:

  • type (String)

    The type to check, e.g. “File”.

Returns:

  • (Boolean)


240
241
242
# File 'lib/ro_crate/model/entity.rb', line 240

def has_type?(type)
  @properties.has_type?(type)
end

#hashObject



178
179
180
# File 'lib/ro_crate/model/entity.rb', line 178

def hash
  canonical_id.hash
end

#idObject



151
152
153
# File 'lib/ro_crate/model/entity.rb', line 151

def id
  @properties['@id']
end

#id=(id) ⇒ Object



155
156
157
158
# File 'lib/ro_crate/model/entity.rb', line 155

def id=(id)
  @canonical_id = nil
  @properties['@id'] = self.class.format_id(id)
end

#inspectObject



172
173
174
175
176
# File 'lib/ro_crate/model/entity.rb', line 172

def inspect
  prop_string = properties.inspect
  prop_string = prop_string[0...509] + '...' if prop_string.length > 509
  "<##{self.class.name} #{canonical_id} @properties=#{prop_string}>"
end

#linked_entities(deep: false, linked: {}) ⇒ Array<Entity>

Gather a list of entities linked to this one through its properties.

Parameters:

  • deep (Boolean) (defaults to: false)

    If false, only consider direct links, otherwise consider transitive links.

  • linked (Hash{String => Entity}) (defaults to: {})

    Discovered entities, mapped by their ID, to avoid loops when recursing.

Returns:



249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
# File 'lib/ro_crate/model/entity.rb', line 249

def linked_entities(deep: false, linked: {})
  properties.each_key do |key|
    value = properties[key] # We're doing this to call the JSONLDHash#[] method which wraps
    value = [value] if value.is_a?(JSONLDHash)

    if value.respond_to?(:each)
      value.each do |v|
        if v.is_a?(JSONLDHash) && !linked.key?(v['@id'])
          entity = v.dereference
          next unless entity
          linked[entity.id] = entity
          if deep
            entity.linked_entities(deep: true, linked: linked).each do |e|
              linked[e.id] = e
            end
          end
        end
      end
    end
  end

  linked.values.compact
end

#raw_propertiesObject



219
220
221
# File 'lib/ro_crate/model/entity.rb', line 219

def raw_properties
  @properties
end

#referenceHash

Return a JSON-LD style reference: { ‘@id’ : ‘#an-entity’ } for this Entity.

Returns:

  • (Hash)


127
128
129
# File 'lib/ro_crate/model/entity.rb', line 127

def reference
  ROCrate::JSONLDHash.new(crate, '@id' => id)
end

#to_jsonObject



231
232
233
# File 'lib/ro_crate/model/entity.rb', line 231

def to_json
  @properties.to_json
end

#typeObject



160
161
162
# File 'lib/ro_crate/model/entity.rb', line 160

def type
  @properties['@type']
end

#type=(type) ⇒ Object



164
165
166
# File 'lib/ro_crate/model/entity.rb', line 164

def type=(type)
  @properties['@type'] = type
end