class Meander::Mutable

This class is a mutable version of Meander::Plain

All keys you alter will be keep up to date if dependend objects updated

Usage

Nesting value updates

a = {}
m = Meander::Mutable.new(a)
a['key'] = 1
m.key       # => 1

Value overloading

a = {}
m = Meander::Mutable.new(a)
m.key = 1
m.key       # => 1
a           # => {}

Deep value overloading

a = {a: {b: {c: 1}}}
m = Meander::Mutable.new(a)
m.a.b.merge!({d: 2})
m.a.b.c     # => 1
m.a.b.d     # => 2
a           # => {a: {b: {c: 1}}}
a[:a][:b][:c] = 3
m.a.b.c     # => 3

Notice

Meander::Mutable support multiple object references

a = {a: 1}
m = Meander::Mutable.new(a)
b = {b: 2}
m.merge!(b)
a[:a] = 3
b[:b] = 4
m.a # => 3  # Value is up to date
m.b # => 4  # This value is also up to date

You can also initialize Meander::Mutable with multiple nested hashes

a = {a: 1}
b = {b: 2}
m = Meander::Mutable.new(a, b)
a[:a] = 3
b[:b] = 4
m.a # => 3  # Value is up to date
m.b # => 4  # This value is also up to date

Public Class Methods

new(required = {}, *args) click to toggle source
# File lib/meander/mutable.rb, line 61
def initialize(required = {}, *args)
  __setobj__(required, *args)
  @own_keys = self.class.own_keys_cover_class.new
end
own_keys_cover_class() click to toggle source
# File lib/meander/mutable.rb, line 54
def self.own_keys_cover_class
  klass = self
  @own_keys_cover_class ||= Class.new(Plain) do
    self.cover_class = klass
  end
end

Public Instance Methods

[](key) click to toggle source
# File lib/meander/mutable.rb, line 99
def [](key)
  val = nil
  if @own_keys.key? key
    val = @own_keys[key]
  else
    val = get_delegated_value(key)
    if val.is_a?(Hash)
      val = self.class.new(val)
      self[key] = val
    end
  end
  val
end
__getobj__() click to toggle source
# File lib/meander/mutable.rb, line 66
def __getobj__
  @delegate
end
__setobj__(*args) click to toggle source
# File lib/meander/mutable.rb, line 70
def __setobj__(*args)
  @delegate = []
  @delegate += args
  @delegate
end
dup() click to toggle source
# File lib/meander/mutable.rb, line 85
def dup
  self.class.new(*__getobj__)
end
each(*args, &block) click to toggle source
# File lib/meander/mutable.rb, line 89
def each(*args, &block)
  return enum_for(:each) unless block_given?

  deep_call.each { |i| i.each(*args, &block) }
end
is_a?(klass)
Alias for: kind_of?
key?(key) click to toggle source
# File lib/meander/mutable.rb, line 81
def key?(key)
  @own_keys.key?(key) || delegated_key?(key)
end
keys() click to toggle source
# File lib/meander/mutable.rb, line 95
def keys
  map { |k, _| convert_key(k) }
end
kind_of?(klass) click to toggle source
# File lib/meander/mutable.rb, line 127
def kind_of?(klass)
  (self.class.cover_class == klass) || __getobj__.all?(klass)
end
Also aliased as: is_a?
merge!(hsh) click to toggle source
# File lib/meander/mutable.rb, line 76
def merge!(hsh)
  @delegate ||= []
  @delegate.unshift hsh
end
method_missing(method_name, *args, &block) click to toggle source
Calls superclass method
# File lib/meander/mutable.rb, line 117
def method_missing(method_name, *args, &block)
  if @own_keys.respond_to?(method_name) || block_given?
    @own_keys.send method_name, *args, &block
  elsif delegated_key?(method_name)
    self[method_name]
  else
    super
  end
end
respond_to_missing?(method_name, include_private = false) click to toggle source
Calls superclass method
# File lib/meander/mutable.rb, line 113
def respond_to_missing?(method_name, include_private = false)
  @own_keys.respond_to?(method_name) || delegated_key?(method_name) || super
end

Private Instance Methods

deep_call(origin: self) click to toggle source
# File lib/meander/mutable.rb, line 138
def deep_call(origin: self)
  stack = []
  if origin.is_a?(Array)
    stack.unshift(*origin)
    origin = stack.pop
  end
  Enumerator.new do |yielder|
    while origin
      own_keys = origin.instance_variable_get(:@own_keys)
      if own_keys
        yielder.yield own_keys
        stack.unshift(*origin.__getobj__)
        origin = stack.pop
      else
        yielder.yield origin
        origin = stack.empty? ? nil : stack.pop
      end
    end
    self
  end
end
delegated_key?(key) click to toggle source
# File lib/meander/mutable.rb, line 160
def delegated_key?(key)
  key = convert_key(key)
  deep_call(origin: __getobj__).any? do |i|
    i.keys.any? { |k| convert_key(k) == key }
  end
end
get_delegated_value(key) click to toggle source
# File lib/meander/mutable.rb, line 167
def get_delegated_value(key)
  value = nil
  key = convert_key(key)
  deep_call(origin: __getobj__).detect do |i|
    i.keys.any? { |k| convert_key(k) == key && value = i[k] }
  end
  value
end