Class: ActiveTriples::Resource

Inherits:
RDF::Graph
  • Object
show all
Extended by:
ActiveModel::Callbacks, ActiveModel::Naming, ActiveModel::Translation, Configurable, Deprecation
Includes:
ActiveModel::Conversion, ActiveModel::Serialization, ActiveModel::Serializers::JSON, ActiveModel::Validations, NestedAttributes, Properties, Reflection
Defined in:
lib/active_triples/resource.rb

Overview

Defines a generic RDF ‘Resource` as an RDF::Graph with property configuration, accessors, and some other methods for managing resources as discrete subgraphs which can be maintained by a Hydra datastream model.

Resources can be instances of ActiveTriples::Resource directly, but more often they will be instances of subclasses with registered properties and configuration. e.g.

class License < Resource
  configure repository: :default
  property :title, predicate: RDF::DC.title, class_name: RDF::Literal do |index|
    index.as :displayable, :facetable
  end
end

Direct Known Subclasses

List::ListResource

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Configurable

configure, rdf_type, transform_type

Methods included from Reflection

add_reflection

Constructor Details

#initialize(*args, &block) ⇒ Resource

Initialize an instance of this resource class. Defaults to a blank node subject. In addition to RDF::Graph parameters, you can pass in a URI and/or a parent to build a resource from a existing data.

You can pass in only a parent with:

Resource.new(nil, parent)

See Also:

  • RDF::Graph


75
76
77
78
79
80
81
82
83
# File 'lib/active_triples/resource.rb', line 75

def initialize(*args, &block)
  resource_uri = args.shift unless args.first.is_a?(Hash)
  self.parent = args.shift unless args.first.is_a?(Hash)
  set_subject!(resource_uri) if resource_uri
  super(*args, &block)
  reload
  # Append type to graph if necessary.
  self.get_values(:type) << self.class.type if self.class.type.kind_of?(RDF::URI) && type.empty?
end

Instance Attribute Details

#parentObject

Returns the value of attribute parent.



35
36
37
# File 'lib/active_triples/resource.rb', line 35

def parent
  @parent
end

Class Method Details

.from_uri(uri, vals = nil) ⇒ ActiveTriples::Resource

Adapter for a consistent interface for creating a new Resource from a URI. Similar functionality should exist in all objects which can become a Resource.

Parameters:

  • uri (#to_uri, String)
  • vals (defaults to: nil)

    values to pass as arguments to ::new

Returns:



52
53
54
# File 'lib/active_triples/resource.rb', line 52

def from_uri(uri,vals=nil)
  new(uri, vals)
end

.type_registryObject



39
40
41
# File 'lib/active_triples/resource.rb', line 39

def type_registry
  @@type_registry ||= {}
end

Instance Method Details

#[](uri_or_term_property) ⇒ Object

Returns an array of values belonging to the property requested. Elements in the array may RdfResource objects or a valid datatype.



318
319
320
# File 'lib/active_triples/resource.rb', line 318

def [](uri_or_term_property)
  get_term([uri_or_term_property])
end

#[]=(uri_or_term_property, value) ⇒ Object

Note:

This method will delete existing statements with the correct subject and predicate from the graph

Adds or updates a property with supplied values.



295
296
297
# File 'lib/active_triples/resource.rb', line 295

def []=(uri_or_term_property, value)
  self[uri_or_term_property].set(value)
end

#attributesObject



106
107
108
109
110
111
112
# File 'lib/active_triples/resource.rb', line 106

def attributes
  attrs = {}
  attrs['id'] = id if id
  fields.map { |f| attrs[f.to_s] = get_values(f) }
  unregistered_predicates.map { |uri| attrs[uri.to_s] = get_values(uri) }
  attrs
end

#attributes=(values) ⇒ Object

Raises:

  • (ArgumentError)


125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/active_triples/resource.rb', line 125

def attributes=(values)
  raise ArgumentError, "values must be a Hash, you provided #{values.class}" unless values.kind_of? Hash
  values = values.with_indifferent_access
  id = values.delete(:id)
  set_subject!(id) if id && node?
  values.each do |key, value|
    if reflections.reflect_on_property(key)
      set_value(rdf_subject, key, value)
    elsif nested_attributes_options.keys.map { |k| "#{k}_attributes" }.include?(key)
      send("#{key}=".to_sym, value)
    else
      raise ArgumentError, "No association found for name `#{key}'. Has it been defined yet?"
    end
  end
end

#base_uriString?

Returns the base URI the resource will use when setting its subject. ‘nil` if none is used.

Returns:

  • (String, nil)

    the base URI the resource will use when setting its subject. ‘nil` if none is used.



181
182
183
# File 'lib/active_triples/resource.rb', line 181

def base_uri
  self.class.base_uri
end

#destroyObject Also known as: destroy!



361
362
363
364
365
366
# File 'lib/active_triples/resource.rb', line 361

def destroy
  clear
  persist! if repository
  parent.destroy_child(self) if parent
  @destroyed = true
end

#destroy_child(child) ⇒ Object



377
378
379
380
381
# File 'lib/active_triples/resource.rb', line 377

def destroy_child(child)
  statements.each do |statement|
    delete_statement(statement) if statement.subject == child.rdf_subject || statement.object == child.rdf_subject
  end
end

#destroyed?true, false

Indicates if the Resource has been destroyed.

Returns:

  • (true, false)


373
374
375
# File 'lib/active_triples/resource.rb', line 373

def destroyed?
  @destroyed ||= false
end

#dump(*args) ⇒ String

Returns a serialized string representation of self. Extends the base implementation builds a JSON-LD context if the specified format is :jsonld and a context is provided by #jsonld_context

Parameters:

  • args (Array<Object>)

Returns:

  • (String)

See Also:

  • RDF::Enumerable#dump


151
152
153
154
155
156
157
# File 'lib/active_triples/resource.rb', line 151

def dump(*args)
  if args.first == :jsonld and respond_to?(:jsonld_context)
    args << {} unless args.last.is_a?(Hash)
    args.last[:context] ||= jsonld_context
  end
  super
end

#fetchActiveTriples::Resource

Load data from the #rdf_subject URI. Retrieved data will be parsed into the Resource’s graph from available RDF::Readers and available from property accessors if if predicates are registered.

osu = ActiveTriples::Resource.new('http://dbpedia.org/resource/Oregon_State_University')
osu.fetch
osu.rdf_label.first
# => "Oregon State University"

Returns:



227
228
229
230
# File 'lib/active_triples/resource.rb', line 227

def fetch
  load(rdf_subject)
  self
end

#fieldsArray<Symbol>

Lists fields registered as properties on the object.

Returns:

  • (Array<Symbol>)

    the list of registered properties.



211
212
213
# File 'lib/active_triples/resource.rb', line 211

def fields
  properties.keys.map(&:to_sym).reject{|x| x == :type}
end

#final_parentObject



96
97
98
99
100
101
102
103
104
# File 'lib/active_triples/resource.rb', line 96

def final_parent
  @final_parent ||= begin
    parent = self.parent
    while parent && parent.parent && parent.parent != parent
      parent = parent.parent
    end
    parent
  end
end

#get_term(args) ⇒ Object



323
324
325
326
327
328
# File 'lib/active_triples/resource.rb', line 323

def get_term(args)
  @term_cache ||= {}
  term = Term.new(self, args)
  @term_cache["#{term.send(:rdf_subject)}/#{term.property}/#{term.term_args}"] ||= term
  @term_cache["#{term.send(:rdf_subject)}/#{term.property}/#{term.term_args}"]
end

#get_values(*args) ⇒ Object

Returns an array of values belonging to the property requested. Elements in the array may RdfResource objects or a valid datatype.

Handles two argument patterns. The recommended pattern is:

get_values(property)

For backwards compatibility, there is support for explicitly passing the rdf_subject to be used in th statement:

get_values(uri, property)


310
311
312
# File 'lib/active_triples/resource.rb', line 310

def get_values(*args)
  get_term(args)
end

#graphself

Deprecated.

redundant, simply returns self.

Returns the current object.

Returns:

  • (self)


91
92
93
94
# File 'lib/active_triples/resource.rb', line 91

def graph
  Deprecation.warn Resource, "graph is redundant & deprecated. It will be removed in ActiveTriples 0.2.0.", caller
  self
end

#idObject

A string identifier for the resource



169
170
171
# File 'lib/active_triples/resource.rb', line 169

def id
  node? ? nil : rdf_subject.to_s
end

#mark_for_destructionObject



397
398
399
# File 'lib/active_triples/resource.rb', line 397

def mark_for_destruction
  @marked_for_destruction = true
end

#marked_for_destruction?Boolean

Returns:

  • (Boolean)


401
402
403
# File 'lib/active_triples/resource.rb', line 401

def marked_for_destruction?
  @marked_for_destruction
end

#new_record?true, false

Indicates if the record is ‘new’ (has not yet been persisted).

Returns:

  • (true, false)


387
388
389
# File 'lib/active_triples/resource.rb', line 387

def new_record?
  not persisted?
end

#node?Boolean

Returns:

  • (Boolean)


173
174
175
176
# File 'lib/active_triples/resource.rb', line 173

def node?
  return true if rdf_subject.kind_of? RDF::Node
  false
end

#persist!(opts = {}) ⇒ Object



232
233
234
235
236
237
238
239
240
241
242
243
244
# File 'lib/active_triples/resource.rb', line 232

def persist!(opts={})
  return if @persisting
  return false if opts[:validate] && !valid?
  @persisting = true
  run_callbacks :persist do
    raise "failed when trying to persist to non-existant repository or parent resource" unless repository
    erase_old_resource
    repository << self
    @persisted = true
  end
  @persisting = false
  true
end

#persisted?true, false

Indicates if the resource is persisted.

Returns:

  • (true, false)

See Also:

  • #persist


251
252
253
254
255
# File 'lib/active_triples/resource.rb', line 251

def persisted?
  @persisted ||= false
  return (@persisted and parent.persisted?) if parent
  @persisted
end

#rdf_labelObject

Looks for labels in various default fields, prioritizing configured label fields.



197
198
199
200
201
202
203
204
205
# File 'lib/active_triples/resource.rb', line 197

def rdf_label
  labels = Array(self.class.rdf_label)
  labels += default_labels
  labels.each do |label|
    values = get_values(label)
    return values unless values.empty?
  end
  node? ? [] : [rdf_subject.to_s]
end

#rdf_subjectRDF::URI, RDF::Node Also known as: to_term

Returns a URI or Node which the resource’s properties are about.

Returns:

  • (RDF::URI, RDF::Node)

    a URI or Node which the resource’s properties are about.



162
163
164
# File 'lib/active_triples/resource.rb', line 162

def rdf_subject
  @rdf_subject ||= RDF::Node.new
end

#reflectionsObject



121
122
123
# File 'lib/active_triples/resource.rb', line 121

def reflections
  self.class
end

#reloadtrue, false

Repopulates the graph from the repository or parent resource.

Returns:

  • (true, false)


261
262
263
264
265
266
267
268
269
# File 'lib/active_triples/resource.rb', line 261

def reload
  @term_cache ||= {}
  return false unless repository
  self << repository.query(subject: rdf_subject)
  unless empty?
    @persisted = true
  end
  true
end

#serializable_hash(options = nil) ⇒ Object



114
115
116
117
118
119
# File 'lib/active_triples/resource.rb', line 114

def serializable_hash(options = nil)
  attrs = (fields.map { |f| f.to_s }) << 'id'
  hash = super(:only => attrs)
  unregistered_predicates.map { |uri| hash[uri.to_s] = get_values(uri) }
  hash
end

#set_subject!(uri_or_str) ⇒ Object

Set a new rdf_subject for the resource.

This raises an error if the current subject is not a blank node, and returns false if it can’t figure out how to make a URI from the param. Otherwise it creates a URI for the resource and rebuilds the graph with the updated URI.

Will try to build a uri as an extension of the class’s base_uri if appropriate.

Parameters:

  • uri_or_str (#to_uri, #to_s)

    the uri or string to use



342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
# File 'lib/active_triples/resource.rb', line 342

def set_subject!(uri_or_str)
  raise "Refusing update URI when one is already assigned!" unless node? or rdf_subject == RDF::URI(nil)
  # Refusing set uri to an empty string.
  return false if uri_or_str.nil? or (uri_or_str.to_s.empty? and not uri_or_str.kind_of? RDF::URI)
  # raise "Refusing update URI! This object is persisted to a datastream." if persisted?
  old_subject = rdf_subject
  @rdf_subject = get_uri(uri_or_str)

  each_statement do |statement|
    if statement.subject == old_subject
      delete(statement)
      self << RDF::Statement.new(rdf_subject, statement.predicate, statement.object)
    elsif statement.object == old_subject
      delete(statement)
      self << RDF::Statement.new(statement.subject, statement.predicate, rdf_subject)
    end
  end
end

#set_value(*args) ⇒ Object

Note:

This method will delete existing statements with the correct subject and predicate from the graph

Adds or updates a property with supplied values.

Handles two argument patterns. The recommended pattern is:

set_value(property, values)

For backwards compatibility, there is support for explicitly passing the rdf_subject to be used in the statement:

set_value(uri, property, values)


282
283
284
285
286
287
288
289
# File 'lib/active_triples/resource.rb', line 282

def set_value(*args)
  # Add support for legacy 3-parameter syntax
  if args.length > 3 || args.length < 2
    raise ArgumentError, "wrong number of arguments (#{args.length} for 2-3)"
  end
  values = args.pop
  get_term(args).set(values)
end

#solrizeString

Returns the string representation of the resource.

Returns:

  • (String)

    the string representation of the resource



393
394
395
# File 'lib/active_triples/resource.rb', line 393

def solrize
  node? ? rdf_label : rdf_subject.to_s
end

#typeObject



185
186
187
# File 'lib/active_triples/resource.rb', line 185

def type
  self.get_values(:type).to_a
end

#type=(type) ⇒ Object



189
190
191
192
# File 'lib/active_triples/resource.rb', line 189

def type=(type)
  raise "Type must be an RDF::URI" unless type.kind_of? RDF::URI
  self.update(RDF::Statement.new(rdf_subject, RDF.type, type))
end

#writable?true, false

Specifies whether the object is currently writable.

Returns:

  • (true, false)


61
62
63
# File 'lib/active_triples/resource.rb', line 61

def writable?
  !frozen?
end