From: Chris Pine Date: 2002-12-31T03:13:18+09:00 Subject: Re: capturing puts in mod_ruby Well, I figured it out. Just in case anyone is interested, here is the complete code I'm using. This executes the code in the ``code'' parameter (a string), supplying the strings in the ``input'' array as user input when requested, and it returns the output in a string. (The variable ``@@INPUT'' is just a string I am using to help me to distinguish output from echoed input.) The idea was to create a sufficiently robust execution environment for running code samples and showing what those code samples do if run on the command line. (Of course, "sufficiently" is a moving target... or maybe a shrinking target.) I wanted as few side-effects as possible (since I'm running this in mod_ruby). Aside from a tutorial, I think this might be nice to incorporate into a ruby-based wiki... but I don't know much about $SAFE levels and all that. It's my dream that someday we'll have a wiki-based documentation of the built-in classes and standard libraries, along with live code examples, so that we can all help to keep the docs up-to-date. (The Pickaxe reference section, while wonderful, is slowly falling out of date... it would be nice to have a more-or-less "definitive" place where we could keep up-to-date docs.) Anyway, I need to finish this tutorial first... So here's the code. It handles errors (including parse errors), and all-in-all seems to work pretty well. There are a few sticky areas when running from mod_ruby... basically, this code acts like you are running it in mod_ruby (go figure!) instead of on the command line. def executeCode (code, input) # Wrap code to catch errors and to stop SystemExit. code = <<-END_CODE begin #{code} rescue SystemExit rescue Exception => error puts error.inspect end END_CODE strIO = StringIO.new if !input.empty? input = input.join("\n")+"\n" input = StringIO.new (input, "r") class << strIO; self; end.module_eval do ['gets', 'getc', 'read'].each do |meth| define_method(meth) do |*params| inStr = input.method(meth).call(*params) puts @@INPUT+inStr.chomp+(@@INPUT.reverse) # Echo input. inStr end end end end # Pass these methods to strIO: kernelMethods = ['puts', 'putc', 'gets'] # Swap out Kernel methods... kernelMethods.each do |meth| Kernel.module_eval "alias __temp__tutorial__#{meth}__ #{meth}" Kernel.module_eval do define_method(meth) do |*params| strIO.method(meth).call(*params) end end end begin strIO.instance_eval code rescue Exception => error # Catch parse errors. return error.inspect end # ...and swap them back in. kernelMethods.each do |meth| Kernel.module_eval "alias #{meth} __temp__tutorial__#{meth}__" end strIO.string end Thoughts? Suggestions? Errors? Chris