Class: Babl::Builder::ChainBuilder

Inherits:
Object
  • Object
show all
Defined in:
lib/babl/builder/chain_builder.rb

Overview

Builder provides a simple framework for defining & chaining BABL’s operators easily.

Compiling a template is a multi-phase process:

1- [BABL => ChainBuilder] Template definition (via Builder#construct_node & Builder#construct_terminal) :

The operator chain is created by wrapping blocks (current block stored in 'scope')

2- [Builder => BoundOperator] Template binding (via Builder#bind) :

A BoundOperator is created for each operator and passed to the next, in left-to-right
order. This step is necessary to propagate context from root to leaves. A typical
use-case is the 'enter' operator, which requires the parent context in which it is called.

3- [BoundOperator => Node] Node precompilation (via Builder#precompile):

BoundOperators are transformed into a Node tree, in right-to-left order. Each node
contains its own rendering logic, dependency tracking & documentation generator.

4- [Node => CompiledTemplate] Compilation output: (via Template#compile):

The resulting Node is used to compute the dependencies & generate the documentation.
Finally, we pack everything is a CompiledTemplate which is exposed to the user.

Instance Method Summary collapse

Constructor Details

#initialize(&block) ⇒ ChainBuilder

Returns a new instance of ChainBuilder.



28
29
30
# File 'lib/babl/builder/chain_builder.rb', line 28

def initialize(&block)
    @scope = block
end

Instance Method Details

#bind(bound) ⇒ Object



36
37
38
# File 'lib/babl/builder/chain_builder.rb', line 36

def bind(bound)
    @scope[bound]
end

#construct_node(**new_context) ⇒ Object

Append an operator to the chain, and return a new Builder object



51
52
53
54
55
56
57
# File 'lib/babl/builder/chain_builder.rb', line 51

def construct_node(**new_context)
    wrap { |bound|
        bound.nest(bound.context.merge(new_context)) { |node|
            yield(node, bound.context)
        }
    }
end

#construct_terminalObject

Append a terminal operator, and return a new Builder object



41
42
43
44
45
46
47
48
# File 'lib/babl/builder/chain_builder.rb', line 41

def construct_terminal
    construct_node do |node, context|
        unless [Nodes::InternalValue.instance, Nodes::TerminalValue.instance].include?(node)
            raise Errors::InvalidTemplate, 'Chaining is not allowed after a terminal operator'
        end
        yield context
    end
end

#precompile(node, **context) ⇒ Object



32
33
34
# File 'lib/babl/builder/chain_builder.rb', line 32

def precompile(node, **context)
    bind(BoundOperator.new(context)).precompile(node)
end

#wrapObject



59
60
61
# File 'lib/babl/builder/chain_builder.rb', line 59

def wrap
    self.class.new { |bound| yield bind(bound) }
end