class Eggshell::Bundles::Basic::ControlLoopMacros

Provides iteration and conditional functionality.

Public Instance Methods

chain_type(name) click to toggle source
# File lib/eggshell/bundles/basics.rb, line 823
def chain_type(name)
        if name == 'if'
                return [MH::CHAIN_START, name]
        elsif name == 'elsif'
                return [MH::CHAIN_CONTINUE, 'if']
        elsif name == 'else'
                return [MH::CHAIN_END, 'if']
        end
        
        [MH::CHAIN_NONE, nil]
end
process(name, args, lines, out, call_depth = 0) click to toggle source
# File lib/eggshell/bundles/basics.rb, line 835
def process(name, args, lines, out, call_depth = 0)
        macname = name.to_sym
        st = @state[call_depth]
        if !@state[call_depth]
                st = {:type => macname}

                @state[call_depth] = st
                # erase nested state
                @state[call_depth+1] = nil
        end

        p0 = args[0]
        if macname == :for || macname == :loop || macname == :while
                p1 = args[1] || 'raw'

                looper = nil
                loop_is_map = false

                if macname == :while
                        if p0
                                looper = WhileLoopWrapper.new(@eggshell, p0)
                        end
                else
                        p0 ||= 'true'
                        st[:iter] = p0['items'] || nil
                        st[:item] = p0['item'] || 'item'
                        st[:var] = p0['var']
                        st[:start] = p0['start']
                        st[:stop] = p0['stop']
                        st[:step] = p0['step'] || 1
                        st[:counter] = p0['counter'] || 'counter'

                        if st[:iter].is_a?(Array)
                                if st[:iter][0].is_a?(Symbol)
                                        st[:iter] = @eggshell.expr_eval(st[:iter])
                                end

                                st[:start] = 0 if !st[:start]
                                st[:stop] = st[:iter].length - 1 if !st[:stop]
                                st[:step] = 1 if !st[:step]
                                looper = Range.new(st[:start], st[:stop]).step(st[:step]).to_a
                        elsif st[:iter].respond_to?(:each)
                                looper = st[:iter]
                                loop_is_map = true
                        end
                end

                collector = out
                raw = p1 == 'raw'

                if looper
                        counter = -1
                        looper.each do |i1, i2|
                                counter += 1
                                break if @eggshell.vars[:loop_max_limit] == counter
                                # for maps, use key as the counter
                                val = nil
                                if loop_is_map
                                        @eggshell.vars[st[:counter]] = i1
                                        val = i2
                                else
                                        val = st[:iter][i1]
                                        @eggshell.vars[st[:counter]] = counter
                                end

                                # inject value into :item -- if it's an expression, evaluate first
                                iter_item = val.is_a?(Array) && val[0].is_a?(Symbol) ? @eggshell.expr_eval(val) : val
                                @eggshell.vars[st[:item]] = iter_item

                                # if doing raw, pass through block lines with variable expansion. preserve object type (e.g. Line or String);
                                # sub-macros will get passed collector var as output to assemble().
                                # otherwise, call assemble() on all lines
                                if raw
                                        lines.each do |unit|
                                                if unit.is_a?(Array)
                                                        if unit[0] == :block
                                                                unit[Eggshell::ParseTree::IDX_LINES].each do |line|
                                                                        nline = line
                                                                        if line.is_a?(String)
                                                                                nline = @eggshell.expand_expr(line)
                                                                        else
                                                                                # rather than expand_expr on raw, assume line.line is a subset of line.raw
                                                                                _raw = line.raw
                                                                                _line = @eggshell.expand_expr(line.line)
                                                                                _raw = _raw.gsub(line.line, _line) if _raw
                                                                                nline = line.replace(_line, _raw)
                                                                        end
                                                                        collector << nline
                                                                end
                                                        else
                                                                @eggshell.assemble([unit], call_depth + 1, {:out => collector})
                                                        end
                                                else
                                                        collector << @eggshell.expand_expr(line.to_s)
                                                end
                                        end
                                else
                                        collector << @eggshell.assemble(lines, call_depth + 1)
                                end

                                break if st[:break]
                        end
                end
                
                # clear state
                @state[call_depth] = nil
        # elsif macname == :while
        #    raw = args[1]
        #    while @eggshell.expr_eval(p0)
        #            process_lines(lines, buffer, depth + 1, raw)
        #            break if st[:break]
        #    end
        elsif macname == :if || macname == :elsif || macname == :else
                cond = p0
                st[:if] = true if macname == :if
                if st[:cond_count] == nil || macname == :if
                        st[:cond_count] = 0 
                        st[:cond_eval] = false
                        st[:cond_met] = false
                end

                last_action = st[:last_action]
                st[:last_action] = macname

                # @todo more checks (e.g. no elsif after else, no multiple else, etc.)
                if !st[:if] || (macname != :else && !cond)
                        # @todo exception?
                        return
                end

                if macname != :else
                        if !st[:cond_eval]
                                #cond_struct = Eggshell::ExpressionEvaluator.struct(cond)
                                st[:cond_eval] = @eggshell.expr_eval(cond)
                                #puts "#{cond.inspect} => #{st[:cond_eval]}"
                        end
                else
                        st[:cond_eval] = true
                end

                if st[:cond_eval] && !st[:cond_met]
                        st[:cond_met] = true
                        #process_lines(lines, buffer, depth + 1)
                        @eggshell.assemble(lines, call_depth + 1, {:out => out})
                end
        elsif macname == :break
                lvl = p0 || 1
                i = call_depth - 1

                # set breaks at each found loop until # of levels reached
                while i >= 0
                        st = @state[i]
                        i -= 1
                        next if !st
                        if st[:type] == :for || st[:type] == :while || st[:type] == :loop
                                lvl -= 1
                                st[:break] = true
                                break if lvl <= 0
                        end
                end
        elsif macname == :next
                lvl = p0 || 1
                i = call_depth - 1

                # set breaks at each found loop until # of levels reached
                while i >= 0
                        st = @state[i]
                        i -= 1
                        next if !st
                        if st[:type] == :for || st[:type] == :while || st[:type] == :loop
                                lvl -= 1
                                st[:next] = true
                                break if lvl <= 0
                        end
                end
        end
end
set_processor(proc, opts = nil) click to toggle source

pre. @if(“expression”) {} @elsif(“expression”) {} else {}

#! modes: #! 'raw' (default): collects all generated lines as raw (unless there are sub-macros, which would just collect the output as as-is) #! 'eval': evaluates each unit via Eggshell::Processor.assemble #! note that interpolated expressions are expanded in raw mode # @for({'start': 0, 'stop': var, 'step': 1, 'items': …, 'item': 'varname', 'counter': 'varname'}[, mode])

# File lib/eggshell/bundles/basics.rb, line 811
def set_processor(proc, opts = nil)
        opts = {} if !opts
        @opts = opts
        @eggshell = proc
        @eggshell.add_macro_handler(self, *%w(if elsif else loop for while break next))
        @vars = @eggshell.vars
        @eggshell.vars[:loop_max_limit] = 1000

        @state = []
        # @todo set loop limits from opts or defaults
end