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
599 600 601 602 603 604 |
# File 'lib/active_fedora/semantic_node.rb', line 599 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.
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 711 712 713 714 715 716 |
# File 'lib/active_fedora/semantic_node.rb', line 676 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
606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 |
# File 'lib/active_fedora/semantic_node.rb', line 606 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
583 584 585 586 587 588 |
# File 'lib/active_fedora/semantic_node.rb', line 583 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
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 662 663 664 665 666 667 |
# File 'lib/active_fedora/semantic_node.rb', line 637 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
786 787 788 |
# File 'lib/active_fedora/semantic_node.rb', line 786 def default_predicate_namespace predicate_config[:default_namespace] end |
#find_predicate(predicate) ⇒ Object
790 791 792 793 794 795 796 797 |
# File 'lib/active_fedora/semantic_node.rb', line 790 def find_predicate(predicate) predicate_mappings.each do |namespace,predicates| if predicates.fetch(predicate,nil) return predicates[predicate], namespace end end 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.
519 520 521 |
# File 'lib/active_fedora/semantic_node.rb', line 519 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
488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 |
# File 'lib/active_fedora/semantic_node.rb', line 488 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.
530 531 532 533 534 535 536 537 |
# File 'lib/active_fedora/semantic_node.rb', line 530 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}}}
548 549 550 |
# File 'lib/active_fedora/semantic_node.rb', line 548 def named_relationships_desc @class_named_relationships_desc ||= Hash[:self => {}] end |
#predicate_config ⇒ Object
778 779 780 |
# File 'lib/active_fedora/semantic_node.rb', line 778 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
767 768 769 770 771 772 773 774 775 776 |
# File 'lib/active_fedora/semantic_node.rb', line 767 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
782 783 784 |
# File 'lib/active_fedora/semantic_node.rb', line 782 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.
566 567 568 569 570 |
# File 'lib/active_fedora/semantic_node.rb', line 566 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.
556 557 558 559 560 |
# File 'lib/active_fedora/semantic_node.rb', line 556 def register_named_subject(subject) unless named_relationships_desc.has_key?(subject) named_relationships_desc[subject] = {} end end |
#register_predicate(subject, predicate) ⇒ Object
732 733 734 735 736 737 |
# File 'lib/active_fedora/semantic_node.rb', line 732 def register_predicate(subject, predicate) register_subject(subject) if !relationships[subject].has_key?(predicate) relationships[subject][predicate] = [] end end |
#register_subject(subject) ⇒ Object
726 727 728 729 730 |
# File 'lib/active_fedora/semantic_node.rb', line 726 def register_subject(subject) if !relationships.has_key?(subject) relationships[subject] = {} end end |
#relationships ⇒ Object
relationships are tracked as a hash of structure
721 722 723 |
# File 'lib/active_fedora/semantic_node.rb', line 721 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
745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 |
# File 'lib/active_fedora/semantic_node.rb', line 745 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 |