class Writer def initialize(out) @out = out @level = 0 @indent = ' ' * 2 end def indent(&b) @level += 1 if b yield dedent end end def dedent @level -= 1 end def puts(s) @out.puts (@indent * @level) + s end def block(start, finish) puts start if start indent yield dedent puts finish if finish end def finish_if_block(rtn) if rtn.is_a?(Hash) && rtn.key?(:type) if rtn[:type] == :else_if puts "elif #{rtn[:cond]}\nthen" indent new_rtn = rtn[:block].call dedent finish_if_block new_rtn elsif rtn[:type] == :else puts "else" indent rtn[:block].call dedent puts 'fi' end else puts 'fi' end end def else_if_block(cond, &b) {:type => :else_if, :cond => cond, :block => b} end def else_block(&b) {:type => :else, :block => b} end def if_block(cond, &b) puts "if #{cond}\nthen" indent rtn = yield dedent finish_if_block rtn end end w = Writer.new($stdout) w.if_block 'x=1' do w.puts 'blah' end w.puts '' # works, but kinda sucks to read w.if_block 'x == 1' do w.puts 'x is 1' w.else_if_block 'x == 2' do w.puts 'x is 2' w.else_if_block 'x == 3' do w.puts 'x is 3' w.else_block do w.puts 'fuck knows.' end end end end # this would be better # if false # w.if_block 'x == 1' { # w.puts 'x is 1' # }.elsif_block 'x == 2' { # w.puts 'x is 2' # }.else_block { # w.puts 'fuck knows.' # } # end # but this would require either delaying the output somehow until we # figured out if there was a subsquent call or having a terminator, # which is an easy solution, but kinda leaky: # if false # w.if_block 'x == 1' { # w.puts 'x is 1' # }.elsif_block 'x == 2' { # w.puts 'x is 2' # }.else_block { # w.puts 'fuck knows.' # }.fi # end # hmmm, some sort of invoking call might fix it # def test(x) # puts x.inspect # end # w.if_block w.if_clause('x == 1') { # w.puts 'x is 1' # }.else_clause { # w.puts 'who knows.' # } class Writer class IfBlock attr_accessor :if_b, :else_if_bs, :else_b def initialize @if_b = nil @else_if_bs = [] @else_b = nil end def if(cond, &b) @if_b = [cond, b] self end def else_if(cond, &b) @else_if_bs << [cond, b] self end def else(&b) @else_b = b self end end def if_block_2 block = IfBlock.new yield block puts "if #{block.if_b[0]}\nthen" indent do block.if_b[1].call end block.else_if_bs.each do |else_if_b| puts "elif #{else_if_b[0]}\nthen" indent do else_if_b[1].call end end if block.else_b puts "else" indent do block.else_b.call end end puts "fi" end end # maybe this: puts "\n\nhere:\n" w.if_block_2 do |block| block.if 'x == 1' do w.puts 'x is 1' end block.else_if 'x == 2' do w.puts 'x is 2' end block.else_if 'x == 3' do w.puts 'x is 3' end block.else do w.puts 'fuck knows' end end # or this: puts "\n\nthere:\n" w.if_block_2 do |block| block.if('x == 1') { w.puts 'x is 1' }.else_if('x == 2') { w.puts 'x is 2' }.else_if('x == 3') { w.puts 'x is 3' }.else { w.puts 'fuck knows' } end w.if_block_2 do if_ 'x == 1' do w.puts 'x is 1' end elsif_ 'x == 2' do w.puts 'x is 2' end elsif_ 'x == 3' do w.puts 'x is 3' end else_ do w.puts 'fuck knows' end end class Writer def function(name) puts "#{ name } ()\n{" indent do yield end puts "}" end end w.function "f" do w.puts "echo 'BLAH'" end