Module: Ladder::Resource::ClassMethods

Defined in:
lib/ladder/resource.rb

Instance Method Summary collapse

Instance Method Details

#new_from_graph(graph, objects = {}, pattern = nil) ⇒ Ladder::Resource?

Create a new instance of this class, populated with values and related objects from a given RDF::Graph for this model.

By default, the graph will be traversed starting with the first node that matches the same RDF.type as this class; however, an optional RDF::Queryable pattern can be provided, @see RDF::Queryable#query

As nodes are traversed in the graph, the instantiated objects will be added to a Hash that is passed recursively, in order to prevent infinite traversal in the case of cyclic graphs (ie. mark-and-sweep graph traversal).

Parameters:

  • graph (RDF::Graph)

    an RDF::Graph to traverse

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

    a keyed Hash of already-created objects in the graph

  • pattern (RDF::Query, RDF::Statement, Array(RDF::Term), Hash) (defaults to: nil)

    a query pattern

Returns:



240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
# File 'lib/ladder/resource.rb', line 240

def new_from_graph(graph, objects = {}, pattern = nil)
  # Default to getting the first object in the graph with the same RDF type as this class
  pattern ||= [nil, RDF.type, resource_class.type]

  root_subject = graph.query(pattern).first_subject
  return unless root_subject

  # If the subject is an existing model, just retrieve it
  new_object = Ladder::Resource.from_uri(root_subject) if root_subject.is_a? RDF::URI
  new_object ||= new

  # Add object to stack for recursion
  objects[root_subject] = new_object

  subgraph = graph.query([root_subject])

  subgraph.each_statement do |statement|
    # Group statements for this predicate
    stmts = subgraph.query([root_subject, statement.predicate])

    if stmts.size > 1
      # We have already set this value in a prior pass
      next if new_object.read_attribute new_object.field_from_predicate statement.predicate

      # If there are multiple statements for this predicate, pass an array
      statement.object = RDF::Node.new
      new_object.send(:<<, statement) { stmts.objects.to_a } # TODO: implement #set_value instead

    elsif statement.object.is_a? RDF::Node
      next if objects[statement.object]

      # If the object is a BNode, dereference the relation
      objects[statement.object] = new_object.send(:<<, statement) do  # TODO: implement #set_value instead
        klass = new_object.klass_from_predicate(statement.predicate)
        klass.new_from_graph(graph, objects, [statement.object]) if klass
      end

    else new_object << statement
    end
  end # end each_statement

  new_object
end

#property(field_name, opts = {}) ⇒ ActiveTriples::Resource

Define a Mongoid field/relation on the class as well as an RDF property on the delegated resource

Parameters:

  • field_name (String)

    ActiveModel attribute name for the field

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

    options to pass to Mongoid / ActiveTriples

Returns:

  • (ActiveTriples::Resource)

    a modified resource

See Also:

  • ActiveTriples::Resource#property
  • ActiveTriples::Properties


206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# File 'lib/ladder/resource.rb', line 206

def property(field_name, opts = {})
  if opts[:class_name]
    mongoid_opts = { autosave: true, index: true }.merge(opts.except(:predicate, :multivalue))
    # TODO: add/fix tests for this behaviour when true
    mongoid_opts[:inverse_of] = nil if Ladder::Config.settings[:one_sided_relations]

    has_and_belongs_to_many(field_name, mongoid_opts) unless relations[field_name.to_s]
  else
    mongoid_opts = { localize: Ladder::Config.settings[:base_uri] }.merge(opts.except(:predicate, :multivalue))
    field(field_name, mongoid_opts) unless fields[field_name.to_s]
  end

  opts.except!(*mongoid_opts.keys)

  super
end