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_contextObject



58
59
60
61
62
63
64
65
# File 'lib/babl/builder/chain_builder.rb', line 58

def construct_context
    wrap { |bound|
        new_context = yield(bound.context)
        next bound if bound.context.equal?(new_context)

        BoundOperator.new(new_context, &bound.scope)
    }
end

#construct_nodeObject

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



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

def construct_node
    wrap { |bound|
        BoundOperator.new(bound.context) { |node| bound.scope[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
49
# 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, &:itself)).scope.call(node)
end

#wrapObject



67
68
69
# File 'lib/babl/builder/chain_builder.rb', line 67

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