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