autotest 4.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,61 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{autotest}
8
+ s.version = "4.1.4"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Ryan Davis"]
12
+ s.date = %q{2009-12-19}
13
+ s.executables = ["unit_diff", "autotest"]
14
+ s.extra_rdoc_files = [
15
+ "README.markdown"
16
+ ]
17
+ s.files = [
18
+ ".autotest",
19
+ ".gitignore",
20
+ "History.txt",
21
+ "README.markdown",
22
+ "Rakefile",
23
+ "VERSION",
24
+ "articles/getting_started_with_autotest.html",
25
+ "autotest.gemspec",
26
+ "bin/autotest",
27
+ "bin/unit_diff",
28
+ "example_dot_autotest.rb",
29
+ "lib/autotest.rb",
30
+ "lib/autotest/autoupdate.rb",
31
+ "lib/autotest/once.rb",
32
+ "lib/autotest/rcov.rb",
33
+ "lib/autotest/restart.rb",
34
+ "lib/autotest/timestamp.rb",
35
+ "lib/unit_diff.rb",
36
+ "test/helper.rb",
37
+ "test/test_autotest.rb",
38
+ "test/test_unit_diff.rb"
39
+ ]
40
+ s.homepage = %q{http://github.com/grosser/autotest}
41
+ s.rdoc_options = ["--charset=UTF-8"]
42
+ s.require_paths = ["lib"]
43
+ s.rubygems_version = %q{1.3.5}
44
+ s.summary = %q{Autotest, without ZenTest}
45
+ s.test_files = [
46
+ "test/test_autotest.rb",
47
+ "test/helper.rb",
48
+ "test/test_unit_diff.rb"
49
+ ]
50
+
51
+ if s.respond_to? :specification_version then
52
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
53
+ s.specification_version = 3
54
+
55
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
56
+ else
57
+ end
58
+ else
59
+ end
60
+ end
61
+
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'optparse'
4
+
5
+ options = {}
6
+ OptionParser.new do |opts|
7
+ opts.banner = <<BANNER
8
+ Continuouse testing for your ruby app.
9
+
10
+ Usage:
11
+ autotest [options]
12
+ BANNER
13
+ opts.on("-f", "--fast-start","Do not run full tests at start") { options[:no_full_after_start] = true }
14
+ opts.on("-c", "--no-full-after-failed","Do not run full tests after failed test passed") { options[:no_full_after_failed] = true }
15
+ opts.on("-v", "--verbose","Be verbose. Prints files that autotest doesn't know how to map to tests") { options[:verbose] = true }
16
+ opts.on("-q", "--quiet","Be quiet.") { options[:quiet] = true }
17
+ opts.on("-h", "--help","Show this.") { puts opts;exit }
18
+ end.parse!
19
+
20
+ #TODO remove this ? what does it do ?
21
+ class Dir
22
+ class << self
23
+ alias :old_index :[]
24
+ def [](*args)
25
+ $-w, old_warn = false, $-w
26
+ old_index(*args)
27
+ ensure
28
+ $-w = old_warn
29
+ end
30
+ end
31
+ end
32
+
33
+ #run the correct Autotest variant fitting to the local structure
34
+ require 'autotest'
35
+ Autotest.options.merge!(options)
36
+ target = Autotest
37
+ style = Autotest.autodiscover
38
+ unless style.empty? then
39
+ mod = "autotest/#{style.join("_")}"
40
+ puts "loading #{mod}" unless options[:quiet]
41
+ begin
42
+ require mod
43
+ rescue LoadError
44
+ abort "Autotest style #{mod} doesn't seem to exist. Aborting."
45
+ end
46
+ target = Autotest.const_get(style.map {|s| s.capitalize}.join)
47
+ end
48
+ target.run
@@ -0,0 +1,37 @@
1
+ #!/usr/local/bin/ruby -ws
2
+ #
3
+ # unit_diff - a ruby unit test filter by Ryan Davis <ryand-ruby@zenspider.com>
4
+ #
5
+ # usage:
6
+ #
7
+ # test.rb | unit_diff [options]
8
+ # options:
9
+ # -b ignore whitespace differences
10
+ # -c contextual diff
11
+ # -h show usage
12
+ # -k keep temp diff files around
13
+ # -u unified diff
14
+ # -v display version
15
+
16
+ require 'unit_diff'
17
+
18
+ ############################################################
19
+
20
+ #TODO fix this...
21
+ if defined? $v then
22
+ puts "#{File.basename $0} v. 4.0.3"
23
+ exit 0
24
+ end
25
+
26
+ if defined? $h then
27
+ File.open(__FILE__) do |f|
28
+ begin; end until f.readline =~ /usage:/
29
+ f.readline
30
+ while line = f.readline and line.sub!(/^# ?/, '')
31
+ $stderr.puts line
32
+ end
33
+ end
34
+ exit 0
35
+ end
36
+
37
+ UnitDiff.unit_diff
@@ -0,0 +1,12 @@
1
+ # -*- ruby -*-
2
+
3
+ # require 'autotest/autoupdate'
4
+ # require 'autotest/once'
5
+ # require 'autotest/rcov'
6
+ # require 'autotest/restart'
7
+ # require 'autotest/timestamp'
8
+
9
+ # Autotest::AutoUpdate.sleep_time = o
10
+ # Autotest::AutoUpdate.update_cmd = o
11
+ # Autotest::RCov.command = o
12
+ # Autotest::RCov.pattern = o
@@ -0,0 +1,670 @@
1
+ require 'find'
2
+ require 'rbconfig'
3
+
4
+ $TESTING = false unless defined? $TESTING
5
+
6
+ ##
7
+ # Autotest continuously scans the files in your project for changes
8
+ # and runs the appropriate tests. Test failures are run until they
9
+ # have all passed. Then the full test suite is run to ensure that
10
+ # nothing else was inadvertantly broken.
11
+ #
12
+ # If you want Autotest to start over from the top, hit ^C once. If
13
+ # you want Autotest to quit, hit ^C twice.
14
+ #
15
+ # Rails:
16
+ #
17
+ # The autotest command will automatically discover a Rails directory
18
+ # by looking for config/environment.rb. When Rails is discovered,
19
+ # autotest uses RailsAutotest to perform file mappings and other work.
20
+ # See RailsAutotest for details.
21
+ #
22
+ # Plugins:
23
+ #
24
+ # Plugins are available by creating a .autotest file either in your
25
+ # project root or in your home directory. You can then write event
26
+ # handlers in the form of:
27
+ #
28
+ # Autotest.add_hook hook_name { |autotest| ... }
29
+ #
30
+ # The available hooks are listed in +ALL_HOOKS+.
31
+ #
32
+ # See example_dot_autotest.rb for more details.
33
+ #
34
+ # If a hook returns a true value, it signals to autotest that the hook
35
+ # was handled and should not continue executing hooks.
36
+ #
37
+ # Naming:
38
+ #
39
+ # Autotest uses a simple naming scheme to figure out how to map
40
+ # implementation files to test files following the Test::Unit naming
41
+ # scheme.
42
+ #
43
+ # * Test files must be stored in test/
44
+ # * Test files names must start with test_
45
+ # * Test class names must start with Test
46
+ # * Implementation files must be stored in lib/
47
+ # * Implementation files must match up with a test file named
48
+ # test_.*implementation.rb
49
+ #
50
+ # Strategy:
51
+ #
52
+ # 1. Find all files and associate them from impl <-> test.
53
+ # 2. Run all tests.
54
+ # 3. Scan for failures.
55
+ # 4. Detect changes in ANY (ruby?. file, rerun all failures + changed files.
56
+ # 5. Until 0 defects, goto 3.
57
+ # 6. When 0 defects, goto 2.
58
+
59
+ class Autotest
60
+
61
+ VERSION = File.read( File.join(File.dirname(__FILE__),'..','VERSION') ).strip
62
+
63
+ T0 = Time.at 0
64
+
65
+ ALL_HOOKS = [ :all_good, :died, :green, :initialize, :interrupt, :quit,
66
+ :ran_command, :red, :reset, :run_command, :updated, :waiting ]
67
+
68
+ @@options = {}
69
+ def self.options;@@options;end
70
+ def options;@@options;end
71
+
72
+
73
+ HOOKS = Hash.new { |h,k| h[k] = [] } #unfound keys are []
74
+ unless defined? WINDOZE then
75
+ WINDOZE = /win32/ =~ RUBY_PLATFORM
76
+ SEP = WINDOZE ? '&' : ';'
77
+ end
78
+
79
+ @@discoveries = []
80
+
81
+ ##
82
+ # Add a proc to the collection of discovery procs. See
83
+ # +autodiscover+.
84
+
85
+ def self.add_discovery &proc
86
+ @@discoveries << proc
87
+ end
88
+
89
+ ##
90
+ # Automatically find all potential autotest runner styles by
91
+ # searching your loadpath, vendor/plugins, and rubygems for
92
+ # "autotest/discover.rb". If found, that file is loaded and it
93
+ # should register discovery procs with autotest using
94
+ # +add_discovery+. That proc should return one or more strings
95
+ # describing the user's current environment. Those styles are then
96
+ # combined to dynamically invoke an autotest plugin to suite your
97
+ # environment. That plugin should define a subclass of Autotest with
98
+ # a corresponding name.
99
+ #
100
+ # === Process:
101
+ #
102
+ # 1. All autotest/discover.rb files loaded.
103
+ # 2. Those procs determine your styles (eg ["rails", "rspec"]).
104
+ # 3. Require file by sorting styles and joining (eg 'autotest/rails_rspec').
105
+ # 4. Invoke run method on appropriate class (eg Autotest::RailsRspec.run).
106
+ #
107
+ # === Example autotest/discover.rb:
108
+ #
109
+ # Autotest.add_discovery do
110
+ # "rails" if File.exist? 'config/environment.rb'
111
+ # end
112
+ #
113
+ def self.autodiscover
114
+ require 'rubygems'
115
+
116
+ Gem.find_files("autotest/discover").each do |f|
117
+ load f
118
+ end
119
+
120
+ #call all discover procs an determine style
121
+ @@discoveries.map{ |proc| proc.call }.flatten.compact.sort.uniq
122
+ end
123
+
124
+ ##
125
+ # Initialize and run the system.
126
+
127
+ def self.run
128
+ new.run
129
+ end
130
+
131
+ attr_writer :known_files
132
+ attr_accessor(:completed_re,
133
+ :extra_class_map,
134
+ :extra_files,
135
+ :failed_results_re,
136
+ :files_to_test,
137
+ :find_order,
138
+ :interrupted,
139
+ :last_mtime,
140
+ :libs,
141
+ :order,
142
+ :output,
143
+ :results,
144
+ :sleep,
145
+ :tainted,
146
+ :testlib,
147
+ :find_directories,
148
+ :unit_diff,
149
+ :wants_to_quit)
150
+
151
+ ##
152
+ # Initialize the instance and then load the user's .autotest file, if any.
153
+
154
+ def initialize
155
+ # these two are set directly because they're wrapped with
156
+ # add/remove/clear accessor methods
157
+ @exception_list = []
158
+ @test_mappings = []
159
+
160
+ self.completed_re = /\d+ tests, \d+ assertions, \d+ failures, \d+ errors/
161
+ self.extra_class_map = {}
162
+ self.extra_files = []
163
+ self.failed_results_re = /^\s+\d+\) (?:Failure|Error):\n(.*?)\((.*?)\)/
164
+ self.files_to_test = new_hash_of_arrays
165
+ self.find_order = []
166
+ self.known_files = nil
167
+ self.libs = %w[. lib test].join(File::PATH_SEPARATOR)
168
+ self.order = :random
169
+ self.output = $stderr
170
+ self.sleep = 1
171
+ self.testlib = "test/unit"
172
+ self.find_directories = ['.']
173
+ self.unit_diff = "unit_diff -u"
174
+
175
+ #add Test::Unit mappings
176
+ #file in /lib -> run test in /test
177
+ self.add_mapping(/^lib\/.*\.rb$/) do |filename, _|
178
+ possible = File.basename(filename).gsub '_', '_?'
179
+ files_matching %r%^test/.*#{possible}$%
180
+ end
181
+
182
+ #file in /test -> run it
183
+ self.add_mapping(/^test.*\/test_.*rb$/) do |filename, _|
184
+ filename
185
+ end
186
+
187
+ #execute custom extensions
188
+ [File.expand_path('~/.autotest'), './.autotest'].each do |f|
189
+ load f if File.exist? f
190
+ end
191
+ end
192
+
193
+ ##
194
+ # Repeatedly run failed tests, then all tests, then wait for changes
195
+ # and carry on until killed.
196
+
197
+ def run
198
+ hook :initialize
199
+ reset
200
+ add_sigint_handler
201
+
202
+ self.last_mtime = Time.now if options[:no_full_after_start]
203
+
204
+ loop do
205
+ begin # ^c handler
206
+ get_to_green
207
+ if self.tainted and not options[:no_full_after_failed] then
208
+ rerun_all_tests
209
+ else
210
+ hook :all_good
211
+ end
212
+ wait_for_changes
213
+ rescue Interrupt
214
+ break if self.wants_to_quit
215
+ reset
216
+ end
217
+ end
218
+ hook :quit
219
+ rescue Exception
220
+ hook :died
221
+ end
222
+
223
+ ##
224
+ # Keep running the tests after a change, until all pass.
225
+
226
+ def get_to_green
227
+ begin
228
+ run_tests
229
+ wait_for_changes unless all_good
230
+ end until all_good
231
+ end
232
+
233
+ ##
234
+ # Look for files to test then run the tests and handle the results.
235
+
236
+ def run_tests
237
+ hook :run_command
238
+
239
+ new_mtime = self.find_files_to_test
240
+ return unless new_mtime
241
+ self.last_mtime = new_mtime
242
+
243
+ cmd = self.make_test_cmd self.files_to_test
244
+ return if cmd.empty?
245
+
246
+ puts cmd unless options[:quiet]
247
+
248
+ old_sync = $stdout.sync
249
+ $stdout.sync = true
250
+ self.results = []
251
+ line = []
252
+ begin
253
+ open("| #{cmd}", "r") do |f|
254
+ until f.eof? do
255
+ c = f.getc
256
+ putc c
257
+ line << c
258
+ if c == ?\n then
259
+ self.results << if RUBY_VERSION >= "1.9" then
260
+ line.join
261
+ else
262
+ line.pack "c*"
263
+ end
264
+ line.clear
265
+ end
266
+ end
267
+ end
268
+ ensure
269
+ $stdout.sync = old_sync
270
+ end
271
+ hook :ran_command
272
+ self.results = self.results.join
273
+
274
+ handle_results(self.results)
275
+ end
276
+
277
+ ############################################################
278
+ # Utility Methods, not essential to reading of logic
279
+
280
+ ##
281
+ # Installs a sigint handler.
282
+
283
+ def add_sigint_handler
284
+ trap 'INT' do
285
+ if self.interrupted then
286
+ self.wants_to_quit = true
287
+ else
288
+ unless hook :interrupt then
289
+ puts "Interrupt a second time to quit"
290
+ self.interrupted = true
291
+ Kernel.sleep 1.5
292
+ end
293
+ raise Interrupt, nil # let the run loop catch it
294
+ end
295
+ end
296
+ end
297
+
298
+ ##
299
+ # If there are no files left to test (because they've all passed),
300
+ # then all is good.
301
+
302
+ def all_good
303
+ files_to_test.empty?
304
+ end
305
+
306
+ ##
307
+ # Convert a path in a string, s, into a class name, changing
308
+ # underscores to CamelCase, etc.
309
+
310
+ def path_to_classname(s)
311
+ sep = File::SEPARATOR
312
+ f = s.sub(/^test#{sep}/, '').sub(/\.rb$/, '').split(sep)
313
+ f = f.map { |path| path.split(/_|(\d+)/).map { |seg| seg.capitalize }.join }
314
+ f = f.map { |path| path =~ /^Test/ ? path : "Test#{path}" }
315
+ f.join('::')
316
+ end
317
+
318
+ ##
319
+ # Returns a hash mapping a file name to the known failures for that
320
+ # file.
321
+
322
+ def consolidate_failures(failed)
323
+ filters = new_hash_of_arrays
324
+
325
+ class_map = Hash[*self.find_order.grep(/^test/).map { |f| # TODO: ugly
326
+ [path_to_classname(f), f]
327
+ }.flatten]
328
+ class_map.merge!(self.extra_class_map)
329
+
330
+ failed.each do |method, klass|
331
+ if class_map.has_key? klass then
332
+ filters[class_map[klass]] << method
333
+ else
334
+ output.puts "Unable to map class #{klass} to a file"
335
+ end
336
+ end
337
+
338
+ return filters
339
+ end
340
+
341
+ ##
342
+ # Find the files to process, ignoring temporary files, source
343
+ # configuration management files, etc., and return a Hash mapping
344
+ # filename to modification time.
345
+
346
+ def find_files
347
+ result = {}
348
+ targets = self.find_directories + self.extra_files
349
+ self.find_order.clear
350
+
351
+ targets.each do |target|
352
+ order = []
353
+ Find.find(target) do |f|
354
+ Find.prune if f =~ self.exceptions
355
+
356
+ next if test ?d, f
357
+ next if f =~ /(swp|~|rej|orig)$/ # temporary/patch files
358
+ next if f =~ /\/\.?#/ # Emacs autosave/cvs merge files
359
+
360
+ filename = f.sub(/^\.\//, '')
361
+
362
+ result[filename] = File.stat(filename).mtime rescue next
363
+ order << filename
364
+ end
365
+ self.find_order.push(*order.sort)
366
+ end
367
+
368
+ return result
369
+ end
370
+
371
+ ##
372
+ # Find the files which have been modified, update the recorded
373
+ # timestamps, and use this to update the files to test. Returns
374
+ # the latest mtime of the files modified or nil when nothing was
375
+ # modified.
376
+ def find_files_to_test(files=find_files)
377
+ updated = files.select { |filename, mtime| self.last_mtime < mtime }
378
+
379
+ unless updated.empty? or self.last_mtime.to_i == 0 #nothing to update or initial run
380
+ p updated if options[:verbose]
381
+ hook :updated, updated
382
+ end
383
+
384
+ updated.map { |f,m| test_files_for(f) }.flatten.uniq.each do |filename|
385
+ self.files_to_test[filename] # creates key with default value
386
+ end
387
+
388
+ if updated.empty? then
389
+ nil
390
+ else
391
+ files.values.max
392
+ end
393
+ end
394
+
395
+ ##
396
+ # Check results for failures, set the "bar" to red or green, and if
397
+ # there are failures record this.
398
+
399
+ def handle_results(results)
400
+ failed = results.scan(self.failed_results_re)
401
+ completed = results =~ self.completed_re
402
+
403
+ self.files_to_test = consolidate_failures failed if completed
404
+
405
+ color = completed && self.files_to_test.empty? ? :green : :red
406
+ hook color unless $TESTING
407
+
408
+ self.tainted = true unless self.files_to_test.empty?
409
+ end
410
+
411
+ ##
412
+ # Lazy accessor for the known_files hash.
413
+
414
+ def known_files
415
+ unless @known_files then
416
+ @known_files = Hash[*find_order.map { |f| [f, true] }.flatten]
417
+ end
418
+ @known_files
419
+ end
420
+
421
+ ##
422
+ # Generate the commands to test the supplied files
423
+
424
+ def make_test_cmd files_to_test
425
+ cmds = []
426
+ full, partial = reorder(files_to_test).partition { |k,v| v.empty? }
427
+ base_cmd = "#{ruby} -I#{libs} -rubygems"
428
+
429
+ unless full.empty? then
430
+ classes = full.map {|k,v| k}.flatten.uniq
431
+ classes.unshift testlib
432
+ cmds << "#{base_cmd} -e \"%w[#{classes.join(' ')}].each { |f| require f }\" | #{unit_diff}"
433
+ end
434
+
435
+ partial.each do |klass, methods|
436
+ regexp = Regexp.union(*methods).source
437
+ cmds << "#{base_cmd} #{klass} -n \"/^(#{regexp})$/\" | #{unit_diff}"
438
+ end
439
+
440
+ return cmds.join("#{SEP} ")
441
+ end
442
+
443
+ def new_hash_of_arrays
444
+ Hash.new { |h,k| h[k] = [] }
445
+ end
446
+
447
+ def reorder files_to_test
448
+ case self.order
449
+ when :alpha then
450
+ files_to_test.sort_by { |k,v| k }
451
+ when :reverse then
452
+ files_to_test.sort_by { |k,v| k }.reverse
453
+ when :random then
454
+ max = files_to_test.size
455
+ files_to_test.sort_by { |k,v| rand(max) }
456
+ when :natural then
457
+ (self.find_order & files_to_test.keys).map { |f| [f, files_to_test[f]] }
458
+ else
459
+ raise "unknown order type: #{self.order.inspect}"
460
+ end
461
+ end
462
+
463
+ ##
464
+ # Rerun the tests from cold (reset state)
465
+
466
+ def rerun_all_tests
467
+ reset
468
+ run_tests
469
+
470
+ hook :all_good if all_good
471
+ end
472
+
473
+ ##
474
+ # Clear all state information about test failures and whether
475
+ # interrupts will kill autotest.
476
+
477
+ def reset
478
+ self.files_to_test.clear
479
+ self.find_order.clear
480
+ self.interrupted = false
481
+ self.known_files = nil
482
+ self.last_mtime = T0
483
+ self.tainted = false
484
+ self.wants_to_quit = false
485
+
486
+ hook :reset
487
+ end
488
+
489
+ ##
490
+ # Determine and return the path of the ruby executable.
491
+
492
+ def ruby
493
+ ruby = ENV['RUBY']
494
+ ruby ||= File.join(Config::CONFIG['bindir'],
495
+ Config::CONFIG['ruby_install_name'])
496
+
497
+ ruby.gsub! File::SEPARATOR, File::ALT_SEPARATOR if File::ALT_SEPARATOR
498
+
499
+ return ruby
500
+ end
501
+
502
+ ##
503
+ # Return the name of the file with the tests for filename by finding
504
+ # a +test_mapping+ that matches the file and executing the mapping's
505
+ # proc.
506
+
507
+ def test_files_for(filename)
508
+ result = @test_mappings.find { |file_re, ignored| filename =~ file_re }
509
+
510
+ p :test_file_for => [filename, result.first] if result and $DEBUG
511
+
512
+ result = result.nil? ? [] : [result.last.call(filename, $~)].flatten
513
+
514
+ output.puts "No tests matched #{filename}" if
515
+ (options[:verbose] or $TESTING) and result.empty?
516
+
517
+ result.sort.uniq.select { |f| known_files[f] }
518
+ end
519
+
520
+ ##
521
+ # Sleep then look for files to test, until there are some.
522
+
523
+ def wait_for_changes
524
+ hook :waiting
525
+ Kernel.sleep self.sleep until find_files_to_test
526
+ end
527
+
528
+ ############################################################
529
+ # File Mappings:
530
+
531
+ ##
532
+ # Returns all known files in the codebase matching +regexp+.
533
+
534
+ def files_matching regexp
535
+ self.find_order.select { |k| k =~ regexp }
536
+ end
537
+
538
+ ##
539
+ # Adds a file mapping, optionally prepending the mapping to the
540
+ # front of the list if +prepend+ is true. +regexp+ should match a
541
+ # file path in the codebase. +proc+ is passed a matched filename and
542
+ # Regexp.last_match. +proc+ should return an array of tests to run.
543
+ #
544
+ # For example, if test_helper.rb is modified, rerun all tests:
545
+ #
546
+ # at.add_mapping(/test_helper.rb/) do |f, _|
547
+ # at.files_matching(/^test.*rb$/)
548
+ # end
549
+
550
+ def add_mapping(regexp, prepend = false, &proc)
551
+ if prepend then
552
+ @test_mappings.unshift [regexp, proc]
553
+ else
554
+ @test_mappings.push [regexp, proc]
555
+ end
556
+ nil
557
+ end
558
+
559
+ ##
560
+ # Removed a file mapping matching +regexp+.
561
+
562
+ def remove_mapping regexp
563
+ @test_mappings.delete_if do |k,v|
564
+ k == regexp
565
+ end
566
+ nil
567
+ end
568
+
569
+ ##
570
+ # Clears all file mappings. This is DANGEROUS as it entirely
571
+ # disables autotest. You must add at least one file mapping that
572
+ # does a good job of rerunning appropriate tests.
573
+
574
+ def clear_mappings
575
+ @test_mappings.clear
576
+ nil
577
+ end
578
+
579
+ ############################################################
580
+ # Exceptions:
581
+
582
+ ##
583
+ # Adds +regexp+ to the list of exceptions for find_file. This must
584
+ # be called _before_ the exceptions are compiled.
585
+
586
+ def add_exception regexp
587
+ raise "exceptions already compiled" if defined? @exceptions
588
+ @exception_list << regexp
589
+ nil
590
+ end
591
+
592
+ ##
593
+ # Removes +regexp+ to the list of exceptions for find_file. This
594
+ # must be called _before_ the exceptions are compiled.
595
+
596
+ def remove_exception regexp
597
+ raise "exceptions already compiled" if defined? @exceptions
598
+ @exception_list.delete regexp
599
+ nil
600
+ end
601
+
602
+ ##
603
+ # Clears the list of exceptions for find_file. This must be called
604
+ # _before_ the exceptions are compiled.
605
+
606
+ def clear_exceptions
607
+ raise "exceptions already compiled" if defined? @exceptions
608
+ @exception_list.clear
609
+ nil
610
+ end
611
+
612
+ ##
613
+ # Return a compiled regexp of exceptions for find_files or nil if no
614
+ # filtering should take place. This regexp is generated from
615
+ # +exception_list+.
616
+
617
+ def exceptions
618
+ unless defined? @exceptions then
619
+ if @exception_list.empty? then
620
+ @exceptions = nil
621
+ else
622
+ @exceptions = Regexp.union(*@exception_list)
623
+ end
624
+ end
625
+
626
+ @exceptions
627
+ end
628
+
629
+ ############################################################
630
+ # Hooks:
631
+
632
+ ##
633
+ # Call the event hook named +name+, executing all registered hooks
634
+ # until one returns true. Returns false if no hook handled the
635
+ # event.
636
+
637
+ def hook(name, *args)
638
+ deprecated = {
639
+ # none currently
640
+ }
641
+
642
+ if deprecated[name] and not HOOKS[name].empty? then
643
+ warn "hook #{name} has been deprecated, use #{deprecated[name]}"
644
+ end
645
+
646
+ HOOKS[name].any? do |plugin|
647
+ plugin[self, *args]
648
+ end
649
+ end
650
+
651
+ ##
652
+ # Add the supplied block to the available hooks, with the given
653
+ # name.
654
+
655
+ def self.add_hook(name, &block)
656
+ HOOKS[name] << block
657
+ end
658
+
659
+ private
660
+
661
+ #list of all available rubygem load paths
662
+ def self.rubygem_load_paths
663
+ begin
664
+ require 'rubygems'
665
+ Gem.latest_load_paths
666
+ rescue LoadError
667
+ []
668
+ end
669
+ end
670
+ end