guard-sclang 0.1.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: ec4f743fda4d9f4624f0ac998c2c56116f41f7d7
4
- data.tar.gz: 73d9b97ca0bd8e8693bc2e0f0e22756f7e08537d
2
+ SHA256:
3
+ metadata.gz: ea35a0bfba850d4f17a1f3cf76f1df062053c28630e5eb17f7ccafa8f221de99
4
+ data.tar.gz: 30aa8b33db6642b9490f3ac451943acabfb6fe63e0a50bac88d240982560de62
5
5
  SHA512:
6
- metadata.gz: ccb809137015499345dd6aa8166de1934d79105110fcecc943f4d4b5e044b125ac5317b3812c64aaf9681f70b26e914abc63b898a33bbfa508ffa657af5a3c13
7
- data.tar.gz: d32873acf76ad416693b03cbcd1d97a1eabccd394158143905a474b978ffb10f578394cb28a5be313860ac2a22000e43b1ecfdf64561c0130cb56e95ea3fe488
6
+ metadata.gz: 6191fde9ce607a751469a55c78250c7ba77106c7beb02e9cc43039d1d87db39d0d709806664539ba056373c49807d5153d59991e2cffd20e0b9c4dbd68fbbb9c
7
+ data.tar.gz: c7d8a6ec4df2c08a2391ddf2ffb589f8d04b55c0ba979ce1346c743c62799cfeb6199d55823f7ff6e9ddd4dfc59c8ccbc6054145b71e95840af1eabe1b46c3d4
@@ -19,3 +19,7 @@ please follow these
19
19
  [guidelines on contributing](http://blog.adamspiers.org/2012/11/10/7-principles-for-contributing-patches-to-software-projects/) so that you can help me to help you ;-)
20
20
 
21
21
  Thanks in advance!
22
+
23
+ ## Guide for maintainers
24
+
25
+ See [`MAINTAINERS.md`](MAINTAINERS.md).
data/README.md CHANGED
@@ -1,13 +1,17 @@
1
+ [![Build Status](https://travis-ci.org/aspiers/guard-sclang.svg?branch=master)](https://travis-ci.org/aspiers/guard-sclang)
2
+
1
3
  Guard::Sclang
2
4
  =============
3
5
 
4
- This [Guard](http://guardgem.org/) plugin allows you to run SuperCollider [`UnitTest` test
5
- suites](http://doc.sccode.org/Classes/UnitTest.html) commands when
6
- files are added or altered.
6
+ This [Guard](http://guardgem.org/) plugin allows you to run
7
+ SuperCollider [`UnitTest` test
8
+ suites](http://doc.sccode.org/Classes/UnitTest.html) automatically
9
+ when files are added or altered, so that you can immediately see the
10
+ impact of code changes on your tests.
7
11
 
8
12
 
9
- Install
10
- -------
13
+ Installation
14
+ ------------
11
15
 
12
16
  Make sure you have [Guard](http://guardgem.org/) installed.
13
17
 
@@ -15,17 +19,25 @@ Install the gem with:
15
19
 
16
20
  gem install guard-sclang
17
21
 
18
- Or add it to your `Gemfile`:
22
+ Or, better, add it to your `Gemfile`, and then use
23
+ [Bundler](http://bundler.io/) to install it:
19
24
 
20
- gem 'guard-sclang'
25
+ echo "gem 'guard-sclang'" >> Gemfile
26
+ bundle install
21
27
 
22
- And then add a basic setup to your `Guardfile`:
23
28
 
24
- guard init sclang
29
+ Configuring a `Guardfile`
30
+ ---------------------------
25
31
 
32
+ Before you can launch Guard, you need to configure a `Guardfile` which
33
+ tells Guard which of your SuperCollider tests to run via the
34
+ `guard-sclang` plugin.
26
35
 
27
- Usage
28
- -----
36
+ You can create a stub `Guardfile` from a built-in template via:
37
+
38
+ bundle exec guard init sclang
39
+
40
+ The rest of this section explains how to configure the `Guardfile`.
29
41
 
30
42
  When one or more files matching a `watch` block's regular expression
31
43
  changes, guard-sclang simply runs the UnitTest subclass returned by
@@ -76,7 +88,7 @@ end
76
88
 
77
89
  ### Other options
78
90
 
79
- To run everything on start pass `:all_on_start` to `#guard`:
91
+ To run everything on start, pass `:all_on_start` to `#guard`:
80
92
 
81
93
  ``` ruby
82
94
  guard :sclang, all_on_start: true do
@@ -84,6 +96,39 @@ guard :sclang, all_on_start: true do
84
96
  end
85
97
  ```
86
98
 
99
+ To run everything after previously failing tests succeeded, pass
100
+ `:all_after_pass` to `#guard`:
101
+
102
+ ``` ruby
103
+ guard :sclang, all_after_pass: true do
104
+ ...
105
+ end
106
+ ```
107
+
108
+
109
+ Usage
110
+ -----
111
+
112
+ Once you have set up your `Guardfile` with the `guard-sclang` plugin
113
+ enabled, you are ready to launch Guard.
114
+
115
+ `guard-sclang` assumes that the `sclang` interpreter is to be found
116
+ somewhere on your `$PATH`. If you installed SuperCollider on Linux
117
+ via a distribution package, this should happen automatically, in which
118
+ case you can simply launch Guard by typing this into your shell:
119
+
120
+ bundle exec guard
121
+
122
+ However if you installed from source, or you are using MacOS, maybe
123
+ `sclang` won't be on the `$PATH`, in which case you will need to set
124
+ it. This can either be done temporarily for each invocation of Guard,
125
+ e.g.
126
+
127
+ PATH=/path/to/dir/containing/sclang:$PATH bundle exec guard
128
+
129
+ or by configuring your interactive shell setup (e.g. `~/.bashrc`) to
130
+ set `$PATH` on startup.
131
+
87
132
 
88
133
  Development / support / feedback
89
134
  --------------------------------
@@ -6,10 +6,13 @@ require 'guard/sclang/version'
6
6
 
7
7
  module Guard
8
8
  class Sclang < Plugin
9
+ attr_accessor :last_failed
10
+
9
11
  def initialize(options={})
10
12
  super
11
13
  options[:args] ||= []
12
14
  options[:timeout] ||= 3
15
+ @last_failed = false
13
16
  end
14
17
 
15
18
  # Calls #run_all if the :all_on_start option is present.
@@ -21,10 +24,13 @@ module Guard
21
24
  def stop
22
25
  end
23
26
 
24
- # Call #run_on_change for all files which match this guard.
27
+ # Test for all files which match this guard.
25
28
  def run_all
26
- all = Compat.matching_files(self, Dir.glob('{,**/}*.sc{,d}'))
27
- run_on_modifications(all)
29
+ run_sclang
30
+ end
31
+
32
+ def all_paths
33
+ Compat.matching_files(self, Dir.glob('{,**/}*.sc{,d}'))
28
34
  end
29
35
 
30
36
  def run_on_additions(paths)
@@ -53,10 +59,19 @@ module Guard
53
59
  else
54
60
  title = tester.join " "
55
61
  end
56
- [cmd, title]
62
+ return [cmd, title]
63
+ end
64
+
65
+ def run_sclang(paths=nil)
66
+ success = run_sclang_once(paths || all_paths)
67
+ if paths && options[:all_after_pass] && success && last_failed
68
+ success = run_all
69
+ end
70
+ @last_failed = !success
71
+ return success
57
72
  end
58
73
 
59
- def run_sclang(paths)
74
+ def run_sclang_once(paths)
60
75
  paths = paths.uniq
61
76
  cmd, title = _get_cmd_and_title(paths)
62
77
 
@@ -64,17 +79,40 @@ module Guard
64
79
  print Compat::UI.color("=" * (ENV["COLUMNS"] || "72").to_i, :blue)
65
80
  print Compat::UI.color("Running: " + cmd.join(" ") + "\n", :blue)
66
81
 
67
- got_status, exit_status = _run_cmd(cmd, title)
82
+ run_status, exit_status = _run_cmd(cmd, title)
68
83
 
69
- unless got_status
84
+ if run_status
85
+ return run_status == :success
86
+ else
87
+ # Couldn't figure out the result from the output. Even if
88
+ # the exit code is 0, this could simply mean something went
89
+ # wrong in unit-test-cli.scd's handling of an error, so we
90
+ # assume the worst.
70
91
  _handle_missing_status(exit_status, title)
92
+ return :failed
71
93
  end
72
94
  end
73
95
 
96
+ # Returns [run_status, exit_status] pair.
97
+ #
98
+ # Run the test runner, add colour for PASS/FAIL/ERROR/WARNING, and
99
+ # try to extract the final test result (100% pass / some failures
100
+ # / compilation error) from the runner output. If the test result
101
+ # is successfully extracted from the output, the appropriate
102
+ # notification will be sent, and the run_status value returned
103
+ # will be :success or :failed. However if something goes wrong
104
+ # then we won't be able to determine the result from the output,
105
+ # in which case at least we capture the exit status of the runner
106
+ # process, and success is determined based on this exit status.
107
+ #
108
+ # Note that due to quirks in SuperCollider which are not yet
109
+ # understood, it is possible for the exit code to be non-zero even
110
+ # when the test suite passes 100% and the test runner is
111
+ # apparently working as designed.
74
112
  def _run_cmd(cmd, title)
75
113
  command, *args = *cmd
76
114
 
77
- got_status = false
115
+ run_status = nil
78
116
  exit_status = nil
79
117
 
80
118
  # Using PTY instead of Open3.popen2e should work around
@@ -87,7 +125,7 @@ module Guard
87
125
  colors =
88
126
  if line =~ /^PASS:/
89
127
  [:green]
90
- elsif line =~ /^FAIL:/
128
+ elsif line =~ /^FAIL:|^There were failures/
91
129
  [:red]
92
130
  elsif line =~ /^ERROR:/
93
131
  [:bright, :red]
@@ -97,10 +135,18 @@ module Guard
97
135
  []
98
136
  end
99
137
 
100
- status, msg, line = _check_line_for_status(line)
101
- if status
102
- got_status = true
103
- Compat::UI.notify(msg, title: title, image: status)
138
+ line_status, msg, line = _check_line_for_status(line)
139
+ if line_status
140
+ # Allow for multiple summary lines just in case, e.g.
141
+ # some with no failures and others with failures.
142
+ # Hopefully this won't happen though.
143
+ if line_status == :success
144
+ run_status ||= line_status
145
+ else
146
+ run_status = line_status
147
+ end
148
+
149
+ Compat::UI.notify(msg, title: title, image: line_status)
104
150
  end
105
151
 
106
152
  print Compat::UI.color(line, *colors)
@@ -112,6 +158,9 @@ module Guard
112
158
  rescue Errno::EIO => e
113
159
  # Ran out of output to read
114
160
  exit_status = $?
161
+ unless exit_status
162
+ Compat::UI.error("$? returned #{exit_status}")
163
+ end
115
164
  end
116
165
  end
117
166
  rescue PTY::ChildExited => e
@@ -119,7 +168,7 @@ module Guard
119
168
  exit_status = e.status.exitstatus
120
169
  end
121
170
 
122
- [got_status, exit_status]
171
+ [run_status, exit_status]
123
172
  end
124
173
 
125
174
  def _check_line_for_status(line)
@@ -140,13 +189,16 @@ module Guard
140
189
  [status, msg, line]
141
190
  end
142
191
 
192
+ # Couldn't figure out the result from the output, so rely on
193
+ # the exit code instead.
143
194
  def _handle_missing_status(exit_status, title)
144
195
  msg = "Pid %d exited with status %d" % [exit_status.pid, exit_status.exitstatus]
145
- status = exit_status == 0 ? :success : :failed
196
+ status = exit_status.success? ? :success : :failed
146
197
  Compat::UI.notify(msg, title: title, image: status)
147
198
  level = status == :success ? :warning : :error
148
199
  Compat::UI.send(level, msg)
149
200
  Compat::UI.warning("Didn't find test results in output")
201
+ exit_status.success?
150
202
  end
151
203
  end
152
204
  end
@@ -1,5 +1,5 @@
1
1
  module Guard
2
2
  module SclangVersion
3
- VERSION = '0.1.0'
3
+ VERSION = '0.3.0'
4
4
  end
5
5
  end
@@ -31,6 +31,8 @@ var excludes = [
31
31
  // Have to wrap this in a Task so that we can wait.
32
32
  t = Task.new {
33
33
  UnitTest.reset;
34
+ //UnitTest.reportPasses = false;
35
+ UnitTest.passVerbosity = UnitTest.brief;
34
36
  if (thisProcess.argv.isEmpty) {
35
37
  UnitTest.allSubclasses.do { |testClass|
36
38
  if (excludes.includes(testClass.asString).not) {
@@ -44,7 +46,7 @@ t = Task.new {
44
46
  } {
45
47
  thisProcess.argv.do { |name|
46
48
  if (name.contains("/")) {
47
- name = name.basename.removeExtension;
49
+ name = PathName(name.basename).fileNameWithoutExtension;
48
50
  };
49
51
  if (name.contains(":")) {
50
52
  UnitTest.runTest(name);
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: guard-sclang
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adam Spiers
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-12-29 00:00:00.000000000 Z
11
+ date: 2018-04-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: guard
@@ -44,6 +44,20 @@ dependencies:
44
44
  - - "~>"
45
45
  - !ruby/object:Gem::Version
46
46
  version: '1.0'
47
+ - !ruby/object:Gem::Dependency
48
+ name: bundler
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: 1.13.0
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: 1.13.0
47
61
  - !ruby/object:Gem::Dependency
48
62
  name: rake
49
63
  requirement: !ruby/object:Gem::Requirement
@@ -98,7 +112,6 @@ files:
98
112
  - LICENSE
99
113
  - README.md
100
114
  - lib/guard/sclang.rb
101
- - lib/guard/sclang.rb.orig
102
115
  - lib/guard/sclang/templates/Guardfile
103
116
  - lib/guard/sclang/version.rb
104
117
  - unit-test-cli.scd
@@ -122,7 +135,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
122
135
  version: '0'
123
136
  requirements: []
124
137
  rubyforge_project:
125
- rubygems_version: 2.6.8
138
+ rubygems_version: 2.7.6
126
139
  signing_key:
127
140
  specification_version: 4
128
141
  summary: Guard gem for running sclang commands
@@ -1,166 +0,0 @@
1
- require 'open3'
2
- require 'pathname'
3
-
4
- require 'guard/compat/plugin'
5
- require 'guard/sclang/version'
6
-
7
- module Guard
8
- class Sclang < Plugin
9
- <<<<<<< HEAD
10
- def initialize
11
- =======
12
- def initialize(options)
13
- >>>>>>> c984ace... fix tests
14
- super
15
- options[:args] ||= []
16
- options[:timeout] ||= 3
17
- end
18
-
19
- # Calls #run_all if the :all_on_start option is present.
20
- def start
21
- run_all if options[:all_on_start]
22
- end
23
-
24
- # Defined only to make callback(:stop_begin) and callback(:stop_end) working
25
- def stop
26
- end
27
-
28
- # Call #run_on_change for all files which match this guard.
29
- def run_all
30
- all = Compat.matching_files(self, Dir.glob('{,**/}*.sc{,d}'))
31
- run_on_modifications(all)
32
- end
33
-
34
- def run_on_additions(paths)
35
- run_sclang(paths)
36
- end
37
-
38
- def run_on_modifications(paths)
39
- run_sclang(paths)
40
- end
41
-
42
- def run_on_removals(paths)
43
- run_sclang(paths)
44
- end
45
-
46
- def _get_cmd_and_title(paths)
47
- # -i scqt is required to compile IDE libraries, otherwise we get
48
- # compile warnings on Quarks which extend classes provided by those
49
- # IDE libraries.
50
- here = Pathname.new(__FILE__).dirname
51
- runner = here.parent.parent + "unit-test-cli.scd"
52
- tester = ["sclang"] + options[:args] + [runner.to_s]
53
- cmd = ["timeout", options[:timeout].to_s] + tester
54
- if paths
55
- cmd += paths
56
- title = paths.join " "
57
- else
58
- title = tester.join " "
59
- end
60
- [cmd, title]
61
- end
62
-
63
- def run_sclang(paths)
64
- cmd, title = _get_cmd_and_title(paths)
65
-
66
- outerr = ''
67
- print Compat::UI.color("=" * (ENV["COLUMNS"] || "72").to_i, :blue)
68
- print Compat::UI.color("Running: " + cmd.join(" ") + "\n", :blue)
69
-
70
- got_status, exit_status = _run_cmd(cmd, title)
71
-
72
- unless got_status
73
- _handle_missing_status(exit_status)
74
- end
75
- end
76
-
77
- def _run_cmd(cmd, title)
78
- got_status = false
79
- exit_status = nil
80
-
81
- Open3.popen2e(*cmd) do |stdin, stdouterr, wait_thr|
82
- stdouterr.each do |line|
83
- #Compat::UI.info(line)
84
- colors =
85
- if line =~ /^PASS:/
86
- [:green]
87
- elsif line =~ /^FAIL:/
88
- [:red]
89
- elsif line =~ /^ERROR:/
90
- [:bright, :red]
91
- elsif line =~ /^WARNING:/
92
- [:yellow]
93
- else
94
- []
95
- end
96
-
97
- status, msg, line = _check_line_for_status(line)
98
- if status
99
- got_status = true
100
- Compat::UI.notify(msg, title: title, image: status)
101
- end
102
-
103
- print Compat::UI.color(line, *colors)
104
- end
105
-
106
- exit_status = wait_thr.value
107
- end
108
-
109
- [got_status, exit_status]
110
- end
111
-
112
- def _check_line_for_status(line)
113
- status, msg = nil
114
-
115
- if line =~ /Finished running test\(s\): (\d+ pass(?:es), (\d+) failures?)/
116
- msg, failures = $1, $2
117
- status = failures == "0" ? :success : :failed # :pending also supported
118
- elsif line =~ /(Library has not been compiled successfully)\./
119
- msg = $1
120
- status = :failed
121
- end
122
-
123
- if status
124
- line = Compat::UI.color(line, status == :success ? :green : :red)
125
- end
126
-
127
- [status, msg, line]
128
- end
129
-
130
- def _handle_missing_status(exit_status)
131
- msg = "Pid %d exited with status %d" % [exit_status.pid, exit_status]
132
- status = exit_status == 0 ? :success : :failed
133
- Compat::UI.notify(msg, title: title, image: status)
134
- level = status == :success ? :warning : :error
135
- Compat::UI.send(level, msg)
136
- Compat::UI.warning("Didn't find test results in output")
137
- end
138
- end
139
-
140
- class Dsl
141
- # Easy method to display a notification
142
- def n(msg, title='', image=nil)
143
- Compat::UI.notify(msg, :title => title, :image => image)
144
- end
145
-
146
- # Eager prints the result for stdout and stderr as it would be written when
147
- # running the command from the terminal. This is useful for long running
148
- # tasks.
149
- def eager(command)
150
- require 'pty'
151
-
152
- begin
153
- PTY.spawn command do |r, w, pid|
154
- begin
155
- $stdout.puts
156
- r.each {|line| print line }
157
- rescue Errno::EIO
158
- # the process has finished
159
- end
160
- end
161
- rescue PTY::ChildExited
162
- $stdout.puts "The child process exited!"
163
- end
164
- end
165
- end
166
- end