Module: ActiveTriples::RDFSource
- Extended by:
- ActiveSupport::Concern
- Includes:
- ActiveModel::Conversion, ActiveModel::Serialization, ActiveModel::Serializers::JSON, ActiveModel::Validations, NestedAttributes, Persistable, Properties, RDF::Queryable, RDF::Value
- Included in:
- List::ListResource, Resource
- Defined in:
- lib/active_triples/rdf_source.rb
Overview
complete RDF::Value/RDF::Term/RDF::Resource interfaces
Defines a concern for managing RDF::Graph driven Resources as discrete, stateful graphs using ActiveModel-style objects.
An ‘RDFSource` models a resource (RDF::Resource) with a state that may change over time. The current state is represented by an RDF::Graph, accessible as Persistable#graph. The source is an RDF::Resource represented by #rdf_subject, which may be either an RDF::URI or an RDF::Node.
The graph of a source may contain contain arbitrary triples, including full representations of the state of other sources. The triples in the graph should be limited to statements that have bearing on the resource’s state.
Properties may be defined on inheriting classes to configure accessor methods for predicates.
An ‘RDFSource` is an RDF::Term—it can be used as a subject, predicate, object, or context in an RDF::Statement.
Defined Under Namespace
Modules: ClassMethods
Class Method Summary collapse
Instance Method Summary collapse
-
#==(other) ⇒ Object
Compares self to other for RDF::Term equality.
-
#[](term_or_property) ⇒ Object
Returns an array of values belonging to the property requested.
-
#[]=(term_or_property, value) ⇒ Object
Adds or updates a property with supplied values.
- #add_observer(observer) ⇒ Object
-
#attributes ⇒ Hash<String, Array<Object>>
Gives a hash containing both the registered and unregistered attributes of the resource.
- #attributes=(values) ⇒ Object
-
#base_uri ⇒ String?
The base URI the resource will use when setting its subject.
- #count ⇒ Object
-
#default_labels ⇒ Array<RDF::URI>
A group of properties to use for default labels.
-
#delete_observer(observer) ⇒ #notify?
The deleted observer; nil if the observer was not registered.
-
#dump(*args) ⇒ String
Returns a serialized string representation of self.
- #each ⇒ Object
- #escape ⇒ Object
-
#fetch(*args) {|resource| ... } ⇒ ActiveTriples::RDFSource
Load data from the #rdf_subject URI.
-
#get_relation(args) ⇒ Object
deprecated
Deprecated.
for removal in 1.0; use ‘#get_values` insctead.
-
#get_values(*args) ⇒ ActiveTriples::Relation
Returns an array of values belonging to the property requested.
-
#graph_name ⇒ nil
Returns ‘nil` as the `graph_name`.
- #has_statement? ⇒ Object
-
#humanize ⇒ String
A string identifier for the resource; ” if the resource is a node.
- #id ⇒ String
-
#initialize(*args, &block) ⇒ Object
Initialize an instance of this resource class.
- #inspect ⇒ String
- #load! ⇒ Object
- #mark_for_destruction ⇒ Object
- #marked_for_destruction? ⇒ Boolean
-
#new_record? ⇒ Boolean
Indicates if the record is ‘new’ (has not yet been persisted).
-
#node? ⇒ Boolean
True if the Term is a node.
-
#notify_observers(property) ⇒ void
Sends ‘#notify` messages with the property symbol and the current values for the property to each observer.
-
#parent ⇒ Object
Delegate parent to the persistence strategy if possible.
- #parent=(parent) ⇒ Object
- #query ⇒ Object
-
#rdf_label ⇒ Object
Looks for labels in various default fields, prioritizing configured label fields.
-
#rdf_subject ⇒ RDF::URI, RDF::Node
(also: #to_term)
Gives the representation of this RDFSource as an RDF::Term.
- #serializable_hash ⇒ Hash
-
#set_subject!(uri_or_str) ⇒ void
Set a new rdf_subject for the resource.
-
#set_value(*args) ⇒ ActiveTriples::Relation
Adds or updates a property by creating triples for each of the supplied values.
- #term? ⇒ Object
- #to_base ⇒ Object
-
#to_uri ⇒ RDF::URI
The uri.
- #type ⇒ Object
- #type=(type) ⇒ Object
-
#uri? ⇒ Boolean
True if the Term is a uri.
Methods included from Persistable
#delete_statement, #destroy, #destroyed?, #graph, #insert_statement, #persist!, #persisted?, #persistence_strategy, #reload, #set_persistence_strategy
Class Method Details
.type_registry ⇒ Object
58 59 60 |
# File 'lib/active_triples/rdf_source.rb', line 58 def type_registry @@type_registry ||= {} end |
Instance Method Details
#==(other) ⇒ Object
Compares self to other for RDF::Term equality.
Delegates the check to ‘other#==` passing it the term version of `self`.
144 145 146 |
# File 'lib/active_triples/rdf_source.rb', line 144 def ==(other) other == to_term end |
#[](term_or_property) ⇒ Object
Returns an array of values belonging to the property requested. Elements in the array may RdfResource objects or a valid datatype.
518 519 520 |
# File 'lib/active_triples/rdf_source.rb', line 518 def [](term_or_property) get_values(term_or_property) end |
#[]=(term_or_property, value) ⇒ Object
This method will delete existing statements with the correct subject and predicate from the graph
Adds or updates a property with supplied values.
531 532 533 |
# File 'lib/active_triples/rdf_source.rb', line 531 def []=(term_or_property, value) self[term_or_property].set(value) end |
#add_observer(observer) ⇒ Object
590 591 592 |
# File 'lib/active_triples/rdf_source.rb', line 590 def add_observer(observer) @observers.add(observer) end |
#attributes ⇒ Hash<String, Array<Object>>
Gives a hash containing both the registered and unregistered attributes of the resource. Unregistered attributes are given with full URIs.
@todo: should this, ‘#attributes=`, and `#serializable_hash` be moved out
into a dedicated `Serializer` object?
185 186 187 188 189 190 191 |
# File 'lib/active_triples/rdf_source.rb', line 185 def attributes attrs = {} attrs['id'] = 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
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 |
# File 'lib/active_triples/rdf_source.rb', line 193 def attributes=(values) raise(ArgumentError, "values must be a Hash. Got: #{values.class}") unless values.is_a? Hash values = values.with_indifferent_access id = values.delete(:id) set_subject!(id) if node? && id && get_uri(id).uri? values.each do |key, value| if reflections.has_property?(key) set_value(key, value) elsif .keys.any? { |k| key == "#{k}_attributes" } send("#{key}=".to_sym, value) else raise ArgumentError, "No association found for name `#{key}'. " \ 'Has it been defined yet?' end end end |
#base_uri ⇒ String?
Returns the base URI the resource will use when setting its subject. ‘nil` if none is used.
349 350 351 |
# File 'lib/active_triples/rdf_source.rb', line 349 def base_uri self.class.base_uri end |
#count ⇒ Object
90 |
# File 'lib/active_triples/rdf_source.rb', line 90 delegate :query, :each, :load!, :count, :has_statement?, to: :graph |
#default_labels ⇒ Array<RDF::URI>
Returns a group of properties to use for default labels.
216 217 218 219 220 221 222 |
# File 'lib/active_triples/rdf_source.rb', line 216 def default_labels [RDF::Vocab::SKOS.prefLabel, RDF::Vocab::DC.title, RDF::RDFS.label, RDF::Vocab::SKOS.altLabel, RDF::Vocab::SKOS.hiddenLabel] end |
#delete_observer(observer) ⇒ #notify?
Returns the deleted observer; nil if the observer was not registered.
599 600 601 |
# File 'lib/active_triples/rdf_source.rb', line 599 def delete_observer(observer) @observers.delete?(observer) 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
244 245 246 247 248 249 250 |
# File 'lib/active_triples/rdf_source.rb', line 244 def dump(*args) if args.first == :jsonld && respond_to?(:jsonld_context) args << {} unless args.last.is_a?(Hash) args.last[:context] ||= jsonld_context end super end |
#each ⇒ Object
90 |
# File 'lib/active_triples/rdf_source.rb', line 90 delegate :query, :each, :load!, :count, :has_statement?, to: :graph |
#escape ⇒ Object
99 |
# File 'lib/active_triples/rdf_source.rb', line 99 delegate :to_base, :term?, :escape, to: :to_term |
#fetch(*args) {|resource| ... } ⇒ ActiveTriples::RDFSource
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.
401 402 403 404 405 406 407 408 409 410 411 412 413 414 |
# File 'lib/active_triples/rdf_source.rb', line 401 def fetch(*args, &_block) begin load(rdf_subject, *args) rescue => e if block_given? yield(self) else raise "#{self} is a blank node; " \ 'Cannot fetch a resource without a URI' if node? raise e end end self end |
#get_relation(args) ⇒ Object
for removal in 1.0; use ‘#get_values` insctead.
538 539 540 541 542 |
# File 'lib/active_triples/rdf_source.rb', line 538 def get_relation(args) warn 'DEPRECATION: `ActiveTriples::RDFSource#get_relation` will be' \ 'removed in 1.0; use `#get_values` instead.' get_values(*args) end |
#get_values(property) ⇒ ActiveTriples::Relation #get_values(uri, property) ⇒ ActiveTriples::Relation
should this raise an error when the property argument is not an RDF::Term or a registered property key?
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, which accesses properties directly on this RDFSource, is:
get_values(property)
506 507 508 509 510 511 |
# File 'lib/active_triples/rdf_source.rb', line 506 def get_values(*args) @relation_cache ||= {} rel = Relation.new(self, args) @relation_cache["#{rel.send(:rdf_subject)}/#{rel.property}/#{rel.rel_args}"] ||= rel @relation_cache["#{rel.send(:rdf_subject)}/#{rel.property}/#{rel.rel_args}"] end |
#graph_name ⇒ nil
Returns ‘nil` as the `graph_name`. This behavior mimics an `RDF::Graph` with no graph name, or one without named graph support.
@note: it’s possible to think of an ‘RDFSource` as “supporting named
graphs" in the sense that the `#rdf_subject` is an implied graph name.
For RDF.rb's purposes, however, it has a nil graph name: when
enumerating statements, we treat them as triples.
297 298 299 |
# File 'lib/active_triples/rdf_source.rb', line 297 def graph_name nil end |
#has_statement? ⇒ Object
90 |
# File 'lib/active_triples/rdf_source.rb', line 90 delegate :query, :each, :load!, :count, :has_statement?, to: :graph |
#humanize ⇒ String
Returns A string identifier for the resource; ” if the resource is a node.
304 305 306 |
# File 'lib/active_triples/rdf_source.rb', line 304 def humanize node? ? '' : rdf_subject.to_s end |
#id ⇒ String
318 319 320 |
# File 'lib/active_triples/rdf_source.rb', line 318 def id node? ? rdf_subject.id : rdf_subject.to_s end |
#initialize(*args, &block) ⇒ Object
move this logic out to a Builder?
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:
new(nil, parent)
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
# File 'lib/active_triples/rdf_source.rb', line 112 def initialize(*args, &block) @observers = Set.new resource_uri = args.shift unless args.first.is_a?(Hash) @rdf_subject = get_uri(resource_uri) if resource_uri if args.first.is_a?(Hash) || args.empty? set_persistence_strategy(RepositoryStrategy) else set_persistence_strategy(ParentStrategy) persistence_strategy.parent = args.shift end persistence_strategy.graph = RDF::Graph.new(*args, &block) reload # Append type to graph if necessary. Array.wrap(self.class.type).each do |type| get_values(:type) << type unless get_values(:type).include?(type) end end |
#inspect ⇒ String
Without a custom #inspect, we inherit from RDF::Value.
326 327 328 |
# File 'lib/active_triples/rdf_source.rb', line 326 def inspect sprintf("#<%s:%#0x ID:%s>", self.class.to_s, self.object_id, self.to_base) end |
#load! ⇒ Object
90 |
# File 'lib/active_triples/rdf_source.rb', line 90 delegate :query, :each, :load!, :count, :has_statement?, to: :graph |
#mark_for_destruction ⇒ Object
578 579 580 |
# File 'lib/active_triples/rdf_source.rb', line 578 def mark_for_destruction @marked_for_destruction = true end |
#marked_for_destruction? ⇒ Boolean
582 583 584 |
# File 'lib/active_triples/rdf_source.rb', line 582 def marked_for_destruction? @marked_for_destruction end |
#new_record? ⇒ Boolean
Indicates if the record is ‘new’ (has not yet been persisted).
574 575 576 |
# File 'lib/active_triples/rdf_source.rb', line 574 def new_record? !persisted? end |
#node? ⇒ Boolean
Returns true if the Term is a node.
334 335 336 |
# File 'lib/active_triples/rdf_source.rb', line 334 def node? rdf_subject.node? end |
#notify_observers(property) ⇒ void
We short circuit to avoid query costs if no observers are present. If there are regisetred observers, values are returned as an array. This means that we incur query costs immediately and only once.
This method returns an undefined value.
Sends ‘#notify` messages with the property symbol and the current values for the property to each observer.
627 628 629 630 631 |
# File 'lib/active_triples/rdf_source.rb', line 627 def notify_observers(property) return if @observers.empty? values = get_values(property).to_a @observers.each { |o| o.notify(property, values) } end |
#parent ⇒ Object
establish a better pattern for this. ‘#parent` has been a public method in the past, but it’s probably time to deprecate it.
Delegate parent to the persistence strategy if possible
257 258 259 260 261 262 |
# File 'lib/active_triples/rdf_source.rb', line 257 def parent return persistence_strategy.parent if persistence_strategy.respond_to?(:parent) nil end |
#parent=(parent) ⇒ Object
deprecate/remove
267 268 269 270 271 272 |
# File 'lib/active_triples/rdf_source.rb', line 267 def parent=(parent) return persistence_strategy.parent = parent if persistence_strategy.respond_to?(:parent=) nil end |
#query ⇒ Object
90 |
# File 'lib/active_triples/rdf_source.rb', line 90 delegate :query, :each, :load!, :count, :has_statement?, to: :graph |
#rdf_label ⇒ Object
Looks for labels in various default fields, prioritizing configured label fields.
370 371 372 373 374 375 376 377 378 |
# File 'lib/active_triples/rdf_source.rb', line 370 def rdf_label labels = Array.wrap(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_subject ⇒ RDF::URI, RDF::Node Also known as: to_term
Gives the representation of this RDFSource as an RDF::Term
281 282 283 |
# File 'lib/active_triples/rdf_source.rb', line 281 def rdf_subject @rdf_subject ||= RDF::Node.new end |
#serializable_hash ⇒ Hash
226 227 228 229 230 231 232 |
# File 'lib/active_triples/rdf_source.rb', line 226 def serializable_hash(*) attrs = fields.map(&: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) ⇒ void
This method returns an undefined value.
Set a new rdf_subject for the resource.
Will try to build a uri as an extension of the class’s base_uri if appropriate.
557 558 559 560 561 562 563 564 565 566 567 568 |
# File 'lib/active_triples/rdf_source.rb', line 557 def set_subject!(uri_or_str) raise 'Refusing to update URI when one is already assigned!' unless node? || rdf_subject == RDF::URI(nil) return if uri_or_str.nil? || (uri_or_str.to_s.empty? && !uri_or_str.is_a?(RDF::URI)) new_subject = get_uri(uri_or_str) rewrite_statement_uris(rdf_subject, new_subject) @rdf_subject = new_subject end |
#set_value(property, values) ⇒ ActiveTriples::Relation #set_value(subject, property, values) ⇒ ActiveTriples::Relation
This method will delete existing statements with the given subject and predicate from the graph
Adds or updates a property by creating triples for each of the supplied values.
The ‘property` argument may be either a symbol representing a registered property name, or an RDF::Term to use as the predicate.
The recommended pattern, which sets properties directly on this RDFSource, is: ‘set_value(property, values)`
472 473 474 475 476 477 478 479 480 |
# File 'lib/active_triples/rdf_source.rb', line 472 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_values(*args).set(values) end |
#term? ⇒ Object
99 |
# File 'lib/active_triples/rdf_source.rb', line 99 delegate :to_base, :term?, :escape, to: :to_term |
#to_base ⇒ Object
99 |
# File 'lib/active_triples/rdf_source.rb', line 99 delegate :to_base, :term?, :escape, to: :to_term |
#to_uri ⇒ RDF::URI
Returns the uri.
310 311 312 |
# File 'lib/active_triples/rdf_source.rb', line 310 def to_uri rdf_subject if uri? end |
#type ⇒ Object
353 354 355 |
# File 'lib/active_triples/rdf_source.rb', line 353 def type get_values(:type) end |
#type=(type) ⇒ Object
357 358 359 360 361 362 363 |
# File 'lib/active_triples/rdf_source.rb', line 357 def type=(type) raise(ArgumentError, "Type must be an RDF::URI. Got: #{type.class}, #{type}") unless type.is_a? RDF::URI update(RDF::Statement.new(rdf_subject, RDF.type, type)) end |
#uri? ⇒ Boolean
Returns true if the Term is a uri.
342 343 344 |
# File 'lib/active_triples/rdf_source.rb', line 342 def uri? rdf_subject.uri? end |