Module: ActiveFedora::SemanticNode::ClassMethods
- Defined in:
- lib/active_fedora/semantic_node.rb
Instance Method Summary collapse
-
#create_bidirectional_named_relationship_methods(name, outbound_name) ⇒ Object
** EXPERIMENTAL ** Similar to
create_named_relationship_methods
except we are merely creating an alias for outbound portion of bidirectional. -
#create_bidirectional_relationship_finders(name, outbound_predicate, inbound_predicate, opts = {}) ⇒ Object
Generates relationship finders for predicates that point in both directions and registers predicate relationships for each direction.
- #create_inbound_relationship_finders(name, predicate, opts = {}) ⇒ Object
-
#create_named_relationship_methods(name) ⇒ Object
** EXPERIMENTAL ** Used in has_relationship call to create dynamic helper methods to append and remove objects to and from a named relationship ====Example For the following relationship.
- #create_outbound_relationship_finders(name, predicate, opts = {}) ⇒ Object
- #default_predicate_namespace ⇒ Object
- #find_predicate(predicate) ⇒ Object
-
#has_bidirectional_relationship(name, outbound_predicate, inbound_predicate, opts = {}) ⇒ Object
Generates relationship finders for predicates that point in both directions.
-
#has_relationship(name, predicate, opts = {}) ⇒ Object
Allows for a relationship to be treated like any other attribute of a model class.
-
#named_predicate_exists_with_different_name?(subject, name, predicate) ⇒ Boolean
** EXPERIMENTAL **.
-
#named_relationships_desc ⇒ Object
** EXPERIMENTAL ** Return hash that stores named relationship metadata defined by has_relationship calls ====Example For the following relationship.
- #predicate_config ⇒ Object
-
#predicate_lookup(predicate, namespace = "info:fedora/fedora-system:def/relations-external#") ⇒ Object
If predicate is a symbol, looks up the predicate in the predicate_mappings If predicate is not a Symbol, returns the predicate untouched.
- #predicate_mappings ⇒ Object
-
#register_named_relationship(subject, name, predicate, opts) ⇒ Object
** EXPERIMENTAL **.
-
#register_named_subject(subject) ⇒ Object
** EXPERIMENTAL ** Internal method that ensures a relationship subject such as :self and :inbound exist within the named_relationships_desc hash tracking named relationships metadata.
- #register_predicate(subject, predicate) ⇒ Object
- #register_subject(subject) ⇒ Object
-
#relationships ⇒ Object
relationships are tracked as a hash of structure.
-
#relationships_to_rels_ext(pid, relationships = self.relationships) ⇒ Object
Creates a RELS-EXT datastream for insertion into a Fedora Object Note: This method is implemented on SemanticNode instead of RelsExtDatastream because SemanticNode contains the relationships array.
Instance Method Details
#create_bidirectional_named_relationship_methods(name, outbound_name) ⇒ Object
** EXPERIMENTAL **
Similar to +create_named_relationship_methods+ except we are merely creating an alias for outbound portion of bidirectional
====Example
has_bidirectional_relationship "members", :has_collection_member, :is_member_of_collection
Method members_outbound_append and members_outbound_remove added
This method will create members_append which does same thing as members_outbound_append
and will create members_remove which does same thing as members_outbound_remove
379 380 381 382 383 384 |
# File 'lib/active_fedora/semantic_node.rb', line 379 def create_bidirectional_named_relationship_methods(name,outbound_name) append_method_name = "#{name.to_s.downcase}_append" remove_method_name = "#{name.to_s.downcase}_remove" self.send(:define_method,:"#{append_method_name}") {|object| add_named_relationship(outbound_name,object)} self.send(:define_method,:"#{remove_method_name}") {|object| remove_named_relationship(outbound_name,object)} end |
#create_bidirectional_relationship_finders(name, outbound_predicate, inbound_predicate, opts = {}) ⇒ Object
Generates relationship finders for predicates that point in both directions and registers predicate relationships for each direction.
428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 |
# File 'lib/active_fedora/semantic_node.rb', line 428 def create_bidirectional_relationship_finders(name, outbound_predicate, inbound_predicate, opts={}) inbound_method_name = name.to_s+"_inbound" outbound_method_name = name.to_s+"_outbound" has_relationship(outbound_method_name, outbound_predicate, opts) has_relationship(inbound_method_name, inbound_predicate, opts.merge!(:inbound=>true)) #create methods that mirror the outbound append and remove with our bidirectional name, assume just add and remove locally create_bidirectional_relationship_name_methods(name,outbound_method_name) class_eval <<-END def #{name}(opts={}) opts = {:rows=>25}.merge(opts) if opts[:response_format] == :solr || opts[:response_format] == :load_from_solr outbound_id_array = [] predicate = outbound_relationship_predicates["#{name}_outbound"] if !outbound_relationships[predicate].nil? outbound_relationships[predicate].each do |rel| outbound_id_array << rel.gsub("info:fedora/", "") end end #outbound_id_array = #{outbound_method_name}(:response_format=>:id_array) query = self.class.bidirectional_relationship_query(self.pid,"#{name}",outbound_id_array) solr_result = SolrService.instance.conn.query(query, :rows=>opts[:rows]) if opts[:response_format] == :solr return solr_result elsif opts[:response_format] == :load_from_solr || self.load_from_solr return ActiveFedora::SolrService.reify_solr_results(solr_result,{:load_from_solr=>true}) else return ActiveFedora::SolrService.reify_solr_results(solr_result) end else ary = #{inbound_method_name}(opts) + #{outbound_method_name}(opts) return ary.uniq end end def #{name}_ids #{name}(:response_format => :id_array) end def #{name}_from_solr #{name}(:response_format => :load_from_solr) end def #{name}_query relationship_query("#{name}") end END end |
#create_inbound_relationship_finders(name, predicate, opts = {}) ⇒ Object
387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 |
# File 'lib/active_fedora/semantic_node.rb', line 387 def create_inbound_relationship_finders(name, predicate, opts = {}) class_eval <<-END def #{name}(opts={}) load_inbound_relationship('#{name}', '#{predicate}', opts) end def #{name}_ids #{name}(:response_format => :id_array) end def #{name}_from_solr #{name}(:response_format => :load_from_solr) end def #{name}_query relationship_query("#{name}") end END end |
#create_named_relationship_methods(name) ⇒ Object
** EXPERIMENTAL **
Used in has_relationship call to create dynamic helper methods to append and remove objects to and from a named relationship
Example
For the following relationship
has_relationship "audio_records", :has_part, :type=>AudioRecord
Methods audio_records_append and audio_records_remove are created. Boths methods take an object that is kind_of? ActiveFedora::Base as a parameter
363 364 365 366 367 368 |
# File 'lib/active_fedora/semantic_node.rb', line 363 def create_named_relationship_methods(name) append_method_name = "#{name.to_s.downcase}_append" remove_method_name = "#{name.to_s.downcase}_remove" self.send(:define_method,:"#{append_method_name}") {|object| add_named_relationship(name,object)} self.send(:define_method,:"#{remove_method_name}") {|object| remove_named_relationship(name,object)} end |
#create_outbound_relationship_finders(name, predicate, opts = {}) ⇒ Object
404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 |
# File 'lib/active_fedora/semantic_node.rb', line 404 def create_outbound_relationship_finders(name, predicate, opts = {}) class_eval <<-END def #{name}(opts={}) load_outbound_relationship(#{name.inspect}, #{predicate.inspect}, opts) end def #{name}_ids #{name}(:response_format => :id_array) end def #{name}_from_solr #{name}(:response_format => :load_from_solr) end def #{name}_query relationship_query("#{name}") end END end |
#default_predicate_namespace ⇒ Object
545 546 547 |
# File 'lib/active_fedora/semantic_node.rb', line 545 def default_predicate_namespace predicate_config[:default_namespace] end |
#find_predicate(predicate) ⇒ Object
549 550 551 552 553 554 555 556 |
# File 'lib/active_fedora/semantic_node.rb', line 549 def find_predicate(predicate) predicate_mappings.each do |namespace,predicates| if predicates.fetch(predicate,nil) return predicates[predicate], namespace end end raise ActiveFedora::UnregisteredPredicateError, "Unregistered predicate: #{predicate.inspect}" end |
#has_bidirectional_relationship(name, outbound_predicate, inbound_predicate, opts = {}) ⇒ Object
Generates relationship finders for predicates that point in both directions
Example:
has_bidirectional_relationship("parts", :has_part, :is_part_of)
will create three instance methods: parts_outbound, and parts_inbound and parts the inbound and outbound methods are the same that would result from calling create_inbound_relationship_finders and create_outbound_relationship_finders The third method combines the results of both and handles generating appropriate solr queries where necessary.
298 299 300 |
# File 'lib/active_fedora/semantic_node.rb', line 298 def has_bidirectional_relationship(name, outbound_predicate, inbound_predicate, opts={}) create_bidirectional_relationship_finders(name, outbound_predicate, inbound_predicate, opts) end |
#has_relationship(name, predicate, opts = {}) ⇒ Object
Allows for a relationship to be treated like any other attribute of a model class. You define relationships in your model class using this method. You then have access to several helper methods to list, append, and remove objects from the list of relationships.
Examples to define two relationships
class AudioRecord < ActiveFedora::Base
has_relationship "oral_history", :has_part, :inbound=>true, :type=>OralHistory
# returns all similar audio
has_relationship "similar_audio", :has_part, :type=>AudioRecord
#returns only similar audio with format wav
has_relationship "similar_audio_wav", :has_part, :solr_fq=>"format_t:wav"
The first two parameters are required:
name: relationship name
predicate: predicate for the relationship
opts:
possible parameters
:inbound => if true loads an external relationship via Solr (defaults to false)
:type => The type of model to use when instantiated an object from the pid in this relationship (defaults to ActiveFedora::Base)
:solr_fq => Define a solr query here if you want to filter out some objects in your relationship (must be a properly formatted solr query)
If inbound is true it expects the relationship to be defined by another object’s RELS-EXT and to load that relationship from Solr. Otherwise, if inbound is true the relationship is stored in this object’s RELS-EXT datastream
Word of caution - The same predicate may not be used twice for two inbound or two outbound relationships. However, it may be used twice if one is inbound and one is outbound as shown in the example above. A full list of possible predicates are defined by predicate_mappings
For the oral_history relationship in the example above the following helper methods are created:
oral_history: returns array of OralHistory objects that have this AudioRecord with predicate :has_part
oral_history_ids: Return array of pids for OralHistory objects that have this AudioRecord with predicate :has_part
oral_history_query: Return solr query that can be used to retrieve related objects as solr documents
For the outbound relationship “similar_audio” there are two additional methods to append and remove objects from that relationship since it is managed internally:
similar_audio: Return array of AudioRecord objects that have been added to similar_audio relationship
similar_audio_ids: Return array of AudioRecord object pids that have been added to similar_audio relationship
similar_audio_query: Return solr query that can be used to retrieve related objects as solr documents
similar_audio_append: Add an AudioRecord object to the similar_audio relationship
similar_audio_remove: Remove an AudioRecord from the similar_audio relationship
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 |
# File 'lib/active_fedora/semantic_node.rb', line 267 def has_relationship(name, predicate, opts = {}) opts = {:singular => nil, :inbound => false}.merge(opts) if opts[:inbound] == true #raise "Duplicate use of predicate for inbound relationship name not allowed" if predicate_exists_with_different_relationship_name?(:inbound,name,predicate) register_relationship_desc(:inbound, name, predicate, opts) register_predicate(:inbound, predicate) create_inbound_relationship_finders(name, predicate, opts) else #raise "Duplicate use of predicate for named outbound relationship \"#{predicate.inspect}\" not allowed" if named_predicate_exists_with_different_name?(:self,name,predicate) register_relationship_desc(:self, name, predicate, opts) register_predicate(:self, predicate) create_relationship_name_methods(name) create_outbound_relationship_finders(name, predicate, opts) end end |
#named_predicate_exists_with_different_name?(subject, name, predicate) ⇒ Boolean
** EXPERIMENTAL **
Check to make sure a subject,name, and predicate triple does not already exist with the same subject but different name. This method is used to ensure conflicting has_relationship calls are not made because predicates cannot be reused across relationship names. Otherwise, the mapping of relationship name to predicate in RELS-EXT would be broken.
309 310 311 312 313 314 315 316 |
# File 'lib/active_fedora/semantic_node.rb', line 309 def named_predicate_exists_with_different_name?(subject,name,predicate) if named_relationships_desc.has_key?(subject) named_relationships_desc[subject].each_pair do |existing_name, args| return true if !args[:predicate].nil? && args[:predicate] == predicate && existing_name != name end end return false end |
#named_relationships_desc ⇒ Object
** EXPERIMENTAL **
Return hash that stores named relationship metadata defined by has_relationship calls
Example
For the following relationship
has_relationship "audio_records", :has_part, :type=>AudioRecord
Results in the following returned by named_relationships_desc
{:self=>{"audio_records"=>{:type=>AudioRecord, :singular=>nil, :predicate=>:has_part, :inbound=>false}}}
327 328 329 330 |
# File 'lib/active_fedora/semantic_node.rb', line 327 def named_relationships_desc @class_named_relationships_desc ||= Hash[:self => {}] #class_named_relationships_desc end |
#predicate_config ⇒ Object
537 538 539 |
# File 'lib/active_fedora/semantic_node.rb', line 537 def predicate_config @@predicate_config ||= YAML::load(File.open(ActiveFedora.predicate_config)) if File.exist?(ActiveFedora.predicate_config) end |
#predicate_lookup(predicate, namespace = "info:fedora/fedora-system:def/relations-external#") ⇒ Object
If predicate is a symbol, looks up the predicate in the predicate_mappings If predicate is not a Symbol, returns the predicate untouched
526 527 528 529 530 531 532 533 534 535 |
# File 'lib/active_fedora/semantic_node.rb', line 526 def predicate_lookup(predicate,namespace="info:fedora/fedora-system:def/relations-external#") if predicate.class == Symbol if predicate_mappings[namespace].has_key?(predicate) return predicate_mappings[namespace][predicate] else raise ActiveFedora::UnregisteredPredicateError end end return predicate end |
#predicate_mappings ⇒ Object
541 542 543 |
# File 'lib/active_fedora/semantic_node.rb', line 541 def predicate_mappings predicate_config[:predicate_mapping] end |
#register_named_relationship(subject, name, predicate, opts) ⇒ Object
** EXPERIMENTAL **
Internal method that adds relationship name and predicate pair to either an outbound (:self) or inbound (:inbound) relationship types.
346 347 348 349 350 |
# File 'lib/active_fedora/semantic_node.rb', line 346 def register_named_relationship(subject, name, predicate, opts) register_named_subject(subject) opts.merge!({:predicate=>predicate}) named_relationships_desc[subject][name] = opts end |
#register_named_subject(subject) ⇒ Object
** EXPERIMENTAL **
Internal method that ensures a relationship subject such as :self and :inbound exist within the named_relationships_desc hash tracking named relationships metadata.
336 337 338 339 340 |
# File 'lib/active_fedora/semantic_node.rb', line 336 def register_named_subject(subject) unless named_relationships_desc.has_key?(subject) named_relationships_desc[subject] = {} end end |
#register_predicate(subject, predicate) ⇒ Object
491 492 493 494 495 496 |
# File 'lib/active_fedora/semantic_node.rb', line 491 def register_predicate(subject, predicate) register_subject(subject) if !relationships[subject].has_key?(predicate) relationships[subject][predicate] = [] end end |
#register_subject(subject) ⇒ Object
485 486 487 488 489 |
# File 'lib/active_fedora/semantic_node.rb', line 485 def register_subject(subject) if !relationships.has_key?(subject) relationships[subject] = {} end end |
#relationships ⇒ Object
relationships are tracked as a hash of structure
479 480 481 482 |
# File 'lib/active_fedora/semantic_node.rb', line 479 def relationships @class_relationships ||= Hash[:self => {}] #class_relationships end |
#relationships_to_rels_ext(pid, relationships = self.relationships) ⇒ Object
Creates a RELS-EXT datastream for insertion into a Fedora Object Note: This method is implemented on SemanticNode instead of RelsExtDatastream because SemanticNode contains the relationships array
504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 |
# File 'lib/active_fedora/semantic_node.rb', line 504 def relationships_to_rels_ext(pid, relationships=self.relationships) starter_xml = <<-EOL <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <rdf:Description rdf:about="info:fedora/#{pid}"> </rdf:Description> </rdf:RDF> EOL xml = REXML::Document.new(starter_xml) # Iterate through the hash of predicates, adding an element to the RELS-EXT for each "object" in the predicate's corresponding array. self.outbound_relationships.each do |predicate, targets_array| targets_array.each do |target| #puts ". #{predicate} #{target}" xml.root.elements["rdf:Description"].add_element(predicate_lookup(predicate), {"xmlns" => "info:fedora/fedora-system:def/relations-external#", "rdf:resource"=>target}) end end xml.to_s end |