Permalink
Fetching contributors…
Cannot retrieve contributors at this time
178 lines (154 sloc) 3.84 KB
require 'irb/ruby-lex'
require 'stringio'
class MimickIRB < RubyLex
attr_accessor :started
class Continue < StandardError; end
class Empty < StandardError; end
def initialize
super
set_input(StringIO.new)
end
def run(str,line_no=nil)
obj = nil
@io << str
@io.rewind
unless l = lex
raise Empty if @line == ''
else
case l.strip
when "reset"
@line = ""
when "time"
@line = "puts %{You started \#{IRBalike.started.since} ago.}"
else
@line << l << "\n"
if @ltype or @continue or @indent > 0
raise Continue
end
end
end
unless @line.empty?
obj = eval @line, TOPLEVEL_BINDING
end
@line = ''
#@line_no = line_no if line_no
@exp_line_no = line_no || @line_no
@indent = 0
@indent_stack = []
$stdout.rewind
output = $stdout.read
$stdout.truncate(0)
$stdout.rewind
[output, obj]
rescue Object => e
case e when Empty, Continue
else @line = ""
end
raise e
ensure
set_input(StringIO.new)
end
end
# TO DO: output of blocks is gathered and shown at the end of the block
# when lines in a block have ->, they should be rememberd, and when
# output is generated when closing the block, each output line should
# be appended to the in-block -> lines before showing lines after the block.
class ExampleExpander
def initialize(sep=" -> ", align=52)
@sep = sep
@align = align
@irb = MimickIRB.new
@output = ""
end
def add_line(line,line_num=nil)
line = line.chomp
line = $1 if /(.+)#{@sep}.*/.match line
$stdout = StringIO.new
begin
out,obj = @irb.run(line, line_num)
@output << line_output(line,out)
rescue MimickIRB::Empty
@output << line_output(line)
rescue MimickIRB::Continue
@output << line_output(line)
rescue Object => e
#msg = "Exception : #{e.message}"
msg = "Exception : #{e.class}"
# msg = "#{e.class}: #{e.message}"
@output << line_output(line,msg)
STDERR.puts "#{msg}\n"
end
$stdout = STDOUT
end
def output
@output
end
def clear
@output = ""
end
protected
def line_output(line,output=nil)
if output
output = output.chomp
output = nil if output.strip.empty?
end
out = line.dup
if output
line_size = line.size
output.split("\n").each do |out_line|
out << " "*[0,(@align-line_size)].max + @sep + out_line
out << "\n"
line_size = 0
end
end
out
end
end
def expand_text(txt,non_code_block_prefix=nil) # text with indented blocks of code
exex = ExampleExpander.new
indent = nil
txt_out = ""
line_num = 0
accum = ""
skip_until_blank = false
disabled = false
txt.split("\n").each do |line|
line_num += 1
code = false
line.chomp!
if skip_until_blank
if line.strip.empty?
skip_until_blank = false
end
else
unless line.strip.empty? || disabled
line_indent = /^\s*/.match(line)[0]
indent ||= line_indent
indent = line_indent if line_indent.size < indent.size
if line[line_indent.size,1]=='*'
inner_indent = /^\s*/.match(line[line_indent.size+1..-1])[0]
indent += '*'+inner_indent
else
if line_indent.size > indent.size
code = true
end
end
end
if code
exex.add_line line, line_num
line = exex.output.chomp
exex.clear
else
disabled = true if line[0,7]=="EXPAND-"
disabled = false if line[0,7]=="EXPAND+"
skip_until_blank = true if line[0,1]==non_code_block_prefix
end
end
txt_out << line + "\n"
end
txt_out
end
require 'rubygems'
$:.unshift File.dirname(__FILE__) + '/lib'
require File.dirname(__FILE__) + '/lib/decimal'
puts expand_text(File.read(ARGV.shift),"[")