class AttributeStruct

Constants

AttributeHash

This class has dubious semantics and we only have it so that people can write params instead of params.

UNSET_VALUE

value used to identify unset value

VALID_CAMEL_STYLES

@return [Hash] valid styles and mapped value

VERSION

Current library version

Attributes

camel_keys[R]

@return [Truthy, Falsey] global flag for camel keys

camel_style[R]

@return [Symbol] camel key style

_arg_state[R]

@return [AtributeStruct::AttributeHash, Mash] holding space for state

_camel_keys[R]

@return [Truthy, Falsey] current camelizing setting

_camel_style[R]

@return [Symbol] current camel style

arg_state![R]

@return [AtributeStruct::AttributeHash, Mash] holding space for state

camel_keys![R]

@return [Truthy, Falsey] current camelizing setting

camel_style![R]

@return [Symbol] current camel style

Public Class Methods

build(&block) click to toggle source

Create AttributeStruct instance and dump the resulting hash

# File lib/attribute_struct/attribute_struct.rb, line 71
def build(&block)
  raise ArgumentError.new "Block required for build!" unless block
  new(&block)._dump
end
camel_keys=(val) click to toggle source

Automatically converts keys to camel case

@param val [TrueClass, FalseClass] @return [TrueClass, FalseClass]

# File lib/attribute_struct/attribute_struct.rb, line 28
def camel_keys=(val)
  load_the_camels if val
  @camel_keys = !!val
end
camel_style=(val) click to toggle source

Set default style of camel keys

@param val [Symbol] @return [Symbol]

# File lib/attribute_struct/attribute_struct.rb, line 37
def camel_style=(val)
  @camel_style = validate_camel_style(val)
end
hashish() click to toggle source

@return [AttributeStruct::AttributeHash]

# File lib/attribute_struct/attribute_struct.rb, line 66
def hashish
  ::AttributeStruct::AttributeHash
end
irb_compat!() click to toggle source

Enable IRB compatibility mode

@return [TrueClass] @note this will add methods required for working within IRB

# File lib/attribute_struct/attribute_struct.rb, line 80
def irb_compat!
  self.send(:include, IrbCompat)
  true
end
load_the_camels() click to toggle source

Loads helpers for camel casing

# File lib/attribute_struct/attribute_struct.rb, line 58
def load_the_camels
  unless (@camels_loaded)
    require "attribute_struct/monkey_camels"
    @camels_loaded = true
  end
end
new(init_hash = nil, &block) click to toggle source

Create new instance

@param init_hash [Hash] hash to initialize struct @yield block to execute within struct context

# File lib/attribute_struct/attribute_struct.rb, line 106
def initialize(init_hash = nil, &block)
  @_camel_keys = _klass.camel_keys
  @_arg_state = __hashish.new
  @_objectified = false
  @table = __hashish.new
  if (init_hash)
    _load(init_hash)
  end
  if (block)
    self.instance_exec(&block)
  end
end
validate_camel_style(style) click to toggle source

Validate requested camel style and return mapped value used internally

@param style [Symbol] @return [Symbol] @raises [ArgumentError]

# File lib/attribute_struct/attribute_struct.rb, line 47
def validate_camel_style(style)
  if (VALID_CAMEL_STYLES.has_key?(style))
    VALID_CAMEL_STYLES[style]
  else
    valid_types = VALID_CAMEL_STYLES.keys(&:inspect).join(", ")
    raise ArgumentError.new "Unsupported camel style provided " \
                            "`#{style.inspect}`! (Allowed: #{valid_types})"
  end
end

Public Instance Methods

[](key) click to toggle source

Direct data access

@param key [String, Symbol] @return [Object]

# File lib/attribute_struct/attribute_struct.rb, line 192
def [](key)
  _data[_process_key(key)]
end
__hashish() click to toggle source

@return [Class] hashish type available

# File lib/attribute_struct/attribute_struct.rb, line 478
def __hashish
  ::AttributeStruct::AttributeHash
end
_array(*args) click to toggle source

Create an Array and evaluate discovered AttributeStructs

@param args [Object] array contents @return [Array]

# File lib/attribute_struct/attribute_struct.rb, line 612
def _array(*args)
  args.map do |maybe_block|
    if (maybe_block.is_a?(::Proc))
      klass = _klass_new
      if (maybe_block.arity > 0)
        klass.instance_exec(klass, &maybe_block)
      else
        klass.instance_exec(&maybe_block)
      end
      klass
    else
      maybe_block
    end
  end
end
Also aliased as: array!
_build(&block) click to toggle source

Execute block within current context

@yield block to execute @return [Object]

# File lib/attribute_struct/attribute_struct.rb, line 123
def _build(&block)
  self.instance_exec(&block)
end
Also aliased as: build!
_camel_keys=(val) click to toggle source

Enable/disable camel keys

@param val [TrueClass, FalseClass] @return [TrueClass, FalseClass]

# File lib/attribute_struct/attribute_struct.rb, line 160
def _camel_keys=(val)
  _klass.load_the_camels if val
  @_camel_keys = !!val
end
_camel_keys_action() click to toggle source

@return [Symbol, NilClass] :auto_disable or :auto_enable

# File lib/attribute_struct/attribute_struct.rb, line 585
def _camel_keys_action
  @_camel_keys_set
end
_camel_keys_set(v) click to toggle source

Set custom rule for processed keys at this context level

@param v [Symbol] :auto_disable or :auto_enable @return [Symbol]

# File lib/attribute_struct/attribute_struct.rb, line 578
def _camel_keys_set(v)
  @_camel_keys_set = v
end
Also aliased as: camel_keys_set!
_camel_style=(val) click to toggle source

Set style of camel keys

@param val [Symbol] @return [Symbol]

# File lib/attribute_struct/attribute_struct.rb, line 169
def _camel_style=(val)
  @_camel_style = ::AttributeStruct.validate_camel_style(val)
end
_clone(_new_parent = nil) click to toggle source

@return [AttributeStruct] clone of current instance

# File lib/attribute_struct/attribute_struct.rb, line 674
def _clone(_new_parent = nil)
  _cloned_inst = _klass_new
  _cloned_inst._data.replace __hashish[
                               @table.map { |_key, _value|
                                 if (_key.is_a?(::AttributeStruct))
                                   _key = _key._clone
                                 else
                                   _key = _do_dup(_key)
                                 end
                                 if (_value.is_a?(::AttributeStruct))
                                   _value = _value._clone
                                 else
                                   _value = _do_dup(_value)
                                 end
                                 [_key, _value]
                               }
                             ]
  _cloned_inst._parent(_new_parent) if _new_parent
  _cloned_inst
end
Also aliased as: clone!
_data() click to toggle source

@return [AttributeStruct::AttributeHash, Mash] underlying struct data

# File lib/attribute_struct/attribute_struct.rb, line 369
def _data
  @table
end
Also aliased as: data!
_deep_copy(thing = nil) click to toggle source

Create a “deep” copy

@param thing [Object] struct to copy. defaults to self @return [Object] new instance

# File lib/attribute_struct/attribute_struct.rb, line 499
def _deep_copy(thing = nil)
  thing ||= _dump
  if (thing.is_a?(::Enumerable))
    val = thing.map { |v| v.is_a?(::Enumerable) ? _deep_copy(v) : _do_dup(v) }
  else
    val = _do_dup(thing)
  end
  if (thing.is_a?(::Hash))
    val = __hashish[*val.flatten(1)]
  end
  val
end
_delete(key) click to toggle source

Delete entry from struct

@param key [String, Symbol] @return [Object] value of entry

# File lib/attribute_struct/attribute_struct.rb, line 379
def _delete(key)
  _data.delete(_process_key(key))
end
Also aliased as: delete!
_do_dup(v) click to toggle source

Provide dup of instance

@param v [Object] @return [Object] duped instance @note if Symbol provided, String is returned

# File lib/attribute_struct/attribute_struct.rb, line 487
def _do_dup(v)
  begin
    v.dup
  rescue
    v.is_a?(::Symbol) ? v.to_s : v
  end
end
_dump() click to toggle source

@return [AttributeStruct::AttributeHash, Mash] dump struct to hashish

# File lib/attribute_struct/attribute_struct.rb, line 413
def _dump
  processed = @table.keys.map do |key|
    value = @table[key]
    val = _dump_unpacker(value)
    [_dump_unpacker(key), val] unless val == UNSET_VALUE
  end.compact
  __hashish[*processed.flatten(1)]
end
Also aliased as: dump!
_dump_unpacker(item) click to toggle source

Process and unpack items for dumping within deeply nested enumerable types

@param item [Object] @return [Object]

# File lib/attribute_struct/attribute_struct.rb, line 390
def _dump_unpacker(item)
  if (item.is_a?(::Enumerable))
    if (item.respond_to?(:keys))
      item.class[
        *item.map do |entry|
          _dump_unpacker(entry)
        end.flatten(1)
      ]
    else
      item.class[
        *item.map do |entry|
          _dump_unpacker(entry)
        end
      ]
    end
  elsif (item.is_a?(::AttributeStruct))
    item.nil? ? UNSET_VALUE : item._dump
  else
    item
  end
end
_kernelify() click to toggle source

Inject Kernel methods

@return [TrueClass]

# File lib/attribute_struct/attribute_struct.rb, line 651
def _kernelify
  unless (kernelified?)
    @_kernelified = true
    (::Kernel.public_instance_methods + ::Kernel.private_instance_methods).each do |m_name|
      self.instance_eval("def #{m_name}(*a, &b); ::Kernel.instance_method(:#{m_name}).bind(self).curry.call(*a, &b); end")
    end
  end
  true
end
Also aliased as: kernelify!
_keys() click to toggle source

@return [Array<String,Symbol>] keys within struct

# File lib/attribute_struct/attribute_struct.rb, line 362
def _keys
  _data.keys
end
Also aliased as: keys!
_klass() click to toggle source

@return [Class] this class

# File lib/attribute_struct/attribute_struct.rb, line 547
def _klass
  ::AttributeStruct
end
_klass_new(*args, &block) click to toggle source

@return [AttributeStruct] new struct instance @note will set self as parent and propogate camelizing status

# File lib/attribute_struct/attribute_struct.rb, line 561
def _klass_new(*args, &block)
  n = _klass.new(*args, &block)
  unless (_camel_keys_action == :auto_discovery)
    n._camel_keys_set(_camel_keys_action)
  end
  n._camel_keys = _camel_keys
  n._camel_style = _camel_style if _camel_style
  n._objectify if objectified?
  n._kernelify if kernelified?
  n._parent(self)
  n
end
_load(hashish) click to toggle source

Clear current struct data and replace

@param hashish [Hash] hashish type instance @return [self]

# File lib/attribute_struct/attribute_struct.rb, line 428
def _load(hashish)
  @table.clear
  if (_root._camel_keys_action == :auto_discovery)
    starts = hashish.keys.map { |k| k[0, 1] }
    unless (starts.detect { |k| k =~ /[A-Z]/ })
      _camel_keys_set(:auto_disable)
    else
      _camel_keys_set(:auto_enable) unless _parent.nil?
    end
  end
  hashish.each do |key, value|
    if (value.is_a?(::Enumerable))
      flat = value.map do |v|
        v.is_a?(::Hash) ? _klass_new(v) : v
      end
      value = value.is_a?(::Hash) ? __hashish[*flat.flatten(1)] : flat
    end
    if (value.is_a?(::Hash))
      self._set(key)._load(value)
    else
      self._set(key, value)
    end
  end
  self
end
Also aliased as: load!
_merge(overlay) click to toggle source

Perform deep merge

@param overlay [AttributeStruct] @return [AttributeStruct] newly merged instance

# File lib/attribute_struct/attribute_struct.rb, line 460
def _merge(overlay)
  source = _deep_copy
  dest = overlay._deep_copy
  result = source.deep_merge(dest)
  _klass_new(result)
end
_merge!(overlay) click to toggle source

Perform deep merge in place

@param overlay [AttributeStruct] @return [self]

# File lib/attribute_struct/attribute_struct.rb, line 471
def _merge!(overlay)
  result = _merge(overlay)._dump
  _load(result)
  self
end
_objectified_constant_lookup(konst) click to toggle source

Lookup constant in root namespace

@param konst [Symbol, String] @return [Object, NilClass]

# File lib/attribute_struct/attribute_struct.rb, line 642
def _objectified_constant_lookup(konst)
  if (konst.to_s[0].match(/[A-Z]/) && ::Object.const_defined?(konst))
    ::Object.const_get(konst)
  end
end
_objectify(enable = true) click to toggle source

Enable/disable root constant lookups

@param enable [TrueClass, FalseClass] @return [TrueClass, FalseClass]

# File lib/attribute_struct/attribute_struct.rb, line 177
def _objectify(enable = true)
  @_objectified = !!enable
end
Also aliased as: objectify!
_parent(obj = nil) click to toggle source

@return [AttributeStruct, NilClass] parent of this struct

# File lib/attribute_struct/attribute_struct.rb, line 590
def _parent(obj = nil)
  @_parent = obj if obj
  @_parent
end
Also aliased as: parent!
_process_key(key, *args) click to toggle source

Provide expected key format based on context

@param key [String, Symbol] @param args [Object] argument list (:force will force processing) @return [String, Symbol]

# File lib/attribute_struct/attribute_struct.rb, line 517
def _process_key(key, *args)
  if (key.is_a?(::String) || key.is_a?(::Symbol))
    key = ::CamelString.new(key.to_s)
    if (_camel_keys && _camel_keys_action && !key._hump_format_requested?)
      case _camel_keys_action
      when :auto_disable
        key._no_hump
      when :auto_enable
        key._hump
      end
    end
    if (_camel_keys && (key._camel? || args.include?(:force)))
      camel_args = [key]
      if (key._hump_style || _camel_style == :no_leading)
        unless (key._hump_style == :leading_hump)
          camel_args << false
        end
      end
      ::Bogo::Utility.camel(*camel_args)
    else
      key
    end
  else
    key
  end
end
Also aliased as: process_key!
_root() click to toggle source

@return [AttributeStruct, NilClass] root of the struct or nil if self is root

# File lib/attribute_struct/attribute_struct.rb, line 598
def _root
  r = self
  until (r._parent == nil)
    r = r._parent
  end
  r
end
Also aliased as: root!
_set(key, val = UNSET_VALUE, &block) click to toggle source

Directly set value into struct. Useful when the key is not valid ruby syntax for a method

@param key [String, Symbol] @param val [Object] @yield block to execute within context @return [Object]

# File lib/attribute_struct/attribute_struct.rb, line 203
def _set(key, val = UNSET_VALUE, &block)
  if (val != UNSET_VALUE)
    self.method_missing(key, val, &block)
  else
    self.method_missing(key, &block)
  end
end
Also aliased as: set!
_set_state(args = {}) click to toggle source

Set state into current context

@param args [Hashish] hashish type holding data for context @return [Hashish]

# File lib/attribute_struct/attribute_struct.rb, line 133
def _set_state(args = {})
  _arg_state.merge!(args)
end
Also aliased as: set_state!
_state(key, traverse = true) click to toggle source

Value of requested state

@param key [Symbol, String] @param traverse [TrueClass, FalseClass] traverse towards root for matching key @return [Object, NilClass]

# File lib/attribute_struct/attribute_struct.rb, line 144
def _state(key, traverse = true)
  if (_arg_state.has_key?(key))
    _arg_state[key]
  else
    if (traverse && _parent)
      _parent._state(key)
    end
  end
end
Also aliased as: state!
array!(*args)
Alias for: _array
build!(&block)
Alias for: _build
camel_keys_set!(v)
Alias for: _camel_keys_set
class()
Alias for: klass!
class!()
Alias for: klass!
clone!(_new_parent = nil)
Alias for: _clone
data!()
Alias for: _data
delete!(key)
Alias for: _delete
dump!()
Alias for: _dump
has_key?(key)
Alias for: key?
hash() click to toggle source

@return [Numeric]

# File lib/attribute_struct/attribute_struct.rb, line 669
def hash
  ::Kernel.instance_method(:hash).bind(self).curry.call
end
is_a?(klass) click to toggle source

Determine if self is a class

@param klass [Class] @return [TrueClass, FalseClass]

# File lib/attribute_struct/attribute_struct.rb, line 345
def is_a?(klass)
  (_klass.ancestors + [::AttributeStruct]).include?(klass)
end
Also aliased as: kind_of?
kernelified?() click to toggle source

@return [TrueClass, FalseClass] Kernel methods have been injected

# File lib/attribute_struct/attribute_struct.rb, line 664
def kernelified?
  !!@_kernelified
end
kernelify!()
Alias for: _kernelify
key?(key) click to toggle source

Check if key exists within struct

@param key [String, Symbol] @return [TrueClass, FalseClass]

# File lib/attribute_struct/attribute_struct.rb, line 355
def key?(key)
  self._keys.include?(_process_key(key))
end
Also aliased as: has_key?
keys!()
Alias for: _keys
kind_of?(klass)
Alias for: is_a?
klass!() click to toggle source

@return [Class] this clas

# File lib/attribute_struct/attribute_struct.rb, line 552
def klass!
  _klass
end
Also aliased as: class!, class
load!(hashish)
Alias for: _load
method_missing(_sym, *_args, &_block) click to toggle source

Provides struct DSL behavior

@param sym [Symbol, String] method name @param args [Object] argument list @yield provided block @return [Object] existing value or newly set value @note Dragons and unicorns all over in here

# File lib/attribute_struct/attribute_struct.rb, line 220
def method_missing(_sym, *_args, &_block)
  if (objectified? && _args.empty? && _block.nil?)
    _o_lookup = _objectified_constant_lookup(_sym)
    return _o_lookup if _o_lookup
  end
  if (_sym.is_a?(::String) || _sym.is_a?(::Symbol))
    if ((_s = _sym.to_s).end_with?("="))
      _s.slice!(-1, _s.length)
      _sym = _s
    end
    _sym = _process_key(_sym)
  end
  if (!_args.empty? || _block)
    if (_args.empty? && _block)
      _base = @table.fetch(_sym, UNSET_VALUE)
      if (_state(:value_collapse) && !_base.is_a?(self.class!))
        _orig = _base
        _base = _klass_new
      else
        unless (_base.is_a?(self.class!))
          _base = _klass_new
        end
      end
      @table[_sym] = _base
      if (_block.arity == 0)
        _base.instance_exec(&_block)
      else
        _base.instance_exec(_base, &_block)
      end
      if (_orig.is_a?(::NilClass))
        @table[_sym] = _base
      else
        if (_orig == UNSET_VALUE)
          @table[_sym] = _base
        else
          unless (_orig.is_a?(CollapseArray))
            _orig = CollapseArray.new.push(_orig)
          end
          _orig << _base
          @table[_sym] = _orig
        end
      end
    elsif (!_args.empty? && _block)
      _result = _leaf = _base = @table.fetch(_sym, _klass_new)
      @table[_sym] = _result

      _args.flatten.each do |_arg|
        _leaf = _base[_arg]
        unless (_leaf.is_a?(_klass))
          _leaf = _klass_new
          _base._set(_arg, _leaf)
          _base = _leaf
        end
      end
      if (!_leaf.nil? && _state(:value_collapse))
        _orig = _leaf
        _leaf = _orig.parent._klass_new
      end
      _block.arity == 0 ? _leaf._build(&_block) : _leaf._build(_leaf, &_block)
      if (_orig)
        unless (_orig.is_a?(CollapseArray))
          _orig = CollapseArray.new.push(_orig)
        end
        _orig << _leaf
      else
        _orig = _leaf
      end
    else
      if (_args.size > 1 && _args.all? { |_i| _i.is_a?(::String) || _i.is_a?(::Symbol) } && !_state(:value_collapse))
        @table[_sym] = _klass_new unless @table[_sym].is_a?(_klass)
        _endpoint = _args.inject(@table[_sym]) do |_memo, _k|
          unless (_memo[_k].is_a?(_klass))
            _memo._set(_k, _klass_new)
          end
          _memo[_k]
        end
        return _endpoint # custom break out
      else
        if (_args.size > 1)
          _val = _args.map do |_v|
            if (_v.is_a?(::Hash) && _state(:hash_load_struct))
              _val = _klass_new
              _val._load(_v)
            else
              _v
            end
          end
        else
          if (_args.first.is_a?(::Hash) && _state(:hash_load_struct))
            _val = _klass_new
            _val._load(_args.first)
          else
            _val = _args.first
          end
        end
        if (_state(:value_collapse) && !(_leaf = @table[_sym]).nil?)
          unless (_leaf.is_a?(CollapseArray))
            _leaf = CollapseArray.new.push(_leaf)
          end
          _leaf << _val
          @table[_sym] = _leaf
        else
          @table[_sym] = _val
        end
      end
    end
  end
  @table[_sym] = _klass_new if @table[_sym].nil? && !@table[_sym].is_a?(_klass)
  @table[_sym]
end
nil?() click to toggle source

@return [TrueClass, FalseClass] struct is nil (empty data)

# File lib/attribute_struct/attribute_struct.rb, line 332
def nil?
  _data.empty?
end
objectified?() click to toggle source

@return [TrueClass, FalseClass]

# File lib/attribute_struct/attribute_struct.rb, line 184
def objectified?
  @_objectified
end
objectify!(enable = true)
Alias for: _objectify
parent!(obj = nil)
Alias for: _parent
present?() click to toggle source

@return [TrueClass, FalseClass] struct is present (not empty)

# File lib/attribute_struct/attribute_struct.rb, line 337
def present?
  !nil?
end
process_key!(key, *args)
Alias for: _process_key
respond_to?(name) click to toggle source

Instance responds to method name

@param name [Symbol, String] @return [TrueClass, FalseClass]

# File lib/attribute_struct/attribute_struct.rb, line 634
def respond_to?(name)
  _klass.instance_methods.map(&:to_sym).include?(name.to_sym)
end
root!()
Alias for: _root
set!(key, val = UNSET_VALUE, &block)
Alias for: _set
set_state!(args = {})
Alias for: _set_state
state!(key, traverse = true)
Alias for: _state