guard-haskell 1.1.0 → 1.2.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
- 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