rcodetools 0.5.0.0 → 0.7.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. data/CHANGES +14 -0
  2. data/README +63 -0
  3. data/README.TDC +158 -0
  4. data/README.ja +84 -0
  5. data/README.vim +11 -0
  6. data/Rakefile +15 -2
  7. data/THANKS +5 -0
  8. data/bin/rct-complete +4 -2
  9. data/bin/rct-doc +4 -2
  10. data/bin/rct-meth-args +1 -1
  11. data/bin/xmpfilter +7 -1
  12. data/icicles-rcodetools.el +2 -1
  13. data/lib/rcodetools/completion.rb +36 -18
  14. data/lib/rcodetools/doc.rb +3 -0
  15. data/lib/rcodetools/fork.rb +222 -0
  16. data/lib/rcodetools/fork_config.rb +26 -0
  17. data/lib/rcodetools/options.rb +34 -1
  18. data/lib/rcodetools/xmpfilter.rb +106 -18
  19. data/lib/rcodetools/xmptestunitfilter.rb +116 -55
  20. data/lib/ruby_toggle_file.rb +99 -0
  21. data/rcodetools.el +64 -9
  22. data/rcodetools.vim +41 -6
  23. data/test/data/completion_class_info-input.rb +1 -0
  24. data/test/data/completion_class_info-output.rb +10 -0
  25. data/test/data/completion_class_info_no_candidates-input.rb +1 -0
  26. data/test/data/completion_class_info_no_candidates-output.rb +1 -0
  27. data/test/data/completion_detect_rbtest-input.rb +7 -0
  28. data/test/data/completion_detect_rbtest-output.rb +2 -0
  29. data/test/data/completion_detect_rbtest2-input.rb +1 -0
  30. data/test/data/completion_detect_rbtest2-output.rb +2 -0
  31. data/test/data/completion_in_method-input.rb +3 -0
  32. data/test/data/completion_in_method-output.rb +1 -0
  33. data/test/data/completion_in_method-test.rb +6 -0
  34. data/test/data/completion_rbtest-input.rb +7 -0
  35. data/test/data/completion_rbtest-output.rb +2 -0
  36. data/test/data/doc_detect_rbtest-input.rb +1 -0
  37. data/test/data/doc_detect_rbtest-output.rb +1 -0
  38. data/test/data/doc_detect_rbtest2-input.rb +7 -0
  39. data/test/data/doc_detect_rbtest2-output.rb +1 -0
  40. data/test/data/doc_rbtest-input.rb +7 -0
  41. data/test/data/doc_rbtest-output.rb +1 -0
  42. data/test/data/rspec-input.rb +9 -9
  43. data/test/data/rspec-output.rb +21 -21
  44. data/test/data/rspec_poetry-input.rb +9 -9
  45. data/test/data/rspec_poetry-output.rb +21 -21
  46. data/test/data/sample_test_script.rb +9 -0
  47. data/test/data/unit_test_detect_rbtest-input.rb +50 -0
  48. data/test/data/unit_test_detect_rbtest-output.rb +52 -0
  49. data/test/data/unit_test_detect_rbtest2-input.rb +6 -0
  50. data/test/data/unit_test_detect_rbtest2-output.rb +6 -0
  51. data/test/data/unit_test_rbtest-input.rb +6 -0
  52. data/test/data/unit_test_rbtest-output.rb +6 -0
  53. data/test/test_completion.rb +37 -3
  54. data/test/test_doc.rb +2 -0
  55. data/test/test_functional.rb +75 -14
  56. data/test/test_options.rb +1 -0
  57. data/test/test_ruby_toggle_file.rb +125 -0
  58. data/test/test_run.rb +7 -3
  59. data/test/test_xmpfilter.rb +132 -5
  60. data/test/test_xmptestunitfilter.rb +1 -0
  61. metadata +76 -43
@@ -3,8 +3,12 @@
3
3
  # rubikitch <rubikitch@ruby-lang.org>
4
4
  # Use and distribution subject to the terms of the Ruby license.
5
5
 
6
+ require 'rcodetools/fork_config'
7
+
8
+ module Rcodetools
9
+
6
10
  class XMPFilter
7
- VERSION = "0.5.0"
11
+ VERSION = "0.7.0"
8
12
 
9
13
  MARKER = "!XMP#{Time.new.to_i}_#{Process.pid}_#{rand(1000000)}!"
10
14
  XMP_RE = Regexp.new("^" + Regexp.escape(MARKER) + '\[([0-9]+)\] (=>|~>|==>) (.*)')
@@ -17,6 +21,22 @@ class XMPFilter
17
21
  :include_paths => [], :warnings => true,
18
22
  :use_parentheses => true}
19
23
 
24
+ def self.windows?
25
+ /win|mingw/ =~ RUBY_PLATFORM && /darwin/ !~ RUBY_PLATFORM
26
+ end
27
+
28
+ Interpreter = Struct.new(:options, :execute_method, :accept_debug, :chdir_proc)
29
+ INTERPRETER_RUBY = Interpreter.new(["-w"],
30
+ windows? ? :execute_tmpfile : :execute_popen,
31
+ true, nil)
32
+ INTERPRETER_RBTEST = Interpreter.new(["-S", "rbtest"], :execute_script, false, nil)
33
+ INTERPRETER_FORK = Interpreter.new(["-S", "rct-fork-client"], :execute_tmpfile, false,
34
+ lambda { Fork::chdir_fork_directory })
35
+
36
+ def self.detect_rbtest(code, opts)
37
+ opts[:use_rbtest] ||= (opts[:detect_rbtest] and code =~ /^=begin test./) ? true : false
38
+ end
39
+
20
40
  # The processor (overridable)
21
41
  def self.run(code, opts)
22
42
  new(opts).annotate(code)
@@ -24,6 +44,7 @@ class XMPFilter
24
44
 
25
45
  def initialize(opts = {})
26
46
  options = INITIALIZE_OPTS.merge opts
47
+ @interpreter_info = INTERPRETER_RUBY
27
48
  @interpreter = options[:interpreter]
28
49
  @options = options[:options]
29
50
  @libs = options[:libs]
@@ -34,8 +55,52 @@ class XMPFilter
34
55
  @warnings = options[:warnings]
35
56
  @parentheses = options[:use_parentheses]
36
57
  @ignore_NoMethodError = options[:ignore_NoMethodError]
37
-
58
+ test_script = options[:test_script]
59
+ test_method = options[:test_method]
60
+ filename = options[:filename]
38
61
  @postfix = ""
62
+
63
+ initialize_rct_fork if options[:detect_rct_fork]
64
+ initialize_rbtest if options[:use_rbtest]
65
+ initialize_for_test_script test_script, test_method, filename if test_script and !options[:use_rbtest]
66
+ end
67
+
68
+ def initialize_rct_fork
69
+ if Fork::run?
70
+ @interpreter_info = INTERPRETER_FORK
71
+ end
72
+ end
73
+
74
+ def initialize_rbtest
75
+ @interpreter_info = INTERPRETER_RBTEST
76
+ end
77
+
78
+ def initialize_for_test_script(test_script, test_method, filename)
79
+ test_script.replace File.expand_path(test_script)
80
+ filename.replace File.expand_path(filename)
81
+ unless test_script == filename
82
+ basedir = common_path(test_script, filename)
83
+ relative_filename = filename[basedir.length+1 .. -1].sub(%r!^lib/!, '')
84
+ @evals << %Q!$LOADED_FEATURES << #{relative_filename.dump}!
85
+ @evals << %Q!require 'test/unit'!
86
+ @evals << %Q!load #{test_script.dump}!
87
+ end
88
+ test_method = get_test_method_from_lineno(test_script, test_method.to_i) if test_method =~ /^\d/
89
+ @evals << %Q!Test::Unit::AutoRunner.run(false, nil, ["-n", #{test_method.dump}])! if test_method
90
+ end
91
+
92
+ def get_test_method_from_lineno(filename, lineno)
93
+ lines = File.readlines(filename)
94
+ (lineno-1).downto(0) do |i|
95
+ if lines[i] =~ /^ *def *(test_[A-Za-z0-9?!_]+)$/
96
+ return $1
97
+ end
98
+ end
99
+ nil
100
+ end
101
+
102
+ def common_path(a, b)
103
+ (a.split(File::Separator) & b.split(File::Separator)).join(File::Separator)
39
104
  end
40
105
 
41
106
  def add_markers(code, min_codeline_size = 50)
@@ -82,10 +147,6 @@ class XMPFilter
82
147
  v = "#{VAR}"
83
148
  blocal = "__#{VAR}"
84
149
  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
150
  oneline_ize(<<-EOF).chomp
90
151
  #{v} = (#{expr})
91
152
  $stderr.puts("#{MARKER}[#{idx}] => " + #{v}.class.to_s + " " + #{v}.inspect) || begin
@@ -108,23 +169,33 @@ end || #{v}
108
169
  alias_method :prepare_line, :prepare_line_annotation
109
170
 
110
171
  def execute_tmpfile(code)
172
+ ios = %w[_ stdin stdout stderr]
111
173
  stdin, stdout, stderr = (1..3).map do |i|
112
- fname = "xmpfilter.tmpfile_#{Process.pid}-#{i}.rb"
174
+ fname = if $DEBUG
175
+ "xmpfilter.tmpfile_#{ios[i]}.rb"
176
+ else
177
+ "xmpfilter.tmpfile_#{Process.pid}-#{i}.rb"
178
+ end
113
179
  f = File.open(fname, "w+")
114
- at_exit { f.close unless f.closed?; File.unlink fname }
180
+ at_exit { f.close unless f.closed?; File.unlink fname unless $DEBUG}
115
181
  f
116
182
  end
117
183
  stdin.puts code
118
184
  stdin.close
119
185
  exe_line = <<-EOF.map{|l| l.strip}.join(";")
120
- $stdout.reopen('#{stdout.path}', 'w')
121
- $stderr.reopen('#{stderr.path}', 'w')
122
- $0.replace '#{stdin.path}'
186
+ $stdout.reopen('#{File.expand_path(stdout.path)}', 'w')
187
+ $stderr.reopen('#{File.expand_path(stderr.path)}', 'w')
188
+ $0.replace '#{File.expand_path(stdin.path)}'
123
189
  ARGV.replace(#{@options.inspect})
124
- load #{stdin.path.inspect}
190
+ load #{File.expand_path(stdin.path).inspect}
125
191
  #{@evals.join(";")}
126
192
  EOF
193
+ debugprint "execute command = #{(interpreter_command << "-e" << exe_line).join ' '}"
194
+
195
+ oldpwd = Dir.pwd
196
+ @interpreter_info.chdir_proc and @interpreter_info.chdir_proc.call
127
197
  system(*(interpreter_command << "-e" << exe_line))
198
+ Dir.chdir oldpwd
128
199
  [stdout, stderr]
129
200
  end
130
201
 
@@ -137,15 +208,30 @@ end || #{v}
137
208
  [stdout, stderr]
138
209
  end
139
210
 
140
- if /win|mingw/ =~ RUBY_PLATFORM && /darwin/ !~ RUBY_PLATFORM
141
- alias_method :execute, :execute_tmpfile
142
- else
143
- alias_method :execute, :execute_popen
211
+ def execute_script(code)
212
+ codefile = "xmpfilter.tmpfile_#{Process.pid}.rb"
213
+ File.open(codefile, "w"){|f| f.puts code}
214
+ path = File.expand_path(codefile)
215
+ at_exit { File.unlink path if File.exist? path}
216
+ stdout, stderr = (1..2).map do |i|
217
+ fname = "xmpfilter.tmpfile_#{Process.pid}-#{i}.rb"
218
+ fullname = File.expand_path(fname)
219
+ at_exit { File.unlink fullname if File.exist? fullname}
220
+ File.open(fname, "w+")
221
+ end
222
+ args = *(interpreter_command << %["#{codefile}"] << "2>" <<
223
+ %["#{stderr.path}"] << ">" << %["#{stdout.path}"])
224
+ system(args.join(" "))
225
+ [stdout, stderr]
226
+ end
227
+
228
+ def execute(code)
229
+ __send__ @interpreter_info.execute_method, code
144
230
  end
145
231
 
146
232
  def interpreter_command
147
- r = [@interpreter, "-w"]
148
- r << "-d" if $DEBUG
233
+ r = [ @interpreter ] + @interpreter_info.options
234
+ r << "-d" if $DEBUG and @interpreter_info.accept_debug
149
235
  r << "-I#{@include_paths.join(":")}" unless @include_paths.empty?
150
236
  @libs.each{|x| r << "-r#{x}" } unless @libs.empty?
151
237
  (r << "-").concat @options unless @options.empty?
@@ -207,3 +293,5 @@ class XMPAddMarkers < XMPFilter
207
293
  new(opts).add_markers(code, opts[:min_codeline_size])
208
294
  end
209
295
  end
296
+
297
+ end
@@ -1,4 +1,7 @@
1
1
  require 'rcodetools/xmpfilter'
2
+
3
+ module Rcodetools
4
+
2
5
  class XMPTestUnitFilter < XMPFilter
3
6
  def initialize(opts = {})
4
7
  super
@@ -117,81 +120,139 @@ end
117
120
 
118
121
  class XMPRSpecFilter < XMPTestUnitFilter
119
122
  private
120
- def execute(code)
121
- codefile = "xmpfilter.rspec_tmpfile_#{Process.pid}.rb"
122
- File.open(codefile, "w"){|f| f.puts code}
123
- path = File.expand_path(codefile)
124
- at_exit { File.unlink path if File.exist? path}
125
- stdout, stderr = (1..2).map do |i|
126
- fname = "xmpfilter.rspec_tmpfile_#{Process.pid}-#{i}.rb"
127
- fullname = File.expand_path(fname)
128
- at_exit { File.unlink fullname if File.exist? fullname}
129
- File.open(fname, "w+")
130
- end
131
- args = *(interpreter_command << %["#{codefile}"] << "2>" <<
132
- %["#{stderr.path}"] << ">" << %["#{stdout.path}"])
133
- system(args.join(" "))
134
- [stdout, stderr]
135
- end
123
+ alias :execute :execute_script
136
124
 
137
125
  def interpreter_command
138
126
  [@interpreter] + @libs.map{|x| "-r#{x}"}
139
127
  end
140
128
 
141
- def raise_assertion(expression, exceptions, index)
142
- ["lambda{#{expression}}.should_raise #{exceptions[index][0]}"]
129
+ begin
130
+ require 'spec/version'
131
+ rescue LoadError
132
+ require 'rubygems'
133
+ begin
134
+ require 'spec/version'
135
+ rescue LoadError # if rspec isn't available, use most recent conventions
136
+ module Spec::VERSION; STRING = "1.0.0" end
137
+ end
143
138
  end
144
139
 
145
- module WithParentheses
146
- def nil_assertion(expression)
147
- ["(#{expression}).should_be_nil"]
140
+ if Spec::VERSION::STRING >= "0.8.0"
141
+
142
+ def raise_assertion(expression, exceptions, index)
143
+ ["lambda{#{expression}}.should raise_error(#{exceptions[index][0]})"]
148
144
  end
149
-
150
- def value_assertions(klass_txt, value_txt, value, expression)
151
- case value
152
- when Float
153
- ["(#{expression}).should_be_close #{value.inspect}, 0.0001"]
154
- when Numeric, String, Hash, Array, Regexp, TrueClass, FalseClass, Symbol, NilClass
155
- ["(#{expression}).should_equal #{value_txt}"]
156
- else
157
- object_assertions klass_txt, value_txt, expression
145
+
146
+ module WithParentheses
147
+ def nil_assertion(expression)
148
+ ["(#{expression}).should be_nil"]
158
149
  end
159
- end
160
150
 
161
- def object_assertions(klass_txt, value_txt, expression)
162
- [ "(#{expression}).should_be_a_kind_of #{klass_txt}",
163
- "(#{expression}.inspect).should_equal #{value_txt.inspect}" ]
164
- end
151
+ def value_assertions(klass_txt, value_txt, value, expression)
152
+ case value
153
+ when Float
154
+ ["(#{expression}).should be_close(#{value.inspect}, 0.0001)"]
155
+ when Numeric, String, Hash, Array, Regexp, TrueClass, FalseClass, Symbol, NilClass
156
+ ["(#{expression}).should == (#{value_txt})"]
157
+ else
158
+ object_assertions klass_txt, value_txt, expression
159
+ end
160
+ end
165
161
 
166
- def equal_assertion(expected, actual)
167
- "(#{actual}).should_equal #{expected}"
168
- end
169
- end
162
+ def object_assertions(klass_txt, value_txt, expression)
163
+ [ "(#{expression}).should be_a_kind_of(#{klass_txt})",
164
+ "(#{expression}.inspect).should == (#{value_txt.inspect})" ]
165
+ end
170
166
 
171
- module Poetry
172
- def nil_assertion(expression)
173
- ["#{expression}.should_be_nil"]
167
+ def equal_assertion(expected, actual)
168
+ "(#{actual}).should == (#{expected})"
169
+ end
174
170
  end
175
171
 
176
- def value_assertions(klass_txt, value_txt, value, expression)
177
- case value
178
- when Float
179
- ["#{expression}.should_be_close #{value.inspect}, 0.0001"]
180
- when Numeric, String, Hash, Array, Regexp, TrueClass, FalseClass, Symbol, NilClass
181
- ["#{expression}.should_equal #{value_txt}"]
182
- else
183
- object_assertions klass_txt, value_txt, expression
172
+ module Poetry
173
+ def nil_assertion(expression)
174
+ ["#{expression}.should be_nil"]
175
+ end
176
+
177
+ def value_assertions(klass_txt, value_txt, value, expression)
178
+ case value
179
+ when Float
180
+ ["#{expression}.should be_close(#{value.inspect}, 0.0001)"]
181
+ when Numeric, String, Hash, Array, Regexp, TrueClass, FalseClass, Symbol, NilClass
182
+ ["#{expression}.should == #{value_txt}"]
183
+ else
184
+ object_assertions klass_txt, value_txt, expression
185
+ end
186
+ end
187
+
188
+ def object_assertions(klass_txt, value_txt, expression)
189
+ [ "#{expression}.should be_a_kind_of(#{klass_txt})",
190
+ "#{expression}.inspect.should == #{value_txt.inspect}" ]
191
+ end
192
+
193
+ def equal_assertion(expected, actual)
194
+ "#{actual}.should == #{expected}"
184
195
  end
185
196
  end
197
+ else
198
+ # old rspec, use deprecated syntax
199
+ def raise_assertion(expression, exceptions, index)
200
+ ["lambda{#{expression}}.should_raise_error(#{exceptions[index][0]})"]
201
+ end
186
202
 
187
- def object_assertions(klass_txt, value_txt, expression)
188
- [ "#{expression}.should_be_a_kind_of #{klass_txt}",
189
- "#{expression}.inspect.should_equal #{value_txt.inspect}" ]
203
+ module WithParentheses
204
+ def nil_assertion(expression)
205
+ ["(#{expression}).should_be_nil"]
206
+ end
207
+
208
+ def value_assertions(klass_txt, value_txt, value, expression)
209
+ case value
210
+ when Float
211
+ ["(#{expression}).should_be_close(#{value.inspect}, 0.0001)"]
212
+ when Numeric, String, Hash, Array, Regexp, TrueClass, FalseClass, Symbol, NilClass
213
+ ["(#{expression}).should_equal(#{value_txt})"]
214
+ else
215
+ object_assertions klass_txt, value_txt, expression
216
+ end
217
+ end
218
+
219
+ def object_assertions(klass_txt, value_txt, expression)
220
+ [ "(#{expression}).should_be_a_kind_of(#{klass_txt})",
221
+ "(#{expression}.inspect).should_equal(#{value_txt.inspect})" ]
222
+ end
223
+
224
+ def equal_assertion(expected, actual)
225
+ "(#{actual}).should_equal(#{expected})"
226
+ end
190
227
  end
191
228
 
192
- def equal_assertion(expected, actual)
193
- "#{actual}.should_equal #{expected}"
229
+ module Poetry
230
+ def nil_assertion(expression)
231
+ ["#{expression}.should_be_nil"]
232
+ end
233
+
234
+ def value_assertions(klass_txt, value_txt, value, expression)
235
+ case value
236
+ when Float
237
+ ["#{expression}.should_be_close #{value.inspect}, 0.0001"]
238
+ when Numeric, String, Hash, Array, Regexp, TrueClass, FalseClass, Symbol, NilClass
239
+ ["#{expression}.should_equal #{value_txt}"]
240
+ else
241
+ object_assertions klass_txt, value_txt, expression
242
+ end
243
+ end
244
+
245
+ def object_assertions(klass_txt, value_txt, expression)
246
+ [ "#{expression}.should_be_a_kind_of #{klass_txt}",
247
+ "#{expression}.inspect.should_equal #{value_txt.inspect}" ]
248
+ end
249
+
250
+ def equal_assertion(expected, actual)
251
+ "#{actual}.should_equal #{expected}"
252
+ end
194
253
  end
195
254
  end
255
+
196
256
  end
197
257
 
258
+ end
@@ -0,0 +1,99 @@
1
+
2
+ # The name is taken from EmacsLisp
3
+ def run_hooks_with_args_until_success(regexp, *args)
4
+ private_methods(true).concat(methods(true)).grep(regexp).sort.each do |m|
5
+ _ = __send__(m, *args)
6
+ return _ if _
7
+ end
8
+ nil
9
+ end
10
+
11
+ class RubyToggleFile
12
+ def ruby_toggle_file(file)
13
+ if File.basename(file) =~ /(?:^test_|_test\.rb$)/
14
+ implementation_file(file)
15
+ else
16
+ test_file(file)
17
+ end
18
+ end
19
+
20
+ LIB_RE = %r!/lib/(.+)\.rb$!
21
+ TEST_RE = %r!/test/(.+/)?test_(.+)\.rb$!
22
+
23
+ def test_file(implementation)
24
+ if m = LIB_RE.match(implementation)
25
+ dir, node = File.split m[1]
26
+ dir = (dir == '.') ? nil : dir+"/"
27
+ else
28
+ dir = node = nil
29
+ end
30
+ run_hooks_with_args_until_success %r/^test_file_/, implementation, m&&(m.pre_match+"/"), dir, node
31
+ end
32
+
33
+ def implementation_file(test)
34
+ m = TEST_RE.match(test)
35
+ run_hooks_with_args_until_success %r/^implementation_file_/, test, m&&(m.pre_match+"/"), m&&m[1], m&&m[2]
36
+ end
37
+
38
+ private
39
+ def exist(file)
40
+ file if File.exist? file
41
+ end
42
+
43
+ RAILS_MVC2TESTNAME = { 'models' => 'unit', 'controllers' => 'functional' }
44
+ RAILS_TESTNAME2MVC = RAILS_MVC2TESTNAME.invert
45
+ def test_file_00_rails(implementation, basedir, dir, node) # rails
46
+ if m = %r!app/(models|controllers)/(.+)\.rb$!.match(implementation)
47
+ "%stest/%s/%s_test.rb" % [ m.pre_match, RAILS_MVC2TESTNAME[m[1]], m[2] ]
48
+ end
49
+ end
50
+
51
+ def test_file_05_rails_lib(implementation, basedir, dir, node)
52
+ if basedir and File.directory?( File.join(basedir, "app") )
53
+ "#{basedir}test/unit/test_#{node}.rb"
54
+ end
55
+ end
56
+
57
+ def test_file_10_no_match(implementation, basedir, dir, node)
58
+ if [basedir, dir, node].all?{|x| x.nil?}
59
+ "#{File.dirname(implementation)}/test_#{File.basename(implementation)}"
60
+ end
61
+ end
62
+
63
+ def test_file_20_simple(implementation, basedir, dir, node) # test/test_NODE.rb
64
+ exist "#{basedir}test/test_#{node}.rb"
65
+ end
66
+
67
+ def test_file_30_flat(implementation, basedir, dir, node) # lib/XXX/NODE.rb -> test/test_NODE.rb
68
+ exist "#{basedir}test/test_#{node}.rb" if dir
69
+ end
70
+
71
+ def test_file_99_autotest_default(implementation, basedir, dir, node) # lib/XXX/NODE.rb -> test/XXX/test_NODE.rb
72
+ "#{basedir}test/#{dir}test_#{node}.rb"
73
+ end
74
+
75
+ def implementation_file_00_rails(test, basedir, dir, node)
76
+ if m = %r!test/(unit|functional)/(.+)_test.rb$!.match(test)
77
+ "%sapp/%s/%s.rb" % [ m.pre_match, RAILS_TESTNAME2MVC[m[1]], m[2] ]
78
+ end
79
+ end
80
+
81
+ def implementation_file_10_no_match(test, basename, dir, node)
82
+ if dir == nil and node == nil and test =~ %r!/test_(.+)\.rb$!
83
+ test.sub("/test_", "/")
84
+ end
85
+ end
86
+
87
+ def implementation_file_20(test, basedir, dir, node)
88
+ exist("#{basedir}lib/#{dir}#{node}.rb")
89
+ end
90
+
91
+ def implementation_file_30_flat(test, basedir, dir, node)
92
+ Dir[ "#{basedir}lib/**/#{node}.rb" ].first
93
+ end
94
+
95
+ def implementation_file_99_default(test, basedir, dir, node)
96
+ "#{basedir}lib/#{dir}#{node}.rb"
97
+ end
98
+
99
+ end