Class: BinData::LazyEvaluator

Inherits:
Object
  • Object
show all
Defined in:
lib/bindata/lazy.rb

Overview

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.

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(obj, overrides = {}) ⇒ LazyEvaluator

Creates a new evaluator. All lazy evaluation is performed in the context of obj. overrides is an optional obj.parameters like hash.



45
46
47
48
# File 'lib/bindata/lazy.rb', line 45

def initialize(obj, overrides = {})
  @obj = obj
  @overrides = overrides
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(symbol, *args) ⇒ Object



86
87
88
89
90
91
92
93
94
# File 'lib/bindata/lazy.rb', line 86

def method_missing(symbol, *args)
  return @overrides[symbol] if @overrides.has_key?(symbol)

  if @obj.parent
    eval_symbol_in_parent_context(symbol, args)
  else
    super
  end
end

Class Method Details

.eval(obj, val, overrides = {}) ⇒ Object

Lazily evaluates val in the context of obj, with possibility of overrides.



25
26
27
28
29
30
31
32
# File 'lib/bindata/lazy.rb', line 25

def eval(obj, val, overrides = {})
  if can_eval?(val)
    env = self.new(obj, overrides)
    env.lazy_eval(val)
  else
    val
  end
end

Instance Method Details

#indexObject

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

Raises:

  • (NoMethodError)


71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/bindata/lazy.rb', line 71

def index
  return @overrides[:index] if @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) ⇒ Object



50
51
52
53
54
55
56
57
58
# File 'lib/bindata/lazy.rb', line 50

def lazy_eval(val)
  if val.is_a? Symbol
    __send__(val)
  elsif val.respond_to? :arity
    instance_eval(&val)
  else
    val
  end
end

#parentObject

Returns a LazyEvaluator for the parent of this data object.



61
62
63
64
65
66
67
# File 'lib/bindata/lazy.rb', line 61

def parent
  if @obj.parent
    LazyEvaluator.new(@obj.parent)
  else
    nil
  end
end