rcodetools 0.4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +18 -0
- data/README +34 -0
- data/README.emacs +54 -0
- data/README.method_analysis +13 -0
- data/README.vim +84 -0
- data/README.xmpfilter +202 -0
- data/Rakefile +123 -0
- data/Rakefile.method_analysis +30 -0
- data/THANKS +6 -0
- data/bin/rct-complete +37 -0
- data/bin/rct-doc +50 -0
- data/bin/rct-meth-args +392 -0
- data/bin/xmpfilter +75 -0
- data/icicles-rcodetools.el +31 -0
- data/lib/method_analyzer.rb +107 -0
- data/lib/rcodetools/completion.rb +282 -0
- data/lib/rcodetools/doc.rb +176 -0
- data/lib/rcodetools/options.rb +83 -0
- data/lib/rcodetools/xmpfilter.rb +208 -0
- data/lib/rcodetools/xmptestunitfilter.rb +197 -0
- data/rcodetools.el +162 -0
- data/rcodetools.vim +118 -0
- data/setup.rb +1585 -0
- data/test/data/add_markers-input.rb +2 -0
- data/test/data/add_markers-output.rb +2 -0
- data/test/data/bindings-input.rb +26 -0
- data/test/data/bindings-output.rb +31 -0
- data/test/data/completion-input.rb +1 -0
- data/test/data/completion-output.rb +2 -0
- data/test/data/completion_emacs-input.rb +1 -0
- data/test/data/completion_emacs-output.rb +5 -0
- data/test/data/completion_emacs_icicles-input.rb +1 -0
- data/test/data/completion_emacs_icicles-output.rb +5 -0
- data/test/data/doc-input.rb +1 -0
- data/test/data/doc-output.rb +1 -0
- data/test/data/method_analyzer-data.rb +33 -0
- data/test/data/method_args.data.rb +106 -0
- data/test/data/no_warnings-input.rb +3 -0
- data/test/data/no_warnings-output.rb +4 -0
- data/test/data/refe-input.rb +1 -0
- data/test/data/refe-output.rb +1 -0
- data/test/data/ri-input.rb +1 -0
- data/test/data/ri-output.rb +1 -0
- data/test/data/ri_emacs-input.rb +1 -0
- data/test/data/ri_emacs-output.rb +1 -0
- data/test/data/ri_vim-input.rb +1 -0
- data/test/data/ri_vim-output.rb +1 -0
- data/test/data/rspec-input.rb +48 -0
- data/test/data/rspec-output.rb +52 -0
- data/test/data/rspec_poetry-input.rb +48 -0
- data/test/data/rspec_poetry-output.rb +52 -0
- data/test/data/simple_annotation-input.rb +8 -0
- data/test/data/simple_annotation-output.rb +8 -0
- data/test/data/unit_test-input.rb +50 -0
- data/test/data/unit_test-output.rb +52 -0
- data/test/data/unit_test_poetry-input.rb +50 -0
- data/test/data/unit_test_poetry-output.rb +52 -0
- data/test/test_completion.rb +467 -0
- data/test/test_doc.rb +403 -0
- data/test/test_functional.rb +18 -0
- data/test/test_method_analyzer.rb +99 -0
- data/test/test_method_args.rb +134 -0
- data/test/test_run.rb +41 -0
- data/test/test_xmpfilter.rb +36 -0
- data/test/test_xmptestunitfilter.rb +84 -0
- metadata +139 -0
@@ -0,0 +1,176 @@
|
|
1
|
+
require 'rcodetools/completion'
|
2
|
+
# Call Ri for any editors!!
|
3
|
+
# by rubikitch <rubikitch@ruby-lang.org>
|
4
|
+
class XMPDocFilter < XMPFilter
|
5
|
+
include ProcessParticularLine
|
6
|
+
|
7
|
+
def initialize(opts = {})
|
8
|
+
super
|
9
|
+
@filename = opts[:filename]
|
10
|
+
extend UseMethodAnalyzer if opts[:use_method_analyzer]
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.run(code, opts)
|
14
|
+
new(opts).doc(code, opts[:lineno], opts[:column])
|
15
|
+
end
|
16
|
+
|
17
|
+
def prepare_line(expr, column)
|
18
|
+
set_expr_and_postfix!(expr, column){|c|
|
19
|
+
withop_re = /^.{#{c-1}}[#{OPERATOR_CHARS}]+/
|
20
|
+
if expr =~ withop_re
|
21
|
+
withop_re
|
22
|
+
else
|
23
|
+
/^.{#{c}}[\w#{OPERATOR_CHARS}]*/
|
24
|
+
end
|
25
|
+
}
|
26
|
+
recv = expr
|
27
|
+
|
28
|
+
# When expr already knows receiver and method,
|
29
|
+
return(__prepare_line :recv => expr.eval_string, :meth => expr.meth) if expr.eval_string
|
30
|
+
|
31
|
+
case expr
|
32
|
+
when /^(?:::)?([A-Z].*)(?:::|\.)(.*)$/ # nested constants / class methods
|
33
|
+
__prepare_line :klass => $1, :meth_or_constant => $2
|
34
|
+
when /^(?:::)?[A-Z]/ # normal constants
|
35
|
+
__prepare_line :klass => expr
|
36
|
+
when /\.([^.]*)$/ # method call
|
37
|
+
__prepare_line :recv => Regexp.last_match.pre_match, :meth => $1
|
38
|
+
when /^(.+)(\[\]=?)$/ # [], []=
|
39
|
+
__prepare_line :recv => $1, :meth => $2
|
40
|
+
when /[#{OPERATOR_CHARS}]+$/ # operator
|
41
|
+
__prepare_line :recv => Regexp.last_match.pre_match, :meth => $&
|
42
|
+
else # bare words
|
43
|
+
__prepare_line :recv => "self", :meth => expr
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def __prepare_line(x)
|
48
|
+
v = "#{VAR}"
|
49
|
+
klass = "#{VAR}_klass"
|
50
|
+
flag = "#{VAR}_flag"
|
51
|
+
which_methods = "#{VAR}_methods"
|
52
|
+
ancestor_class = "#{VAR}_ancestor_class"
|
53
|
+
idx = 1
|
54
|
+
recv = x[:recv] || x[:klass] || raise(ArgumentError, "need :recv or :klass")
|
55
|
+
meth = x[:meth_or_constant] || x[:meth]
|
56
|
+
debugprint "recv=#{recv}", "meth=#{meth}"
|
57
|
+
if meth
|
58
|
+
code = <<-EOC
|
59
|
+
#{v} = (#{recv})
|
60
|
+
if Class === #{v}
|
61
|
+
#{flag} = #{v}.respond_to?('#{meth}') ? "." : "::"
|
62
|
+
#{klass} = #{v}
|
63
|
+
#{which_methods} = :methods
|
64
|
+
else
|
65
|
+
#{flag} = "#"
|
66
|
+
#{klass} = #{v}.class
|
67
|
+
#{which_methods} = :instance_methods
|
68
|
+
end
|
69
|
+
#{ancestor_class} = #{klass}.ancestors.delete_if{|c| c==Kernel }.find{|c| c.__send__(#{which_methods}, false).include? '#{meth}' }
|
70
|
+
$stderr.print("#{MARKER}[#{idx}] => " + #{v}.class.to_s + " ")
|
71
|
+
|
72
|
+
if #{ancestor_class}
|
73
|
+
$stderr.puts(#{ancestor_class}.to_s + #{flag} + '#{meth}')
|
74
|
+
else
|
75
|
+
[Kernel, Module, Class].each do |k|
|
76
|
+
if (k.instance_methods(false) + k.private_instance_methods(false)).include? '#{meth}'
|
77
|
+
$stderr.printf("%s#%s\\n", k, '#{meth}'); exit
|
78
|
+
end
|
79
|
+
end
|
80
|
+
$stderr.puts(#{v}.to_s + '::' + '#{meth}')
|
81
|
+
end
|
82
|
+
exit
|
83
|
+
EOC
|
84
|
+
else
|
85
|
+
code = <<-EOC
|
86
|
+
#{v} = (#{recv})
|
87
|
+
$stderr.print("#{MARKER}[#{idx}] => " + #{v}.class.to_s + " ")
|
88
|
+
$stderr.puts(#{v}.to_s)
|
89
|
+
exit
|
90
|
+
EOC
|
91
|
+
end
|
92
|
+
oneline_ize(code)
|
93
|
+
end
|
94
|
+
|
95
|
+
# overridable by module
|
96
|
+
def _doc(code, lineno, column)
|
97
|
+
end
|
98
|
+
|
99
|
+
def doc(code, lineno, column=nil)
|
100
|
+
_doc(code, lineno, column) or runtime_data(code, lineno, column).to_s
|
101
|
+
end
|
102
|
+
|
103
|
+
module UseMethodAnalyzer
|
104
|
+
METHOD_ANALYSIS = "method_analysis"
|
105
|
+
def have_method_analysis
|
106
|
+
File.file? METHOD_ANALYSIS
|
107
|
+
end
|
108
|
+
|
109
|
+
def find_method_analysis
|
110
|
+
here = Dir.pwd
|
111
|
+
oldpwd = here
|
112
|
+
begin
|
113
|
+
while ! have_method_analysis
|
114
|
+
Dir.chdir("..")
|
115
|
+
if Dir.pwd == here
|
116
|
+
return nil # not found
|
117
|
+
end
|
118
|
+
here = Dir.pwd
|
119
|
+
end
|
120
|
+
ensure
|
121
|
+
Dir.chdir oldpwd
|
122
|
+
end
|
123
|
+
yield(File.join(here, METHOD_ANALYSIS))
|
124
|
+
end
|
125
|
+
|
126
|
+
def _doc(code, lineno, column=nil)
|
127
|
+
find_method_analysis do |ma_file|
|
128
|
+
methods = open(ma_file, "rb"){ |f| Marshal.load(f)}
|
129
|
+
line = File.readlines(@filename)[lineno-1]
|
130
|
+
current_method = line[ /^.{#{column}}\w*/][ /\w+[\?!]?$/ ].sub(/:+/,'')
|
131
|
+
filename = @filename # FIXME
|
132
|
+
begin
|
133
|
+
methods[filename][lineno].grep(Regexp.new(Regexp.quote(current_method)))[0]
|
134
|
+
rescue NoMethodError
|
135
|
+
raise "doc/method_analyzer:cannot find #{current_method}"
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
143
|
+
|
144
|
+
# ReFe is so-called `Japanese Ri'.
|
145
|
+
class XMPReFeFilter < XMPDocFilter
|
146
|
+
def doc(code, lineno, column=nil)
|
147
|
+
"refe '#{super}'"
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
class XMPRiFilter < XMPDocFilter
|
152
|
+
def doc(code, lineno, column=nil)
|
153
|
+
"ri '#{super}'"
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
class XMPRiEmacsFilter < XMPDocFilter
|
158
|
+
def doc(code, lineno, column=nil)
|
159
|
+
begin
|
160
|
+
%!(rct-find-tag-or-ri "#{super}")!
|
161
|
+
rescue Exception => err
|
162
|
+
return %Q[(error "#{err.message}")]
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
class XMPRiVimFilter < XMPDocFilter
|
168
|
+
def doc(code, lineno, column=nil)
|
169
|
+
begin
|
170
|
+
%{call RCT_find_tag_or_ri("#{super}")}
|
171
|
+
rescue Exception => err
|
172
|
+
return %Q[echo #{err.message.inspect}]
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
# Domain specific OptionParser extensions
|
4
|
+
module OptionHandler
|
5
|
+
def set_banner
|
6
|
+
self.banner = "Usage: #{$0} [options] [inputfile] [-- cmdline args]"
|
7
|
+
end
|
8
|
+
|
9
|
+
def handle_position(options)
|
10
|
+
separator ""
|
11
|
+
separator "Position options:"
|
12
|
+
on("--line=LINE", "Current line number.") do |n|
|
13
|
+
options[:lineno] = n.to_i
|
14
|
+
end
|
15
|
+
on("--column=COLUMN", "Current column number.") do |n|
|
16
|
+
options[:column] = n.to_i
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def handle_interpreter(options)
|
21
|
+
separator ""
|
22
|
+
separator "Interpreter options:"
|
23
|
+
on("-S FILE", "--interpreter FILE", "Use interpreter FILE.") do |interpreter|
|
24
|
+
options[:interpreter] = interpreter
|
25
|
+
end
|
26
|
+
on("-I PATH", "Add PATH to $LOAD_PATH") do |path|
|
27
|
+
options[:include_paths] << path
|
28
|
+
end
|
29
|
+
on("-r LIB", "Require LIB before execution.") do |lib|
|
30
|
+
options[:libs] << lib
|
31
|
+
end
|
32
|
+
on("-e EXPR", "--eval=EXPR", "--stub=EXPR", "Evaluate EXPR after execution.") do |expr|
|
33
|
+
options[:evals] << expr
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
def handle_misc(options)
|
39
|
+
separator ""
|
40
|
+
separator "Misc options:"
|
41
|
+
on("--cd DIR", "Change working directory to DIR.") do |dir|
|
42
|
+
options[:wd] = dir
|
43
|
+
end
|
44
|
+
on("--debug", "Write transformed source code to xmp-tmp.PID.rb.") do
|
45
|
+
options[:dump] = "xmp-tmp.#{Process.pid}.rb"
|
46
|
+
end
|
47
|
+
separator ""
|
48
|
+
on("-h", "--help", "Show this message") do
|
49
|
+
puts self
|
50
|
+
exit
|
51
|
+
end
|
52
|
+
on("-v", "--version", "Show version information") do
|
53
|
+
puts "#{File.basename($0)} #{XMPFilter::VERSION}"
|
54
|
+
exit
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
def set_extra_opts(options)
|
62
|
+
if idx = ARGV.index("--")
|
63
|
+
options[:options] = ARGV[idx+1..-1]
|
64
|
+
ARGV.replace ARGV[0...idx]
|
65
|
+
else
|
66
|
+
options[:options] = []
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
DEFAULT_OPTIONS = {
|
71
|
+
:interpreter => "ruby",
|
72
|
+
:options => ["hoge"],
|
73
|
+
:min_codeline_size => 50,
|
74
|
+
:libs => [],
|
75
|
+
:evals => [],
|
76
|
+
:include_paths => [],
|
77
|
+
:dump => nil,
|
78
|
+
:wd => nil,
|
79
|
+
:warnings => true,
|
80
|
+
:use_parentheses => true,
|
81
|
+
:column => nil,
|
82
|
+
:output_stdout => true,
|
83
|
+
}
|
@@ -0,0 +1,208 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Copyright (c) 2005-2006 Mauricio Fernandez <mfp@acm.org> http://eigenclass.org
|
3
|
+
# rubikitch <rubikitch@ruby-lang.org>
|
4
|
+
# Use and distribution subject to the terms of the Ruby license.
|
5
|
+
|
6
|
+
class XMPFilter
|
7
|
+
VERSION = "0.4.0"
|
8
|
+
|
9
|
+
MARKER = "!XMP#{Time.new.to_i}_#{Process.pid}_#{rand(1000000)}!"
|
10
|
+
XMP_RE = Regexp.new("^" + Regexp.escape(MARKER) + '\[([0-9]+)\] (=>|~>|==>) (.*)')
|
11
|
+
VAR = "_xmp_#{Time.new.to_i}_#{Process.pid}_#{rand(1000000)}"
|
12
|
+
WARNING_RE = /.*:([0-9]+): warning: (.*)/
|
13
|
+
|
14
|
+
RuntimeData = Struct.new(:results, :exceptions, :bindings)
|
15
|
+
|
16
|
+
INITIALIZE_OPTS = {:interpreter => "ruby", :options => [], :libs => [],
|
17
|
+
:include_paths => [], :warnings => true,
|
18
|
+
:use_parentheses => true}
|
19
|
+
|
20
|
+
# The processor (overridable)
|
21
|
+
def self.run(code, opts)
|
22
|
+
new(opts).annotate(code)
|
23
|
+
end
|
24
|
+
|
25
|
+
def initialize(opts = {})
|
26
|
+
options = INITIALIZE_OPTS.merge opts
|
27
|
+
@interpreter = options[:interpreter]
|
28
|
+
@options = options[:options]
|
29
|
+
@libs = options[:libs]
|
30
|
+
@evals = options[:evals] || []
|
31
|
+
@include_paths = options[:include_paths]
|
32
|
+
@output_stdout = options[:output_stdout]
|
33
|
+
@dump = options[:dump]
|
34
|
+
@warnings = options[:warnings]
|
35
|
+
@parentheses = options[:use_parentheses]
|
36
|
+
@ignore_NoMethodError = options[:ignore_NoMethodError]
|
37
|
+
|
38
|
+
@postfix = ""
|
39
|
+
end
|
40
|
+
|
41
|
+
def add_markers(code, min_codeline_size = 50)
|
42
|
+
maxlen = code.map{|x| x.size}.max
|
43
|
+
maxlen = [min_codeline_size, maxlen + 2].max
|
44
|
+
ret = ""
|
45
|
+
code.each do |l|
|
46
|
+
l = l.chomp.gsub(/ # (=>|!>).*/, "").gsub(/\s*$/, "")
|
47
|
+
ret << (l + " " * (maxlen - l.size) + " # =>\n")
|
48
|
+
end
|
49
|
+
ret
|
50
|
+
end
|
51
|
+
|
52
|
+
def annotate(code)
|
53
|
+
idx = 0
|
54
|
+
newcode = code.gsub(/^(.*) # =>.*/){|l| prepare_line($1, idx += 1) }
|
55
|
+
if @dump
|
56
|
+
File.open(@dump, "w"){|f| f.puts newcode}
|
57
|
+
end
|
58
|
+
stdout, stderr = execute(newcode)
|
59
|
+
output = stderr.readlines
|
60
|
+
runtime_data = extract_data(output)
|
61
|
+
idx = 0
|
62
|
+
annotated = code.gsub(/^(.*) # =>.*/) do |l|
|
63
|
+
expr = $1
|
64
|
+
if /^\s*#/ =~ l
|
65
|
+
l
|
66
|
+
else
|
67
|
+
annotated_line(l, expr, runtime_data, idx += 1)
|
68
|
+
end
|
69
|
+
end.gsub(/ # !>.*/, '').gsub(/# (>>|~>)[^\n]*\n/m, "");
|
70
|
+
ret = final_decoration(annotated, output)
|
71
|
+
if @output_stdout and (s = stdout.read) != ""
|
72
|
+
ret << s.inject(""){|s,line| s + "# >> #{line}".chomp + "\n" }
|
73
|
+
end
|
74
|
+
ret
|
75
|
+
end
|
76
|
+
|
77
|
+
def annotated_line(line, expression, runtime_data, idx)
|
78
|
+
"#{expression} # => " + (runtime_data.results[idx].map{|x| x[1]} || []).join(", ")
|
79
|
+
end
|
80
|
+
|
81
|
+
def prepare_line_annotation(expr, idx)
|
82
|
+
v = "#{VAR}"
|
83
|
+
blocal = "__#{VAR}"
|
84
|
+
blocal2 = "___#{VAR}"
|
85
|
+
# rubikitch: oneline-ized
|
86
|
+
# <<EOF.chomp
|
87
|
+
# ((#{v} = (#{expr}); $stderr.puts("#{MARKER}[#{idx}] => " + #{v}.class.to_s + " " + #{v}.inspect) || 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 }; nil rescue Exception; nil end || #{v}))
|
88
|
+
# EOF
|
89
|
+
oneline_ize(<<-EOF).chomp
|
90
|
+
#{v} = (#{expr})
|
91
|
+
$stderr.puts("#{MARKER}[#{idx}] => " + #{v}.class.to_s + " " + #{v}.inspect) || begin
|
92
|
+
$stderr.puts local_variables
|
93
|
+
local_variables.each{|#{blocal}|
|
94
|
+
#{blocal2} = eval(#{blocal})
|
95
|
+
if #{v} == #{blocal2} && #{blocal} != %#{expr}.strip
|
96
|
+
$stderr.puts("#{MARKER}[#{idx}] ==> " + #{blocal})
|
97
|
+
elsif [#{blocal2}] == #{v}
|
98
|
+
$stderr.puts("#{MARKER}[#{idx}] ==> [" + #{blocal} + "]")
|
99
|
+
end
|
100
|
+
}
|
101
|
+
nil
|
102
|
+
rescue Exception
|
103
|
+
nil
|
104
|
+
end || #{v}
|
105
|
+
EOF
|
106
|
+
|
107
|
+
end
|
108
|
+
alias_method :prepare_line, :prepare_line_annotation
|
109
|
+
|
110
|
+
def execute_tmpfile(code)
|
111
|
+
stdin, stdout, stderr = (1..3).map do |i|
|
112
|
+
fname = "xmpfilter.tmpfile_#{Process.pid}-#{i}.rb"
|
113
|
+
at_exit { File.unlink fname }
|
114
|
+
File.open(fname, "w+")
|
115
|
+
end
|
116
|
+
stdin.puts code
|
117
|
+
stdin.close
|
118
|
+
exe_line = <<-EOF.map{|l| l.strip}.join(";")
|
119
|
+
$stdout.reopen('#{stdout.path}', 'w')
|
120
|
+
$stderr.reopen('#{stderr.path}', 'w')
|
121
|
+
$0.replace '#{stdin.path}'
|
122
|
+
ARGV.replace(#{@options.inspect})
|
123
|
+
load #{stdin.path.inspect}
|
124
|
+
#{@evals.join(";")}
|
125
|
+
EOF
|
126
|
+
system(*(interpreter_command << "-e" << exe_line))
|
127
|
+
[stdout, stderr]
|
128
|
+
end
|
129
|
+
|
130
|
+
def execute_popen(code)
|
131
|
+
require 'open3'
|
132
|
+
stdin, stdout, stderr = Open3::popen3(*interpreter_command)
|
133
|
+
stdin.puts code
|
134
|
+
@evals.each{|x| stdin.puts x } unless @evals.empty?
|
135
|
+
stdin.close
|
136
|
+
[stdout, stderr]
|
137
|
+
end
|
138
|
+
|
139
|
+
if /win|mingw/ =~ RUBY_PLATFORM && /darwin/ !~ RUBY_PLATFORM
|
140
|
+
alias_method :execute, :execute_tmpfile
|
141
|
+
else
|
142
|
+
alias_method :execute, :execute_popen
|
143
|
+
end
|
144
|
+
|
145
|
+
def interpreter_command
|
146
|
+
r = [@interpreter, "-w"]
|
147
|
+
r << "-d" if $DEBUG
|
148
|
+
r << "-I#{@include_paths.join(":")}" unless @include_paths.empty?
|
149
|
+
@libs.each{|x| r << "-r#{x}" } unless @libs.empty?
|
150
|
+
(r << "-").concat @options unless @options.empty?
|
151
|
+
r
|
152
|
+
end
|
153
|
+
|
154
|
+
def extract_data(output)
|
155
|
+
results = Hash.new{|h,k| h[k] = []}
|
156
|
+
exceptions = Hash.new{|h,k| h[k] = []}
|
157
|
+
bindings = Hash.new{|h,k| h[k] = []}
|
158
|
+
output.grep(XMP_RE).each do |line|
|
159
|
+
result_id, op, result = XMP_RE.match(line).captures
|
160
|
+
case op
|
161
|
+
when "=>"
|
162
|
+
klass, value = /(\S+)\s+(.*)/.match(result).captures
|
163
|
+
results[result_id.to_i] << [klass, value]
|
164
|
+
when "~>"
|
165
|
+
exceptions[result_id.to_i] << result
|
166
|
+
when "==>"
|
167
|
+
bindings[result_id.to_i] << result unless result.index(VAR)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
RuntimeData.new(results, exceptions, bindings)
|
171
|
+
end
|
172
|
+
|
173
|
+
def final_decoration(code, output)
|
174
|
+
warnings = {}
|
175
|
+
output.join.grep(WARNING_RE).map do |x|
|
176
|
+
md = WARNING_RE.match(x)
|
177
|
+
warnings[md[1].to_i] = md[2]
|
178
|
+
end
|
179
|
+
idx = 0
|
180
|
+
ret = code.map do |line|
|
181
|
+
w = warnings[idx+=1]
|
182
|
+
if @warnings
|
183
|
+
w ? (line.chomp + " # !> #{w}") : line
|
184
|
+
else
|
185
|
+
line
|
186
|
+
end
|
187
|
+
end
|
188
|
+
output = output.reject{|x| /^-:[0-9]+: warning/.match(x)}
|
189
|
+
if exception = /^-:[0-9]+:.*/m.match(output.join)
|
190
|
+
ret << exception[0].map{|line| "# ~> " + line }
|
191
|
+
end
|
192
|
+
ret
|
193
|
+
end
|
194
|
+
|
195
|
+
def oneline_ize(code)
|
196
|
+
"((" + code.gsub(/\r?\n|\r/, ';') + "))#{@postfix}\n"
|
197
|
+
end
|
198
|
+
|
199
|
+
def debugprint(*args)
|
200
|
+
$stderr.puts(*args) if $DEBUG
|
201
|
+
end
|
202
|
+
end # clas XMPFilter
|
203
|
+
|
204
|
+
class XMPAddMarkers < XMPFilter
|
205
|
+
def self.run(code, opts)
|
206
|
+
new(opts).add_markers(code, opts[:min_codeline_size])
|
207
|
+
end
|
208
|
+
end
|