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
@@ -1,27 +1,28 @@
1
1
  module Guard
2
2
  module Guardfile
3
-
4
3
  # This class is responsible for generating the Guardfile and adding Guard'
5
4
  # plugins' templates into it.
6
5
  #
7
6
  # @see Guard::CLI
8
7
  #
9
8
  class Generator
10
-
11
- require 'guard'
12
- require 'guard/ui'
9
+ require "guard"
10
+ require "guard/ui"
13
11
 
14
12
  attr_reader :options
15
13
 
16
14
  # The Guardfile template for `guard init`
17
- GUARDFILE_TEMPLATE = File.expand_path('../../../guard/templates/Guardfile', __FILE__)
15
+ GUARDFILE_TEMPLATE = File.expand_path(
16
+ "../../../guard/templates/Guardfile",
17
+ __FILE__)
18
18
 
19
19
  # The location of user defined templates
20
20
  begin
21
- HOME_TEMPLATES = File.expand_path('~/.guard/templates')
22
- rescue ArgumentError => e
23
- # home isn't defined. Set to the root of the drive. Trust that there won't be user defined templates there
24
- HOME_TEMPLATES = File.expand_path('/')
21
+ HOME_TEMPLATES = File.expand_path("~/.guard/templates")
22
+ rescue ArgumentError
23
+ # home isn't defined. Set to the root of the drive. Trust that there
24
+ # won't be user defined templates there
25
+ HOME_TEMPLATES = File.expand_path("/")
25
26
  end
26
27
 
27
28
  # Initialize a new `Guard::Guardfile::Generator` object.
@@ -40,9 +41,9 @@ module Guard
40
41
  # @see Guard::CLI#init
41
42
  #
42
43
  def create_guardfile
43
- if !File.exist?('Guardfile')
44
+ if !File.exist?("Guardfile")
44
45
  ::Guard::UI.info "Writing new Guardfile to #{ Dir.pwd }/Guardfile"
45
- FileUtils.cp(GUARDFILE_TEMPLATE, 'Guardfile')
46
+ FileUtils.cp(GUARDFILE_TEMPLATE, "Guardfile")
46
47
  elsif options[:abort_on_existence]
47
48
  ::Guard::UI.error "Guardfile already exists at #{ Dir.pwd }/Guardfile"
48
49
  abort
@@ -61,21 +62,27 @@ module Guard
61
62
  if plugin_util.plugin_class(fail_gracefully: true)
62
63
  plugin_util.add_to_guardfile
63
64
 
64
- @options[:guardfile] = File.read('Guardfile') if File.exists?('Guardfile')
65
+ begin
66
+ @options[:guardfile] = IO.read("Guardfile")
67
+ rescue Errno::ENOENT
68
+ end
65
69
 
66
70
  elsif File.exist?(File.join(HOME_TEMPLATES, plugin_name))
67
- content = File.read('Guardfile')
71
+ content = File.read("Guardfile")
68
72
 
69
- File.open('Guardfile', 'wb') do |f|
73
+ File.open("Guardfile", "wb") do |f|
70
74
  f.puts(content)
71
- f.puts('')
75
+ f.puts("")
72
76
  f.puts(File.read(File.join(HOME_TEMPLATES, plugin_name)))
73
77
  end
74
78
 
75
- ::Guard::UI.info "#{ plugin_name } template added to Guardfile, feel free to edit it"
79
+ ::Guard::UI.info \
80
+ "#{ plugin_name } template added to Guardfile, feel free to edit it"
76
81
  else
77
- const_name = plugin_name.downcase.gsub('-', '')
78
- UI.error "Could not load 'guard/#{ plugin_name.downcase }' or '~/.guard/templates/#{ plugin_name.downcase }' or find class Guard::#{ const_name.capitalize }"
82
+ const_name = plugin_name.downcase.gsub("-", "")
83
+ UI.error "Could not load 'guard/#{ plugin_name.downcase }'"\
84
+ " or '~/.guard/templates/#{ plugin_name.downcase }'"\
85
+ " or find class Guard::#{ const_name.capitalize }"
79
86
  end
80
87
  end
81
88
 
@@ -87,8 +94,6 @@ module Guard
87
94
  def initialize_all_templates
88
95
  ::Guard::PluginUtil.plugin_names.each { |g| initialize_template(g) }
89
96
  end
90
-
91
97
  end
92
-
93
98
  end
94
99
  end
@@ -1,326 +1,85 @@
1
- require 'pry'
1
+ require "guard/ui"
2
2
 
3
- require 'guard/commands/all'
4
- require 'guard/commands/change'
5
- require 'guard/commands/notification'
6
- require 'guard/commands/pause'
7
- require 'guard/commands/reload'
8
- require 'guard/commands/scope'
9
- require 'guard/commands/show'
10
- require 'guard/ui'
3
+ require "guard/jobs/sleep"
4
+ require "guard/jobs/pry_wrapper"
11
5
 
12
6
  module Guard
13
-
14
- # The Guard interactor is a Pry REPL with a Guard
15
- # specific command set.
16
- #
17
7
  class Interactor
18
-
19
- # The default Ruby script to configure Guard Pry if the option `:guard_rc` is not defined.
20
- GUARD_RC = '~/.guardrc'
21
-
22
- # The default Guard Pry history file if the option `:history_file` is not defined.
23
- HISTORY_FILE = '~/.guard_history'
24
-
25
- # List of shortcuts for each interactor command
26
- SHORTCUTS = {
27
- help: 'h',
28
- all: 'a',
29
- reload: 'r',
30
- change: 'c',
31
- show: 's',
32
- scope: 'o',
33
- notification: 'n',
34
- pause: 'p',
35
- exit: 'e',
36
- quit: 'q'
37
- }
38
-
39
- attr_accessor :thread
40
-
41
- # Get the interactor options
42
- #
43
- # @return [Hash] the options
44
- #
45
- def self.options
46
- @options ||= {}
47
- end
48
-
49
- # Set the interactor options
50
- #
51
- # @param [Hash] options the interactor options
52
- # @option options [String] :guard_rc the Ruby script to configure Guard Pry
53
- # @option options [String] :history_file the file to write the Pry history to
54
- #
55
- def self.options=(options)
56
- @options = options
57
- end
58
-
59
- # Is the interactor enabled?
60
- #
61
- # @return [Boolean] true if enabled
62
- #
63
- def self.enabled
64
- @enabled || @enabled.nil?
65
- end
66
-
67
- # Set the enabled status for the interactor
68
- #
69
- # @param [Boolean] status true if enabled
70
- #
71
- def self.enabled=(status)
72
- @enabled = status
73
- end
74
-
75
- # Converts and validates a plain text scope
76
- # to a valid plugin or group scope.
77
- #
78
- # @param [Array<String>] entries the text scope
79
- # @return [Hash, Array<String>] the plugin or group scope, the unknown entries
80
- #
81
- def self.convert_scope(entries)
82
- scopes = { plugins: [], groups: [] }
83
- unknown = []
84
-
85
- entries.each do |entry|
86
- if plugin = ::Guard.plugin(entry)
87
- scopes[:plugins] << plugin
88
- elsif group = ::Guard.group(entry)
89
- scopes[:groups] << group
90
- else
91
- unknown << entry
92
- end
93
- end
94
-
95
- [scopes, unknown]
96
- end
97
-
98
8
  # Initializes the interactor. This configures
99
9
  # Pry and creates some custom commands and aliases
100
10
  # for Guard.
101
11
  #
102
- def initialize
103
- return if ENV['GUARD_ENV'] == 'test'
104
-
105
- Pry.config.should_load_rc = false
106
- Pry.config.should_load_local_rc = false
107
- Pry.config.history.file = File.expand_path(self.class.options[:history_file] || HISTORY_FILE)
108
-
109
- @stty_exists = nil
110
- _add_hooks
111
-
112
- _replace_reset_command
113
- _create_run_all_command
114
- _create_command_aliases
115
- _create_guard_commands
116
- _create_group_commands
117
-
118
- _configure_prompt
119
- end
120
-
121
- # Start the line reader in its own thread and
122
- # stop Guard on Ctrl-D.
123
- #
124
- def start
125
- return if ENV['GUARD_ENV'] == 'test'
126
-
127
- _store_terminal_settings if _stty_exists?
128
-
129
- unless @thread
130
- ::Guard::UI.debug 'Start interactor'
131
-
132
- @thread = Thread.new do
133
- Pry.start
134
- ::Guard.stop
135
- end
136
- end
137
- end
138
-
139
- # Kill interactor thread if not current
140
- #
141
- def stop
142
- return if !@thread || ENV['GUARD_ENV'] == 'test'
143
-
144
- unless Thread.current == @thread
145
- ::Guard::UI.reset_line
146
- ::Guard::UI.debug 'Stop interactor'
147
- @thread.kill
148
- @thread = nil
149
- end
150
-
151
- _restore_terminal_settings if _stty_exists?
152
- end
153
-
154
- private
155
-
156
- # Add Pry hooks:
157
- #
158
- # * Load `~/.guardrc` within each new Pry session.
159
- # * Load project's `.guardrc` within each new Pry session.
160
- # * Restore prompt after each evaluation.
161
- #
162
- def _add_hooks
163
- _add_load_guard_rc_hook
164
- _add_load_project_guard_rc_hook
165
- _add_restore_visibility_hook if _stty_exists?
166
- end
12
+ def initialize(no_interaction = false)
13
+ @interactive = !no_interaction && self.class.enabled?
167
14
 
168
- # Add a `when_started` hook that loads a global .guardrc if it exists.
169
- #
170
- def _add_load_guard_rc_hook
171
- Pry.config.hooks.add_hook :when_started, :load_guard_rc do
172
- (self.class.options[:guard_rc] || GUARD_RC).tap do |p|
173
- load p if File.exist?(File.expand_path(p))
174
- end
175
- end
15
+ job_klass = interactive? ? Jobs::PryWrapper : Jobs::Sleep
16
+ @idle_job = job_klass.new(self.class.options)
176
17
  end
177
18
 
178
- # Add a `when_started` hook that loads a project .guardrc if it exists.
179
- #
180
- def _add_load_project_guard_rc_hook
181
- Pry.config.hooks.add_hook :when_started, :load_project_guard_rc do
182
- project_guard_rc = Dir.pwd + '/.guardrc'
183
- load project_guard_rc if File.exist?(project_guard_rc)
184
- end
19
+ def interactive?
20
+ @interactive
185
21
  end
186
22
 
187
- # Add a `after_eval` hook that restores visibility after a command is eval.
188
- #
189
- def _add_restore_visibility_hook
190
- Pry.config.hooks.add_hook :after_eval, :restore_visibility do
191
- system("stty echo 2>#{ DEV_NULL }")
192
- end
23
+ # Run in foreground and wait until interrupted or closed
24
+ def foreground
25
+ idle_job.foreground
193
26
  end
194
27
 
195
- # Replaces reset defined inside of Pry with a reset that
196
- # instead restarts guard.
197
- #
198
- def _replace_reset_command
199
- Pry.commands.command "reset", "Reset the Guard to a clean state." do
200
- output.puts "Guard reset."
201
- exec "guard"
202
- end
28
+ # Remove interactor so other tasks can run in foreground
29
+ def background
30
+ idle_job.background
203
31
  end
204
32
 
205
- # Creates a command that triggers the `:run_all` action
206
- # when the command is empty (just pressing enter on the
207
- # beginning of a line).
208
- #
209
- def _create_run_all_command
210
- Pry.commands.block_command /^$/, 'Hit enter to run all' do
211
- Pry.run_command 'all'
212
- end
33
+ def handle_interrupt
34
+ idle_job.handle_interrupt
213
35
  end
214
36
 
215
- # Creates command aliases for the commands
216
- # `help`, `reload`, `change`, `scope`, `notification`, `pause`, `exit` and `quit`,
217
- # which will be the first letter of the command.
218
- #
219
- def _create_command_aliases
220
- SHORTCUTS.each do |command, shortcut|
221
- Pry.commands.alias_command shortcut, command.to_s
37
+ class << self
38
+ def options
39
+ @options ||= {}
222
40
  end
223
- end
224
41
 
225
- # Create a shorthand command to run the `:run_all`
226
- # action on a specific Guard plugin. For example,
227
- # when guard-rspec is available, then a command
228
- # `rspec` is created that runs `all rspec`.
229
- #
230
- def _create_guard_commands
231
- ::Guard.plugins.each do |guard_plugin|
232
- Pry.commands.create_command guard_plugin.name, "Run all #{ guard_plugin.title }" do
233
- group 'Guard'
42
+ # Pass options to interactor's job when it's created
43
+ attr_writer :options
234
44
 
235
- def process
236
- Pry.run_command "all #{ match }"
237
- end
238
- end
45
+ # TODO: allow custom user idle jobs, e.g. [:pry, :sleep, :exit, ...]
46
+ def enabled?
47
+ @enabled || @enabled.nil?
239
48
  end
240
- end
241
-
242
- # Create a shorthand command to run the `:run_all`
243
- # action on a specific Guard group. For example,
244
- # when you have a group `frontend`, then a command
245
- # `frontend` is created that runs `all frontend`.
246
- #
247
- def _create_group_commands
248
- ::Guard.groups.each do |group|
249
- next if group.name == :default
250
49
 
251
- Pry.commands.create_command group.name.to_s, "Run all #{ group.title }" do
252
- group 'Guard'
253
-
254
- def process
255
- Pry.run_command "all #{ match }"
50
+ alias_method :enabled, :enabled?
51
+
52
+ # TODO: handle switching interactors during runtime?
53
+ attr_writer :enabled
54
+
55
+ # Converts and validates a plain text scope
56
+ # to a valid plugin or group scope.
57
+ #
58
+ # @param [Array<String>] entries the text scope
59
+ # @return [Hash, Array<String>] the plugin or group scope, the unknown
60
+ # entries
61
+ #
62
+ # TODO: call this from within action, not within interactor command
63
+ def convert_scope(entries)
64
+ scopes = { plugins: [], groups: [] }
65
+ unknown = []
66
+
67
+ entries.each do |entry|
68
+ if plugin = ::Guard.plugin(entry)
69
+ scopes[:plugins] << plugin
70
+ elsif group = ::Guard.group(entry)
71
+ scopes[:groups] << group
72
+ else
73
+ unknown << entry
256
74
  end
257
75
  end
258
- end
259
- end
260
76
 
261
- # Configures the pry prompt to see `guard` instead of
262
- # `pry`.
263
- #
264
- def _configure_prompt
265
- Pry.config.prompt = [_prompt('>'), _prompt('*')]
266
- end
267
-
268
- # Returns the plugins scope, or the groups scope ready for display in the
269
- # prompt.
270
- #
271
- def _scope_for_prompt
272
- [:plugins, :groups].each do |scope_name|
273
- return "#{_join_scope_for_prompt(scope_name)} " unless ::Guard.scope[scope_name].empty?
274
- end
275
-
276
- ''
277
- end
278
-
279
- # Joins the scope corresponding to the given scope name with commas.
280
- #
281
- def _join_scope_for_prompt(scope_name)
282
- ::Guard.scope[scope_name].map(&:title).join(',')
283
- end
284
-
285
- # Returns a proc that will return itself a string ending with the given
286
- # `ending_char` when called.
287
- #
288
- def _prompt(ending_char)
289
- proc do |target_self, nest_level, pry|
290
- history = pry.input_array.size
291
- process = ::Guard.listener.paused? ? 'pause' : 'guard'
292
- level = ":#{ nest_level }" unless nest_level.zero?
293
-
294
- "[#{ history }] #{ _scope_for_prompt }#{ process }(#{ _clip_name(target_self) })#{ level }#{ ending_char } "
77
+ [scopes, unknown]
295
78
  end
296
79
  end
297
80
 
298
- def _clip_name(target)
299
- Pry.view_clip(target)
300
- end
301
-
302
- # Detects whether or not the stty command exists
303
- # on the user machine.
304
- #
305
- # @return [Boolean] the status of stty
306
- #
307
- def _stty_exists?
308
- @stty_exists ||= system('hash', 'stty') ? true : false if @stty_exists.nil?
309
- @stty_exists
310
- end
311
-
312
- # Stores the terminal settings so we can resore them
313
- # when stopping.
314
- #
315
- def _store_terminal_settings
316
- @stty_save = `stty -g 2>#{ DEV_NULL }`.chomp
317
- end
318
-
319
- # Restore terminal settings
320
- #
321
- def _restore_terminal_settings
322
- system("stty #{ @stty_save } 2>#{ DEV_NULL }") if @stty_save
323
- end
81
+ private
324
82
 
83
+ attr_reader :idle_job
325
84
  end
326
85
  end