guard 1.5.4 → 1.6.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.
data/CHANGELOG.md CHANGED
@@ -1,16 +1,41 @@
1
+ ## 1.6.0 - 21 December, 2012
2
+
3
+ ### New features
4
+
5
+ - Allow the Guard scope to be defined from the `Guardfile` with the `scope` DSL method. ([@netzpirat][])
6
+ - [#378][] Scope plugins and groups from CLI and interactor. ([@netzpirat][])
7
+ - [#369][] Allow Guard plugins to specify their template location. ([@schmurfy][])
8
+ - [#364][] Add `ignore!` and `filter!` DSL methods. ([@tarsolya][])
9
+ - [#362][] Add interactor options `:history_file` and `:guard_rc`. ([@netzpirat][])
10
+
11
+ ### Improvements
12
+
13
+ - [#372][] Restore original TMux settings on stop. ([@rudicode][])
14
+ - [#376][] Delegate Ctrl-C to Pry to exit continuation. ([@netzpirat][])
15
+ - [#360][] Improve Guard/listen/interactor thread coordination. ([@netzpirat][])
16
+ - [#368][] Detecting duplicate definitions and then warning the user. ([@jfolkins][])
17
+ - [#367][] Change modeline's fgcolor when changing bgcolor in emacs notifier. ([@iljoo][])
18
+
19
+ ### Bug fixes
20
+
21
+ - [#377][] Add the 'a' alias for the 'all' Pry command. (reported by [@cknadler][], fixed by [@rymai][])
22
+ - [#365][] Fix terminal reset redirect to null devise on Windows. ([@cablegram][])
23
+ - [#365][] Fix Emacs notifier detection on Windows. ([@cablegram][])
24
+ - [#361][] Tmux notifier affects only the local session. ([@netzpirat][])
25
+
1
26
  ## 1.5.4 - 9 November, 2012
2
27
 
3
28
  ### Improvements
4
29
 
5
30
  - Thread handling improved and added thread debug mode. ([@netzpirat][])
6
31
 
7
- ## Bug fix
32
+ ### Bug fix
8
33
 
9
34
  - [#358][] Ignore `~/.pryrc` since it breaks Guard when loading the Rails env. ([@netzpirat][])
10
35
 
11
36
  ## 1.5.3 - 31 October, 2012
12
37
 
13
- ### Bug fix
38
+ ### Bug fixes
14
39
 
15
40
  - [#352][] Guard always reloading twice. ([@netzpirat][])
16
41
  - [#354][] Ignore `./.pryrc` since it breaks Guard when loading the Rails env. ([@netzpirat][])
@@ -657,6 +682,17 @@ The Listen integration has been supervised by [@thibaudgg][] and executed by [@M
657
682
  [#353]: https://github.com/guard/guard/issues/353
658
683
  [#354]: https://github.com/guard/guard/issues/354
659
684
  [#358]: https://github.com/guard/guard/issues/358
685
+ [#360]: https://github.com/guard/guard/issues/360
686
+ [#361]: https://github.com/guard/guard/issues/361
687
+ [#362]: https://github.com/guard/guard/issues/362
688
+ [#364]: https://github.com/guard/guard/issues/364
689
+ [#365]: https://github.com/guard/guard/issues/365
690
+ [#367]: https://github.com/guard/guard/issues/367
691
+ [#368]: https://github.com/guard/guard/issues/368
692
+ [#369]: https://github.com/guard/guard/issues/369
693
+ [#376]: https://github.com/guard/guard/issues/376
694
+ [#377]: https://github.com/guard/guard/issues/377
695
+ [#378]: https://github.com/guard/guard/issues/378
660
696
  [@Gazer]: https://github.com/Gazer
661
697
  [@Maher4Ever]: https://github.com/Maher4Ever
662
698
  [@alandipert]: https://github.com/alandipert
@@ -665,9 +701,11 @@ The Listen integration has been supervised by [@thibaudgg][] and executed by [@M
665
701
  [@benolee]: https://github.com/benolee
666
702
  [@brainopia]: https://github.com/brainopia
667
703
  [@bronson]: https://github.com/bronson
704
+ [@cablegram]: https://github.com/cablegram
668
705
  [@capotej]: https://github.com/capotej
669
706
  [@ches]: https://github.com/ches
670
707
  [@chrisberkhout]: https://github.com/chrisberkhout
708
+ [@cknadler]: https://github.com/cknadler
671
709
  [@d1]: https://github.com/d1
672
710
  [@dgutov]: https://github.com/dgutov
673
711
  [@dnagir]: https://github.com/dnagir
@@ -685,9 +723,11 @@ The Listen integration has been supervised by [@thibaudgg][] and executed by [@M
685
723
  [@hawx]: https://github.com/hawx
686
724
  [@hron]: https://github.com/hron
687
725
  [@ianwhite]: https://github.com/ianwhite
726
+ [@iljoo]: https://github.com/iljoo
688
727
  [@indirect]: https://github.com/indirect
689
728
  [@japgolly]: https://github.com/japgolly
690
729
  [@jeffutter]: https://github.com/jeffutter
730
+ [@jfolkins]: https://github.com/jfolkins
691
731
  [@johnbintz]: https://github.com/johnbintz
692
732
  [@jredville]: https://github.com/jredville
693
733
  [@jrsacks]: https://github.com/jrsacks
@@ -716,6 +756,7 @@ The Listen integration has been supervised by [@thibaudgg][] and executed by [@M
716
756
  [@royvandewater]: https://github.com/royvandewater
717
757
  [@rupert654]: https://github.com/rupert654
718
758
  [@rymai]: https://github.com/rymai
759
+ [@schmurfy]: https://github.com/schmurfy
719
760
  [@scottdavis]: https://github.com/scottdavis
720
761
  [@semperos]: https://github.com/semperos
721
762
  [@spadin]: https://github.com/spadin
@@ -724,6 +765,7 @@ The Listen integration has been supervised by [@thibaudgg][] and executed by [@M
724
765
  [@stouset]: https://github.com/stouset
725
766
  [@sunaku]: https://github.com/sunaku
726
767
  [@sutherland]: https://github.com/sutherland
768
+ [@tarsolya]: https://github.com/tarsolya
727
769
  [@thibaudgg]: https://github.com/thibaudgg
728
770
  [@thierryhenrio]: https://github.com/thierryhenrio
729
771
  [@tinogomes]: https://github.com/tinogomes
data/README.md CHANGED
@@ -101,7 +101,7 @@ group :development do
101
101
  end
102
102
  ```
103
103
 
104
- ### System notifications
104
+ ## System notifications
105
105
 
106
106
  You can configure Guard to make use of the following system notification libraries:
107
107
 
@@ -374,7 +374,7 @@ Notifications can also be disabled globally by setting a `GUARD_NOTIFY` environm
374
374
 
375
375
  #### `-g`/`--group` option
376
376
 
377
- Only certain plugin groups can be run:
377
+ Scope Guard to certain plugin groups on start:
378
378
 
379
379
  ```bash
380
380
  $ guard --group group_name another_group_name
@@ -383,6 +383,15 @@ $ guard -g group_name another_group_name # shortcut
383
383
 
384
384
  See the Guardfile DSL below for creating groups.
385
385
 
386
+ #### `-P`/`--plugins` option
387
+
388
+ Scope Guard to certain plugins on start:
389
+
390
+ ```bash
391
+ $ guard --plugins plugin_name another_plugin_name
392
+ $ guard -p plugin_name another_plugin_name # shortcut
393
+ ```
394
+
386
395
  #### `-d`/`--debug` option
387
396
 
388
397
  Guard can display debug information which can be very usefull for plugins
@@ -499,6 +508,7 @@ commands:
499
508
  * `n`, `notification`: Toggles the notifications.
500
509
  * `p`, `pause`: Toggles the file listener.
501
510
  * `r`, `reload`: Reload all plugins.
511
+ * `o`, `scope`: Scope Guard actions to plugins or groups.
502
512
  * `s`, `show`: Show all Guard plugins.
503
513
  * `e`, `exit`: Stop all plugins and quit Guard
504
514
 
@@ -636,6 +646,29 @@ $ guard -g specs
636
646
 
637
647
  Guard plugins that don't belong to a group are considered global and are always run.
638
648
 
649
+ ### scope
650
+
651
+ The `scope` method allows you to define the default plugin or group scope for Guard, if not
652
+ specified as command line option. Thus command line group and plugin scope takes precedence over
653
+ the DSL scope configuration.
654
+
655
+ You can define either a single plugin or group:
656
+
657
+ ```ruby
658
+ scope :plugin => :rspec
659
+ scope :group => :docs
660
+ ```
661
+
662
+ or specify multiple plugins or groups.
663
+
664
+ ```ruby
665
+ scope :plugins => [:test, :jasmine]
666
+ scope :groups => [:docs, :frontend]
667
+ ```
668
+
669
+ If you define both the plugin and group scope, the plugin scope has precedence. If you use both the
670
+ plural and the singular option, the plural has precedence.
671
+
639
672
  ### notification
640
673
 
641
674
  If you don't specify any notification configuration in your `Guardfile`, Guard goes through the list of available
@@ -675,6 +708,12 @@ notification :off
675
708
 
676
709
  ### interactor
677
710
 
711
+ You can customize the Pry interactor history and RC file like:
712
+
713
+ ```ruby
714
+ interactor :guard_rc => '~/.my_guard-rc', :history_file => '~/.my_guard_history_file'
715
+ ```
716
+
678
717
  If you do not need the Pry interactions with Guard at all, you can turn it off:
679
718
 
680
719
  ```ruby
@@ -711,10 +750,18 @@ are ignored.
711
750
  Please note that method only accept regexps. More on the
712
751
  [Listen README](https://github.com/guard/listen#the-patterns-for-filtering-and-ignoring-paths).
713
752
 
753
+ To append to the default ignored files and directories, use the `ignore` method:
754
+
714
755
  ```ruby
715
756
  ignore %r{^ignored/path/}, /public/
716
757
  ```
717
758
 
759
+ To _replace_ to default ignored files and directories, use the `ignore!` method:
760
+
761
+ ```ruby
762
+ ignore! /data/
763
+ ```
764
+
718
765
  ### filter
719
766
 
720
767
  The `filter` method allows you to focus by filtering files and directories without having to specify them by hand in the
@@ -728,6 +775,12 @@ Please note that method only accept regexps. More on the
728
775
  filter /\.txt$/, /.*\.zip/
729
776
  ```
730
777
 
778
+ To _replace_ any existing filter, use the `filter!` method:
779
+
780
+ ```ruby
781
+ filter /\.js$/
782
+ ```
783
+
731
784
  ### logger
732
785
 
733
786
  The `logger` method allows you to customize the Guard log output to your needs by specifying one or more options like:
data/lib/guard.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require 'rbconfig'
1
2
  require 'thread'
2
3
  require 'listen'
3
4
 
@@ -21,8 +22,11 @@ module Guard
21
22
  # The location of user defined templates
22
23
  HOME_TEMPLATES = File.expand_path('~/.guard/templates')
23
24
 
25
+ WINDOWS = RbConfig::CONFIG["host_os"] =~ %r!(msdos|mswin|djgpp|mingw)!
26
+ DEV_NULL = WINDOWS ? "NUL" : "/dev/null"
27
+
24
28
  class << self
25
- attr_accessor :options, :interactor, :runner, :listener, :lock
29
+ attr_accessor :options, :interactor, :runner, :listener, :lock, :scope, :running
26
30
 
27
31
  # Initialize the Guard singleton:
28
32
  #
@@ -40,12 +44,14 @@ module Guard
40
44
  # @deprecated @option options [Boolean] no_vendor ignore vendored dependencies
41
45
  #
42
46
  def setup(options = {})
47
+ @running = true
43
48
  @lock = Mutex.new
44
49
  @options = options.dup
45
50
  @watchdir = (options[:watchdir] && File.expand_path(options[:watchdir])) || Dir.pwd
46
51
  @runner = ::Guard::Runner.new
52
+ @scope = { :plugins => [], :groups => []}
47
53
 
48
- if @options[:debug]
54
+ if options[:debug]
49
55
  Thread.abort_on_exception = true
50
56
  ::Guard::UI.options[:level] = :debug
51
57
  debug_command_execution
@@ -62,6 +68,14 @@ module Guard
62
68
  ::Guard::Dsl.evaluate_guardfile(options)
63
69
  ::Guard::UI.error 'No guards found in Guardfile, please add at least one.' if @guards.empty?
64
70
 
71
+ if @options[:group]
72
+ @scope[:groups] = @options[:group].map { |g| ::Guard.groups(g) }
73
+ end
74
+
75
+ if @options[:plugin]
76
+ @scope[:plugins] = @options[:plugin].map { |p| ::Guard.guards(p) }
77
+ end
78
+
65
79
  runner.deprecation_warning if @options[:show_deprecations]
66
80
 
67
81
  setup_notifier
@@ -91,15 +105,26 @@ module Guard
91
105
  # Currently two signals are caught:
92
106
  # - `USR1` which pauses listening to changes.
93
107
  # - `USR2` which resumes listening to changes.
108
+ # - 'INT' which is delegated to Pry if active, otherwise stops Guard.
94
109
  #
95
110
  def setup_signal_traps
96
111
  unless defined?(JRUBY_VERSION)
97
112
  if Signal.list.keys.include?('USR1')
98
- Signal.trap('USR1') { ::Guard.pause unless @listener.paused? }
113
+ Signal.trap('USR1') { ::Guard.pause unless listener.paused? }
99
114
  end
100
115
 
101
116
  if Signal.list.keys.include?('USR2')
102
- Signal.trap('USR2') { ::Guard.pause if @listener.paused? }
117
+ Signal.trap('USR2') { ::Guard.pause if listener.paused? }
118
+ end
119
+
120
+ if Signal.list.keys.include?('INT')
121
+ Signal.trap('INT') do
122
+ if interactor
123
+ interactor.thread.raise(Interrupt)
124
+ else
125
+ ::Guard.stop
126
+ end
127
+ end
103
128
  end
104
129
  end
105
130
  end
@@ -132,7 +157,7 @@ module Guard
132
157
  # Initializes the interactor unless the user has specified not to.
133
158
  #
134
159
  def setup_interactor
135
- unless options[:no_interactions]
160
+ unless options[:no_interactions] || !::Guard::Interactor.enabled
136
161
  @interactor = ::Guard::Interactor.new
137
162
  end
138
163
  end
@@ -156,25 +181,25 @@ module Guard
156
181
  #
157
182
  def start(options = {})
158
183
  setup(options)
159
- ::Guard::UI.info "Guard is now watching at '#{ @watchdir }'"
160
184
 
161
185
  within_preserved_state do
186
+ ::Guard::UI.debug 'Guard starts all plugins'
162
187
  runner.run(:start)
188
+ ::Guard::UI.info "Guard is now watching at '#{ @watchdir }'"
189
+ listener.start(false)
163
190
  end
164
-
165
- # Blocks main thread
166
- listener.start
167
191
  end
168
192
 
169
193
  # Stop Guard listening to file changes
170
194
  #
171
195
  def stop
172
196
  within_preserved_state(false) do
197
+ ::Guard::UI.debug 'Guard stops all plugins'
173
198
  runner.run(:stop)
199
+ ::Guard::Notifier.turn_off
174
200
  ::Guard::UI.info 'Bye bye...', :reset => true
175
-
176
- # Unblocks main thread
177
201
  listener.stop
202
+ ::Guard.running = false
178
203
  end
179
204
  end
180
205
 
@@ -185,6 +210,8 @@ module Guard
185
210
  # @param [Hash] scopes hash with a Guard plugin or a group scope
186
211
  #
187
212
  def reload(scopes = {})
213
+ scopes = convert_scopes(scopes)
214
+
188
215
  within_preserved_state do
189
216
  ::Guard::UI.clear(:force => true)
190
217
  ::Guard::UI.action_with_scopes('Reload', scopes)
@@ -202,6 +229,8 @@ module Guard
202
229
  # @param [Hash] scopes hash with a Guard plugin or a group scope
203
230
  #
204
231
  def run_all(scopes = {})
232
+ scopes = convert_scopes(scopes)
233
+
205
234
  within_preserved_state do
206
235
  ::Guard::UI.clear(:force => true)
207
236
  ::Guard::UI.action_with_scopes('Run', scopes)
@@ -333,6 +362,7 @@ module Guard
333
362
  interactor.stop if interactor
334
363
  @result = yield
335
364
  rescue Interrupt
365
+ # Bring back Pry when the block is halted with Ctrl-C
336
366
  end
337
367
 
338
368
  interactor.start if interactor && restart_interactor
@@ -400,7 +430,14 @@ module Guard
400
430
  #
401
431
  def guard_gem_names
402
432
  if Gem::Version.create(Gem::VERSION) >= Gem::Version.create('1.8.0')
403
- Gem::Specification.find_all.select { |x| x.name =~ /^guard-/ }
433
+ Gem::Specification.find_all.select do |x|
434
+ if x.name =~ /^guard-/
435
+ true
436
+ elsif x.name != "guard"
437
+ guard_plugin_path = File.join(x.full_gem_path, "lib/guard/#{x.name}.rb")
438
+ File.exists?( guard_plugin_path )
439
+ end
440
+ end
404
441
  else
405
442
  Gem.source_index.find_name(/^guard-/)
406
443
  end.map { |x| x.name.sub(/^guard-/, '') }
@@ -444,5 +481,40 @@ module Guard
444
481
  ::Guard::UI.deprecation(NO_VENDOR_DEPRECATION) if options[:no_vendor]
445
482
  end
446
483
 
484
+ # Convert the old scope format to the new scope format.
485
+ #
486
+ # @example Convert old scopes
487
+ # convert_scopes({ :guard => :rspec, :group => :backend })
488
+ # => { :plugins => [:rspec], :groups => [:backend] }
489
+ #
490
+ def convert_scopes(scopes)
491
+ if scopes[:guard]
492
+ scopes[:plugins] = [scopes[:guard]]
493
+ scopes.delete(:guard)
494
+ end
495
+
496
+ if scopes[:group]
497
+ scopes[:groups] = [scopes[:group]]
498
+ scopes.delete(:group)
499
+ end
500
+
501
+ scopes
502
+ end
503
+
504
+ # Determine if Guard needs to quit. This
505
+ # checks for Ctrl-D pressed.
506
+ #
507
+ # @return [Boolean] whether to quit or not
508
+ #
509
+ def quit?
510
+ STDIN.read_nonblock(1)
511
+ false
512
+ rescue Errno::EINTR
513
+ false
514
+ rescue Errno::EAGAIN
515
+ false
516
+ rescue EOFError
517
+ true
518
+ end
447
519
  end
448
520
  end
data/lib/guard/cli.rb CHANGED
@@ -41,6 +41,12 @@ module Guard
41
41
  :aliases => '-g',
42
42
  :banner => 'Run only the passed groups'
43
43
 
44
+ method_option :plugin,
45
+ :type => :array,
46
+ :default => [],
47
+ :aliases => '-P',
48
+ :banner => 'Run only the passed plugins'
49
+
44
50
  method_option :watchdir,
45
51
  :type => :string,
46
52
  :aliases => '-w',
@@ -102,9 +108,12 @@ module Guard
102
108
  def start
103
109
  verify_bundler_presence unless options[:no_bundler_warning]
104
110
  ::Guard.start(options)
105
- rescue Interrupt
106
- ::Guard.stop
107
- abort
111
+
112
+ return if ENV['GUARD_ENV'] == 'test'
113
+
114
+ while ::Guard.running do
115
+ sleep 0.5
116
+ end
108
117
  end
109
118
 
110
119
  desc 'list', 'Lists guards that can be used with init'
@@ -0,0 +1,32 @@
1
+ module Guard
2
+ class Interactor
3
+
4
+ SCOPE = Pry::CommandSet.new do
5
+ create_command 'scope' do
6
+
7
+ group 'Guard'
8
+ description 'Scope Guard actions to groups and plugins.'
9
+
10
+ banner <<-BANNER
11
+ Usage: scope <scope>
12
+
13
+ Set the global Guard scope.
14
+ BANNER
15
+
16
+ def process(*entries)
17
+ scope, rest = ::Guard::Interactor.convert_scope(entries)
18
+
19
+ if rest.length == 0
20
+ ::Guard.scope = scope
21
+ else
22
+ output.puts "Unkown scope #{ rest.join(', ') }"
23
+ end
24
+ end
25
+
26
+ end
27
+ end
28
+
29
+ end
30
+ end
31
+
32
+ Pry.commands.import ::Guard::Interactor::SCOPE