test-loop 1.2.0 → 2.0.0

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.
Files changed (4) hide show
  1. data/README.md +41 -2
  2. data/bin/test-loop +83 -39
  3. metadata +3 -4
  4. data/LICENSE +0 -15
data/README.md CHANGED
@@ -24,7 +24,7 @@ Features
24
24
  * Supports Test::Unit, RSpec, or any other testing framework that is utilized
25
25
  by your application's `test/test_helper.rb` and `spec/spec_helper.rb` files.
26
26
 
27
- * Implemented in less than 40 (SLOC) lines of code! :-)
27
+ * Implemented in less than 60 (SLOC) lines of code! :-)
28
28
 
29
29
 
30
30
  Installation
@@ -63,7 +63,46 @@ Operation
63
63
  * Press Control-C (or send the SIGINT signal) to quit the test loop.
64
64
 
65
65
 
66
+ Configuration
67
+ -------------
68
+
69
+ test-loop looks for a configuration file named `.test-loop` in the current
70
+ working directory. This configuration file is a normal Ruby script which can
71
+ define the following instance variables:
72
+
73
+ * `@overhead_file_globs` is an array of file globbing patterns that describe a
74
+ set of Ruby scripts that are loaded into the main Ruby process as overhead.
75
+
76
+ * `@reabsorb_file_globs` is an array of file globbing patterns that describe a
77
+ set of files which cause the overhead to be reabsorbed whenever they change.
78
+
79
+ * `@source_file_to_test_file_mapping` is a hash that maps a file globbing
80
+ pattern describing a set of source files to a [Rake pathmap expression](
81
+ http://rake.rubyforge.org/classes/String.html#M000017 ) yielding a file
82
+ globbing pattern describing a set of test files that need to be run. In
83
+ other words, whenever the source files (the hash key; left-hand side of the
84
+ mapping) change, their associated test files (the hash value; right-hand
85
+ side of the mapping) are run.
86
+
87
+ * `@after_test_execution` is a proc/lambda object that is executed after tests
88
+ are run. It is passed three things: the status of the test execution
89
+ subprocess, the time when the tests were run, and the list of test files
90
+ that were run.
91
+
92
+ For example, to get on-screen-display notifications through libnotify,
93
+ add the following to your `.test-loop` file:
94
+
95
+ @after_test_execution = lambda do |status, ran_at, files|
96
+ if status.success?
97
+ result, icon = 'PASS', 'apple-green'
98
+ else
99
+ result, icon = 'FAIL', 'apple-red'
100
+ end
101
+ system 'notify-send', '-i', icon, "#{result} at #{ran_at}", files.join("\n")
102
+ end
103
+
104
+
66
105
  License
67
106
  -------
68
107
 
69
- See the LICENSE file for details.
108
+ See the `bin/test-loop` file.
data/bin/test-loop CHANGED
@@ -1,54 +1,98 @@
1
1
  #!/usr/bin/env ruby
2
- require 'rake' # for String#pathmap
2
+ # Continuous testing for Ruby with fork/eval
3
+ # https://github.com/sunaku/test-loop#readme
4
+ #-----------------------------------------------------------------------------
5
+ # (the ISC license)
6
+ #
7
+ # Copyright 2010 Suraj N. Kurapati <sunaku@gmail.com>
8
+ #
9
+ # Permission to use, copy, modify, and/or distribute this software for any
10
+ # purpose with or without fee is hereby granted, provided that the above
11
+ # copyright notice and this permission notice appear in all copies.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14
+ # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15
+ # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16
+ # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17
+ # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18
+ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19
+ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20
+ #-----------------------------------------------------------------------------
3
21
 
4
- # absorb test execution overhead into master process
5
- overhead_file_glob = '{test,spec}/*{test,spec}_helper.rb'
6
- $LOAD_PATH.unshift 'lib' # for non-Rails applications
22
+ require 'rake' # for String#pathmap
7
23
 
8
- puts 'test-loop: Absorbing overhead...'
9
- Dir[overhead_file_glob].each do |file|
10
- $LOAD_PATH.insert 1, file.pathmap('%d')
11
- require file.pathmap('%n')
24
+ def notify message
25
+ puts "test-loop: #{message}"
12
26
  end
13
27
 
14
- # continuously watch for and test changed code
15
- started_at = last_ran_at = Time.now
16
- never_ran_at = Time.at(0)
28
+ begin
29
+ notify 'Loading configuration...'
30
+ config_file = File.join(Dir.pwd, '.test-loop')
31
+ load config_file if File.exist? config_file
17
32
 
18
- trap :QUIT do
19
- puts 'test-loop: Re-executing loop...'
20
- started_at = never_ran_at
21
- end
33
+ (@overhead_file_globs ||= []).
34
+ push('{test,spec}/*{test,spec}_helper.rb').uniq!
22
35
 
23
- trap :TSTP do
24
- puts 'test-loop: Testing everything...'
25
- last_ran_at = never_ran_at
26
- end
36
+ (@reabsorb_file_globs ||= []).
37
+ concat(@overhead_file_globs).
38
+ push(config_file, 'config/*.{rb,yml}').uniq!
27
39
 
28
- puts 'test-loop: Ready for testing!'
29
- loop do
30
- # figure out what test files need to be run
31
- test_files = {
40
+ (@source_file_to_test_file_mapping ||= {}).merge!(
32
41
  '{test,spec}/**/*_{test,spec}.rb' => '%p',
33
42
  '{lib,app}/**/*.rb' => '{test,spec}/**/%n_{test,spec}%x',
34
- }.
35
- map do |source_file_glob, test_file_pathmap|
36
- Dir[source_file_glob].
37
- select {|file| File.mtime(file) > last_ran_at }.
38
- map {|path| Dir[path.pathmap(test_file_pathmap)] }
39
- end.flatten.uniq
40
-
41
- # fork worker process to run the test files
42
- unless test_files.empty?
43
- last_ran_at = Time.now
44
- fork { test_files.each {|file| load file } }
45
- Process.wait
43
+ )
44
+
45
+ @after_test_execution ||= lambda {|status, ran_at, files|}
46
+
47
+ # absorb test execution overhead into master process
48
+ $LOAD_PATH.unshift 'lib' # for non-Rails applications
49
+
50
+ notify 'Absorbing overhead...'
51
+ Dir[*@overhead_file_globs].each do |file|
52
+ $LOAD_PATH.insert 1, file.pathmap('%d')
53
+ require file.pathmap('%n')
46
54
  end
47
55
 
48
- # reabsorb test execution overhead as necessary
49
- if Dir[overhead_file_glob].any? {|file| File.mtime(file) > started_at }
50
- exec 'ruby', __FILE__, *ARGV
56
+ # continuously watch for and test changed code
57
+ started_at = last_ran_at = Time.now
58
+ never_ran_at = Time.at(0)
59
+
60
+ trap :QUIT do
61
+ notify 'Re-executing loop...'
62
+ started_at = never_ran_at
63
+ end
64
+
65
+ trap :TSTP do
66
+ notify 'Testing everything...'
67
+ last_ran_at = never_ran_at
51
68
  end
52
69
 
53
- sleep 1
70
+ notify 'Ready for testing!'
71
+ loop do
72
+ # figure out what test files need to be run
73
+ test_files = @source_file_to_test_file_mapping.
74
+ map do |source_file_glob, test_file_pathmap|
75
+ Dir[source_file_glob].
76
+ select {|file| File.mtime(file) > last_ran_at }.
77
+ map {|path| Dir[path.pathmap(test_file_pathmap)] }
78
+ end.flatten.uniq
79
+
80
+ # fork worker process to run the test files
81
+ unless test_files.empty?
82
+ last_ran_at = Time.now
83
+ fork { test_files.each {|file| notify file; load file } }
84
+ Process.wait
85
+ @after_test_execution.call($?, last_ran_at, test_files)
86
+ end
87
+
88
+ # reabsorb test execution overhead as necessary
89
+ if Dir[*@reabsorb_file_globs].any? {|file| File.mtime(file) > started_at }
90
+ exec $0, *ARGV
91
+ end
92
+
93
+ sleep 1
94
+ end
95
+ rescue StandardError, LoadError => error
96
+ puts error.inspect, error.backtrace
97
+ sleep 1 and exec $0, *ARGV
54
98
  end
metadata CHANGED
@@ -3,10 +3,10 @@ name: test-loop
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
- - 1
7
6
  - 2
8
7
  - 0
9
- version: 1.2.0
8
+ - 0
9
+ version: 2.0.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Suraj N. Kurapati
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-11-23 00:00:00 -08:00
17
+ date: 2010-12-31 00:00:00 -08:00
18
18
  default_executable:
19
19
  dependencies: []
20
20
 
@@ -27,7 +27,6 @@ extensions: []
27
27
  extra_rdoc_files: []
28
28
 
29
29
  files:
30
- - LICENSE
31
30
  - README.md
32
31
  - bin/test-loop
33
32
  has_rdoc: true
data/LICENSE DELETED
@@ -1,15 +0,0 @@
1
- (the ISC license)
2
-
3
- Copyright 2010 Suraj N. Kurapati <sunaku@gmail.com>
4
-
5
- Permission to use, copy, modify, and/or distribute this software for any
6
- purpose with or without fee is hereby granted, provided that the above
7
- copyright notice and this permission notice appear in all copies.
8
-
9
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.