class Hash

Alteration to Hash and Array for support of structural processing: additional methods to address elements of, and process, structural combinations of Hashes, Arrays, and ByteArrays SOMEDAY: @Hash extend these to the pain-in-the-ass Struct class as well.

Public Class Methods

gxg_import(the_exported_record=nil) click to toggle source
# File lib/gxg/gxg_augmented.rb, line 3579
def self.gxg_import(the_exported_record=nil)
  result = nil
  if the_exported_record.is_a?(Hash)
    if the_exported_record[:type] == "Array"
      result = ::Array::gxg_import(the_exported_record)
    else
      import_value = Proc.new do |type,value|
        if value.is_a?(String)
          begin
            the_class = eval(type)
            if the_class.respond_to?(:parse)
              value = the_class.parse(value)
            else
              if the_class.respond_to?(:new)
                value = the_class.new(value)
              else
                if the_class.respond_to?(:try_convert)
                  value = the_class.try_convert(value)
                end
              end
            end
          rescue Exception => the_error
          end
        end
        value
      end
      if the_exported_record[:type] == "Hash"
        result = {}
        import_db = [{:parent => nil, :parent_selector => nil, :object => result, :record => the_exported_record}]
        while import_db.size > 0 do
          entry = import_db.shift
          if entry[:record][:content].is_a?(Hash)
            entry[:record][:content].each_pair do |selector, value|
              if value[:type] == "Hash"
                entry[:object][(selector)] = {}
                import_db << {:parent => entry[:object], :parent_selector => selector, :object => entry[:object][(selector)], :record => value}
              else
                if value[:type] == "Array"
                  entry[:object][(selector)] = []
                  import_db << {:parent => entry[:object], :parent_selector => selector, :object => entry[:object][(selector)], :record => value}
                else
                  entry[:object][(selector)] = import_value.call(value[:type], value[:content])
                end
              end
            end
          else
            if entry[:record][:content].is_a?(Array)
              entry[:record][:content].each_with_index do |value, selector|
                if value[:type] == "Hash"
                  entry[:object][(selector)] = {}
                  import_db << {:parent => entry[:object], :parent_selector => selector, :object => entry[:object][(selector)], :record => value}
                else
                  if value[:type] == "Array"
                    entry[:object][(selector)] = []
                    import_db << {:parent => entry[:object], :parent_selector => selector, :object => entry[:object][(selector)], :record => value}
                  else
                    entry[:object][(selector)] = import_value.call(value[:type], value[:content])
                  end
                end
              end
            end
          end
        end
      else
        result = import_value.call(the_exported_record[:type], the_exported_record[:content])
      end
    end
  end
  result
end
process(the_hash={},&block) click to toggle source
# File lib/gxg/gxg_augmented.rb, line 3291
def self.process(the_hash={},&block)
  new_hash = {}
  if block.respond_to?(:call)
    if the_hash.is_any?(::Array, ::Hash, ::Struct, ::GxG::Database::PersistedHash, ::GxG::Database::PersistedArray)
      new_hash = the_hash.process!(&block)
    else
      raise ArgumentError, "you must pass a Hash or an Array, or a ByteArray"
    end
  end
  new_hash
end

Public Instance Methods

get_at_path(the_path="/") click to toggle source
# File lib/gxg/gxg_augmented.rb, line 3466
def get_at_path(the_path="/")
  result = nil
  if the_path == "/"
    result = self
  else
    object_stack = [(self)]
    path_stack = the_path.split("/")
    path_stack.to_enum.each do |path_element|
      element = nil
      if path_element.size > 0
        if (path_element =~ /^(?:[0-9])*[0-9](?:[0-9])*$/) == 0
          element = path_element.to_i
        else
          element = path_element
          element.gsub!("%2f","/")
          if element[0] == ":"
            element = element[(1..-1)].to_sym
          end
        end
      end
      if element
        result = object_stack.first[(element)]
        if result.is_a?(NilClass)
          break
        else
          object_stack.unshift(result)
        end
      else
        # ignore double slashes? '//'
        # break
      end
    end
  end
  result
end
gxg_export() click to toggle source
# File lib/gxg/gxg_augmented.rb, line 3533
def gxg_export()
  result = {:type => "Hash", :content => {}}
  export_db = [{:parent => nil, :parent_selector => nil, :object => self, :record => result}]
  children_of = Proc.new do |the_parent=nil|
    list = []
    export_db.each do |node|
      if node[:parent].object_id == the_parent.object_id
        list << node
      end
    end
    list
  end
  export_record = Proc.new do |the_value|
    if the_value.is_any?(Integer, Float, String)
      {:type => (the_value.class.to_s), :content => the_value}
    else
      {:type => (the_value.class.to_s), :content => the_value.to_s}
    end
  end
  # Build up export_db:
  self.search do |the_value, the_selector, the_container|
    if the_value.is_a?(::Hash)
      export_db << {:parent => the_container, :parent_selector => the_selector.clone, :object => the_value, :record => {:type => "Hash", :content => {}}}
    else
      if the_value.is_a?(::Array)
        export_db << {:parent => the_container, :parent_selector => the_selector.clone, :object => the_value, :record => {:type => "Array", :content => []}}
      else
        export_db << {:parent => the_container, :parent_selector => the_selector.clone, :object => the_value, :record => export_record.call(the_value)}
      end
    end
  end
  # Collect children export content:
  link_db =[(export_db[0])]
  while link_db.size > 0 do
    entry = link_db.shift
    children_of.call(entry[:object]).each do |the_child|
      entry[:record][:content][(the_child[:parent_selector])] = the_child[:record]
      if the_child[:object].is_any?(Hash, Array)
        link_db << the_child
      end
    end
  end
  #
  result
end
iterative(&block) click to toggle source
# File lib/gxg/gxg_augmented.rb, line 3315
def iterative(&block)
  result = []
  visit = Proc.new do |the_node=nil, accumulator=[]|
    node_stack = []
    if the_node
      node_stack << ({:parent => nil, :parent_selector => nil, :object => (the_node)})
      while (node_stack.size > 0) do
        a_node = node_stack.shift
        #
        if a_node[:object].is_any?(::Hash, ::Struct, ::GxG::Database::PersistedHash)
          a_node[:object].each_pair do |the_key, the_value|
            node_stack << ({:parent => a_node[:object], :parent_selector => the_key, :object => the_value})
          end
        end
        if a_node[:object].is_any?(::Array, ::GxG::Database::PersistedArray)
          a_node[:object].each_with_index do |the_value, the_index|
            node_stack << ({:parent => a_node[:object], :parent_selector => the_index, :object => the_value})
          end
        end
        #
        accumulator << a_node
      end
    end
    accumulator
  end
  #
  children_of = Proc.new do |the_db=[], the_parent=nil|
    list = []
    the_db.each do |node|
      if node[:parent].object_id == the_parent.object_id
        list << node
      end
    end
    list
  end
  #
  begin
    database = visit.call(self,[])
    link_db = children_of.call(database, self)
    if block.respond_to?(:call)
      while (link_db.size > 0) do
        entry = link_db.shift
        unless entry[:object].object_id == self.object_id
          # calls with parameters: the_value, the_key/the_index (the_selector), the_container
          raw_result = block.call(entry[:object], entry[:parent_selector], entry[:parent])
          if raw_result
            result << raw_result
          end
        end
        if entry[:object].object_id != nil.object_id
          children = children_of.call(database, entry[:object])
          children.each do |child|
            link_db << child
          end
        end
      end
    end
    #
  rescue Exception => the_error
    log_error({:error => the_error, :parameters => {}})
  end
  #
  result
end
paths_to(the_object=nil,base_path="") click to toggle source
# File lib/gxg/gxg_augmented.rb, line 3399
def paths_to(the_object=nil,base_path="")
  # new idea here:
  search_results = []
  unless base_path[0] == "/"
    base_path = ("/" << base_path)
  end
  if base_path.size > 1
    path_stack = base_path.split("/")[1..-1].reverse
  else
    path_stack = []
  end
  origin = self.get_at_path(base_path)
  container_stack = [{:selector => nil, :container => origin, :prefix => "/"}]
  find_container = Proc.new do |the_container|
    result = nil
    container_stack.each_with_index do |entry, index|
      if entry[:container] == the_container
        result = entry
        break
      end
    end
    result
  end
  last_container = origin
  found = false
  # tester = {:a=>1, :b=>2, :c=>[0, 5], :testing=>{:d=>4.0, :e=>0.9, :f => nil}}
  if origin.is_any?(::Hash, ::Array, ::Struct, ::GxG::Database::PersistedHash, ::GxG::Database::PersistedArray)
    origin.process! do |the_value, selector, container|
      if last_container.object_id != container.object_id
        container_record = find_container.call(container)
        if container_record
          path_stack = container_record[:prefix].split("/").reverse
          if path_stack.size == 0
            path_stack << ""
          end
        end
        last_container = container
      end
      if selector.is_a?(Symbol)
        safe_key = (":" + selector.to_s)
      else
        safe_key = selector.to_s
      end
      safe_key = safe_key.gsub("/","%2f")
      path_stack.unshift(safe_key)
      # compare the_value
      found = false
      if (the_value == the_object)
        found = true
      end
      if found
        search_results << ("/" << path_stack.reverse.join("/"))
      end
      #
      if the_value.is_any?(::Array, ::Hash, ::Struct, ::GxG::Database::PersistedHash, ::GxG::Database::PersistedArray)
        container_stack.unshift({:selector => selector, :container => the_value, :prefix => (path_stack.reverse.join("/"))})
      end
      path_stack.shift
      #
      nil
    end
  else
    search_results << ("/" << path_stack.join("/"))
  end
  search_results
end
process(&block) click to toggle source
# File lib/gxg/gxg_augmented.rb, line 3380
def process(&block)
  result = self.clone
  result.iterative(&block)
  result
end
process!(&block) click to toggle source
# File lib/gxg/gxg_augmented.rb, line 3386
def process!(&block)
  self.iterative(&block)
  self
end
set_at_path(the_path="/",the_value=nil) click to toggle source
# File lib/gxg/gxg_augmented.rb, line 3502
def set_at_path(the_path="/",the_value=nil)
  result = nil
  if the_path != "/"
    container = self.get_at_path(::File::dirname(the_path))
    if container
      raw_selector = ::File::basename(the_path)
      selector = nil
      if raw_selector.size > 0
        if (raw_selector =~ /^(?:[0-9])*[0-9](?:[0-9])*$/) == 0
          selector = raw_selector.to_i
        else
          selector = raw_selector
          selector.gsub!("%2f","/")
          if selector[0] == ":"
            selector = selector[(1..-1)].to_sym
          end
        end
      end
      if selector
        container[(selector)] = the_value
        result = container[(selector)]
      else
        # ignore double slashes? '//'
        # break
      end
      #
    end
  end
  result
end
symbolize_keys() click to toggle source

def to_xml_simple(options={})

#      keyattr keeproot contentkey noattr rootname
#      xmldeclaration outputfile noescape suppressempty
#      anonymoustag indent grouptags noindent attrprefix
the_options = {:xmldeclaration => true, :rootname => :root, :keeproot => false}
if options.is_a?(::Hash)
  if options[:XmlDeclaration].is_any?(::TrueClass, ::FalseClass)
    the_options[:xmldeclaration] = options[:XmlDeclaration]
  end
  if options[:xmldeclaration].is_any?(::TrueClass, ::FalseClass)
    the_options[:xmldeclaration] = options[:xmldeclaration]
  end
  if options[:RootName].is_any?(::String, ::Symbol)
    the_options[:rootname] = options[:RootName]
  end
  if options[:rootname].is_any?(::String, ::Symbol)
    the_options[:rootname] = options[:rootname]
  end
  if options[:KeepRoot].is_any?(::TrueClass, ::FalseClass)
    the_options[:keeproot] = options[:KeepRoot]
  end
  if options[:keeproot].is_any?(::TrueClass, ::FalseClass)
    the_options[:keeproot] = options[:keeproot]
  end
else
  raise ArgumentError, "You MUST provide options in the form of a Hash."
end
::XmlSimple.xml_out(self, the_options).gsub("\n", "")

end

def to_json()

::JSON.generate(self)

end

# File lib/gxg/gxg_augmented.rb, line 3684
def symbolize_keys()
  self.process! do |value, selector, container|
    if container.is_a?(::Hash)
      unless selector.is_a?(::Symbol)
        container[(selector.to_sym)] = container.delete(selector)
      end
    end
    nil
  end
  self
end