guard 2.6.1 → 2.7.0

Sign up to get free protection for your applications and to get access to all the features.
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