guard 2.6.1 → 2.7.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.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +73 -58
  3. data/bin/guard +2 -2
  4. data/lib/guard.rb +64 -59
  5. data/lib/guard/cli.rb +66 -60
  6. data/lib/guard/cli.rb.orig +215 -0
  7. data/lib/guard/commander.rb +45 -69
  8. data/lib/guard/commands/all.rb +21 -19
  9. data/lib/guard/commands/change.rb +17 -22
  10. data/lib/guard/commands/notification.rb +15 -16
  11. data/lib/guard/commands/pause.rb +14 -15
  12. data/lib/guard/commands/reload.rb +19 -20
  13. data/lib/guard/commands/scope.rb +23 -19
  14. data/lib/guard/commands/show.rb +13 -16
  15. data/lib/guard/deprecated_methods.rb +6 -10
  16. data/lib/guard/deprecator.rb +52 -37
  17. data/lib/guard/dsl.rb +55 -33
  18. data/lib/guard/dsl_describer.rb +83 -31
  19. data/lib/guard/dsl_describer.rb.orig +184 -0
  20. data/lib/guard/group.rb +7 -6
  21. data/lib/guard/guard.rb +4 -4
  22. data/lib/guard/guard.rb.orig +42 -0
  23. data/lib/guard/guardfile.rb +12 -13
  24. data/lib/guard/guardfile/evaluator.rb +77 -55
  25. data/lib/guard/guardfile/evaluator.rb.orig +275 -0
  26. data/lib/guard/guardfile/generator.rb +25 -20
  27. data/lib/guard/interactor.rb +52 -293
  28. data/lib/guard/interactor.rb.orig +85 -0
  29. data/lib/guard/jobs/base.rb +21 -0
  30. data/lib/guard/jobs/pry_wrapper.rb +290 -0
  31. data/lib/guard/jobs/pry_wrapper.rb.orig +293 -0
  32. data/lib/guard/jobs/sleep.rb +25 -0
  33. data/lib/guard/notifier.rb +42 -39
  34. data/lib/guard/notifiers/base.rb +25 -24
  35. data/lib/guard/notifiers/emacs.rb +30 -24
  36. data/lib/guard/notifiers/file_notifier.rb +3 -7
  37. data/lib/guard/notifiers/gntp.rb +22 -22
  38. data/lib/guard/notifiers/growl.rb +16 -15
  39. data/lib/guard/notifiers/libnotify.rb +7 -10
  40. data/lib/guard/notifiers/notifysend.rb +15 -14
  41. data/lib/guard/notifiers/rb_notifu.rb +8 -10
  42. data/lib/guard/notifiers/terminal_notifier.rb +15 -11
  43. data/lib/guard/notifiers/terminal_title.rb +4 -8
  44. data/lib/guard/notifiers/tmux.rb +104 -71
  45. data/lib/guard/options.rb +1 -5
  46. data/lib/guard/plugin.rb +1 -3
  47. data/lib/guard/plugin/base.rb +12 -9
  48. data/lib/guard/plugin/hooker.rb +1 -5
  49. data/lib/guard/plugin_util.rb +46 -25
  50. data/lib/guard/plugin_util.rb.orig +178 -0
  51. data/lib/guard/rake_task.rb +4 -7
  52. data/lib/guard/reevaluator.rb +13 -0
  53. data/lib/guard/runner.rb +50 -78
  54. data/lib/guard/runner.rb.orig +200 -0
  55. data/lib/guard/setuper.rb +199 -130
  56. data/lib/guard/setuper.rb.orig +348 -0
  57. data/lib/guard/sheller.rb +107 -0
  58. data/lib/guard/tags +367 -0
  59. data/lib/guard/ui.rb +50 -38
  60. data/lib/guard/ui.rb.orig +254 -0
  61. data/lib/guard/ui/colors.rb +17 -21
  62. data/lib/guard/version.rb +1 -1
  63. data/lib/guard/version.rb.orig +3 -0
  64. data/lib/guard/watcher.rb +49 -62
  65. metadata +21 -4
  66. data/lib/guard/notifiers/growl_notify.rb +0 -93
@@ -0,0 +1,215 @@
1
+ require "thor"
2
+
3
+ require "guard"
4
+ require "guard/version"
5
+ require "guard/dsl_describer"
6
+ require "guard/guardfile"
7
+
8
+ module Guard
9
+ # Facade for the Guard command line interface managed by
10
+ # [Thor](https://github.com/wycats/thor).
11
+ #
12
+ # This is the main interface to Guard that is called by the Guard binary
13
+ # `bin/guard`. Do not put any logic in here, create a class and delegate
14
+ # instead.
15
+ #
16
+ class CLI < Thor
17
+ default_task :start
18
+
19
+ desc "start", "Starts Guard"
20
+
21
+ method_option :clear,
22
+ type: :boolean,
23
+ default: false,
24
+ aliases: "-c",
25
+ banner: "Auto clear shell before each action"
26
+
27
+ method_option :notify,
28
+ type: :boolean,
29
+ default: true,
30
+ aliases: "-n",
31
+ banner: "Notifications feature"
32
+
33
+ method_option :debug,
34
+ type: :boolean,
35
+ default: false,
36
+ aliases: "-d",
37
+ banner: "Show debug information"
38
+
39
+ method_option :group,
40
+ type: :array,
41
+ default: [],
42
+ aliases: "-g",
43
+ banner: "Run only the passed groups"
44
+
45
+ method_option :plugin,
46
+ type: :array,
47
+ default: [],
48
+ aliases: "-P",
49
+ banner: "Run only the passed plugins"
50
+
51
+ method_option :watchdir,
52
+ type: :array,
53
+ aliases: "-w",
54
+ banner: "Specify the directories to watch"
55
+
56
+ method_option :guardfile,
57
+ type: :string,
58
+ aliases: "-G",
59
+ banner: "Specify a Guardfile"
60
+
61
+ method_option :no_interactions,
62
+ type: :boolean,
63
+ default: false,
64
+ aliases: "-i",
65
+ banner: "Turn off completely any Guard terminal interactions"
66
+
67
+ method_option :no_bundler_warning,
68
+ type: :boolean,
69
+ default: false,
70
+ aliases: "-B",
71
+ banner: "Turn off warning when Bundler is not present"
72
+
73
+ method_option :show_deprecations,
74
+ type: :boolean,
75
+ default: false,
76
+ banner: "Turn on deprecation warnings"
77
+
78
+ # Listen options
79
+ method_option :latency,
80
+ type: :numeric,
81
+ aliases: "-l",
82
+ banner: 'Overwrite Listen\'s default latency'
83
+
84
+ method_option :force_polling,
85
+ type: :boolean,
86
+ default: false,
87
+ aliases: "-p",
88
+ banner: "Force usage of the Listen polling listener"
89
+
90
+ method_option :wait_for_delay,
91
+ type: :numeric,
92
+ aliases: "-y",
93
+ banner: 'Overwrite Listen\'s default wait_for_delay'
94
+
95
+ method_option :listen_on,
96
+ type: :string,
97
+ aliases: "-o",
98
+ default: false,
99
+ banner: "Specify a network address to Listen on for "\
100
+ "file change events (e.g. for use in VMs)"
101
+
102
+ # Start Guard by initializing the defined Guard plugins and watch the file
103
+ # system.
104
+ #
105
+ # This is the default task, so calling `guard` is the same as calling
106
+ # `guard start`.
107
+ #
108
+ # @see Guard.start
109
+ #
110
+ def start
111
+ _verify_bundler_presence unless options[:no_bundler_warning]
112
+ ::Guard.start(options)
113
+ end
114
+
115
+ desc "list", "Lists Guard plugins that can be used with init"
116
+
117
+ # List the Guard plugins that are available for use in your system and
118
+ # marks those that are currently used in your `Guardfile`.
119
+ #
120
+ # @see Guard::DslDescriber.list
121
+ #
122
+ def list
123
+ ::Guard::DslDescriber.new(options).list
124
+ end
125
+
126
+ desc "notifiers", "Lists notifiers and its options"
127
+
128
+ # List the Notifiers for use in your system.
129
+ #
130
+ # @see Guard::DslDescriber.notifiers
131
+ #
132
+ def notifiers
133
+ ::Guard::DslDescriber.new(options).notifiers
134
+ end
135
+
136
+ desc "version", "Show the Guard version"
137
+ map %w(-v --version) => :version
138
+
139
+ # Shows the current version of Guard.
140
+ #
141
+ # @see Guard::VERSION
142
+ #
143
+ def version
144
+ STDOUT.puts "Guard version #{ ::Guard::VERSION }"
145
+ end
146
+
147
+ desc "init [GUARDS]", "Generates a Guardfile at the current directory"\
148
+ " (if it is not already there) and adds all installed Guard plugins"\
149
+ " or the given GUARDS into it"
150
+
151
+ method_option :bare,
152
+ type: :boolean,
153
+ default: false,
154
+ aliases: "-b",
155
+ banner: "Generate a bare Guardfile without adding any"\
156
+ " installed plugin into it"
157
+
158
+ # Initializes the templates of all installed Guard plugins and adds them
159
+ # to the `Guardfile` when no Guard name is passed. When passing
160
+ # Guard plugin names it does the same but only for those Guard plugins.
161
+ #
162
+ # @see Guard::Guardfile.initialize_template
163
+ # @see Guard::Guardfile.initialize_all_templates
164
+ #
165
+ # @param [Array<String>] plugin_names the name of the Guard plugins to
166
+ # initialize
167
+ #
168
+ def init(*plugin_names)
169
+ _verify_bundler_presence unless options[:no_bundler_warning]
170
+
171
+ ::Guard::Guardfile.create_guardfile(abort_on_existence: options[:bare])
172
+
173
+ return if options[:bare]
174
+
175
+ if plugin_names.empty?
176
+ ::Guard::Guardfile.initialize_all_templates
177
+ else
178
+ plugin_names.each do |plugin_name|
179
+ ::Guard::Guardfile.initialize_template(plugin_name)
180
+ end
181
+ end
182
+ end
183
+
184
+ desc "show", "Show all defined Guard plugins and their options"
185
+ map %w(-T) => :show
186
+
187
+ # Shows all Guard plugins and their options that are defined in
188
+ # the `Guardfile`
189
+ #
190
+ # @see Guard::DslDescriber.show
191
+ #
192
+ def show
193
+ ::Guard::DslDescriber.new(options).show
194
+ end
195
+
196
+ private
197
+
198
+ # Verifies if Guard is run with `bundle exec` and
199
+ # shows a hint to do so if not.
200
+ #
201
+ def _verify_bundler_presence
202
+ return unless File.exist?("Gemfile")
203
+ return if ENV["BUNDLE_GEMFILE"] || ENV["RUBYGEMS_GEMDEPS"]
204
+
205
+ ::Guard::UI.info <<EOF
206
+
207
+ Guard here! It looks like your project has a Gemfile, yet you are running
208
+ `guard` outside of Bundler. If this is your intent, feel free to ignore this
209
+ message. Otherwise, consider using `bundle exec guard` to ensure your
210
+ dependencies are loaded correctly.
211
+ (You can run `guard` with --no-bundler-warning to get rid of this message.)
212
+ EOF
213
+ end
214
+ end
215
+ end
@@ -1,9 +1,8 @@
1
1
  module Guard
2
-
2
+ # Commands supported by guard
3
3
  module Commander
4
-
5
- # Start Guard by evaluating the `Guardfile`, initializing declared Guard plugins
6
- # and starting the available file change listener.
4
+ # Start Guard by evaluating the `Guardfile`, initializing declared Guard
5
+ # plugins and starting the available file change listener.
7
6
  # Main method for Guard that is called from the CLI when Guard starts.
8
7
  #
9
8
  # - Setup Guard internals
@@ -21,29 +20,23 @@ module Guard
21
20
  # @see CLI#start
22
21
  #
23
22
  def start(options = {})
24
- setup(options) unless running
23
+ setup(options)
24
+ ::Guard::UI.debug "Guard starts all plugins"
25
+ runner.run(:start)
26
+ listener.start
27
+ ::Guard::UI.info "Guard is now watching at '#{ @watchdirs.join "', '" }'"
25
28
 
26
- within_preserved_state do
27
- ::Guard::UI.debug 'Guard starts all plugins'
28
- runner.run(:start)
29
- ::Guard::UI.info "Guard is now watching at '#{ @watchdirs.join "', '" }'"
30
- listener.start
31
- end
29
+ _interactor_loop
32
30
  end
33
31
 
34
- # Stop Guard listening to file changes.
35
- #
32
+ # TODO: refactor (left to avoid breaking too many specs)
36
33
  def stop
37
- setup unless running
38
-
39
- within_preserved_state do
40
- ::Guard::UI.debug 'Guard stops all plugins'
41
- runner.run(:stop)
42
- ::Guard::Notifier.turn_off
43
- ::Guard::UI.info 'Bye bye...', reset: true
44
- listener.stop
45
- @running = false
46
- end
34
+ listener.stop
35
+ interactor.background
36
+ ::Guard::UI.debug "Guard stops all plugins"
37
+ runner.run(:stop)
38
+ ::Guard::Notifier.turn_off
39
+ ::Guard::UI.info "Bye bye...", reset: true
47
40
  end
48
41
 
49
42
  # Reload Guardfile and all Guard plugins currently enabled.
@@ -53,17 +46,13 @@ module Guard
53
46
  # @param [Hash] scopes hash with a Guard plugin or a group scope
54
47
  #
55
48
  def reload(scopes = {})
56
- setup unless running
57
-
58
- within_preserved_state do
59
- ::Guard::UI.clear(force: true)
60
- ::Guard::UI.action_with_scopes('Reload', scopes)
49
+ ::Guard::UI.clear(force: true)
50
+ ::Guard::UI.action_with_scopes("Reload", scopes)
61
51
 
62
- if scopes.empty?
63
- evaluator.reevaluate_guardfile
64
- else
65
- runner.run(:reload, scopes)
66
- end
52
+ if scopes.empty?
53
+ evaluator.reevaluate_guardfile
54
+ else
55
+ runner.run(:reload, scopes)
67
56
  end
68
57
  end
69
58
 
@@ -72,50 +61,37 @@ module Guard
72
61
  # @param [Hash] scopes hash with a Guard plugin or a group scope
73
62
  #
74
63
  def run_all(scopes = {})
75
- setup unless running
76
-
77
- within_preserved_state do
78
- ::Guard::UI.clear(force: true)
79
- ::Guard::UI.action_with_scopes('Run', scopes)
80
- runner.run(:run_all, scopes)
81
- end
64
+ ::Guard::UI.clear(force: true)
65
+ ::Guard::UI.action_with_scopes("Run", scopes)
66
+ runner.run(:run_all, scopes)
82
67
  end
83
68
 
84
69
  # Pause Guard listening to file changes.
85
70
  #
86
- def pause
87
- if listener.paused?
88
- ::Guard::UI.info 'Un-paused files modification listening', reset: true
89
- listener.unpause
90
- else
91
- ::Guard::UI.info 'Paused files modification listening', reset: true
92
- listener.pause
93
- end
71
+ def pause(expected = nil)
72
+ paused = listener.paused?
73
+ states = { paused: true, unpaused: false, toggle: !paused }
74
+ pause = states[expected || :toggle]
75
+ fail ArgumentError, "invalid mode: #{expected.inspect}" if pause.nil?
76
+ return if pause == paused
77
+
78
+ listener.send(pause ? :pause : :unpause)
79
+ UI.info "File modification listening is now #{pause.to_s.upcase}"
94
80
  end
95
81
 
96
- # Runs a block where the interactor is
97
- # blocked and execution is synchronized
98
- # to avoid state inconsistency.
99
- #
100
- # @param [Boolean] restart_interactor whether to restart the interactor or
101
- # not
102
- # @yield the block to run
103
- #
104
- def within_preserved_state
105
- lock.synchronize do
106
- begin
107
- interactor.stop if interactor
108
- @result = yield
109
- rescue Interrupt
110
- # Bring back Pry when the block is halted with Ctrl-C
111
- end
82
+ def show
83
+ ::Guard::DslDescriber.new(::Guard.options).show
84
+ end
112
85
 
113
- interactor.start if interactor && running
114
- end
86
+ private
115
87
 
116
- @result
88
+ # TODO: remove (left to avoid breaking too many specs)
89
+ def _interactor_loop
90
+ while interactor.foreground != :exit
91
+ _process_queue while pending_changes?
92
+ end
93
+ rescue Interrupt
94
+ stop
117
95
  end
118
-
119
96
  end
120
-
121
97
  end
@@ -1,34 +1,36 @@
1
- module Guard
2
- class Interactor
3
-
4
- ALL = Pry::CommandSet.new do
5
- create_command 'all' do
1
+ # required for async_queue_add
2
+ require "pry"
3
+ require "guard"
6
4
 
7
- group 'Guard'
8
- description 'Run all plugins.'
9
-
10
- banner <<-BANNER
5
+ module Guard
6
+ module Commands
7
+ class All
8
+ def self.import
9
+ Pry::Commands.create_command "all" do
10
+ group "Guard"
11
+ description "Run all plugins."
12
+
13
+ banner <<-BANNER
11
14
  Usage: all <scope>
12
15
 
13
16
  Run the Guard plugin `run_all` action.
14
17
 
15
18
  You may want to specify an optional scope to the action,
16
19
  either the name of a Guard plugin or a plugin group.
17
- BANNER
20
+ BANNER
18
21
 
19
- def process(*entries)
20
- scopes, rest = ::Guard::Interactor.convert_scope(entries)
22
+ def process(*entries)
23
+ scopes, unknown = ::Guard::Interactor.convert_scope(entries)
21
24
 
22
- if rest.empty?
23
- ::Guard.run_all scopes
24
- else
25
- output.puts "Unknown scope #{ rest.join(', ') }"
25
+ unless unknown.empty?
26
+ output.puts "Unknown scopes: #{ unknown.join(", ") }"
27
+ return
28
+ end
29
+
30
+ ::Guard.async_queue_add([:guard_run_all, scopes])
26
31
  end
27
32
  end
28
33
  end
29
34
  end
30
-
31
35
  end
32
36
  end
33
-
34
- Pry.commands.import ::Guard::Interactor::ALL
@@ -1,34 +1,29 @@
1
- module Guard
2
- class Interactor
3
-
4
- CHANGE = Pry::CommandSet.new do
5
- create_command 'change' do
6
-
7
- group 'Guard'
8
- description 'Trigger a file change.'
1
+ require "pry"
9
2
 
10
- banner <<-BANNER
3
+ module Guard
4
+ module Commands
5
+ class Change
6
+ def self.import
7
+ Pry::Commands.create_command "change" do
8
+ group "Guard"
9
+ description "Trigger a file change."
10
+
11
+ banner <<-BANNER
11
12
  Usage: change <file> <other_file>
12
13
 
13
14
  Pass the given files to the Guard plugin `run_on_changes` action.
14
- BANNER
15
-
16
- def process(*entries)
17
- scopes, files = ::Guard::Interactor.convert_scope(entries)
15
+ BANNER
18
16
 
19
- if files.empty?
20
- output.puts 'Please specify a file.'
21
- else
22
- ::Guard.within_preserved_state do
23
- ::Guard.runner.run_on_changes(files, [], [])
17
+ def process(*files)
18
+ if files.empty?
19
+ output.puts "Please specify a file."
20
+ return
24
21
  end
22
+
23
+ ::Guard.async_queue_add(modified: files, added: [], removed: [])
25
24
  end
26
25
  end
27
-
28
26
  end
29
27
  end
30
-
31
28
  end
32
29
  end
33
-
34
- Pry.commands.import ::Guard::Interactor::CHANGE