guard 1.8.3 → 2.0.0.pre

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 (47) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +68 -10
  3. data/README.md +54 -33
  4. data/lib/guard.rb +133 -483
  5. data/lib/guard/cli.rb +78 -82
  6. data/lib/guard/commander.rb +121 -0
  7. data/lib/guard/commands/all.rb +1 -1
  8. data/lib/guard/commands/reload.rb +1 -1
  9. data/lib/guard/deprecated_methods.rb +59 -0
  10. data/lib/guard/deprecator.rb +107 -0
  11. data/lib/guard/dsl.rb +143 -329
  12. data/lib/guard/dsl_describer.rb +101 -57
  13. data/lib/guard/group.rb +27 -8
  14. data/lib/guard/guard.rb +25 -150
  15. data/lib/guard/guardfile.rb +35 -85
  16. data/lib/guard/guardfile/evaluator.rb +245 -0
  17. data/lib/guard/guardfile/generator.rb +89 -0
  18. data/lib/guard/interactor.rb +147 -163
  19. data/lib/guard/notifier.rb +83 -137
  20. data/lib/guard/notifiers/base.rb +220 -0
  21. data/lib/guard/notifiers/emacs.rb +39 -37
  22. data/lib/guard/notifiers/file_notifier.rb +29 -25
  23. data/lib/guard/notifiers/gntp.rb +68 -75
  24. data/lib/guard/notifiers/growl.rb +49 -52
  25. data/lib/guard/notifiers/growl_notify.rb +51 -56
  26. data/lib/guard/notifiers/libnotify.rb +41 -48
  27. data/lib/guard/notifiers/notifysend.rb +58 -38
  28. data/lib/guard/notifiers/rb_notifu.rb +54 -54
  29. data/lib/guard/notifiers/terminal_notifier.rb +48 -36
  30. data/lib/guard/notifiers/terminal_title.rb +23 -19
  31. data/lib/guard/notifiers/tmux.rb +110 -93
  32. data/lib/guard/options.rb +21 -0
  33. data/lib/guard/plugin.rb +66 -0
  34. data/lib/guard/plugin/base.rb +178 -0
  35. data/lib/guard/plugin/hooker.rb +123 -0
  36. data/lib/guard/plugin_util.rb +158 -0
  37. data/lib/guard/rake_task.rb +47 -0
  38. data/lib/guard/runner.rb +62 -82
  39. data/lib/guard/setuper.rb +248 -0
  40. data/lib/guard/ui.rb +24 -80
  41. data/lib/guard/ui/colors.rb +60 -0
  42. data/lib/guard/version.rb +1 -2
  43. data/lib/guard/watcher.rb +30 -30
  44. data/man/guard.1 +4 -4
  45. data/man/guard.1.html +6 -4
  46. metadata +25 -11
  47. data/lib/guard/hook.rb +0 -120
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rake'
4
+ require 'rake/tasklib'
5
+
6
+ require 'guard/cli'
7
+
8
+ module Guard
9
+
10
+ # Provides a method to define a Rake task that
11
+ # runs the Guard plugins.
12
+ #
13
+ class RakeTask < ::Rake::TaskLib
14
+
15
+ # Name of the main, top level task
16
+ attr_accessor :name
17
+
18
+ # CLI options
19
+ attr_accessor :options
20
+
21
+ # Initialize the Rake task
22
+ #
23
+ # @param [Symbol] name the name of the Rake task
24
+ # @param [String] options the CLI options
25
+ # @yield [Guard::RakeTask] the task
26
+ #
27
+ def initialize(name = :guard, options = '')
28
+ @name = name
29
+ @options = options
30
+
31
+ yield self if block_given?
32
+
33
+ desc "Starts Guard with options: '#{options}'"
34
+ task name => ["#{name}:start"]
35
+
36
+ namespace(name) do
37
+
38
+ desc "Starts Guard with options: '#{options}'"
39
+ task(:start) do
40
+ ::Guard::CLI.start(options.split)
41
+ end
42
+
43
+ end
44
+ end
45
+
46
+ end
47
+ end
@@ -1,56 +1,24 @@
1
+ require 'lumberjack'
2
+
3
+ require 'guard/ui'
4
+ require 'guard/watcher'
5
+
1
6
  module Guard
2
7
 
3
- # The runner is responsible for running all methods defined on each guards.
8
+ # The runner is responsible for running all methods defined on each plugin.
4
9
  #
5
10
  class Runner
6
11
 
7
- require 'guard'
8
- require 'guard/ui'
9
- require 'guard/watcher'
10
-
11
- require 'lumberjack'
12
-
13
- # Deprecation message for the `run_on_change` method
14
- RUN_ON_CHANGE_DEPRECATION = <<-EOS.gsub(/^\s*/, '')
15
- Starting with Guard v1.1 the use of the 'run_on_change' method in the '%s' guard is deprecated.
16
-
17
- Please consider replacing that method-call with 'run_on_changes' if the type of change
18
- is not important for your usecase or using either 'run_on_modifications' or 'run_on_additions'
19
- based on the type of the changes you want to handle.
20
-
21
- For more information on how to update existing guards, please head over to:
22
- https://github.com/guard/guard/wiki/Upgrade-guide-for-existing-guards-to-Guard-v1.1
23
- EOS
24
-
25
- # Deprecation message for the `run_on_deletion` method
26
- RUN_ON_DELETION_DEPRECATION = <<-EOS.gsub(/^\s*/, '')
27
- Starting with Guard v1.1 the use of the 'run_on_deletion' method in the '%s' guard is deprecated.
28
-
29
- Please consider replacing that method-call with 'run_on_removals' for future proofing your code.
30
-
31
- For more information on how to update existing guards, please head over to:
32
- https://github.com/guard/guard/wiki/Upgrade-guide-for-existing-guards-to-Guard-v1.1
33
- EOS
34
-
35
- # Displays a warning for each deprecated-method used is any registered guard.
36
- #
37
- def deprecation_warning
38
- ::Guard.guards.each do |guard|
39
- ::Guard::UI.deprecation(RUN_ON_CHANGE_DEPRECATION % guard.class.name) if guard.respond_to?(:run_on_change)
40
- ::Guard::UI.deprecation(RUN_ON_DELETION_DEPRECATION % guard.class.name) if guard.respond_to?(:run_on_deletion)
41
- end
42
- end
43
-
44
- # Runs a Guard-task on all registered guards.
12
+ # Runs a Guard-task on all registered plugins.
45
13
  #
46
14
  # @param [Symbol] task the task to run
47
15
  # @param [Hash] scopes either the Guard plugin or the group to run the task on
48
16
  #
49
17
  # @see self.run_supervised_task
50
18
  #
51
- def run(task, scopes = {})
19
+ def run(task, scope = {})
52
20
  Lumberjack.unit_of_work do
53
- scoped_guards(scopes) do |guard|
21
+ _scoped_plugins(scope) do |guard|
54
22
  run_supervised_task(guard, task) if guard.respond_to?(task)
55
23
  end
56
24
  end
@@ -60,7 +28,7 @@ module Guard
60
28
  ADDITION_TASKS = [:run_on_additions, :run_on_changes, :run_on_change]
61
29
  REMOVAL_TASKS = [:run_on_removals, :run_on_changes, :run_on_deletion]
62
30
 
63
- # Runs the appropriate tasks on all registered guards
31
+ # Runs the appropriate tasks on all registered plugins
64
32
  # based on the passed changes.
65
33
  #
66
34
  # @param [Array<String>] modified the modified paths.
@@ -69,16 +37,16 @@ module Guard
69
37
  #
70
38
  def run_on_changes(modified, added, removed)
71
39
  ::Guard::UI.clearable
72
- scoped_guards do |guard|
40
+ _scoped_plugins do |guard|
73
41
  modified_paths = ::Guard::Watcher.match_files(guard, modified)
74
42
  added_paths = ::Guard::Watcher.match_files(guard, added)
75
43
  removed_paths = ::Guard::Watcher.match_files(guard, removed)
76
44
 
77
- ::Guard::UI.clear if clearable?(guard, modified_paths, added_paths, removed_paths)
45
+ ::Guard::UI.clear if _clearable?(guard, modified_paths, added_paths, removed_paths)
78
46
 
79
- run_first_task_found(guard, MODIFICATION_TASKS, modified_paths) unless modified_paths.empty?
80
- run_first_task_found(guard, ADDITION_TASKS, added_paths) unless added_paths.empty?
81
- run_first_task_found(guard, REMOVAL_TASKS, removed_paths) unless removed_paths.empty?
47
+ _run_first_task_found(guard, MODIFICATION_TASKS, modified_paths) unless modified_paths.empty?
48
+ _run_first_task_found(guard, ADDITION_TASKS, added_paths) unless added_paths.empty?
49
+ _run_first_task_found(guard, REMOVAL_TASKS, removed_paths) unless removed_paths.empty?
82
50
  end
83
51
  end
84
52
 
@@ -87,14 +55,14 @@ module Guard
87
55
  # When the Group has `:halt_on_fail` disabled, we've to catch `:task_has_failed`
88
56
  # here in order to avoid an uncaught throw error.
89
57
  #
90
- # @param [Guard::Guard] guard the Guard to execute
58
+ # @param [Guard::Plugin] guard the Guard to execute
91
59
  # @param [Symbol] task the task to run
92
60
  # @param [Array] args the arguments for the task
93
61
  # @raise [:task_has_failed] when task has failed
94
62
  #
95
63
  def run_supervised_task(guard, task, *args)
96
64
  begin
97
- catch Runner.stopping_symbol_for(guard) do
65
+ catch self.class.stopping_symbol_for(guard) do
98
66
  guard.hook("#{ task }_begin", *args)
99
67
  result = guard.send(task, *args)
100
68
  guard.hook("#{ task }_end", result)
@@ -105,7 +73,7 @@ module Guard
105
73
  ::Guard::UI.error("#{ guard.class.name } failed to achieve its <#{ task.to_s }>, exception was:" +
106
74
  "\n#{ ex.class }: #{ ex.message }\n#{ ex.backtrace.join("\n") }")
107
75
 
108
- ::Guard.guards.delete guard
76
+ ::Guard.plugins.delete guard
109
77
  ::Guard::UI.info("\n#{ guard.class.name } has just been fired")
110
78
 
111
79
  ex
@@ -117,28 +85,25 @@ module Guard
117
85
  # @note If a Guard group is being run and it has the `:halt_on_fail`
118
86
  # option set, this method returns :no_catch as it will be caught at the
119
87
  # group level.
120
- # @see .scoped_guards
88
+ # @see ._scoped_plugins
121
89
  #
122
- # @param [Guard::Guard] guard the Guard plugin to execute
90
+ # @param [Guard::Plugin] guard the Guard plugin to execute
123
91
  # @return [Symbol] the symbol to catch
124
92
  #
125
93
  def self.stopping_symbol_for(guard)
126
- return :task_has_failed if guard.group.class != Symbol
127
-
128
- group = ::Guard.groups(guard.group)
129
- group.options.fetch(:halt_on_fail, false) ? :no_catch : :task_has_failed
94
+ guard.group.options[:halt_on_fail] ? :no_catch : :task_has_failed
130
95
  end
131
96
 
132
- private
97
+ private
133
98
 
134
99
  # Tries to run the first implemented task by a given guard
135
100
  # from a collection of tasks.
136
101
  #
137
- # @param [Guard::Guard] guard the Guard plugin to run the first found task on
102
+ # @param [Guard::Plugin] guard the Guard plugin to run the first found task on
138
103
  # @param [Array<Symbol>] tasks the tasks to run the first among
139
104
  # @param [Object] task_param the param to pass to each task
140
105
  #
141
- def run_first_task_found(guard, tasks, task_param)
106
+ def _run_first_task_found(guard, tasks, task_param)
142
107
  tasks.each do |task|
143
108
  if guard.respond_to?(task)
144
109
  run_supervised_task(guard, task, task_param)
@@ -161,16 +126,16 @@ module Guard
161
126
  # @param [Hash] scopes hash with plugins or a groups scope
162
127
  # @yield the task to run
163
128
  #
164
- def scoped_guards(scopes = {})
165
- if guards = current_plugins_scope(scopes)
166
- guards.each do |guard|
129
+ def _scoped_plugins(scopes = {})
130
+ if plugins = _current_plugins_scope(scopes)
131
+ plugins.each do |guard|
167
132
  yield(guard)
168
133
  end
169
134
  else
170
- current_groups_scope(scopes).each do |group|
135
+ _current_groups_scope(scopes).each do |group|
171
136
  current_plugin = nil
172
137
  block_return = catch :task_has_failed do
173
- ::Guard.guards(:group => group.name).each do |guard|
138
+ ::Guard.plugins(group: group.name).each do |guard|
174
139
  current_plugin = guard
175
140
  yield(guard)
176
141
  end
@@ -186,12 +151,12 @@ module Guard
186
151
  # Logic to know if the UI can be cleared or not in the run_on_changes method
187
152
  # based on the guard and the changes.
188
153
  #
189
- # @param [Guard::Guard] guard the Guard plugin where run_on_changes is called
154
+ # @param [Guard::Plugin] guard the Guard plugin where run_on_changes is called
190
155
  # @param [Array<String>] modified_paths the modified paths.
191
156
  # @param [Array<String>] added_paths the added paths.
192
157
  # @param [Array<String>] removed_paths the removed paths.
193
158
  #
194
- def clearable?(guard, modified_paths, added_paths, removed_paths)
159
+ def _clearable?(guard, modified_paths, added_paths, removed_paths)
195
160
  (MODIFICATION_TASKS.any? { |task| guard.respond_to?(task) } && !modified_paths.empty?) ||
196
161
  (ADDITION_TASKS.any? { |task| guard.respond_to?(task) } && !added_paths.empty?) ||
197
162
  (REMOVAL_TASKS.any? { |task| guard.respond_to?(task) } && !removed_paths.empty?)
@@ -202,15 +167,13 @@ module Guard
202
167
  # If no plugins scope is found, then NO plugins are returned.
203
168
  #
204
169
  # @param [Hash] scopes hash with a local plugins or a groups scope
205
- # @return [Array<Guard::Guard>] the plugins to scope to
170
+ # @return [Array<Guard::Plugin>] the plugins to scope to
206
171
  #
207
- def current_plugins_scope(scopes)
208
- if scopes[:plugins] && !scopes[:plugins].empty?
209
- scopes[:plugins]
210
-
211
- elsif !::Guard.scope[:plugins].empty?
212
- ::Guard.scope[:plugins]
213
-
172
+ def _current_plugins_scope(scope)
173
+ if plugins = _find_non_empty_plugins_scope(scope)
174
+ Array(plugins).map do |plugin|
175
+ plugin.is_a?(Symbol) ? ::Guard.plugin(plugin) : plugin
176
+ end
214
177
  else
215
178
  nil
216
179
  end
@@ -223,16 +186,33 @@ module Guard
223
186
  # @param [Hash] scopes hash with a local plugins or a groups scope
224
187
  # @return [Array<Guard::Group>] the groups to scope to
225
188
  #
226
- def current_groups_scope(scopes)
227
- if scopes[:groups] && !scopes[:groups].empty?
228
- scopes[:groups]
189
+ def _current_groups_scope(scope)
190
+ Array(_find_non_empty_groups_scope(scope)).map do |group|
191
+ group.is_a?(Symbol) ? ::Guard.group(group) : group
192
+ end
193
+ end
194
+
195
+ # Find the first non empty element in the given possibilities
196
+ #
197
+ def _find_non_empty_scope(type, local_scope, *additional_possibilities)
198
+ [
199
+ local_scope[:"#{type}s"],
200
+ local_scope[type.to_sym],
201
+ ::Guard.scope[:"#{type}s"],
202
+ additional_possibilities.flatten
203
+ ].compact.find { |a| !Array(a).empty? }
204
+ end
229
205
 
230
- elsif !::Guard.scope[:groups].empty?
231
- ::Guard.scope[:groups]
206
+ # Find the first non empty plugins scope
207
+ #
208
+ def _find_non_empty_plugins_scope(scope)
209
+ _find_non_empty_scope(:plugin, scope)
210
+ end
232
211
 
233
- else
234
- ::Guard.groups
235
- end
212
+ # Find the first non empty groups scope
213
+ #
214
+ def _find_non_empty_groups_scope(scope)
215
+ _find_non_empty_scope(:group, scope, ::Guard.groups)
236
216
  end
237
217
  end
238
218
  end
@@ -0,0 +1,248 @@
1
+ require 'thread'
2
+ require 'listen'
3
+ require 'guard/options'
4
+
5
+ module Guard
6
+
7
+ module Setuper
8
+
9
+ DEFAULT_OPTIONS = {
10
+ clear: false,
11
+ notify: true,
12
+ debug: false,
13
+ group: [],
14
+ plugin: [],
15
+ watchdir: nil,
16
+ guardfile: nil,
17
+ no_interactions: false,
18
+ no_bundler_warning: false,
19
+ show_deprecations: false,
20
+ latency: nil,
21
+ force_polling: false
22
+ }
23
+ DEFAULT_GROUPS = [:default]
24
+
25
+ # Initializes the Guard singleton:
26
+ #
27
+ # * Initialize the internal Guard state;
28
+ # * Create the interactor when necessary for user interaction;
29
+ # * Select and initialize the file change listener.
30
+ #
31
+ # @option options [Boolean] clear if auto clear the UI should be done
32
+ # @option options [Boolean] notify if system notifications should be shown
33
+ # @option options [Boolean] debug if debug output should be shown
34
+ # @option options [Array<String>] group the list of groups to start
35
+ # @option options [Array<String>] watchdir the directories to watch
36
+ # @option options [String] guardfile the path to the Guardfile
37
+ #
38
+ # @return [Guard] the Guard singleton
39
+ #
40
+ def setup(opts = {})
41
+ @running = true
42
+ @lock = Mutex.new
43
+ @opts = opts
44
+ @watchdirs = [Dir.pwd]
45
+ @evaluator = ::Guard::Guardfile::Evaluator.new(opts)
46
+ @runner = ::Guard::Runner.new
47
+
48
+ if options.watchdir
49
+ # Ensure we have an array
50
+ @watchdirs = Array(options.watchdir).map { |dir| File.expand_path dir }
51
+ end
52
+
53
+ ::Guard::UI.clear(force: true)
54
+ _setup_debug if options.debug
55
+ _setup_listener
56
+ _setup_signal_traps
57
+
58
+ reset_groups
59
+ reset_plugins
60
+ reset_scope
61
+
62
+ evaluate_guardfile
63
+
64
+ setup_scope(groups: options.group, plugins: options.plugin)
65
+
66
+ _setup_notifier
67
+ _setup_interactor
68
+
69
+ self
70
+ end
71
+
72
+ # Lazy initializer for Guard's options hash
73
+ #
74
+ def options
75
+ @options ||= ::Guard::Options.new(@opts || {}, DEFAULT_OPTIONS)
76
+ end
77
+
78
+ # Clear Guard's options hash
79
+ #
80
+ def clear_options
81
+ @options = nil
82
+ end
83
+
84
+ # Initializes the groups array with the default group(s).
85
+ #
86
+ # @see DEFAULT_GROUPS
87
+ #
88
+ def reset_groups
89
+ @groups = DEFAULT_GROUPS.map { |name| Group.new(name) }
90
+ end
91
+
92
+ # Initializes the plugins array to an empty array.
93
+ #
94
+ # @see Guard.plugins
95
+ #
96
+ def reset_plugins
97
+ @plugins = []
98
+ end
99
+
100
+ # Initializes the scope hash to `{ groups: [], plugins: [] }`.
101
+ #
102
+ # @see Guard.setup_scope
103
+ #
104
+ def reset_scope
105
+ @scope = { groups: [], plugins: [] }
106
+ end
107
+
108
+ # Stores the scopes defined by the user via the `--group` / `-g` option (to run
109
+ # only a specific group) or the `--plugin` / `-P` option (to run only a
110
+ # specific plugin).
111
+ #
112
+ # @see CLI#start
113
+ # @see Dsl#scope
114
+ #
115
+ def setup_scope(new_scope)
116
+ if new_scope[:groups] && new_scope[:groups].any?
117
+ scope[:groups] = new_scope[:groups].map { |group| ::Guard.add_group(group) }
118
+ end
119
+
120
+ if new_scope[:plugins] && new_scope[:plugins].any?
121
+ scope[:plugins] = new_scope[:plugins].map { |plugin| ::Guard.plugin(plugin) }
122
+ end
123
+ end
124
+
125
+ # Evaluates the Guardfile content. It displays an error message if no
126
+ # Guard plugins are instantiated after the Guardfile evaluation.
127
+ #
128
+ # @see Guard::Guardfile::Evaluator#evaluate_guardfile
129
+ #
130
+ def evaluate_guardfile
131
+ evaluator.evaluate_guardfile
132
+ ::Guard::UI.error 'No plugins found in Guardfile, please add at least one.' if plugins.empty?
133
+ end
134
+
135
+ private
136
+
137
+ # Sets up various debug behaviors:
138
+ #
139
+ # * Abort threads on exception;
140
+ # * Set the logging level to `:debug`;
141
+ # * Modify the system and ` methods to log themselves before being executed
142
+ #
143
+ # @see #_debug_command_execution
144
+ #
145
+ def _setup_debug
146
+ Thread.abort_on_exception = true
147
+ ::Guard::UI.options.level = :debug
148
+ _debug_command_execution
149
+ end
150
+
151
+ # Initializes the listener and registers a callback for changes.
152
+ #
153
+ def _setup_listener
154
+ listener_callback = lambda do |modified, added, removed|
155
+ # Convert to relative paths (respective to the watchdir it came from)
156
+ @watchdirs.each do |watchdir|
157
+ [modified, added, removed].each do |paths|
158
+ paths.map! do |path|
159
+ if path.start_with? watchdir
160
+ path.sub "#{watchdir}#{File::SEPARATOR}", ''
161
+ else
162
+ path
163
+ end
164
+ end
165
+ end
166
+ end
167
+ evaluator.reevaluate_guardfile if ::Guard::Watcher.match_guardfile?(modified)
168
+
169
+ within_preserved_state do
170
+ runner.run_on_changes(modified, added, removed)
171
+ end
172
+ end
173
+
174
+ listener_options = {}
175
+ %w[latency force_polling].each do |option|
176
+ listener_options[option.to_sym] = options.send(option) if options.send(option)
177
+ end
178
+
179
+ listen_args = @watchdirs + [listener_options]
180
+ @listener = Listen.to(*listen_args).change(&listener_callback)
181
+ end
182
+
183
+ # Sets up traps to catch signals used to control Guard.
184
+ #
185
+ # Currently two signals are caught:
186
+ # - `USR1` which pauses listening to changes.
187
+ # - `USR2` which resumes listening to changes.
188
+ # - 'INT' which is delegated to Pry if active, otherwise stops Guard.
189
+ #
190
+ def _setup_signal_traps
191
+ unless defined?(JRUBY_VERSION)
192
+ if Signal.list.keys.include?('USR1')
193
+ Signal.trap('USR1') { ::Guard.pause unless listener.paused? }
194
+ end
195
+
196
+ if Signal.list.keys.include?('USR2')
197
+ Signal.trap('USR2') { ::Guard.pause if listener.paused? }
198
+ end
199
+
200
+ if Signal.list.keys.include?('INT')
201
+ Signal.trap('INT') do
202
+ if interactor && interactor.thread
203
+ interactor.thread.raise(Interrupt)
204
+ else
205
+ ::Guard.stop
206
+ end
207
+ end
208
+ end
209
+ end
210
+ end
211
+
212
+ # Enables or disables the notifier based on user's configurations.
213
+ #
214
+ def _setup_notifier
215
+ if options.notify && ENV['GUARD_NOTIFY'] != 'false'
216
+ ::Guard::Notifier.turn_on
217
+ else
218
+ ::Guard::Notifier.turn_off
219
+ end
220
+ end
221
+
222
+ # Initializes the interactor unless the user has specified not to.
223
+ #
224
+ def _setup_interactor
225
+ unless options.no_interactions || !::Guard::Interactor.enabled
226
+ @interactor = ::Guard::Interactor.new
227
+ end
228
+ end
229
+
230
+ # Adds a command logger in debug mode. This wraps common command
231
+ # execution functions and logs the executed command before execution.
232
+ #
233
+ def _debug_command_execution
234
+ Kernel.send(:alias_method, :original_system, :system)
235
+ Kernel.send(:define_method, :system) do |command, *args|
236
+ ::Guard::UI.debug "Command execution: #{ command } #{ args.join(' ') }"
237
+ Kernel.send :original_system, command, *args
238
+ end
239
+
240
+ Kernel.send(:alias_method, :original_backtick, :'`')
241
+ Kernel.send(:define_method, :'`') do |command|
242
+ ::Guard::UI.debug "Command execution: #{ command }"
243
+ Kernel.send :original_backtick, command
244
+ end
245
+ end
246
+
247
+ end
248
+ end