class BinData::LazyEvaluator

field instead of obj.field.
This resolution process makes the lambda easier to read as we just write
a lambda or a symbol.
An evaluation will recurse until it returns a result that is not
resolution propagates up the chain of parent data objects.
in #parameters, and secondly as methods in this parent. This
parent of the bound data object. Resolution is attempted firstly as keys
When evaluating lambdas, unknown methods are resolved in the context of the
As a shortcut, :foo is the equivalent of lambda { foo }.
BinData::String.new(:value => lambda { %w{a test message}.join(“ ”) })
are those that are passed to data objects as parameters, e.g.:
lambdas in the context of this data object. These lambdas
A LazyEvaluator is bound to a data object. The evaluator will evaluate

def eval_symbol_in_parent_context(symbol, args)

def eval_symbol_in_parent_context(symbol, args)
  result = resolve_symbol_in_parent_context(symbol, args)
  recursively_eval(result, args)
end

def index

array.
Returns the index of this data object inside it's nearest container
def index
  return @overrides[:index] if @overrides and @overrides.has_key?(:index)
  child = @obj
  parent = @obj.parent
  while parent
    if parent.respond_to?(:find_index_of)
      return parent.find_index_of(child)
    end
    child = parent
    parent = parent.parent
  end
  raise NoMethodError, "no index found"
end

def initialize(obj)

context of +obj+.
Creates a new evaluator. All lazy evaluation is performed in the
def initialize(obj)
  @obj = obj
end

def lazy_eval(val, overrides = nil)

def lazy_eval(val, overrides = nil)
  @overrides = overrides if overrides
  if val.is_a? Symbol
    __send__(val)
  elsif val.respond_to? :arity
    instance_exec(&val)
  else
    val
  end
end

def method_missing(symbol, *args)

def method_missing(symbol, *args)
  return @overrides[symbol] if defined? @overrides and @overrides.has_key?(symbol)
  if @obj.parent
    eval_symbol_in_parent_context(symbol, args)
  else
    super
  end
end

def parent

Returns a LazyEvaluator for the parent of this data object.
def parent
  if @obj.parent
    @obj.parent.lazy_evaluator
  else
    nil
  end
end

def recursively_eval(val, args)

def recursively_eval(val, args)
  if val.is_a?(Symbol)
    parent.__send__(val, *args)
  elsif val.respond_to?(:arity)
    parent.instance_exec(&val)
  else
    val
  end
end

def resolve_symbol_in_parent_context(symbol, args)

def resolve_symbol_in_parent_context(symbol, args)
  obj_parent = @obj.parent
  if obj_parent.has_parameter?(symbol)
    obj_parent.get_parameter(symbol)
  elsif obj_parent.safe_respond_to?(symbol, true)
    obj_parent.__send__(symbol, *args)
  else
    symbol
  end
end