Parent

Files

Rcodetools::XMPFilter

Constants

VERSION
MARKER
XMP_RE
VAR
WARNING_RE
RuntimeData
INITIALIZE_OPTS
Interpreter
INTERPRETER_RUBY
INTERPRETER_RBTEST
INTERPRETER_FORK
SINGLE_LINE_RE
MULTI_LINE_RE

Public Class Methods

detect_rbtest(code, opts) click to toggle source
    # 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
new(opts = {}) click to toggle source
    # 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
run(code, opts) click to toggle source

The processor (overridable)

    # File lib/rcodetools/xmpfilter.rb, line 49
49:   def self.run(code, opts)
50:     new(opts).annotate(code)
51:   end

Public Instance Methods

add_markers(code, min_codeline_size = 50) click to toggle source
     # 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
annotate(code) click to toggle source
     # 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
annotated_line(line, expression, runtime_data, idx) click to toggle source
     # 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
annotated_multi_line(line, expression, indent, runtime_data, idx) click to toggle source
     # 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
common_path(a, b) click to toggle source
     # 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
debugprint(*args) click to toggle source
     # File lib/rcodetools/xmpfilter.rb, line 338
338:   def debugprint(*args)
339:     $stderr.puts(*args) if $DEBUG
340:   end
execute(code) click to toggle source
     # File lib/rcodetools/xmpfilter.rb, line 278
278:   def execute(code)
279:     __send__ @interpreter_info.execute_method, code
280:   end
execute_popen(code) click to toggle source
     # 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
execute_ruby(code) click to toggle source
     # 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
execute_script(code) click to toggle source
     # 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
execute_tmpfile(code) click to toggle source
     # 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
extract_data(output) click to toggle source
     # 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
final_decoration(code, output) click to toggle source
     # 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
get_test_method_from_lineno(filename, lineno) click to toggle source
     # 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
initialize_for_test_script(test_script, test_method, filename) click to toggle source
     # 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
initialize_rbtest() click to toggle source
    # File lib/rcodetools/xmpfilter.rb, line 85
85:   def initialize_rbtest
86:     @interpreter_info = INTERPRETER_RBTEST
87:   end
initialize_rct_fork() click to toggle source
    # 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
interpreter_command() click to toggle source
     # 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
oneline_ize(code) click to toggle source
     # File lib/rcodetools/xmpfilter.rb, line 334
334:   def oneline_ize(code)
335:     "((" + code.gsub(/\r?\n|\r/, ';') + "));#{@postfix}\n"
336:   end
prepare_line(expr, idx, multi_line=false) click to toggle source
prepare_line_annotation(expr, idx, multi_line=false) click to toggle source
     # 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
Also aliased as: prepare_line
windows?() click to toggle source
    # File lib/rcodetools/xmpfilter.rb, line 31
31:   def windows?
32:     /win|mingw/ =~ RUBY_PLATFORM && /darwin/ !~ RUBY_PLATFORM
33:   end

Private Instance Methods

safe_require_code(lib) click to toggle source
     # File lib/rcodetools/xmpfilter.rb, line 204
204:   def safe_require_code(lib)
205:     oldverbose = "$#{VAR}_old_verbose"
206:     "#{oldverbose} = $VERBOSE; $VERBOSE = false; require '#{lib}'; $VERBOSE = #{oldverbose}"
207:   end

Disabled; run with --debug to generate this.

[Validate]

Generated with the Darkfish Rdoc Generator 1.1.6.