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
593 594 595 596 597 598 |
# File 'lib/active_fedora/semantic_node.rb', line 593 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.
670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 |
# File 'lib/active_fedora/semantic_node.rb', line 670 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_named_relationship_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 escaped_uri = self.internal_uri.gsub(/(:)/, '\\:') query = "#{inbound_predicate}_s:\#{escaped_uri}" outbound_id_array = #{outbound_method_name}(:response_format=>:id_array) query = query + " OR " + ActiveFedora::SolrService.construct_query_for_pids(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 END end |
#create_inbound_relationship_finders(name, predicate, opts = {}) ⇒ Object
600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 |
# File 'lib/active_fedora/semantic_node.rb', line 600 def create_inbound_relationship_finders(name, predicate, opts = {}) class_eval <<-END def #{name}(opts={}) opts = {:rows=>25}.merge(opts) escaped_uri = self.internal_uri.gsub(/(:)/, '\\:') solr_result = SolrService.instance.conn.query("#{predicate}_s:\#{escaped_uri}", :rows=>opts[:rows]) if opts[:response_format] == :solr return solr_result else if opts[:response_format] == :id_array id_array = [] solr_result.hits.each do |hit| id_array << hit[SOLR_DOCUMENT_ID] end return id_array 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 end end def #{name}_ids #{name}(:response_format => :id_array) end def #{name}_from_solr #{name}(:response_format => :load_from_solr) 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
577 578 579 580 581 582 |
# File 'lib/active_fedora/semantic_node.rb', line 577 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
631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 |
# File 'lib/active_fedora/semantic_node.rb', line 631 def create_outbound_relationship_finders(name, predicate, opts = {}) class_eval <<-END def #{name}(opts={}) id_array = [] if !outbound_relationships[#{predicate.inspect}].nil? outbound_relationships[#{predicate.inspect}].each do |rel| id_array << rel.gsub("info:fedora/", "") end end if opts[:response_format] == :id_array return id_array else query = ActiveFedora::SolrService.construct_query_for_pids(id_array) solr_result = SolrService.instance.conn.query(query) 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 end end def #{name}_ids #{name}(:response_format => :id_array) end def #{name}_from_solr #{name}(:response_format => :load_from_solr) end END end |
#default_predicate_namespace ⇒ Object
780 781 782 |
# File 'lib/active_fedora/semantic_node.rb', line 780 def default_predicate_namespace predicate_config[:default_namespace] end |
#find_predicate(predicate) ⇒ Object
784 785 786 787 788 789 790 791 792 |
# File 'lib/active_fedora/semantic_node.rb', line 784 def find_predicate(predicate) predicate_mappings.each do |namespace,predicates| if predicates.fetch(predicate,nil) return predicates[predicate], namespace end end debugger raise ActiveFedora::UnregisteredPredicateError 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.
513 514 515 |
# File 'lib/active_fedora/semantic_node.rb', line 513 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 named 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
has_relationship "similar_audio", :has_part, :type=>AudioRecord
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)
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
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_append: Add an AudioRecord object to the similar_audio relationship
similar_audio_remove: Remove an AudioRecord from the similar_audio relationship
482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 |
# File 'lib/active_fedora/semantic_node.rb', line 482 def has_relationship(name, predicate, opts = {}) opts = {:singular => nil, :inbound => false}.merge(opts) if opts[:inbound] == true raise "Duplicate use of predicate for named inbound relationship not allowed" if named_predicate_exists_with_different_name?(:inbound,name,predicate) register_named_relationship(: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 not allowed" if named_predicate_exists_with_different_name?(:self,name,predicate) register_named_relationship(:self, name, predicate, opts) register_predicate(:self, predicate) create_named_relationship_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.
524 525 526 527 528 529 530 531 |
# File 'lib/active_fedora/semantic_node.rb', line 524 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}}}
542 543 544 |
# File 'lib/active_fedora/semantic_node.rb', line 542 def named_relationships_desc @class_named_relationships_desc ||= Hash[:self => {}] end |
#predicate_config ⇒ Object
772 773 774 |
# File 'lib/active_fedora/semantic_node.rb', line 772 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
761 762 763 764 765 766 767 768 769 770 |
# File 'lib/active_fedora/semantic_node.rb', line 761 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
776 777 778 |
# File 'lib/active_fedora/semantic_node.rb', line 776 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.
560 561 562 563 564 |
# File 'lib/active_fedora/semantic_node.rb', line 560 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.
550 551 552 553 554 |
# File 'lib/active_fedora/semantic_node.rb', line 550 def register_named_subject(subject) unless named_relationships_desc.has_key?(subject) named_relationships_desc[subject] = {} end end |
#register_predicate(subject, predicate) ⇒ Object
726 727 728 729 730 731 |
# File 'lib/active_fedora/semantic_node.rb', line 726 def register_predicate(subject, predicate) register_subject(subject) if !relationships[subject].has_key?(predicate) relationships[subject][predicate] = [] end end |
#register_subject(subject) ⇒ Object
720 721 722 723 724 |
# File 'lib/active_fedora/semantic_node.rb', line 720 def register_subject(subject) if !relationships.has_key?(subject) relationships[subject] = {} end end |
#relationships ⇒ Object
relationships are tracked as a hash of structure
715 716 717 |
# File 'lib/active_fedora/semantic_node.rb', line 715 def relationships @class_relationships ||= Hash[:self => {}] 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
739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 |
# File 'lib/active_fedora/semantic_node.rb', line 739 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 |