class SknUtils::NestedResult

Public Class Methods

new(params={}, speed=true) click to toggle source
# File lib/skn_utils/nested_result.rb, line 107
def initialize(params={}, speed=true)
  reset_from_empty!(params, speed)
end
with_instance_vars(args) click to toggle source
# File lib/skn_utils/nested_result.rb, line 103
def self.with_instance_vars(args)
  new(args, true)
end
with_methods(args) click to toggle source

## Onlye good for the first level

# File lib/skn_utils/nested_result.rb, line 100
def self.with_methods(args)
  new(args, false)
end

Public Instance Methods

==(other) click to toggle source

Ruby basic Class methods

# File lib/skn_utils/nested_result.rb, line 151
def ==(other)
  return false unless other.is_a?(NestedResult)
  to_hash.eql?(other.to_hash)
end
Also aliased as: ===
===(other)
Alias for: ==
[](attr) click to toggle source
# File lib/skn_utils/nested_result.rb, line 111
def [](attr)
  container[key_as_sym(attr)]
end
[]=(attr, value) click to toggle source

Feature: if a new attribute is added, on first read method_missing will create getters/setters

# File lib/skn_utils/nested_result.rb, line 116
def []=(attr, value)
  container.store(key_as_sym(attr), value)
end
delete_field(name) click to toggle source
# File lib/skn_utils/nested_result.rb, line 120
def delete_field(name)      # protect public methods
  sym = key_as_sym(name)
  unless !sym.is_a?(Symbol) || self.class.method_defined?(sym)
    singleton_class.send(:remove_method, "#{sym.to_s}=".to_sym, sym) rescue nil
    container.delete(sym)
  end
end
encode_with(coder) click to toggle source

YAML/Psych load support, chance to re-initialize value methods

Use our unwrapped/original input Hash when yaml'ing

# File lib/skn_utils/nested_result.rb, line 175
def encode_with(coder)
  coder['container'] = attributes
end
eql?(other) click to toggle source
# File lib/skn_utils/nested_result.rb, line 157
def eql?(other)
  return false unless other.is_a?(NestedResult)
  to_hash.eql?(other.to_hash)
end
hash() click to toggle source
# File lib/skn_utils/nested_result.rb, line 162
def hash
  to_hash.hash
end
hash_from(sym) click to toggle source

returns hash from any root key starting point: object.root_key

  • protected to reasonably ensure key is a symbol

# File lib/skn_utils/nested_result.rb, line 189
def hash_from(sym)
  starting_sym = key_as_sym(sym)
  bundle = ((starting_sym == container) ? container : { starting_sym => container[starting_sym] })
  bundle.keys.each_with_object({}) do |attr,collector|
    value = bundle[attr]
    case value
      when NestedResult, self.class
        value = value.to_hash
      when Array
        value = value.map {|ele| array_to_hash(ele) }
    end
    collector[attr] = value                                                          # new copy
  end
end
init_with(coder) click to toggle source

Use our hash from above to fully re-initialize this instance

# File lib/skn_utils/nested_result.rb, line 180
def init_with(coder)
  case coder.tag
    when '!ruby/object:SknUtils::NestedResult', "!ruby/object:#{self.class.name}"
      reset_from_empty!( coder.map['container'] )
  end
end
keys() click to toggle source

Feature: returns keys from root input Hash

# File lib/skn_utils/nested_result.rb, line 167
def keys
  container.keys
end
to_h()
Alias for: to_hash
to_hash() click to toggle source

Exporters

# File lib/skn_utils/nested_result.rb, line 131
def to_hash
  attributes
end
Also aliased as: to_h
to_json(*args) click to toggle source
# File lib/skn_utils/nested_result.rb, line 137
def to_json(*args)
  attributes.to_json(*args)
end
to_s() click to toggle source

Returns a string containing a detailed summary of the keys and values.

# File lib/skn_utils/nested_result.rb, line 144
def to_s
  attributes.to_s
end

Protected Instance Methods

marshal_dump() click to toggle source

Marshal.load()/.dump() support, chance to re-initialize value methods

# File lib/skn_utils/nested_result.rb, line 215
def marshal_dump
  to_hash
end
marshal_load(hash) click to toggle source

Using the String from above create and return an instance of this class

# File lib/skn_utils/nested_result.rb, line 220
def marshal_load(hash)
  reset_from_empty!(hash)
end
reset_from_empty!(params={}, speed=true) click to toggle source
# File lib/skn_utils/nested_result.rb, line 206
def reset_from_empty!(params={}, speed=true)
  @container =  Concurrent::Hash.new()
  speed ? initialize_for_speed(params) :
      initialize_from_hash(params)
end
respond_to_missing?(method, incl_private=false) click to toggle source
Calls superclass method
# File lib/skn_utils/nested_result.rb, line 224
def respond_to_missing?(method, incl_private=false)
  method_nsym = method.is_a?(Symbol) ? method.to_s[0..-2].to_sym : method
  container[key_as_sym(method)] || container[method_nsym] || super
end

Private Instance Methods

array_to_hash(array) click to toggle source

Feature: unwrap array of array-of-hashes/object

# File lib/skn_utils/nested_result.rb, line 294
def array_to_hash(array)
  case array
    when self.class
      array.to_hash
    when Array
      array.map { |element| array_to_hash(element) }
    else
      array
  end
end
attribute?(attr) click to toggle source

Feature: attribute must exist and have a non-blank value to cause this method to return true

# File lib/skn_utils/nested_result.rb, line 232
def attribute?(attr)
  return false unless container.key?(key_as_sym(attr))
  ![ "", " ", nil, [],[""], [" "], self.class.new({}), [[]]].any? {|a| a == container[key_as_sym(attr)] }
end
attributes() click to toggle source

Feature: returns a hash of all attributes and their current values

# File lib/skn_utils/nested_result.rb, line 238
def attributes
  hash_from(container)
end
container() click to toggle source
# File lib/skn_utils/nested_result.rb, line 242
def container
  @container ||= Concurrent::Hash.new()
end
enable_dot_notation(sym) click to toggle source

Feature: enables dot.notation and creates matching getter/setters

# File lib/skn_utils/nested_result.rb, line 247
def enable_dot_notation(sym)
  name = key_as_sym(sym)
  unless !name.is_a?(Symbol) || singleton_class.method_defined?(name)
    singleton_class.send(:define_method, name) do
      container[name]
    end

    singleton_class.send(:define_method, "#{name.to_s}=".to_sym) do |x|
      container[name] = x
    end
  end
  name
end
initialize_for_speed(hash) click to toggle source

Don't create methods until first access

# File lib/skn_utils/nested_result.rb, line 262
def initialize_for_speed(hash)
  hash.each_pair do |k,v|
    key = key_as_sym(k)
    case v
      when Array
        value = v.map { |element| translate_value(element) }
        container.store(key, value)
      when Hash
        container.store(key, NestedResult.new(v))
      else
        container.store(key, v)
    end
  end
end
initialize_from_hash(hash) click to toggle source
# File lib/skn_utils/nested_result.rb, line 277
def initialize_from_hash(hash)
  hash.each_pair do |k,v|
    key = key_as_sym(k)
    enable_dot_notation(key)
    case v
      when Array
        value = v.map { |element| translate_value(element) }
        container.store(key, value)
      when Hash
        container.store(key, NestedResult.new(v))
      else
        container.store(key, v)
    end
  end
end
key_as_sym(key) click to toggle source
# File lib/skn_utils/nested_result.rb, line 317
def key_as_sym(key)
  case key
    when Symbol
      key
    when String
      key.to_sym
    else
      key # no change, allows Fixnum and Object instances
  end
end
method_missing(method, *args, &block) click to toggle source

Feature: post-assign key/value pair, <attr>?? predicate, create getter/setter on first access

# File lib/skn_utils/nested_result.rb, line 329
def method_missing(method, *args, &block)
  method_sym = key_as_sym(method)
  method_nsym = method_sym.is_a?(Symbol) ? method.to_s[0..-2].to_sym : method


  if method.to_s.end_with?("=")                                   # add new key/value pair, transform value if Hash or Array
    initialize_from_hash({method_nsym => args.first})             # Add Reader/Writer one first need

  elsif container.key?(method_sym)
    container[method_sym]                                         # Add Reader/Writer one first need

  elsif method.to_s.end_with?('?')                                # order of tests is significant,
    attribute?(method_nsym)

  else # TODO: replace following with nil to match OpenStruct or Hash behavior when key not found
    nil
    # e = NoMethodError.new "undefined method `#{method}' for #{self.class.name}", method, args
    # e.set_backtrace caller(1)
    # raise e

  end
end
translate_value(value) click to toggle source

Feature: wrap array of array-of-hashes/object

# File lib/skn_utils/nested_result.rb, line 306
def translate_value(value)
  case value
    when Hash
      self.class.new(value)
    when Array
      value.map { |element| translate_value(element) }
    else
      value
  end
end