class ROF::Translators::JsonldToRof::Accumulator
@api pubilc The accumulator is a “passive” object. Things happen to it. All in the name of building the hash that is ROF
.
@note The to_rof
will convert blank nodes to arrays of strings for objects that don't have blank node dc:contributor. @note The accumulator is only for one PID. See [ROF::Translators::JsonldToRof::Accumulator#add_pid]
Constants
- MODELS_THAT_HAVE_DC_CONTRIBUTOR_BLANK_NODES
Public Class Methods
@param [Hash] initial_rof - The base ROF
document to which we will be adding elements.
# File lib/rof/translators/jsonld_to_rof/accumulator.rb, line 16 def initialize(initial_rof = {}) @rof = initial_rof @blank_nodes = {} @blank_node_locations = {} end
Public Instance Methods
@api public @param [RDF::Statement] statement @return [RDF::Statement]
# File lib/rof/translators/jsonld_to_rof/accumulator.rb, line 125 def add_blank_node(statement) @blank_nodes[statement.subject] ||= {} @blank_nodes[statement.subject][statement.predicate] ||= [] @blank_nodes[statement.subject][statement.predicate] << statement.object statement end
@api public @param [String] pid - an identifier @return [String] pid @raise PidAlreadySetError
- if you attempted to a different PID
# File lib/rof/translators/jsonld_to_rof/accumulator.rb, line 145 def add_pid(pid) pid = coerce_object_to_string(pid) if @rof.key?('pid') if @rof['pid'] != pid raise PidAlreadySetError, "Attempted to set pid=#{pid}, but it is already set to #{@rof['pid']}" end else @rof['pid'] = pid end pid end
@api public @param [Array<String>, String] location - a list of nested hash keys (or a single string) @param [String] value - a translated value for the original RDF Statement @param [Hash] options @option options [false, RDF::Node] blank_node @option options [Boolean] multiple (default true) - if true will append values to an Array; if false will have a singular (non-Array) value @return [Array] location, value
# File lib/rof/translators/jsonld_to_rof/accumulator.rb, line 164 def add_predicate_location_and_value(location, value, options = {}) blank_node = options.fetch(:blank_node, false) multiple = options.fetch(:multiple, true) # Because I am making transformation on the location via #shift method, I need a duplication. location = Array.wrap(location) if location == ['pid'] return add_pid(value) end if blank_node add_predicate_location_and_value_direct_for_blank_node(location, value, blank_node, multiple) else add_predicate_location_and_value_direct_for_non_blank_node(location, value, multiple) end [location, value] end
@api public @param [RDF::Subject] subject - Fetch the corresponding blank node that was added @return [RDF::Statement] @raise [KeyError] when the subject has not previosly been added @see add_blank_node
# File lib/rof/translators/jsonld_to_rof/accumulator.rb, line 137 def fetch_blank_node(subject) @blank_nodes.fetch(subject) end
@api public @param [String] node_name - the XML node's name (e.g. <node_name>node_value</node_name>) @param [String] node_value - the XML element's value @return [Array] of given node_name and node_value
# File lib/rof/translators/jsonld_to_rof/accumulator.rb, line 113 def register_properties(node_name, node_value) @properties ||= [] @properties << [node_name, coerce_object_to_string(node_value)] [node_name, node_value] end
@api public @return [Hash]
# File lib/rof/translators/jsonld_to_rof/accumulator.rb, line 24 def to_rof rof = @rof.deep_dup rof = expand_blank_node_locations!(rof) rof = normalize_contributor!(rof) rof = append_properties_to(rof) rof end
Private Instance Methods
# File lib/rof/translators/jsonld_to_rof/accumulator.rb, line 182 def add_predicate_location_and_value_direct_for_blank_node(location, value, blank_node, multiple) fetch_blank_node(blank_node) # Ensure the node exists @blank_node_locations[blank_node] ||= {} @blank_node_locations[blank_node][location[0..-2]] ||= [] @blank_node_locations[blank_node][location[0..-2]] << { location[-1] => Array.wrap(coerce_object_to_string(value)) } end
# File lib/rof/translators/jsonld_to_rof/accumulator.rb, line 189 def add_predicate_location_and_value_direct_for_non_blank_node(location, value, multiple) data = @rof location[0..-2].each do |slug| data[slug] ||= {} data = data[slug] end slug = location[-1] if multiple data[slug] ||= [] data[slug] << coerce_object_to_string(value) else if data[slug].present? raise TooManyElementsError.new(location) else data[slug] = coerce_object_to_string(value) end end end
# File lib/rof/translators/jsonld_to_rof/accumulator.rb, line 89 def append_properties_to(rof) return rof unless @properties rof['properties-meta'] = { "mime-type" => "text/xml" } xml = '<fields>' @properties.each do |node_name, object| xml += "<#{node_name}>#{object}</#{node_name}>" end xml += '</fields>' rof['properties'] = xml rof end
# File lib/rof/translators/jsonld_to_rof/accumulator.rb, line 208 def coerce_object_to_string(object) return object if object.nil? if object.to_s =~ ROF::Translators::JsonldToRof::REGEXP_FOR_A_CURATE_RDF_SUBJECT return "und:#{$1}" elsif object.respond_to?(:value) return object.value else object end end
The antics of the blank node! See the specs for blank nodes to see the expected behavior.
# File lib/rof/translators/jsonld_to_rof/accumulator.rb, line 35 def expand_blank_node_locations!(rof) @blank_node_locations.each_pair do |node, locations| locations.each_pair do |location, key_value_pairs| data = rof location[0..-2].each do |slug| data[slug] ||= {} data = data[slug] end # We may encounter a shallow map, if so we need for it to behave differently slug = location[-1] if slug data[slug] ||= [] hash = {} else hash = data end Array.wrap(key_value_pairs).each do |key_value| key_value.each_pair do |key, value| hash[key] ||= [] hash[key] += Array.wrap(value) end end data[slug] << hash if slug end end rof end
Convert dc:contributor from blank node to array for non-ETDs - DLTP1021 The implementation that was developed started from the perspective that the dc:contributor was always a blank node (as implemented in ETDs). However that is not the case.
# File lib/rof/translators/jsonld_to_rof/accumulator.rb, line 70 def normalize_contributor!(rof) return rof unless rof.key?('af-model') return rof unless rof.fetch('metadata', {}).key?('dc:contributor') return rof if MODELS_THAT_HAVE_DC_CONTRIBUTOR_BLANK_NODES.include?(rof['af-model'].first.downcase) contributors = [] Array.wrap(rof['metadata']['dc:contributor']).each do |contributor| case contributor when String contributors << contributor when Hash contributors += Array.wrap(contributor.fetch('dc:contributor')) else raise "Unexpected rof['metadata']['contributor'] value #{contributor.inspect}" end end rof['metadata']['dc:contributor']= contributors rof end