guard-haskell 1.1.0 → 1.2.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
- OTQ0ZGEwYjZhYWUzN2ZmMDAxZDU5YmEyNWZjYTMyMzMwMGNlZDI5Mw==
4
+ NmQxYWQ2YzZiMmUwOGY3YTMzNjIzM2IyYTNjNjcxODk5ZGMyYzFlMQ==
5
5
  data.tar.gz: !binary |-
6
- ZWE4ZTUyODhjNTZmNzMxOTQyN2RlZmU4Y2U5Y2EyYTU0MzQ3MzY4Mg==
6
+ YjEzZjFmZjk3ZWUyNTA4Yjc3MDkwOTgwZTJjNzQ1YzViYjU3NWMyNw==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- MTA3YjUzNGQ2MmYxZjJjZWRhZjFiYTM4MDllMzAwOWRkMDNiMTZmMjY2MWQz
10
- YmYyZjI2ODgwZGU1NjdlNGUwZDc5OWFhZWZjZGMyNTgxNTI3YmI1ZTBjYzUz
11
- ZmQ2ZDAzYmU1ZmU1NjZkMDNkMWQwYmFlNmJhZDcwMTAyYWNjOGE=
9
+ OTE2OTEzZWNjMmZmZjllNTEzMDBlMWMwNmJiYTFmOGMzOGU0NDc2MjNjOWRh
10
+ YjQ2MjI0NjkwODNjMDZiMWNkYTRlNzE2MjhiODkyMDBjMTE3OGI3ZGY1MDQ1
11
+ YWQ2NjU1ZjFiZjAwOWFhNTVmNjFjNjhhYWQ3NTQ4NTkzNmM2ZGQ=
12
12
  data.tar.gz: !binary |-
13
- YjZkYTEyYzc5M2EzNGI5OGNlOTk0YzNhYTc0MWJlODk2NzU4MGQ2ZWExMDRl
14
- YWZlZjNlNzI3M2JkODcwNjJkNTllM2Q5Njk2NWZhZTYzYjA3OTVhZTlmYTRi
15
- NGVmODJmZDIxYWY5MjIyNTI3Y2M3MzQ2YzE4OGQxMGE1ZTFjOTA=
13
+ ZDljODRhOGVmZTYzZjcwNjlhOWUxODcxZDM2ZDliNGE1MjM4YTJmODA0ZDUx
14
+ MTY2NTQ1MzdlNjM2NjBmY2Y3NWM3OGI4ZWM1ZGQxNTNhYjgzOGEzNDE3MWY3
15
+ MjY3NDM4MTFjMTQ1YzMxN2IyMzBlMTVmMzMyYzc5NDc1MDU4ODI=
@@ -0,0 +1,4 @@
1
+ 1.1.0
2
+ =====
3
+
4
+ * Support for `guard init haskell`
@@ -0,0 +1,6 @@
1
+ guard :rspec, all_on_start: true do
2
+ watch(%r{^spec/.+_spec\.rb$})
3
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
4
+ watch('spec/spec_helper.rb') { "spec" }
5
+ end
6
+
data/README.md CHANGED
@@ -71,6 +71,28 @@ Pass custom ghci options, for example, `-XCPP` directives like `-DTEST` (default
71
71
 
72
72
  "Top" spec location (default: `test/Spec.hs`).
73
73
 
74
+ ## Known problems
75
+
76
+ ### App you test uses the GHC API
77
+
78
+ Unfortunately, testing such applications with `guard-haskell` is basically impossible
79
+ because `ghci` uses `GHC API` too. Sooner or later you will see something like:
80
+
81
+ ```
82
+ GHCi runtime linker: fatal error: I found a duplicate definition for symbol
83
+ HUnitzm1zi2zi5zi2_TestziHUnitziBase_zdwzdcshowsPrec_slow
84
+ whilst processing object file
85
+ /home/maksenov/.cabal/lib/HUnit-1.2.5.2/ghc-7.6.2/HSHUnit-1.2.5.2.o
86
+ This could be caused by:
87
+ * Loading two different object files which export the same symbol
88
+ * Specifying the same object file twice on the GHCi command line
89
+ * An incorrect `package.conf' entry, causing some object to be
90
+ loaded twice.
91
+ GHCi cannot safely continue in this situation. Exiting now. Sorry.
92
+ ```
93
+
94
+ Fragile concurrent access is a known limitation of the `GHC API`, which hopefully will be eventually fixed.
95
+
74
96
  [0]: https://github.com/guard/guard#readme
75
97
  [1]: http://hspec.github.io/
76
98
  [2]: http://hspec.github.io/hspec-discover.html
@@ -21,4 +21,5 @@ Gem::Specification.new do |s|
21
21
  s.add_development_dependency 'bundler', '>= 1.3.5'
22
22
  s.add_development_dependency 'rake'
23
23
  s.add_development_dependency 'rspec'
24
+ s.add_development_dependency 'guard-rspec'
24
25
  end
@@ -22,7 +22,7 @@ module ::Guard
22
22
 
23
23
  require 'guard/haskell/repl'
24
24
 
25
- attr_reader :repl, :top_spec, :ghci_options, :targets
25
+ attr_reader :repl, :top_spec, :ghci_options, :targets, :last_run
26
26
  attr_reader :all_on_start, :all_on_pass
27
27
 
28
28
  def initialize options = {}
@@ -43,7 +43,6 @@ module ::Guard
43
43
 
44
44
  if all_on_start
45
45
  run_all
46
- success?
47
46
  end
48
47
  end
49
48
 
@@ -58,28 +57,39 @@ module ::Guard
58
57
 
59
58
  def run_all
60
59
  repl.run
60
+ success?
61
61
  end
62
62
 
63
63
  def run pattern
64
- if @last_run == :success
65
- repl.run(pattern)
66
- else
64
+ if last_run == :runtime_failure
67
65
  repl.rerun
66
+ else
67
+ repl.run(pattern)
68
68
  end
69
+ success?
69
70
  end
70
71
 
71
72
  def success?
72
- if repl.success?
73
- if @last_run == :failure
74
- @last_run = :success
75
- if all_on_pass
76
- run_all
77
- success?
78
- end
73
+ case [last_run, repl.result]
74
+ when [:runtime_failure, :success],
75
+ [:compile_failure, :success]
76
+ @last_run = :success
77
+ Notifier.notify('Success')
78
+ if all_on_pass
79
+ run_all
79
80
  end
81
+ when [:success, :success]
80
82
  Notifier.notify('Success')
81
- else
82
- @last_run = :failure
83
+ when [:runtime_failure, :compile_failure],
84
+ [:runtime_failure, :runtime_failure],
85
+ [:compile_failure, :compile_failure]
86
+ Notifier.notify('Failure', image: :failed)
87
+ when [:compile_failure, :runtime_failure],
88
+ [:success, :runtime_failure]
89
+ @last_run = :runtime_failure
90
+ Notifier.notify('Failure', image: :failed)
91
+ when [:success, :compile_failure]
92
+ @last_run = :compile_failure
83
93
  Notifier.notify('Failure', image: :failed)
84
94
  end
85
95
  end
@@ -95,7 +105,6 @@ module ::Guard
95
105
  case paths.first
96
106
  when /(.+)Spec\.l?hs$/, /(.+)\.l?hs$/
97
107
  run($1.strip_lowercase_directories.path_to_module_name)
98
- success?
99
108
  end
100
109
  end
101
110
  end
@@ -1,12 +1,16 @@
1
- require 'io/wait'
2
1
  require 'open3'
3
2
 
4
3
  class ::Guard::Haskell::Repl
5
- attr_reader :stdin, :reader, :thread, :success
4
+ attr_reader :stdin, :reader, :thread, :result
5
+
6
+ def initialize
7
+ @running = false
8
+ @result = :success
9
+ end
6
10
 
7
11
  def start ghci_options
8
12
  cmd = ["ghci"]
9
- Dir["*"].each { |x| cmd << "-i#{x}" }
13
+ Dir["*"].each { |d| cmd << "-i#{d}" if File.directory?(d) }
10
14
  sandbox = ::Dir[".cabal-sandbox/*packages.conf.d"].first
11
15
  cmd << "-package-db=#{sandbox}" if sandbox
12
16
  cmd.concat(ghci_options)
@@ -14,25 +18,24 @@ class ::Guard::Haskell::Repl
14
18
  @stdin, stdout, @thread = ::Open3.popen2e(*cmd)
15
19
  @reader = ::Thread.new do
16
20
  loop do
17
- n = stdout.nread
18
- if n > 0
19
- out = stdout.read(n)
21
+ while (out = stdout.gets)
20
22
  print out
21
23
  if @running
22
24
  case out
23
25
  when /\d+ examples?, 0 failures/
24
- @success = true
26
+ @result = :success
27
+ @running = false
28
+ when /\d+ examples?, \d+ failures?/
29
+ @result = :runtime_failure
25
30
  @running = false
26
- when /\d+ examples?, \d+ failures?/,
27
- /Failed, modules loaded:/,
31
+ when /Failed, modules loaded:/,
28
32
  /\*{3} Exception:/,
29
- /phase `C preprocessor' failed/
30
- @success = false
33
+ /phase `C preprocessor' failed/,
34
+ /^GHCi runtime linker: fatal error:/
35
+ @result = :compile_failure
31
36
  @running = false
32
37
  end
33
38
  end
34
- else
35
- sleep(0.1)
36
39
  end
37
40
  end
38
41
  end
@@ -59,9 +62,9 @@ class ::Guard::Haskell::Repl
59
62
  _repl ":reload\n:main --color --rerun\n"
60
63
  end
61
64
 
62
- def success?
65
+ def result
63
66
  while @running do sleep(0.01) end
64
- @success
67
+ @result
65
68
  end
66
69
 
67
70
  def _repl command
@@ -1,5 +1,5 @@
1
1
  module Guard
2
2
  module HaskellVersion
3
- VERSION = '1.1.0'
3
+ VERSION = '1.2.0'
4
4
  end
5
5
  end
@@ -79,7 +79,7 @@ describe ::Guard::Haskell do
79
79
  it "runs all specs on start with :all_on_start option enabled" do
80
80
  custom_guard = ::Guard::Haskell.new(all_on_start: true)
81
81
 
82
- expect(custom_guard).to receive(:run_all)
82
+ expect_any_instance_of(::Guard::Haskell::Repl).to receive(:run)
83
83
  expect(custom_guard).to receive(:success?)
84
84
 
85
85
  custom_guard.start
@@ -111,6 +111,15 @@ describe ::Guard::Haskell do
111
111
  end
112
112
 
113
113
  describe "#run" do
114
+ it "checks success after run" do
115
+ expect_any_instance_of(::Guard::Haskell::Repl).to receive(:run).with("Foo")
116
+ expect(guard).to receive(:success?)
117
+ guard.instance_variable_set(:@last_run, :success)
118
+
119
+ guard.start
120
+ guard.run("Foo")
121
+ end
122
+
114
123
  it "runs specs matching pattern if last run was a success" do
115
124
  expect_any_instance_of(::Guard::Haskell::Repl).to receive(:run).with("Foo")
116
125
  guard.instance_variable_set(:@last_run, :success)
@@ -119,36 +128,98 @@ describe ::Guard::Haskell do
119
128
  guard.run("Foo")
120
129
  end
121
130
 
122
- it "reruns previous specs if last run was a failure" do
131
+ it "runs specs matching pattern if last run was a compile time failure" do
132
+ expect_any_instance_of(::Guard::Haskell::Repl).to receive(:run).with("Foo")
133
+ guard.instance_variable_set(:@last_run, :compile_failure)
134
+
135
+ guard.start
136
+ guard.run("Foo")
137
+ end
138
+
139
+ it "reruns previous specs if last run was a runtime failure" do
123
140
  expect_any_instance_of(::Guard::Haskell::Repl).to receive(:rerun)
124
- guard.instance_variable_set(:@last_run, :failure)
141
+ guard.instance_variable_set(:@last_run, :runtime_failure)
125
142
 
126
143
  guard.start
127
144
  guard.run("Foo")
128
145
  end
129
146
  end
130
147
 
131
- describe "#success" do
132
- it "notifies on success" do
133
- ::Guard::Haskell::Repl.any_instance.stub(:success?) { true }
134
- expect_any_instance_of(::Guard::Haskell::Repl).to receive(:success?)
135
- expect(::Guard::Notifier).to receive(:notify).with('Success')
136
- guard.instance_variable_set(:@last_run, :failure)
148
+ describe "#run_all" do
149
+ it "checks success after run" do
150
+ expect_any_instance_of(::Guard::Haskell::Repl).to receive(:run)
151
+ expect(guard).to receive(:success?)
152
+ guard.instance_variable_set(:@last_run, :success)
137
153
 
138
154
  guard.start
139
- guard.success?
140
- expect(guard.instance_variable_get(:@last_run)).to eq(:success)
155
+ guard.run_all
141
156
  end
157
+ end
142
158
 
143
- it "notifies on failure" do
144
- ::Guard::Haskell::Repl.any_instance.stub(:success?) { false }
145
- expect_any_instance_of(::Guard::Haskell::Repl).to receive(:success?)
146
- expect(::Guard::Notifier).to receive(:notify).with('Failure', image: :failed)
147
- guard.instance_variable_set(:@last_run, :success)
159
+ describe "#success" do
160
+ def notify(before, received, after)
161
+ ::Guard::Haskell::Repl.any_instance.stub(:result) { received }
162
+ expect_any_instance_of(::Guard::Haskell::Repl).to receive(:result)
163
+ yield
164
+ guard.instance_variable_set(:@last_run, before)
148
165
 
149
166
  guard.start
150
167
  guard.success?
151
- expect(guard.instance_variable_get(:@last_run)).to eq(:failure)
168
+ expect(guard.instance_variable_get(:@last_run)).to eq(after)
169
+ end
170
+
171
+ it "notifies on success after success" do
172
+ notify(:success, :success, :success) do
173
+ expect(::Guard::Notifier).to receive(:notify).with('Success')
174
+ end
175
+ end
176
+
177
+ it "notifies on success after runtime failure" do
178
+ notify(:runtime_failure, :success, :success) do
179
+ expect(::Guard::Notifier).to receive(:notify).with('Success')
180
+ end
181
+ end
182
+
183
+ it "notifies on success after compile time failure" do
184
+ notify(:compile_failure, :success, :success) do
185
+ expect(::Guard::Notifier).to receive(:notify).with('Success')
186
+ end
187
+ end
188
+
189
+ it "notifies on runtime failure after success" do
190
+ notify(:success, :runtime_failure, :runtime_failure) do
191
+ expect(::Guard::Notifier).to receive(:notify).with('Failure', image: :failed)
192
+ end
193
+ end
194
+
195
+ it "notifies on runtime failure after runtime failure" do
196
+ notify(:runtime_failure, :runtime_failure, :runtime_failure) do
197
+ expect(::Guard::Notifier).to receive(:notify).with('Failure', image: :failed)
198
+ end
199
+ end
200
+
201
+ it "notifies on runtime failure after compile time failure" do
202
+ notify(:compile_failure, :runtime_failure, :runtime_failure) do
203
+ expect(::Guard::Notifier).to receive(:notify).with('Failure', image: :failed)
204
+ end
205
+ end
206
+
207
+ it "notifies on compile time failure after success" do
208
+ notify(:success, :compile_failure, :compile_failure) do
209
+ expect(::Guard::Notifier).to receive(:notify).with('Failure', image: :failed)
210
+ end
211
+ end
212
+
213
+ it "notifies on compile time failure after runtime failure" do
214
+ notify(:runtime_failure, :compile_failure, :runtime_failure) do
215
+ expect(::Guard::Notifier).to receive(:notify).with('Failure', image: :failed)
216
+ end
217
+ end
218
+
219
+ it "notifies on compile time failure after compile time failure" do
220
+ notify(:compile_failure, :compile_failure, :compile_failure) do
221
+ expect(::Guard::Notifier).to receive(:notify).with('Failure', image: :failed)
222
+ end
152
223
  end
153
224
 
154
225
  it "does not run all specs on success after failure by default" do
@@ -161,10 +232,21 @@ describe ::Guard::Haskell do
161
232
  guard.success?
162
233
  end
163
234
 
164
- it "runs all specs on success after failure with :all_on_pass option" do
165
- ::Guard::Haskell::Repl.any_instance.stub(:success?) { true }
235
+ it "runs all specs on success after runtime failure with :all_on_pass option" do
236
+ ::Guard::Haskell::Repl.any_instance.stub(:result) { :success }
237
+ custom_guard = ::Guard::Haskell.new(all_on_pass: true)
238
+ custom_guard.instance_variable_set(:@last_run, :runtime_failure)
239
+
240
+ expect(custom_guard).to receive(:run_all)
241
+
242
+ custom_guard.start
243
+ custom_guard.success?
244
+ end
245
+
246
+ it "runs all specs on success after compile time failure with :all_on_pass option" do
247
+ ::Guard::Haskell::Repl.any_instance.stub(:result) { :success }
166
248
  custom_guard = ::Guard::Haskell.new(all_on_pass: true)
167
- custom_guard.instance_variable_set(:@last_run, :failure)
249
+ custom_guard.instance_variable_set(:@last_run, :compile_failure)
168
250
 
169
251
  expect(custom_guard).to receive(:run_all)
170
252
 
@@ -194,7 +276,7 @@ describe ::Guard::Haskell do
194
276
  describe "#run_on_modifications" do
195
277
  it "run specs for simple haskell files" do
196
278
  expect_any_instance_of(::Guard::Haskell::Repl).to receive(:run).with("Foo")
197
- expect_any_instance_of(::Guard::Haskell::Repl).to receive(:success?)
279
+ expect_any_instance_of(::Guard::Haskell::Repl).to receive(:result)
198
280
 
199
281
  guard.start
200
282
  guard.run_on_modifications(["Foo.hs"])
@@ -202,7 +284,7 @@ describe ::Guard::Haskell do
202
284
 
203
285
  it "run specs for simple literate haskell files" do
204
286
  expect_any_instance_of(::Guard::Haskell::Repl).to receive(:run).with("Foo")
205
- expect_any_instance_of(::Guard::Haskell::Repl).to receive(:success?)
287
+ expect_any_instance_of(::Guard::Haskell::Repl).to receive(:result)
206
288
 
207
289
  guard.start
208
290
  guard.run_on_modifications(["Foo.lhs"])
@@ -210,7 +292,7 @@ describe ::Guard::Haskell do
210
292
 
211
293
  it "run specs for *complex* haskell files" do
212
294
  expect_any_instance_of(::Guard::Haskell::Repl).to receive(:run).with("Bar.Baz")
213
- expect_any_instance_of(::Guard::Haskell::Repl).to receive(:success?)
295
+ expect_any_instance_of(::Guard::Haskell::Repl).to receive(:result)
214
296
 
215
297
  guard.start
216
298
  guard.run_on_modifications(["foo/Bar/Baz.hs"])
@@ -218,7 +300,7 @@ describe ::Guard::Haskell do
218
300
 
219
301
  it "run specs for simple haskell spec files" do
220
302
  expect_any_instance_of(::Guard::Haskell::Repl).to receive(:run).with("Foo")
221
- expect_any_instance_of(::Guard::Haskell::Repl).to receive(:success?)
303
+ expect_any_instance_of(::Guard::Haskell::Repl).to receive(:result)
222
304
 
223
305
  guard.start
224
306
  guard.run_on_modifications(["FooSpec.hs"])
@@ -226,7 +308,7 @@ describe ::Guard::Haskell do
226
308
 
227
309
  it "run specs for simple literate haskell spec files" do
228
310
  expect_any_instance_of(::Guard::Haskell::Repl).to receive(:run).with("Foo")
229
- expect_any_instance_of(::Guard::Haskell::Repl).to receive(:success?)
311
+ expect_any_instance_of(::Guard::Haskell::Repl).to receive(:result)
230
312
 
231
313
  guard.start
232
314
  guard.run_on_modifications(["FooSpec.lhs"])
@@ -234,7 +316,7 @@ describe ::Guard::Haskell do
234
316
 
235
317
  it "run specs for *complex* haskell spec files" do
236
318
  expect_any_instance_of(::Guard::Haskell::Repl).to receive(:run).with("Bar.Baz")
237
- expect_any_instance_of(::Guard::Haskell::Repl).to receive(:success?)
319
+ expect_any_instance_of(::Guard::Haskell::Repl).to receive(:result)
238
320
 
239
321
  guard.start
240
322
  guard.run_on_modifications(["foo/Bar/BazSpec.hs"])
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.1.0
4
+ version: 1.2.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: 2013-11-23 00:00:00.000000000 Z
11
+ date: 2013-12-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: guard
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - ! '>='
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: guard-rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ! '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ! '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
69
83
  description: Guard::Haskell automatically runs your specs
70
84
  email: matvey.aksenov@gmail.com
71
85
  executables: []
@@ -74,7 +88,9 @@ extra_rdoc_files: []
74
88
  files:
75
89
  - .gitignore
76
90
  - .travis.yml
91
+ - CHANGELOG.md
77
92
  - Gemfile
93
+ - Guardfile
78
94
  - LICENSE
79
95
  - README.md
80
96
  - Rakefile
@@ -83,7 +99,7 @@ files:
83
99
  - lib/guard/haskell/repl.rb
84
100
  - lib/guard/haskell/templates/Guardfile
85
101
  - lib/guard/haskell/version.rb
86
- - spec/haskell_spec.rb
102
+ - spec/guard/haskell_spec.rb
87
103
  - spec/spec_helper.rb
88
104
  homepage: https://github.com/supki/guard-haskell#readme
89
105
  licenses:
@@ -110,5 +126,5 @@ signing_key:
110
126
  specification_version: 4
111
127
  summary: Guard gem for Haskell
112
128
  test_files:
113
- - spec/haskell_spec.rb
129
+ - spec/guard/haskell_spec.rb
114
130
  - spec/spec_helper.rb