class BinData::LazyEvaluator

A LazyEvaluator is bound to a data object. The evaluator will evaluate lambdas in the context of this data object. These lambdas are those that are passed to data objects as parameters, e.g.:

BinData::String.new(:value => lambda { %w{a test message}.join(" ") })

As a shortcut, :foo is the equivalent of lambda { foo }.

When evaluating lambdas, unknown methods are resolved in the context of the parent of the bound data object. Resolution is attempted firstly as keys in parameters, and secondly as methods in this parent. This resolution propagates up the chain of parent data objects.

An evaluation will recurse until it returns a result that is not a lambda or a symbol.

This resolution process makes the lambda easier to read as we just write field instead of obj.field.

Public Class Methods

new(obj) click to toggle source

Creates a new evaluator. All lazy evaluation is performed in the context of obj.

# File lib/bindata/lazy.rb, line 24
def initialize(obj)
  @obj = obj
end

Public Instance Methods

index() click to toggle source

Returns the index of this data object inside it's nearest container array.

# File lib/bindata/lazy.rb, line 50
def index
  return @overrides[:index] if defined? @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
lazy_eval(val, overrides = nil) click to toggle source
# File lib/bindata/lazy.rb, line 28
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
method_missing(symbol, *args) click to toggle source
Calls superclass method
# File lib/bindata/lazy.rb, line 65
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
parent() click to toggle source

Returns a LazyEvaluator for the parent of this data object.

# File lib/bindata/lazy.rb, line 40
def parent
  if @obj.parent
    @obj.parent.lazy_evaluator
  else
    nil
  end
end

Private Instance Methods

eval_symbol_in_parent_context(symbol, args) click to toggle source
# File lib/bindata/lazy.rb, line 78
def eval_symbol_in_parent_context(symbol, args)
  result = resolve_symbol_in_parent_context(symbol, args)
  recursively_eval(result, args)
end
recursively_eval(val, args) click to toggle source
# File lib/bindata/lazy.rb, line 95
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
resolve_symbol_in_parent_context(symbol, args) click to toggle source
# File lib/bindata/lazy.rb, line 83
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