guard-haskell 1.6.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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