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: -> { %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
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
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) && @overrides.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
# 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 callable?(val) instance_exec(&val) else val end end
# File lib/bindata/lazy.rb, line 65 def method_missing(symbol, *args) return @overrides[symbol] if defined?(@overrides) && @overrides.key?(symbol) if @obj.parent eval_symbol_in_parent_context(symbol, args) else super end end
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
# File lib/bindata/lazy.rb, line 105 def callable?(obj) Proc === obj || Method === obj || UnboundMethod === obj end
# 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
# File lib/bindata/lazy.rb, line 95 def recursively_eval(val, args) if val.is_a?(Symbol) parent.__send__(val, *args) elsif callable?(val) parent.instance_exec(&val) else val end end
# 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