# File lib/rcodetools/xmpfilter.rb, line 44
44: def self.detect_rbtest(code, opts)
45: opts[:use_rbtest] ||= (opts[:detect_rbtest] and code =~ /^=begin test./) ? true : false
46: end
# File lib/rcodetools/xmpfilter.rb, line 53
53: def initialize(opts = {})
54: options = INITIALIZE_OPTS.merge opts
55: @interpreter_info = INTERPRETER_RUBY
56: @interpreter = options[:interpreter]
57: @options = options[:options]
58: @libs = options[:libs]
59: @evals = options[:evals] || []
60: @include_paths = options[:include_paths]
61: @output_stdout = options[:output_stdout]
62: @dump = options[:dump]
63: @warnings = options[:warnings]
64: @parentheses = options[:use_parentheses]
65: @ignore_NoMethodError = options[:ignore_NoMethodError]
66: test_script = options[:test_script]
67: test_method = options[:test_method]
68: filename = options[:filename]
69: @execute_ruby_tmpfile = options[:execute_ruby_tmpfile]
70: @postfix = ""
71: @stdin_path = nil
72: @width = options[:width]
73:
74: initialize_rct_fork if options[:detect_rct_fork]
75: initialize_rbtest if options[:use_rbtest]
76: initialize_for_test_script test_script, test_method, filename if test_script and !options[:use_rbtest]
77: end
# File lib/rcodetools/xmpfilter.rb, line 117
117: def add_markers(code, min_codeline_size = 50)
118: maxlen = code.map{|x| x.size}.max
119: maxlen = [min_codeline_size, maxlen + 2].max
120: ret = ""
121: code.each do |l|
122: l = l.chomp.gsub(/ # (=>|!>).*/, "").gsub(/\s*$/, "")
123: ret << (l + " " * (maxlen - l.size) + " # =>\n")
124: end
125: ret
126: end
# File lib/rcodetools/xmpfilter.rb, line 130
130: def annotate(code)
131: idx = 0
132: code = code.gsub(/ # !>.*/, '')
133: newcode = code.gsub(SINGLE_LINE_RE){ prepare_line($1, idx += 1) }
134: newcode.gsub!(MULTI_LINE_RE){ prepare_line($1, idx += 1, true)}
135: File.open(@dump, "w"){|f| f.puts newcode} if @dump
136: stdout, stderr = execute(newcode)
137: output = stderr.readlines
138: runtime_data = extract_data(output)
139: idx = 0
140: annotated = code.gsub(SINGLE_LINE_RE) { |l|
141: expr = $1
142: if /^\s*#/ =~ l
143: l
144: else
145: annotated_line(l, expr, runtime_data, idx += 1)
146: end
147: }
148: annotated.gsub!(/ # !>.*/, '')
149: annotated.gsub!(/# (>>|~>)[^\n]*\n/, "");
150: annotated.gsub!(MULTI_LINE_RE) { |l|
151: annotated_multi_line(l, $1, $3, runtime_data, idx += 1)
152: }
153: ret = final_decoration(annotated, output)
154: if @output_stdout and (s = stdout.read) != ""
155: ret << s.inject(""){|s,line| s + "# >> #{line}".chomp + "\n" }
156: end
157: ret
158: end
# File lib/rcodetools/xmpfilter.rb, line 160
160: def annotated_line(line, expression, runtime_data, idx)
161: "#{expression} # => " + (runtime_data.results[idx].map{|x| x[1]} || []).join(", ")
162: end
# File lib/rcodetools/xmpfilter.rb, line 164
164: def annotated_multi_line(line, expression, indent, runtime_data, idx)
165: pretty = (runtime_data.results[idx].map{|x| x[1]} || []).join(", ")
166: first, *rest = pretty.to_a
167: rest.inject("#{expression}\n#{indent}# => #{first || "\n"}") {|s, l| s << "#{indent}# " << l }
168: end
# File lib/rcodetools/xmpfilter.rb, line 113
113: def common_path(a, b)
114: (a.split(File::Separator) & b.split(File::Separator)).join(File::Separator)
115: end
# File lib/rcodetools/xmpfilter.rb, line 338
338: def debugprint(*args)
339: $stderr.puts(*args) if $DEBUG
340: end
# File lib/rcodetools/xmpfilter.rb, line 278
278: def execute(code)
279: __send__ @interpreter_info.execute_method, code
280: end
# File lib/rcodetools/xmpfilter.rb, line 247
247: def execute_popen(code)
248: require 'open3'
249: stdin, stdout, stderr = Open3::popen3(*interpreter_command)
250: stdin.puts code
251: @evals.each{|x| stdin.puts x } unless @evals.empty?
252: stdin.close
253: [stdout, stderr]
254: end
# File lib/rcodetools/xmpfilter.rb, line 210
210: def execute_ruby(code)
211: meth = (windows? or @execute_ruby_tmpfile) ? :execute_tmpfile : :execute_popen
212: __send__ meth, code
213: end
# File lib/rcodetools/xmpfilter.rb, line 256
256: def execute_script(code)
257: path = File.expand_path("xmpfilter.tmpfile_#{Process.pid}.rb", Dir.tmpdir)
258: File.open(path, "w"){|f| f.puts code}
259: at_exit { File.unlink path if File.exist? path}
260: stdout_path, stderr_path = (1..2).map do |i|
261: fname = "xmpfilter.tmpfile_#{Process.pid}-#{i}.rb"
262: File.expand_path(fname, Dir.tmpdir)
263: end
264: args = *(interpreter_command << %["#{path}"] << "2>" <<
265: %["#{stderr_path}"] << ">" << %["#{stdout_path}"])
266: system(args.join(" "))
267:
268: [stdout_path, stderr_path].map do |fullname|
269: f = File.open(fullname, "r")
270: at_exit {
271: f.close unless f.closed?
272: File.unlink fullname if File.exist? fullname
273: }
274: f
275: end
276: end
# File lib/rcodetools/xmpfilter.rb, line 215
215: def execute_tmpfile(code)
216: ios = ]_ stdin stdout stderr]
217: stdin, stdout, stderr = (1..3).map do |i|
218: fname = if $DEBUG
219: "xmpfilter.tmpfile_#{ios[i]}.rb"
220: else
221: "xmpfilter.tmpfile_#{Process.pid}-#{i}.rb"
222: end
223: f = File.open(fname, "w+")
224: at_exit { f.close unless f.closed?; File.unlink fname unless $DEBUG}
225: f
226: end
227: stdin.puts code
228: stdin.close
229: @stdin_path = File.expand_path stdin.path
230: exe_line = $stdout.reopen('#{File.expand_path(stdout.path)}', 'w') $stderr.reopen('#{File.expand_path(stderr.path)}', 'w') $0 = '#{File.expand_path(stdin.path)}' ARGV.replace(#{@options.inspect}) load #{File.expand_path(stdin.path).inspect} #{@evals.join(";")}.map{|l| l.strip}.join(";")
231: debugprint "execute command = #{(interpreter_command << "-e" << exe_line).join ' '}"
232:
233: oldpwd = Dir.pwd
234: @interpreter_info.chdir_proc and @interpreter_info.chdir_proc.call
235: system(*(interpreter_command << "-e" << exe_line))
236: Dir.chdir oldpwd
237: [stdout, stderr]
238: end
# File lib/rcodetools/xmpfilter.rb, line 291
291: def extract_data(output)
292: results = Hash.new{|h,k| h[k] = []}
293: exceptions = Hash.new{|h,k| h[k] = []}
294: bindings = Hash.new{|h,k| h[k] = []}
295: output.grep(XMP_RE).each do |line|
296: result_id, op, result = XMP_RE.match(line).captures
297: case op
298: when "=>"
299: klass, value = /(\S+)\s+(.*)/.match(result).captures
300: results[result_id.to_i] << [klass, value.gsub(/PPPROTECT/, "\n")]
301: when "~>"
302: exceptions[result_id.to_i] << result
303: when "==>"
304: bindings[result_id.to_i] << result unless result.index(VAR)
305: end
306: end
307: RuntimeData.new(results, exceptions, bindings)
308: end
# File lib/rcodetools/xmpfilter.rb, line 310
310: def final_decoration(code, output)
311: warnings = {}
312: output.join.grep(WARNING_RE).map do |x|
313: md = WARNING_RE.match(x)
314: warnings[md[1].to_i] = md[2]
315: end
316: idx = 0
317: ret = code.map do |line|
318: w = warnings[idx+=1]
319: if @warnings
320: w ? (line.chomp + " # !> #{w}") : line
321: else
322: line
323: end
324: end
325: output = output.reject{|x| /^-:[0-9]+: warning/.match(x)}
326: if exception = /^-e?:[0-9]+:.*|^(?!!XMP)[^\n]+:[0-9]+:in .*/.match(output.join)
327: err = exception[0]
328: err.gsub!(Regexp.union(@stdin_path), '-') if @stdin_path
329: ret << err.map{|line| "# ~> " + line }
330: end
331: ret
332: end
# File lib/rcodetools/xmpfilter.rb, line 103
103: def get_test_method_from_lineno(filename, lineno)
104: lines = File.readlines(filename)
105: (lineno-1).downto(0) do |i|
106: if lines[i] =~ /^ *def *(test_[A-Za-z0-9?!_]+)$/
107: return $1
108: end
109: end
110: nil
111: end
# File lib/rcodetools/xmpfilter.rb, line 89
89: def initialize_for_test_script(test_script, test_method, filename)
90: test_script.replace File.expand_path(test_script)
91: filename.replace File.expand_path(filename)
92: unless test_script == filename
93: basedir = common_path(test_script, filename)
94: relative_filename = filename[basedir.length+1 .. 1].sub(%^lib/!, '')
95: @evals << %$LOADED_FEATURES << #{relative_filename.dump}!
96: @evals << safe_require_code('test/unit')
97: @evals << %load #{test_script.dump}!
98: end
99: test_method = get_test_method_from_lineno(test_script, test_method.to_i) if test_method =~ /^\d/
100: @evals << %Test::Unit::AutoRunner.run(false, nil, ["-n", #{test_method.dump}])! if test_method
101: end
# File lib/rcodetools/xmpfilter.rb, line 85
85: def initialize_rbtest
86: @interpreter_info = INTERPRETER_RBTEST
87: end
# File lib/rcodetools/xmpfilter.rb, line 79
79: def initialize_rct_fork
80: if Fork::run?
81: @interpreter_info = INTERPRETER_FORK
82: end
83: end
# File lib/rcodetools/xmpfilter.rb, line 282
282: def interpreter_command
283: r = [ @interpreter ] + @interpreter_info.options
284: r << "-d" if $DEBUG and @interpreter_info.accept_debug
285: r << "-I#{@include_paths.join(":")}" if @interpreter_info.accept_include_paths and !@include_paths.empty?
286: @libs.each{|x| r << "-r#{x}" } unless @libs.empty?
287: (r << "-").concat @options unless @options.empty?
288: r
289: end
# File lib/rcodetools/xmpfilter.rb, line 334
334: def oneline_ize(code)
335: "((" + code.gsub(/\r?\n|\r/, ';') + "));#{@postfix}\n"
336: end
# File lib/rcodetools/xmpfilter.rb, line 170
170: def prepare_line_annotation(expr, idx, multi_line=false)
171: v = "#{VAR}"
172: blocal = "__#{VAR}"
173: blocal2 = "___#{VAR}"
174: lastmatch = "____#{VAR}"
175: if multi_line
176: pp = safe_require_code "pp"
177: result = "((begin; #{lastmatch} = $~; PP.pp(#{v}, '', #{@width-5}).gsub(/\\r?\\n/, 'PPPROTECT'); ensure; $~ = #{lastmatch} end))"
178: else
179: pp = ''
180: result = "#{v}.inspect"
181: end
182: oneline_ize(#{pp}#{v} = (#{expr})$stderr.puts("#{MARKER}[#{idx}] => " + #{v}.class.to_s + " " + #{result}) || begin $stderr.puts local_variables local_variables.each{|#{blocal}| #{blocal2} = eval(#{blocal}) if #{v} == #{blocal2} && #{blocal} != %#{expr}.strip $stderr.puts("#{MARKER}[#{idx}] ==> " + #{blocal}) elsif [#{blocal2}] == #{v} $stderr.puts("#{MARKER}[#{idx}] ==> [" + #{blocal} + "]") end } nilrescue Exception nilend || #{v}).chomp
183:
184: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.