guard-haskell 1.6.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.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- MTlhNDgyMGFhYTJhZDQxMjQyNjhlMWQxMmMwMTE5YzljYzY4NzNhYw==
4
+ Y2MzNjQ5MjQ2NjNmMzU0ODQxZWIwMDU4MTZhZTA3OTE4NmFkNDc2NA==
5
5
  data.tar.gz: !binary |-
6
- NDk2ZjBjMjI0MjdiMDJkMDM5ZDY4ZTg2Y2VjNTk5MWQ3ZmE2ODM5MA==
6
+ YWRkOThmYzYxOWE1ZmQ3ZmQ4YmFhNGVkN2JiNTJmNTM2NTE1YWZmZg==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- MWNhODA4OWM5NDU3ZGJmNzUyYjVmMTUzMWU2Mjc3YmQxMTgyYzkzZjUxMTA5
10
- ZTk4Y2FiYTc3YWQwYmIzNTMyOGNhYTdhMTQ3ODZiZjY4M2RkZTE4OWNiODNj
11
- NzA0MTliMDgyZDVmMzI3MGRjODE1ZDkwMDNlOTFlYTdkOGMwOTU=
9
+ ZjYyNTMxYzVkNjM1YjljMDZkNTg5Mzc1ZjFhZWMwNTQ1OTUwNjI0MTc5OTk2
10
+ ZjY5OGQ1YjY3NjVmNTQzOTMzMDE5MzNlYjNjNjJkNDNkOTE5MDIyYzkyMTlh
11
+ ZmVmY2ZmNWFhMTI0NzA0NGRiMzk0ZWIxYjUwY2I2YzQzMWVhNTI=
12
12
  data.tar.gz: !binary |-
13
- MWExZTU3Mjg0ZDVkODJjMzQzYzg2NzYwYjM3YmE4Y2QwOTg5MThiMjBjMTk3
14
- MTJmMDNkZTc5ZmE4MWE0ZThlMzhjZTI5NThkMzcwNDMxY2MyOTIyNzVlYjM1
15
- YWM5YjFmYmVlYzFiNzI1MzM1YTBlM2Y2ODJhZGM1N2U1YzNhYjY=
13
+ MjgyMGZlYTcwMjMxMTU5ZDc0MDM3N2Q2ZTQ1NGNjMDM1MGQ4NTZkNWRkNDli
14
+ MWVlOWM5ZTc2NjEzMmM3NjI2ZGIyMzk3OGZhYmJjYWUzNWEyNWZlZmU3ZDAw
15
+ MmFkNjA0ZGNiOGIwYThiYmIxYmFkY2FkZDIxNjNkYmZkOWRkZDY=
@@ -1,3 +1,10 @@
1
+ 2.0.0
2
+ =====
3
+
4
+ * Switch to `cabal repl` as an inferior shell
5
+
6
+ * Fix the bug where the cursor does not reappear on guard shutdown
7
+
1
8
  1.6.0
2
9
  =====
3
10
 
@@ -11,6 +18,7 @@
11
18
  =====
12
19
 
13
20
  * Add `sandbox_glob` option
21
+
14
22
  * Separate stages for [re]loading and rerunning specs
15
23
 
16
24
  1.4.0
@@ -22,14 +30,18 @@
22
30
  =====
23
31
 
24
32
  * Ignore user cabal package database if sandbox is found
33
+
25
34
  * Catch CPP failures (previously didn't work because of the typo)
35
+
26
36
  * Add `focus_on_fail` option
27
37
 
28
38
  1.2.0
29
39
  =====
30
40
 
31
41
  * Catch GHCI runtime linker failures
42
+
32
43
  * Separate runtime and compile time failures for `--rerun` to work better
44
+
33
45
  * Fix ignored spec results if spec was run directly from guard repl
34
46
 
35
47
  1.1.0
data/README.md CHANGED
@@ -7,43 +7,40 @@ guard-haskell
7
7
 
8
8
  `Guard::Haskell` automatically runs your specs
9
9
 
10
- # Install
10
+ Install
11
+ -------
11
12
 
12
13
  ```shell
13
14
  % cabal install hspec
14
15
  % gem install guard-haskell
15
16
  ```
16
17
 
17
- # Usage
18
+ Usage
19
+ -----
18
20
 
19
- ## How does it work?
21
+ ### How does it work?
20
22
 
21
23
  For explanation what `guard` is and how to use it, please refer to the [`guard manual`][0]
22
24
 
23
- `guard-haskell` uses [`hspec`][1] to run specs and check results, so it makes some assumptions about your code style:
25
+ `guard-haskell` uses [`hspec`][1] to run specs and check results, so it makes
26
+ some assumptions about your code organization and style:
24
27
 
25
- * `hspec` is your testing framework and
28
+ * `hspec` is your testing framework of choice; therefore,
26
29
 
27
- * [`hspec-discover`][2] (or similar tool) organizes your specs,
28
- i.e. there is a "top" spec (usually `test/Spec.hs`) that pulls others in
30
+ * [`hspec-discover`][2] organizes your specs
29
31
 
30
- When you type in `guard`, `guard-haskell` fires up an `ghci` instance which it talks to, reloading
31
- and rerunning (parts of) "top" spec on files modifications.
32
+ When you type `guard` in the terminal, `guard-haskell` fires up a `cabal repl` instance
33
+ to talk to, running (parts of) examples when files are modified.
32
34
 
33
- ## Guard::Haskell setup
35
+ ### Guard::Haskell setup
34
36
 
35
- For `guard-haskell` to be ready to work we need a top level spec file and a Guardfile:
37
+ For `guard-haskell` to be ready to work we need a test suite named "spec" (that's
38
+ configurable, any test suite name will do) defined in the cabal file and a Guardfile
39
+ (which you can get by running `guard init haskell`)
36
40
 
37
- ```shell
38
- mkdir --parents test
39
- echo '{-# OPTIONS_GHC -F -pgmF hspec-discover #-}' > test/Spec.hs
40
- guard init haskell
41
- guard
42
- ```
43
-
44
- ## Guardfile examples
41
+ ### Guardfile examples
45
42
 
46
- Typical haskell project:
43
+ A typical haskell project:
47
44
 
48
45
  ```ruby
49
46
  guard :haskell do
@@ -52,17 +49,41 @@ guard :haskell do
52
49
  end
53
50
  ```
54
51
 
55
- Customized haskell project:
52
+ A customized haskell project:
53
+
54
+ ```ruby
55
+ options = ["--ghc-options=-ignore-dot-ghci -DTEST"]
56
+
57
+ guard :haskell, all_on_start: true, repl_options: options do
58
+ watch(%r{test/.+Spec\.l?hs$})
59
+ watch(%r{lib/.+\.l?hs$})
60
+ watch(%r{bin/.+\.l?hs$})
61
+ end
62
+ ```
63
+
64
+ Another customized haskell project:
56
65
 
57
66
  ```ruby
58
- guard :haskell, all_on_pass: true, ghci_options: ["-DTEST"] do
67
+ guard :haskell, all_on_start: true, all_on_pass: true, cabal_target: "not-spec" do
59
68
  watch(%r{test/.+Spec\.l?hs$})
60
69
  watch(%r{lib/.+\.l?hs$})
61
70
  watch(%r{bin/.+\.l?hs$})
62
71
  end
63
72
  ```
64
73
 
65
- ## Options
74
+ #### Gemfile
75
+
76
+ It's also advised to have a trivial `Gemfile` in the repository for
77
+ `bundler exec guard` to be able to pick the correct versions of the dependencies:
78
+
79
+ ```ruby
80
+ source "https://rubygems.org"
81
+
82
+ gem "guard-haskell", "~>2.0"
83
+ ```
84
+
85
+ Options
86
+ -------
66
87
 
67
88
  `Guard::Haskell` has a bunch of options:
68
89
 
@@ -72,25 +93,22 @@ Run all examples on start (default: `false`).
72
93
 
73
94
  ### `all_on_pass`
74
95
 
75
- Run all examples after previously failing spec _finally_ passes (default: `false`).
96
+ Run all examples when a failed spec passes again (default: `false`).
76
97
 
77
98
  ### `focus_on_fail`
78
99
 
79
100
  Rerun only failed examples until they pass (default: `true`).
80
101
 
81
- ### `ghci_options`
82
-
83
- Pass custom ghci options, for example, `-XCPP` directives like `-DTEST` (default: `[]`).
84
-
85
- ### `top_spec`
102
+ ### `repl_options`
86
103
 
87
- "Top" spec location (default: `test/Spec.hs`).
104
+ Pass custom cabal repl options (default: `[]`).
88
105
 
89
- ### `sandbox_glob`
106
+ ### `cabal_target`
90
107
 
91
- A glob that matches cabal sandboxes (default: `.cabal-sandbox/*packages.conf.d`)
108
+ The cabal build target to load (default: `spec`).
92
109
 
93
- ## Known problems
110
+ Known problems
111
+ --------------
94
112
 
95
113
  ### App you test uses the GHC API
96
114
 
@@ -0,0 +1,4 @@
1
+ *Main> /usr/bin/ld: dist/build/spec/spec-tmp/Paths_X.o: relocation R_X86_64_32S against `stg_bh_upd_frame_info' can not be used when making a shared object; recompile with -fPIC
2
+ dist/build/spec/spec-tmp/Paths_X.o: could not read symbols: Bad value
3
+ collect2: error: ld returned 1 exit status
4
+ phase `Linker' failed (exitcode = 1)
@@ -3,17 +3,8 @@ require 'guard/plugin'
3
3
  require 'set'
4
4
 
5
5
  class ::String
6
- def strip_lowercase_directories
7
- matches = self.match(/^\p{Lower}[^\/]+\/(.+)/)
8
- if matches
9
- matches[1].strip_lowercase_directories
10
- else
11
- self
12
- end
13
- end
14
-
15
- def path_to_module_name
16
- self.gsub(/\//, ".")
6
+ def to_module_name
7
+ self.split('/').drop_while{|x| /^[[:lower:]]/.match(x)}.join('.')
17
8
  end
18
9
  end
19
10
 
@@ -25,22 +16,20 @@ module ::Guard
25
16
  attr_accessor :opts, :repl
26
17
  attr_reader :targets, :last_run
27
18
 
28
- Options = Struct.new(
29
- :top_spec,
30
- :ghci_options,
19
+ Options = ::Struct.new(
20
+ :cabal_target,
21
+ :repl_options,
31
22
  :all_on_start,
32
23
  :all_on_pass,
33
24
  :focus_on_fail,
34
- :sandbox_glob,
35
25
  )
36
26
 
37
27
  DEFAULT_OPTIONS = {
38
- top_spec: "test/Spec.hs",
39
- ghci_options: [],
28
+ cabal_target: "spec",
29
+ repl_options: [],
40
30
  all_on_start: false,
41
31
  all_on_pass: false,
42
32
  focus_on_fail: true,
43
- sandbox_glob: ".cabal-sandbox/*packages.conf.d",
44
33
  }
45
34
 
46
35
  def initialize(user_options = {})
@@ -50,8 +39,9 @@ module ::Guard
50
39
 
51
40
  def start
52
41
  @last_run = :success # try to prove it wasn't :-)
53
- self.repl = Repl.new(opts.ghci_options, opts.sandbox_glob)
54
- repl.init(opts.top_spec)
42
+ self.repl = Repl.new(opts.cabal_target, opts.repl_options)
43
+ throw :cabal_repl_initialization_has_failed if self.repl.status == :loading_failure
44
+ success?
55
45
 
56
46
  @targets = ::Set.new(::Dir.glob("**/*.{hs,lhs}"))
57
47
 
@@ -74,7 +64,7 @@ module ::Guard
74
64
  success?
75
65
  end
76
66
 
77
- def run pattern
67
+ def run(pattern)
78
68
  if opts.focus_on_fail and last_run == :runtime_failure
79
69
  repl.reload_and_rerun
80
70
  else
@@ -84,7 +74,7 @@ module ::Guard
84
74
  end
85
75
 
86
76
  def success?
87
- case [last_run, repl.result]
77
+ case [last_run, repl.status]
88
78
  when [:runtime_failure, :success],
89
79
  [:compile_failure, :success]
90
80
  @last_run = :success
@@ -108,17 +98,17 @@ module ::Guard
108
98
  end
109
99
  end
110
100
 
111
- def run_on_additions paths
112
- unless paths.all? { |path| targets.include? path }
101
+ def run_on_additions(paths)
102
+ unless paths.all? { |path| targets.include?(path) }
113
103
  @targets += paths
114
- repl.init(opts.top_spec)
104
+ reload
115
105
  end
116
106
  end
117
107
 
118
- def run_on_modifications paths
108
+ def run_on_modifications(paths)
119
109
  case paths.first
120
110
  when /(.+)Spec\.l?hs$/, /(.+)\.l?hs$/
121
- run($1.strip_lowercase_directories.path_to_module_name)
111
+ run($1.to_module_name)
122
112
  end
123
113
  end
124
114
  end
@@ -1,9 +1,9 @@
1
1
  require 'open3'
2
2
 
3
3
  class ::Guard::Haskell::Repl
4
- attr_reader :stdin, :listener, :thread, :result
4
+ attr_reader :stdin, :listener, :inferior, :status
5
5
 
6
- def self.test(str)
6
+ def self.finished_with(str)
7
7
  case str
8
8
  when /\d+ examples?, 0 failures/,
9
9
  /Ok, modules loaded:/
@@ -15,6 +15,7 @@ class ::Guard::Haskell::Repl
15
15
  /cannot find object file for module/,
16
16
  /phase `C pre-processor' failed/,
17
17
  /phase `Haskell pre-processor' failed/,
18
+ /phase `Linker' failed/,
18
19
  /GHCi runtime linker: fatal error:/,
19
20
  /During interactive linking, GHCi couldn't find the following symbol:/,
20
21
  /ghc: could not execute:/
@@ -22,36 +23,21 @@ class ::Guard::Haskell::Repl
22
23
  end
23
24
  end
24
25
 
25
- def initialize(ghci_options, sandbox_glob)
26
- @running = false
27
- @result = :success
28
-
29
- cmd = ["ghci"]
30
-
31
- Dir["*"].each { |d| cmd << "-i#{d}" if File.directory?(d) }
32
- lookup_sandbox(cmd, sandbox_glob)
33
- cmd.concat(ghci_options)
34
-
35
- @stdin, stdout, @thread = ::Open3.popen2e(*cmd)
36
- @listener = ::Thread.new { listen(stdout, STDOUT) }
37
- end
38
-
39
- def lookup_sandbox(cmd, sandbox_glob)
40
- sandboxes = Sandbox.new(sandbox_glob)
41
- sandboxes.with_best_sandbox(->(str) { str.scan(/\d+/).map(&:to_i) }) do |best_sandbox|
42
- puts "Cabal sandboxes found:"
43
- sandboxes.each { |sandbox| puts " #{sandbox}" }
44
- puts "Cabal sandbox used:\n #{best_sandbox}"
45
- cmd.concat(["-no-user-package-db", "-package-db=#{best_sandbox}"])
46
- end
26
+ def initialize(cabal_target, repl_options)
27
+ @listening = false
28
+ @status = :success
29
+ start("cabal", "repl", cabal_target, *repl_options)
47
30
  end
48
31
 
49
- def init(spec)
50
- run_command_and_wait_for_result(":load #{spec}\n")
32
+ def start(*cmd)
33
+ @listening = true
34
+ @stdin, stdout, @inferior = ::Open3.popen2e(*cmd)
35
+ @listener = ::Thread.new { listen_or_die(stdout, STDOUT) }
36
+ wait_for_result
51
37
  end
52
38
 
53
39
  def exit
54
- ::Process::kill("TERM", thread.pid)
40
+ stdin.write(":quit\n")
55
41
  ::Thread.kill(listener)
56
42
  end
57
43
 
@@ -71,53 +57,43 @@ class ::Guard::Haskell::Repl
71
57
  end
72
58
  end
73
59
 
74
- class Sandbox
75
- attr_reader :sandboxes
76
-
77
- include ::Enumerable
78
-
79
- def initialize(glob)
80
- @sandboxes = ::Dir[glob]
81
- end
82
-
83
- def each(&block)
84
- sandboxes.each(&block)
85
- end
86
-
87
- def with_best_sandbox(ordering)
88
- best = sandboxes.max_by(&ordering)
89
- yield best if best
90
- best
91
- end
92
- end
93
-
94
60
  private
95
61
  def run_command_and_wait_for_result(command)
96
- talk_to_repl(command)
62
+ @listening = true
63
+ stdin.write(command)
97
64
  wait_for_result == :success
98
65
  end
99
66
 
100
67
  def wait_for_result
101
- while @running do sleep(0.01) end
102
- @result
68
+ while @listening do sleep(0.01) end
69
+ @status
103
70
  end
104
71
 
105
- def talk_to_repl(command)
106
- @running = true
107
- stdin.write(command)
72
+ def listen_or_die(in_stream, out_stream)
73
+ listen(in_stream, out_stream) # should never return
74
+ stop(:loading_failure)
108
75
  end
109
76
 
110
77
  def listen(in_stream, out_stream)
111
- while (str = in_stream.gets)
112
- out_stream.print(str)
113
- if @running
114
- res = self.class.test(str)
78
+ while (line = in_stream.gets)
79
+ out_stream.print(line)
80
+ if @listening
81
+ res = self.class.finished_with(line)
115
82
  case res
116
83
  when :success, :runtime_failure, :compile_failure
117
- @result = res
118
- @running = false
84
+ # A horrible hack to show the cursor again
85
+ #
86
+ # The problem is that '\e[?25h' code from hspec is waiting on
87
+ # the next line, which we probably will never read :-(
88
+ out_stream.print("\e[?25h")
89
+ stop(res)
119
90
  end
120
91
  end
121
92
  end
122
93
  end
94
+
95
+ def stop(status)
96
+ @status = status
97
+ @listening = false
98
+ end
123
99
  end
@@ -1,8 +1,8 @@
1
- ghci_options =
2
- [ "-ignore-dot-ghci" \
1
+ repl_options =
2
+ [ "--ghc-options=-ignore-dot-ghci" \
3
3
  ]
4
4
 
5
- guard :haskell, ghci_options: ghci_options do
5
+ guard :haskell, repl_options: repl_options do
6
6
  watch(%r{test/.+Spec\.l?hs$})
7
7
  watch(%r{src/.+\.l?hs$})
8
8
  end
@@ -1,5 +1,5 @@
1
1
  module Guard
2
2
  module HaskellVersion
3
- VERSION = '1.6.0'
3
+ VERSION = '2.0.0'
4
4
  end
5
5
  end
@@ -3,25 +3,13 @@ require 'spec_helper'
3
3
  require 'guard/notifier'
4
4
 
5
5
  dev_null = ::File.open("/dev/null", "w")
6
- run_file = ->(file) { "spec/run-files/#{file}" }
6
+ asset = ->(file) { "asset/#{file}" }
7
7
 
8
8
  describe ::Guard::Haskell::Repl do
9
9
  let(:repl) do
10
10
  ::Guard::Haskell::Repl.new
11
11
  end
12
12
 
13
- describe '#init' do
14
- it "calls :load on ghci instance" do
15
- expect(repl).to receive(:run_command_and_wait_for_result).with(/:load/)
16
- repl.init("Spec.hs")
17
- end
18
-
19
- it "loads provided spec" do
20
- expect(repl).to receive(:run_command_and_wait_for_result).with(/FooBarSpec.hs/)
21
- repl.init("FooBarSpec.hs")
22
- end
23
- end
24
-
25
13
  context "running spec" do
26
14
  before(:each) do
27
15
  repl.stub(:run_command_and_wait_for_result) { |_| true }
@@ -62,215 +50,151 @@ describe ::Guard::Haskell::Repl do
62
50
  end
63
51
  end
64
52
 
65
- describe '#test' do
53
+ describe '#finished_with' do
66
54
  it "handles zero examples/failures" do
67
- expect(::Guard::Haskell::Repl.test("0 examples, 0 failures")).to eq(:success)
55
+ expect(::Guard::Haskell::Repl.finished_with("0 examples, 0 failures")).to eq(:success)
68
56
  end
69
57
 
70
58
  it "handles one example/zero failures" do
71
- expect(::Guard::Haskell::Repl.test("1 example, 0 failures")).to eq(:success)
59
+ expect(::Guard::Haskell::Repl.finished_with("1 example, 0 failures")).to eq(:success)
72
60
  end
73
61
 
74
62
  it "handles multiple examples/zero failures" do
75
- expect(::Guard::Haskell::Repl.test("37 examples, 0 failures")).to eq(:success)
63
+ expect(::Guard::Haskell::Repl.finished_with("37 examples, 0 failures")).to eq(:success)
76
64
  end
77
65
 
78
66
  it "handles one example/failure" do
79
- expect(::Guard::Haskell::Repl.test("1 example, 1 failure")).to eq(:runtime_failure)
67
+ expect(::Guard::Haskell::Repl.finished_with("1 example, 1 failure")).to eq(:runtime_failure)
80
68
  end
81
69
 
82
70
  it "handles multiple examples/multiple failures" do
83
- expect(::Guard::Haskell::Repl.test("26 examples, 2 failures")).to eq(:runtime_failure)
71
+ expect(::Guard::Haskell::Repl.finished_with("26 examples, 2 failures")).to eq(:runtime_failure)
84
72
  end
85
73
 
86
74
  it "handles failure to load the module" do
87
- expect(::Guard::Haskell::Repl.test("Failed, modules loaded:")).to eq(:compile_failure)
75
+ expect(::Guard::Haskell::Repl.finished_with("Failed, modules loaded:")).to eq(:compile_failure)
88
76
  end
89
77
 
90
78
  it "handles uncaught exceptions" do
91
- expect(::Guard::Haskell::Repl.test("*** Exception: Prelude.undefined")).to eq(:compile_failure)
79
+ expect(::Guard::Haskell::Repl.finished_with("*** Exception: Prelude.undefined")).to eq(:compile_failure)
92
80
  end
93
81
 
94
82
  it "handles CPP errors" do
95
- expect(::Guard::Haskell::Repl.test("phase `C pre-processor' failed")).to eq(:compile_failure)
83
+ expect(::Guard::Haskell::Repl.finished_with("phase `C pre-processor' failed")).to eq(:compile_failure)
96
84
  end
97
85
 
98
86
  it "handles Haskell pre-processor errors" do
99
- expect(::Guard::Haskell::Repl.test("phase `Haskell pre-processor' failed")).to eq(:compile_failure)
87
+ expect(::Guard::Haskell::Repl.finished_with("phase `Haskell pre-processor' failed")).to eq(:compile_failure)
100
88
  end
101
89
 
102
90
  it "handles runtime linker errors" do
103
- expect(::Guard::Haskell::Repl.test("GHCi runtime linker: fatal error:")).to eq(:compile_failure)
91
+ expect(::Guard::Haskell::Repl.finished_with("GHCi runtime linker: fatal error:")).to eq(:compile_failure)
104
92
  end
105
93
  end
106
94
 
107
95
  describe '#listen' do
108
96
  context 'real world' do
109
97
  it "handles typical pass run" do
110
- in_stream = ::File.open(run_file["spec-pass.success"])
111
- repl.instance_variable_set(:@running, true)
98
+ in_stream = ::File.open(asset["passed/spec-pass.ok"])
99
+ repl.instance_variable_set(:@listening, true)
112
100
 
113
101
  repl.send(:listen, in_stream, dev_null)
114
102
 
115
- expect(repl.instance_variable_get(:@running)).to eq(false)
116
- expect(repl.instance_variable_get(:@result)).to eq(:success)
103
+ expect(repl.instance_variable_get(:@listening)).to eq(false)
104
+ expect(repl.instance_variable_get(:@status)).to eq(:success)
117
105
  end
118
106
 
119
107
  it "handles typical failure run" do
120
- in_stream = ::File.open(run_file["spec-failure.error"])
121
- repl.instance_variable_set(:@running, true)
108
+ in_stream = ::File.open(asset["failed/spec-failure.err"])
109
+ repl.instance_variable_set(:@listening, true)
122
110
 
123
111
  repl.send(:listen, in_stream, dev_null)
124
112
 
125
- expect(repl.instance_variable_get(:@running)).to eq(false)
126
- expect(repl.instance_variable_get(:@result)).to eq(:runtime_failure)
113
+ expect(repl.instance_variable_get(:@listening)).to eq(false)
114
+ expect(repl.instance_variable_get(:@status)).to eq(:runtime_failure)
127
115
  end
128
116
 
129
117
  it 'handles "duplicate definition" runtime linker error' do
130
- in_stream = ::File.open(run_file["runtime-linker-duplicate-definition-for-symbol.error"])
131
- repl.instance_variable_set(:@running, true)
118
+ in_stream = ::File.open(asset["failed/runtime-linker-duplicate-definition-for-symbol.err"])
119
+ repl.instance_variable_set(:@listening, true)
132
120
 
133
121
  repl.send(:listen, in_stream, dev_null)
134
122
 
135
- expect(repl.instance_variable_get(:@running)).to eq(false)
136
- expect(repl.instance_variable_get(:@result)).to eq(:compile_failure)
123
+ expect(repl.instance_variable_get(:@listening)).to eq(false)
124
+ expect(repl.instance_variable_get(:@status)).to eq(:compile_failure)
137
125
  end
138
126
 
139
127
  # Unfortunately I can't remember why it happened :-(
140
128
  it 'handles "couldn\'t find symbol" runtime linker error' do
141
- in_stream = ::File.open(run_file["runtime-linker-couldn't-find-symbol.error"])
142
- repl.instance_variable_set(:@running, true)
129
+ in_stream = ::File.open(asset["failed/runtime-linker-couldn't-find-symbol.err"])
130
+ repl.instance_variable_set(:@listening, true)
143
131
 
144
132
  repl.send(:listen, in_stream, dev_null)
145
133
 
146
- expect(repl.instance_variable_get(:@running)).to eq(false)
147
- expect(repl.instance_variable_get(:@result)).to eq(:compile_failure)
134
+ expect(repl.instance_variable_get(:@listening)).to eq(false)
135
+ expect(repl.instance_variable_get(:@status)).to eq(:compile_failure)
148
136
  end
149
137
 
150
138
  # This one's even trickier to reproduce than the previous one
151
139
  it 'handles "cannot find object file" runtime linker error' do
152
- in_stream = ::File.open(run_file["runtime-linker-cannot-find-object-file.error"])
153
- repl.instance_variable_set(:@running, true)
140
+ in_stream = ::File.open(asset["failed/runtime-linker-cannot-find-object-file.err"])
141
+ repl.instance_variable_set(:@listening, true)
154
142
 
155
143
  repl.send(:listen, in_stream, dev_null)
156
144
 
157
- expect(repl.instance_variable_get(:@running)).to eq(false)
158
- expect(repl.instance_variable_get(:@result)).to eq(:compile_failure)
145
+ expect(repl.instance_variable_get(:@listening)).to eq(false)
146
+ expect(repl.instance_variable_get(:@status)).to eq(:compile_failure)
159
147
  end
160
148
 
161
149
  it "handles hspec exceptions" do
162
- in_stream = ::File.open(run_file["hspec-exception.error"])
163
- repl.instance_variable_set(:@running, true)
150
+ in_stream = ::File.open(asset["failed/exception.err"])
151
+ repl.instance_variable_set(:@listening, true)
164
152
 
165
153
  repl.send(:listen, in_stream, dev_null)
166
154
 
167
- expect(repl.instance_variable_get(:@running)).to eq(false)
168
- expect(repl.instance_variable_get(:@result)).to eq(:compile_failure)
155
+ expect(repl.instance_variable_get(:@listening)).to eq(false)
156
+ expect(repl.instance_variable_get(:@status)).to eq(:compile_failure)
169
157
  end
170
158
 
171
159
  it "handles CPP exceptions" do
172
- in_stream = ::File.open(run_file["cpp-exception.error"])
173
- repl.instance_variable_set(:@running, true)
160
+ in_stream = ::File.open(asset["failed/phase-c-pre-processor-failed.err"])
161
+ repl.instance_variable_set(:@listening, true)
174
162
 
175
163
  repl.send(:listen, in_stream, dev_null)
176
164
 
177
- expect(repl.instance_variable_get(:@running)).to eq(false)
178
- expect(repl.instance_variable_get(:@result)).to eq(:compile_failure)
165
+ expect(repl.instance_variable_get(:@listening)).to eq(false)
166
+ expect(repl.instance_variable_get(:@status)).to eq(:compile_failure)
179
167
  end
180
168
 
181
169
  it "handles preprocessor phase failures" do
182
- in_stream = ::File.open(run_file["preprocessor-phase-failed.error"])
183
- repl.instance_variable_set(:@running, true)
170
+ in_stream = ::File.open(asset["failed/phase-haskell-pre-processor-failed.err"])
171
+ repl.instance_variable_set(:@listening, true)
184
172
 
185
173
  repl.send(:listen, in_stream, dev_null)
186
174
 
187
- expect(repl.instance_variable_get(:@running)).to eq(false)
188
- expect(repl.instance_variable_get(:@result)).to eq(:compile_failure)
175
+ expect(repl.instance_variable_get(:@listening)).to eq(false)
176
+ expect(repl.instance_variable_get(:@status)).to eq(:compile_failure)
189
177
  end
190
178
 
191
179
  it "handles missing preprocessor error" do
192
- in_stream = ::File.open(run_file["missing-preprocessor.error"])
193
- repl.instance_variable_set(:@running, true)
180
+ in_stream = ::File.open(asset["failed/invalid-preprocessor.err"])
181
+ repl.instance_variable_set(:@listening, true)
194
182
 
195
183
  repl.send(:listen, in_stream, dev_null)
196
184
 
197
- expect(repl.instance_variable_get(:@running)).to eq(false)
198
- expect(repl.instance_variable_get(:@result)).to eq(:compile_failure)
185
+ expect(repl.instance_variable_get(:@listening)).to eq(false)
186
+ expect(repl.instance_variable_get(:@status)).to eq(:compile_failure)
199
187
  end
200
- end
201
- end
202
-
203
- describe "#lookup_sandbox" do
204
- include FakeFS::SpecHelpers
205
188
 
206
- before(:each) { ::IO.any_instance.stub(:puts) }
189
+ it "handles linker phase failures" do
190
+ in_stream = ::File.open(asset["failed/phase-linker-failed.err"])
191
+ repl.instance_variable_set(:@listening, true)
207
192
 
208
- it "does not find anything if there are no sandboxes" do
209
- expect_any_instance_of(::IO).not_to receive(:puts)
210
- expect(repl.lookup_sandbox([], "*packages.conf.d")).to be_nil
211
- end
212
-
213
- it "finds a sandbox" do
214
- ::FileUtils.mkdir_p(["ghc-7.6.3-packages.conf.d"])
215
- expect_any_instance_of(::IO).to receive(:puts).with("Cabal sandboxes found:")
216
- expect(repl.lookup_sandbox([], "*packages.conf.d")).to eq("/ghc-7.6.3-packages.conf.d")
217
- end
218
-
219
- it "finds a sandbox with the default settings" do
220
- ::FileUtils.mkdir_p([".cabal-sandbox/foo-bar-ghc-7.6.3-packages.conf.d"])
221
- expect_any_instance_of(::IO).to receive(:puts).with("Cabal sandboxes found:")
222
- expect(repl.lookup_sandbox([], ::Guard::Haskell::DEFAULT_OPTIONS[:sandbox_glob])).to eq("/.cabal-sandbox/foo-bar-ghc-7.6.3-packages.conf.d")
223
- end
193
+ repl.send(:listen, in_stream, dev_null)
224
194
 
225
- it "compares sandboxes cleverly" do
226
- ::FileUtils.mkdir_p(
227
- [ "ghc-1.0-packages.conf.d",
228
- "ghc-1.1-packages.conf.d",
229
- "ghc-1.2-packages.conf.d",
230
- "ghc-1.10-packages.conf.d",
231
- ])
232
- expect(repl.lookup_sandbox([], "*packages.conf.d")).to eq("/ghc-1.10-packages.conf.d")
195
+ expect(repl.instance_variable_get(:@listening)).to eq(false)
196
+ expect(repl.instance_variable_get(:@status)).to eq(:compile_failure)
197
+ end
233
198
  end
234
199
  end
235
200
  end
236
-
237
- describe ::Guard::Haskell::Repl::Sandbox do
238
- ::Sandbox = ::Guard::Haskell::Repl::Sandbox
239
- include FakeFS::SpecHelpers
240
-
241
- let(:id) { ->(x) { x } }
242
- let(:reversed) { ->(str) { str.reverse } }
243
-
244
- before(:each) { ::IO.any_instance.stub(:puts) }
245
-
246
- it "has an empty list of sandboxes if no sandboxes are found" do
247
- expect(::Sandbox.new("*").sandboxes).to eq([])
248
- end
249
-
250
- it "has a singleton list of sandboxes if one sandbox is found" do
251
- ::FileUtils.touch(["foo", "bar", "baz"])
252
- expect(::Sandbox.new("foo").sandboxes).to eq(["/foo"])
253
- end
254
-
255
- it "has a list of sandboxes if more than one sandbox is found" do
256
- ::FileUtils.touch(["foo", "bar", "baz"])
257
- expect(::Sandbox.new("ba*").sandboxes).to eq(["/bar", "/baz"])
258
- end
259
-
260
- it "has a nil for the best sandbox of an empty list of sandboxes" do
261
- expect_any_instance_of(::IO).not_to receive(:puts)
262
- expect(::Sandbox.new("*").with_best_sandbox(id) { |s| puts s }).to be_nil
263
- end
264
-
265
- it "chooses a \"maximum\" for the best sandbox" do
266
- ::FileUtils.touch(["foo", "bar", "baz"])
267
- expect_any_instance_of(::IO).to receive(:puts).with("/foo")
268
- expect(::Sandbox.new("*").with_best_sandbox(id) { |s| puts s }).to eq("/foo")
269
- end
270
-
271
- it "chooses a \"maximum\" of the complex ordering for the best sandbox" do
272
- ::FileUtils.touch(["foo", "bar", "baz", "zap"])
273
- expect_any_instance_of(::IO).to receive(:puts).with("/baz")
274
- expect(::Sandbox.new("*").with_best_sandbox(reversed) { |s| puts s }).to eq("/baz")
275
- end
276
- end
@@ -3,31 +3,21 @@ require 'guard/notifier'
3
3
 
4
4
  describe "monkey patching" do
5
5
  describe ::String do
6
- describe "#strip_lowercase_directories" do
7
- it "works on empty string" do
8
- expect("".strip_lowercase_directories).to eq("")
6
+ describe "#to_module_name" do
7
+ it "converts the empty string to the empty module name" do
8
+ expect("".to_module_name).to eq("")
9
9
  end
10
10
 
11
- it "works on string without lowercase directory prefixes" do
12
- expect("Foo".strip_lowercase_directories).to eq("Foo")
11
+ it "is identity for very simple module paths" do
12
+ expect("Foo".to_module_name).to eq("Foo")
13
13
  end
14
14
 
15
- it "works on string with lowercase directory prefix" do
16
- expect("foo/Bar".strip_lowercase_directories).to eq("Bar")
15
+ it "drops lowercase directory prefixes and substitutes / with ." do
16
+ expect("foo/bar/Qux/Quux".to_module_name).to eq("Qux.Quux")
17
17
  end
18
18
 
19
- it "works on string with multiple lowercase directory prefixes" do
20
- expect("foo/bar/Baz".strip_lowercase_directories).to eq("Baz")
21
- end
22
- end
23
-
24
- describe "#path_to_module_name" do
25
- it "works on string without path separators" do
26
- expect("Foo".path_to_module_name).to eq("Foo")
27
- end
28
-
29
- it "works on string with path separators" do
30
- expect("Foo/Bar/Baz".path_to_module_name).to eq("Foo.Bar.Baz")
19
+ it "does not deal with extensions in the path" do
20
+ expect("foo/bar/Qux/Quux.hs".to_module_name).to eq("Qux.Quux.hs")
31
21
  end
32
22
  end
33
23
  end
@@ -36,6 +26,10 @@ end
36
26
  class ::Guard::Haskell::Repl
37
27
  def initialize(*args)
38
28
  end
29
+
30
+ def status
31
+ :success
32
+ end
39
33
  end
40
34
 
41
35
  describe ::Guard::Haskell do
@@ -56,14 +50,19 @@ describe ::Guard::Haskell do
56
50
 
57
51
  describe "#start" do
58
52
  it "starts repl" do
59
- expect_any_instance_of(::Guard::Haskell::Repl).to receive(:init).with("test/Spec.hs")
53
+ expect_any_instance_of(::Guard::Haskell::Repl).to receive(:initialize).with("spec", [])
54
+
55
+ guard.start
56
+ end
57
+
58
+ it "checks the repl has been loaded successfully" do
59
+ expect(guard).to receive(:success?)
60
60
 
61
61
  guard.start
62
62
  end
63
63
 
64
64
  it "does not run all examples on start by default" do
65
65
  expect(guard).not_to receive(:run_all)
66
- expect(guard).not_to receive(:success?)
67
66
 
68
67
  guard.start
69
68
  end
@@ -72,15 +71,23 @@ describe ::Guard::Haskell do
72
71
  custom_guard = ::Guard::Haskell.new(all_on_start: true)
73
72
 
74
73
  expect_any_instance_of(::Guard::Haskell::Repl).to receive(:reload_and_run_matching).with(no_args)
75
- expect(custom_guard).to receive(:success?)
74
+ expect(custom_guard).to receive(:success?).twice
76
75
 
77
76
  custom_guard.start
78
77
  end
79
78
 
80
- it "starts repl with custom spec specified with :top_spec option" do
81
- expect_any_instance_of(::Guard::Haskell::Repl).to receive(:init).with("test/CustomSpec.hs")
79
+ it "starts repl with custom target specified with :cabal_target option" do
80
+ expect_any_instance_of(::Guard::Haskell::Repl).to receive(:initialize).with("not-spec", [])
82
81
 
83
- custom_guard = ::Guard::Haskell.new(top_spec: "test/CustomSpec.hs")
82
+ custom_guard = ::Guard::Haskell.new(cabal_target: "not-spec")
83
+ custom_guard.start
84
+ end
85
+
86
+ it "starts repl with custom options specified with :repl_options option" do
87
+ expect_any_instance_of(::Guard::Haskell::Repl).to receive(:initialize)
88
+ .with("spec", ["--ghc-options=-Werror"])
89
+
90
+ custom_guard = ::Guard::Haskell.new(repl_options: ["--ghc-options=-Werror"])
84
91
  custom_guard.start
85
92
  end
86
93
  end
@@ -105,10 +112,10 @@ describe ::Guard::Haskell do
105
112
  describe "#run" do
106
113
  it "checks success after run" do
107
114
  expect_any_instance_of(::Guard::Haskell::Repl).to receive(:reload_and_run_matching).with("Foo")
108
- expect(guard).to receive(:success?)
109
115
  guard.instance_variable_set(:@last_run, :success)
110
-
111
116
  guard.start
117
+
118
+ expect(guard).to receive(:success?)
112
119
  guard.run("Foo")
113
120
  end
114
121
 
@@ -152,20 +159,20 @@ describe ::Guard::Haskell do
152
159
  describe "#run_all" do
153
160
  it "checks success after run" do
154
161
  expect_any_instance_of(::Guard::Haskell::Repl).to receive(:reload_and_run_matching)
155
- expect(guard).to receive(:success?)
156
-
157
162
  guard.start
163
+
164
+ expect(guard).to receive(:success?)
158
165
  guard.run_all
159
166
  end
160
167
  end
161
168
 
162
169
  describe "#success" do
163
170
  def notify(before, received, after)
164
- ::Guard::Haskell::Repl.any_instance.stub(:result) { received }
165
- expect_any_instance_of(::Guard::Haskell::Repl).to receive(:result)
171
+ guard.start
172
+ ::Guard::Haskell::Repl.any_instance.stub(:status) { received }
173
+ expect_any_instance_of(::Guard::Haskell::Repl).to receive(:status)
166
174
  yield
167
175
 
168
- guard.start
169
176
  guard.instance_variable_set(:@last_run, before)
170
177
  guard.success?
171
178
  expect(guard.instance_variable_get(:@last_run)).to eq(after)
@@ -235,7 +242,7 @@ describe ::Guard::Haskell do
235
242
  end
236
243
 
237
244
  it "runs all examples on success after runtime failure with :all_on_pass option" do
238
- ::Guard::Haskell::Repl.any_instance.stub(:result) { :success }
245
+ ::Guard::Haskell::Repl.any_instance.stub(:status) { :success }
239
246
  custom_guard = ::Guard::Haskell.new(all_on_pass: true)
240
247
  expect(custom_guard).to receive(:run_all)
241
248
 
@@ -245,7 +252,7 @@ describe ::Guard::Haskell do
245
252
  end
246
253
 
247
254
  it "runs all examples on success after compile time failure with :all_on_pass option" do
248
- ::Guard::Haskell::Repl.any_instance.stub(:result) { :success }
255
+ ::Guard::Haskell::Repl.any_instance.stub(:status) { :success }
249
256
  custom_guard = ::Guard::Haskell.new(all_on_pass: true)
250
257
  expect(custom_guard).to receive(:run_all)
251
258
 
@@ -255,28 +262,14 @@ describe ::Guard::Haskell do
255
262
  end
256
263
  end
257
264
 
258
- describe "#run_on_additions" do
259
- it "reinitializes the repl on new files" do
260
- expect_any_instance_of(::Guard::Haskell::Repl).to receive(:init).twice
261
-
262
- guard.start
263
- guard.instance_variable_set(:@targets, [])
264
- guard.run_on_additions ["foo", "bar"]
265
- end
266
-
267
- it "does not reinitialize the repl if new files were seen before" do
268
- expect_any_instance_of(::Guard::Haskell::Repl).to receive(:init).once
269
-
270
- guard.start
271
- guard.instance_variable_set(:@targets, ["foo", "bar"])
272
- guard.run_on_additions ["foo", "bar"]
265
+ describe "#run_on_modifications" do
266
+ before :each do
267
+ ::Guard::Haskell::Repl.any_instance.stub(:status) { :success }
273
268
  end
274
- end
275
269
 
276
- describe "#run_on_modifications" do
277
270
  it "run examples for simple haskell files" do
278
271
  expect_any_instance_of(::Guard::Haskell::Repl).to receive(:reload_and_run_matching).with("Foo")
279
- expect_any_instance_of(::Guard::Haskell::Repl).to receive(:result)
272
+ expect_any_instance_of(::Guard::Haskell::Repl).to receive(:status)
280
273
 
281
274
  guard.start
282
275
  guard.run_on_modifications(["Foo.hs"])
@@ -284,7 +277,7 @@ describe ::Guard::Haskell do
284
277
 
285
278
  it "run examples for simple literate haskell files" do
286
279
  expect_any_instance_of(::Guard::Haskell::Repl).to receive(:reload_and_run_matching).with("Foo")
287
- expect_any_instance_of(::Guard::Haskell::Repl).to receive(:result)
280
+ expect_any_instance_of(::Guard::Haskell::Repl).to receive(:status)
288
281
 
289
282
  guard.start
290
283
  guard.run_on_modifications(["Foo.lhs"])
@@ -292,7 +285,7 @@ describe ::Guard::Haskell do
292
285
 
293
286
  it "run examples for *complex* haskell files" do
294
287
  expect_any_instance_of(::Guard::Haskell::Repl).to receive(:reload_and_run_matching).with("Bar.Baz")
295
- expect_any_instance_of(::Guard::Haskell::Repl).to receive(:result)
288
+ expect_any_instance_of(::Guard::Haskell::Repl).to receive(:status)
296
289
 
297
290
  guard.start
298
291
  guard.run_on_modifications(["foo/Bar/Baz.hs"])
@@ -300,7 +293,7 @@ describe ::Guard::Haskell do
300
293
 
301
294
  it "run examples for simple haskell spec files" do
302
295
  expect_any_instance_of(::Guard::Haskell::Repl).to receive(:reload_and_run_matching).with("Foo")
303
- expect_any_instance_of(::Guard::Haskell::Repl).to receive(:result)
296
+ expect_any_instance_of(::Guard::Haskell::Repl).to receive(:status)
304
297
 
305
298
  guard.start
306
299
  guard.run_on_modifications(["FooSpec.hs"])
@@ -308,7 +301,7 @@ describe ::Guard::Haskell do
308
301
 
309
302
  it "run examples for simple literate haskell spec files" do
310
303
  expect_any_instance_of(::Guard::Haskell::Repl).to receive(:reload_and_run_matching).with("Foo")
311
- expect_any_instance_of(::Guard::Haskell::Repl).to receive(:result)
304
+ expect_any_instance_of(::Guard::Haskell::Repl).to receive(:status)
312
305
 
313
306
  guard.start
314
307
  guard.run_on_modifications(["FooSpec.lhs"])
@@ -316,10 +309,28 @@ describe ::Guard::Haskell do
316
309
 
317
310
  it "run examples for *complex* haskell spec files" do
318
311
  expect_any_instance_of(::Guard::Haskell::Repl).to receive(:reload_and_run_matching).with("Bar.Baz")
319
- expect_any_instance_of(::Guard::Haskell::Repl).to receive(:result)
312
+ expect_any_instance_of(::Guard::Haskell::Repl).to receive(:status)
320
313
 
321
314
  guard.start
322
315
  guard.run_on_modifications(["foo/Bar/BazSpec.hs"])
323
316
  end
324
317
  end
318
+
319
+ describe "#run_on_additions" do
320
+ it "reinitializes the repl on new files" do
321
+ expect_any_instance_of(::Guard::Haskell).to receive(:reload).once
322
+
323
+ guard.start
324
+ guard.instance_variable_set(:@targets, [])
325
+ guard.run_on_additions(["foo", "bar"])
326
+ end
327
+
328
+ it "does not reinitialize the repl if new files were seen before" do
329
+ expect_any_instance_of(::Guard::Haskell).not_to receive(:reload).once
330
+
331
+ guard.start
332
+ guard.instance_variable_set(:@targets, ["foo", "bar"])
333
+ guard.run_on_additions(["foo", "bar"])
334
+ end
335
+ end
325
336
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: guard-haskell
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matvey Aksenov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-06-15 00:00:00.000000000 Z
11
+ date: 2014-07-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: guard
@@ -108,6 +108,16 @@ files:
108
108
  - LICENSE
109
109
  - README.md
110
110
  - Rakefile
111
+ - asset/failed/exception.err
112
+ - asset/failed/invalid-preprocessor.err
113
+ - asset/failed/phase-c-pre-processor-failed.err
114
+ - asset/failed/phase-haskell-pre-processor-failed.err
115
+ - asset/failed/phase-linker-failed.err
116
+ - asset/failed/runtime-linker-cannot-find-object-file.err
117
+ - asset/failed/runtime-linker-couldn't-find-symbol.err
118
+ - asset/failed/runtime-linker-duplicate-definition-for-symbol.err
119
+ - asset/failed/spec-failure.err
120
+ - asset/passed/spec-pass.ok
111
121
  - guard-haskell.gemspec
112
122
  - lib/guard/haskell.rb
113
123
  - lib/guard/haskell/repl.rb
@@ -115,15 +125,6 @@ files:
115
125
  - lib/guard/haskell/version.rb
116
126
  - spec/guard/haskell/repl_spec.rb
117
127
  - spec/guard/haskell_spec.rb
118
- - spec/run-files/cpp-exception.error
119
- - spec/run-files/hspec-exception.error
120
- - spec/run-files/missing-preprocessor.error
121
- - spec/run-files/preprocessor-phase-failed.error
122
- - spec/run-files/runtime-linker-cannot-find-object-file.error
123
- - spec/run-files/runtime-linker-couldn't-find-symbol.error
124
- - spec/run-files/runtime-linker-duplicate-definition-for-symbol.error
125
- - spec/run-files/spec-failure.error
126
- - spec/run-files/spec-pass.success
127
128
  - spec/spec_helper.rb
128
129
  homepage: https://github.com/supki/guard-haskell#readme
129
130
  licenses:
@@ -152,13 +153,4 @@ summary: Guard gem for Haskell
152
153
  test_files:
153
154
  - spec/guard/haskell/repl_spec.rb
154
155
  - spec/guard/haskell_spec.rb
155
- - spec/run-files/cpp-exception.error
156
- - spec/run-files/hspec-exception.error
157
- - spec/run-files/missing-preprocessor.error
158
- - spec/run-files/preprocessor-phase-failed.error
159
- - spec/run-files/runtime-linker-cannot-find-object-file.error
160
- - spec/run-files/runtime-linker-couldn't-find-symbol.error
161
- - spec/run-files/runtime-linker-duplicate-definition-for-symbol.error
162
- - spec/run-files/spec-failure.error
163
- - spec/run-files/spec-pass.success
164
156
  - spec/spec_helper.rb