-
Notifications
You must be signed in to change notification settings - Fork 5
/
expand.rb
179 lines (155 loc) · 3.89 KB
/
expand.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# TODO: adapt for Github-Flavored-Markdown
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 # -> markers, 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=51)
@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/flt'
puts expand_text(File.read(ARGV.shift),"[")