From: Mark Hubbart Date: 2005-08-19T17:07:26+09:00 Subject: Re: #puts inside ERB On 8/18/05, Gavin Kistner wrote: > On Aug 18, 2005, at 8:47 AM, Gavin Kistner wrote: > > How would I patch ERB so that puts and print were aliased to > > concatenate onto the current eoutvar? This aliasing should be setup > > at the beginning of #result, and removed at the end of #result. > > Here's my horrific hack that does it. It's particularly hacky because > it requires that the 'eoutvar' be set to have a @ at the beginning of > the name (an instance variable). The real solution I suppose requires > a change to the ERB::Compiler#compile method, to replace calls to > puts and print with the local variable concatenation inline. But that > was beyond my foo. How about this? Still somewhat hacky, but maybe less breakable. It should work unless you supply a binding in the Kernel module context; the new #puts is defined in Object. ----- require 'erb' class Object # Object's puts overrides Kernel's. # Use a thread-local default output if available. def puts(*args) if Thread.current[:default_output] Thread.current[:default_output].puts(*args) else super end end # Probably should do the same with Kernel#print, #p, etc. end # This module turns concatenationability (<<) into writability. # We'll use it on the eoutvar to let it be used as an IO, too. module Writeable def write(other) self << other other.size end def puts(*other) other.each{|o| self << (o[-1] == ?\n ? o : o + "\n") } nil end def print(other) self << other nil end end class ERB def set_eoutvar(compiler, eoutvar = '_erbout') compiler.put_cmd = "#{eoutvar}.concat" cmd = [] cmd.push "#{eoutvar} = ''" cmd.push "#{eoutvar}.extend Writeable" cmd.push "Thread.current[:default_output] = #{eoutvar}" compiler.pre_cmd = cmd cmd = [] cmd.push "Thread.current[:default_output] = nil" cmd.push(eoutvar) compiler.post_cmd = cmd end end