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.
- checksums.yaml +4 -4
- data/README.md +73 -58
- data/bin/guard +2 -2
- data/lib/guard.rb +64 -59
- data/lib/guard/cli.rb +66 -60
- data/lib/guard/cli.rb.orig +215 -0
- data/lib/guard/commander.rb +45 -69
- data/lib/guard/commands/all.rb +21 -19
- data/lib/guard/commands/change.rb +17 -22
- data/lib/guard/commands/notification.rb +15 -16
- data/lib/guard/commands/pause.rb +14 -15
- data/lib/guard/commands/reload.rb +19 -20
- data/lib/guard/commands/scope.rb +23 -19
- data/lib/guard/commands/show.rb +13 -16
- data/lib/guard/deprecated_methods.rb +6 -10
- data/lib/guard/deprecator.rb +52 -37
- data/lib/guard/dsl.rb +55 -33
- data/lib/guard/dsl_describer.rb +83 -31
- data/lib/guard/dsl_describer.rb.orig +184 -0
- data/lib/guard/group.rb +7 -6
- data/lib/guard/guard.rb +4 -4
- data/lib/guard/guard.rb.orig +42 -0
- data/lib/guard/guardfile.rb +12 -13
- data/lib/guard/guardfile/evaluator.rb +77 -55
- data/lib/guard/guardfile/evaluator.rb.orig +275 -0
- data/lib/guard/guardfile/generator.rb +25 -20
- data/lib/guard/interactor.rb +52 -293
- data/lib/guard/interactor.rb.orig +85 -0
- data/lib/guard/jobs/base.rb +21 -0
- data/lib/guard/jobs/pry_wrapper.rb +290 -0
- data/lib/guard/jobs/pry_wrapper.rb.orig +293 -0
- data/lib/guard/jobs/sleep.rb +25 -0
- data/lib/guard/notifier.rb +42 -39
- data/lib/guard/notifiers/base.rb +25 -24
- data/lib/guard/notifiers/emacs.rb +30 -24
- data/lib/guard/notifiers/file_notifier.rb +3 -7
- data/lib/guard/notifiers/gntp.rb +22 -22
- data/lib/guard/notifiers/growl.rb +16 -15
- data/lib/guard/notifiers/libnotify.rb +7 -10
- data/lib/guard/notifiers/notifysend.rb +15 -14
- data/lib/guard/notifiers/rb_notifu.rb +8 -10
- data/lib/guard/notifiers/terminal_notifier.rb +15 -11
- data/lib/guard/notifiers/terminal_title.rb +4 -8
- data/lib/guard/notifiers/tmux.rb +104 -71
- data/lib/guard/options.rb +1 -5
- data/lib/guard/plugin.rb +1 -3
- data/lib/guard/plugin/base.rb +12 -9
- data/lib/guard/plugin/hooker.rb +1 -5
- data/lib/guard/plugin_util.rb +46 -25
- data/lib/guard/plugin_util.rb.orig +178 -0
- data/lib/guard/rake_task.rb +4 -7
- data/lib/guard/reevaluator.rb +13 -0
- data/lib/guard/runner.rb +50 -78
- data/lib/guard/runner.rb.orig +200 -0
- data/lib/guard/setuper.rb +199 -130
- data/lib/guard/setuper.rb.orig +348 -0
- data/lib/guard/sheller.rb +107 -0
- data/lib/guard/tags +367 -0
- data/lib/guard/ui.rb +50 -38
- data/lib/guard/ui.rb.orig +254 -0
- data/lib/guard/ui/colors.rb +17 -21
- data/lib/guard/version.rb +1 -1
- data/lib/guard/version.rb.orig +3 -0
- data/lib/guard/watcher.rb +49 -62
- metadata +21 -4
- 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
|
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(
|
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(
|
22
|
-
rescue ArgumentError
|
23
|
-
# home isn't defined. Set to the root of the drive. Trust that there
|
24
|
-
|
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?(
|
44
|
+
if !File.exist?("Guardfile")
|
44
45
|
::Guard::UI.info "Writing new Guardfile to #{ Dir.pwd }/Guardfile"
|
45
|
-
FileUtils.cp(GUARDFILE_TEMPLATE,
|
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
|
-
|
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(
|
71
|
+
content = File.read("Guardfile")
|
68
72
|
|
69
|
-
File.open(
|
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
|
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 }'
|
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
|
data/lib/guard/interactor.rb
CHANGED
@@ -1,326 +1,85 @@
|
|
1
|
-
require
|
1
|
+
require "guard/ui"
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
#
|
188
|
-
|
189
|
-
|
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
|
-
#
|
196
|
-
|
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
|
-
|
206
|
-
|
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
|
-
|
216
|
-
|
217
|
-
|
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
|
-
|
226
|
-
|
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
|
-
|
236
|
-
|
237
|
-
|
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
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
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
|
-
|
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
|
-
|
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
|