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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +68 -10
- data/README.md +54 -33
- data/lib/guard.rb +133 -483
- data/lib/guard/cli.rb +78 -82
- data/lib/guard/commander.rb +121 -0
- data/lib/guard/commands/all.rb +1 -1
- data/lib/guard/commands/reload.rb +1 -1
- data/lib/guard/deprecated_methods.rb +59 -0
- data/lib/guard/deprecator.rb +107 -0
- data/lib/guard/dsl.rb +143 -329
- data/lib/guard/dsl_describer.rb +101 -57
- data/lib/guard/group.rb +27 -8
- data/lib/guard/guard.rb +25 -150
- data/lib/guard/guardfile.rb +35 -85
- data/lib/guard/guardfile/evaluator.rb +245 -0
- data/lib/guard/guardfile/generator.rb +89 -0
- data/lib/guard/interactor.rb +147 -163
- data/lib/guard/notifier.rb +83 -137
- data/lib/guard/notifiers/base.rb +220 -0
- data/lib/guard/notifiers/emacs.rb +39 -37
- data/lib/guard/notifiers/file_notifier.rb +29 -25
- data/lib/guard/notifiers/gntp.rb +68 -75
- data/lib/guard/notifiers/growl.rb +49 -52
- data/lib/guard/notifiers/growl_notify.rb +51 -56
- data/lib/guard/notifiers/libnotify.rb +41 -48
- data/lib/guard/notifiers/notifysend.rb +58 -38
- data/lib/guard/notifiers/rb_notifu.rb +54 -54
- data/lib/guard/notifiers/terminal_notifier.rb +48 -36
- data/lib/guard/notifiers/terminal_title.rb +23 -19
- data/lib/guard/notifiers/tmux.rb +110 -93
- data/lib/guard/options.rb +21 -0
- data/lib/guard/plugin.rb +66 -0
- data/lib/guard/plugin/base.rb +178 -0
- data/lib/guard/plugin/hooker.rb +123 -0
- data/lib/guard/plugin_util.rb +158 -0
- data/lib/guard/rake_task.rb +47 -0
- data/lib/guard/runner.rb +62 -82
- data/lib/guard/setuper.rb +248 -0
- data/lib/guard/ui.rb +24 -80
- data/lib/guard/ui/colors.rb +60 -0
- data/lib/guard/version.rb +1 -2
- data/lib/guard/watcher.rb +30 -30
- data/man/guard.1 +4 -4
- data/man/guard.1.html +6 -4
- metadata +25 -11
- data/lib/guard/hook.rb +0 -120
@@ -0,0 +1,245 @@
|
|
1
|
+
module Guard
|
2
|
+
module Guardfile
|
3
|
+
|
4
|
+
# This class is responsible for evaluating the Guardfile. It delegates
|
5
|
+
# to Guard::Dsl for the actual objects generation from the Guardfile content.
|
6
|
+
#
|
7
|
+
# @see Guard::Dsl
|
8
|
+
#
|
9
|
+
class Evaluator
|
10
|
+
|
11
|
+
attr_reader :options
|
12
|
+
|
13
|
+
# Initializes a new Guard::Guardfile::Evaluator object.
|
14
|
+
#
|
15
|
+
# @option opts [String] guardfile the path to a valid Guardfile
|
16
|
+
# @option opts [String] guardfile_contents a string representing the content of a valid Guardfile
|
17
|
+
#
|
18
|
+
def initialize(opts = {})
|
19
|
+
@options = ::Guard::Options.new([:guardfile, :guardfile_contents].reduce({}) { |h, key| h[key] = opts[key]; h })
|
20
|
+
end
|
21
|
+
|
22
|
+
# Evaluates the DSL methods in the `Guardfile`.
|
23
|
+
#
|
24
|
+
# @example Programmatically evaluate a Guardfile
|
25
|
+
# Guard::Guardfile::Evaluator.new.evaluate_guardfile
|
26
|
+
#
|
27
|
+
# @example Programmatically evaluate a Guardfile with a custom Guardfile path
|
28
|
+
# Guard::Guardfile::Evaluator.new(guardfile: '/Users/guardfile/MyAwesomeGuardfile').evaluate_guardfile
|
29
|
+
#
|
30
|
+
# @example Programmatically evaluate a Guardfile with an inline Guardfile
|
31
|
+
# Guard::Guardfile::Evaluator.new(guardfile_contents: 'guard :rspec').evaluate_guardfile
|
32
|
+
#
|
33
|
+
def evaluate_guardfile
|
34
|
+
_fetch_guardfile_contents
|
35
|
+
_instance_eval_guardfile(guardfile_contents)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Re-evaluates the `Guardfile` to update
|
39
|
+
# the current Guard configuration.
|
40
|
+
#
|
41
|
+
def reevaluate_guardfile
|
42
|
+
_before_reevaluate_guardfile
|
43
|
+
evaluate_guardfile
|
44
|
+
_after_reevaluate_guardfile
|
45
|
+
end
|
46
|
+
|
47
|
+
# Tests if the current `Guardfile` contains a specific Guard plugin.
|
48
|
+
#
|
49
|
+
# @example Programmatically test if a Guardfile contains a specific Guard plugin
|
50
|
+
# File.read('Guardfile')
|
51
|
+
# #=> "guard :rspec"
|
52
|
+
#
|
53
|
+
# Guard::Guardfile::Evaluator.new.guardfile_include?('rspec)
|
54
|
+
# #=> true
|
55
|
+
#
|
56
|
+
# @param [String] plugin_name the name of the Guard
|
57
|
+
# @return [Boolean] whether the Guard plugin has been declared
|
58
|
+
#
|
59
|
+
def guardfile_include?(plugin_name)
|
60
|
+
_guardfile_contents_without_user_config.match(/^guard\s*\(?\s*['":]#{ plugin_name }['"]?/)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Gets the file path to the project `Guardfile`.
|
64
|
+
#
|
65
|
+
# @example Gets the path of the currently evaluated Guardfile
|
66
|
+
# Dir.pwd
|
67
|
+
# #=> "/Users/remy/Code/github/guard"
|
68
|
+
#
|
69
|
+
# evaluator = Guard::Guardfile::Evaluator.new
|
70
|
+
# evaluator.evaluate_guardfile
|
71
|
+
# #=> nil
|
72
|
+
#
|
73
|
+
# evaluator.guardfile_path
|
74
|
+
# #=> "/Users/remy/Code/github/guard/Guardfile"
|
75
|
+
#
|
76
|
+
# @example Gets the "path" of an inline Guardfile
|
77
|
+
# > Guard::Guardfile::Evaluator.new(guardfile_contents: 'guard :rspec').evaluate_guardfile
|
78
|
+
# => nil
|
79
|
+
#
|
80
|
+
# > Guard::Guardfile::Evaluator.new.guardfile_path
|
81
|
+
# => "Inline Guardfile"
|
82
|
+
#
|
83
|
+
# @return [String] the path to the Guardfile or 'Inline Guardfile' if
|
84
|
+
# the Guardfile has been specified via the `:guardfile_contents` option.
|
85
|
+
#
|
86
|
+
def guardfile_path
|
87
|
+
options.guardfile_path || ''
|
88
|
+
end
|
89
|
+
|
90
|
+
# Gets the content of the `Guardfile` concatenated with the global
|
91
|
+
# user configuration file.
|
92
|
+
#
|
93
|
+
# @example Programmatically get the content of the current Guardfile
|
94
|
+
# Guard::Guardfile::Evaluator.new.guardfile_contents
|
95
|
+
# #=> "guard :rspec"
|
96
|
+
#
|
97
|
+
# @return [String] the Guardfile content
|
98
|
+
#
|
99
|
+
def guardfile_contents
|
100
|
+
config = File.read(_user_config_path) if File.exist?(_user_config_path)
|
101
|
+
[_guardfile_contents_without_user_config, config].compact.join("\n")
|
102
|
+
end
|
103
|
+
|
104
|
+
private
|
105
|
+
|
106
|
+
# Gets the default path of the `Guardfile`. This returns the `Guardfile`
|
107
|
+
# from the current directory when existing, or the global `~/.Guardfile`.
|
108
|
+
#
|
109
|
+
# @return [String] the path to the Guardfile
|
110
|
+
#
|
111
|
+
def _guardfile_default_path
|
112
|
+
File.exist?(_local_guardfile_path) ? _local_guardfile_path : _home_guardfile_path
|
113
|
+
end
|
114
|
+
|
115
|
+
# Gets the content of the `Guardfile`.
|
116
|
+
#
|
117
|
+
# @return [String] the Guardfile content
|
118
|
+
#
|
119
|
+
def _guardfile_contents_without_user_config
|
120
|
+
options.guardfile_contents || ''
|
121
|
+
end
|
122
|
+
|
123
|
+
# Evaluates the content of the `Guardfile`.
|
124
|
+
#
|
125
|
+
# @param [String] contents the content to evaluate.
|
126
|
+
#
|
127
|
+
def _instance_eval_guardfile(contents)
|
128
|
+
::Guard::Dsl.new.instance_eval(contents, options.guardfile_path, 1)
|
129
|
+
rescue => ex
|
130
|
+
::Guard::UI.error "Invalid Guardfile, original error is:\n#{ $! }"
|
131
|
+
raise ex
|
132
|
+
end
|
133
|
+
|
134
|
+
# Gets the content to evaluate and stores it into
|
135
|
+
# the options as `:guardfile_contents`.
|
136
|
+
#
|
137
|
+
def _fetch_guardfile_contents
|
138
|
+
if options.guardfile_contents
|
139
|
+
::Guard::UI.info 'Using inline Guardfile.'
|
140
|
+
options.guardfile_path = 'Inline Guardfile'
|
141
|
+
|
142
|
+
elsif options.guardfile
|
143
|
+
if File.exist?(options.guardfile)
|
144
|
+
_read_guardfile(options.guardfile)
|
145
|
+
::Guard::UI.info "Using Guardfile at #{ options.guardfile }."
|
146
|
+
else
|
147
|
+
::Guard::UI.error "No Guardfile exists at #{ options.guardfile }."
|
148
|
+
exit 1
|
149
|
+
end
|
150
|
+
|
151
|
+
else
|
152
|
+
if File.exist?(_guardfile_default_path)
|
153
|
+
_read_guardfile(_guardfile_default_path)
|
154
|
+
else
|
155
|
+
::Guard::UI.error 'No Guardfile found, please create one with `guard init`.'
|
156
|
+
exit 1
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
unless _guardfile_contents_usable?
|
161
|
+
::Guard::UI.error 'No Guard plugins found in Guardfile, please add at least one.'
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
# Reads the current `Guardfile` content.
|
166
|
+
#
|
167
|
+
# @param [String] guardfile_path the path to the Guardfile
|
168
|
+
#
|
169
|
+
def _read_guardfile(guardfile_path)
|
170
|
+
options.guardfile_path = guardfile_path
|
171
|
+
options.guardfile_contents = File.read(guardfile_path)
|
172
|
+
rescue => ex
|
173
|
+
::Guard::UI.error ex.inspect
|
174
|
+
::Guard::UI.error("Error reading file #{ guardfile_path }")
|
175
|
+
exit 1
|
176
|
+
end
|
177
|
+
|
178
|
+
# Stops Guard and clear internal state
|
179
|
+
# before the Guardfile will be re-evaluated.
|
180
|
+
#
|
181
|
+
def _before_reevaluate_guardfile
|
182
|
+
::Guard.runner.run(:stop)
|
183
|
+
::Guard.reset_groups
|
184
|
+
::Guard.reset_plugins
|
185
|
+
::Guard::Notifier.clear_notifiers
|
186
|
+
|
187
|
+
options.guardfile_contents
|
188
|
+
end
|
189
|
+
|
190
|
+
# Starts Guard and notification and show a message
|
191
|
+
# after the Guardfile has been re-evaluated.
|
192
|
+
#
|
193
|
+
def _after_reevaluate_guardfile
|
194
|
+
::Guard::Notifier.turn_on if ::Guard::Notifier.enabled?
|
195
|
+
|
196
|
+
if ::Guard.plugins.empty?
|
197
|
+
::Guard::Notifier.notify('No plugins found in Guardfile, please add at least one.', title: 'Guard re-evaluate', image: :failed)
|
198
|
+
else
|
199
|
+
msg = 'Guardfile has been re-evaluated.'
|
200
|
+
::Guard::UI.info(msg)
|
201
|
+
::Guard::Notifier.notify(msg, title: 'Guard re-evaluate')
|
202
|
+
|
203
|
+
::Guard.runner.run(:start)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
# Tests if the current `Guardfile` content is usable.
|
208
|
+
#
|
209
|
+
# @return [Boolean] if the Guardfile is usable
|
210
|
+
#
|
211
|
+
def _guardfile_contents_usable?
|
212
|
+
guardfile_contents && guardfile_contents =~ /guard/m
|
213
|
+
end
|
214
|
+
|
215
|
+
# The path to the `Guardfile` that is located at
|
216
|
+
# the directory, where Guard has been started from.
|
217
|
+
#
|
218
|
+
# @return [String] the path to the local Guardfile
|
219
|
+
#
|
220
|
+
def _local_guardfile_path
|
221
|
+
File.join(Dir.pwd, 'Guardfile')
|
222
|
+
end
|
223
|
+
|
224
|
+
# The path to the `.Guardfile` that is located at
|
225
|
+
# the users home directory.
|
226
|
+
#
|
227
|
+
# @return [String] the path to `~/.Guardfile`
|
228
|
+
#
|
229
|
+
def _home_guardfile_path
|
230
|
+
File.expand_path(File.join('~', '.Guardfile'))
|
231
|
+
end
|
232
|
+
|
233
|
+
# The path to the user configuration `.guard.rb`
|
234
|
+
# that is located at the users home directory.
|
235
|
+
#
|
236
|
+
# @return [String] the path to `~/.guard.rb`
|
237
|
+
#
|
238
|
+
def _user_config_path
|
239
|
+
File.expand_path(File.join('~', '.guard.rb'))
|
240
|
+
end
|
241
|
+
|
242
|
+
end
|
243
|
+
|
244
|
+
end
|
245
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module Guard
|
2
|
+
module Guardfile
|
3
|
+
|
4
|
+
# This class is responsible for generating the Guardfile and adding Guard'
|
5
|
+
# plugins' templates into it.
|
6
|
+
#
|
7
|
+
# @see Guard::CLI
|
8
|
+
#
|
9
|
+
class Generator
|
10
|
+
|
11
|
+
require 'guard'
|
12
|
+
require 'guard/ui'
|
13
|
+
|
14
|
+
attr_reader :options
|
15
|
+
|
16
|
+
# The Guardfile template for `guard init`
|
17
|
+
GUARDFILE_TEMPLATE = File.expand_path('../../../guard/templates/Guardfile', __FILE__)
|
18
|
+
|
19
|
+
# The location of user defined templates
|
20
|
+
HOME_TEMPLATES = File.expand_path('~/.guard/templates')
|
21
|
+
|
22
|
+
# Initialize a new `Guard::Guardfile::Generator` object.
|
23
|
+
#
|
24
|
+
# @param [Hash] options The options for creating a Guardfile
|
25
|
+
# @option options [Boolean] :abort_on_existence Whether to abort or not
|
26
|
+
# when a Guardfile already exists
|
27
|
+
#
|
28
|
+
def initialize(options = {})
|
29
|
+
@options = options
|
30
|
+
end
|
31
|
+
|
32
|
+
# Creates the initial Guardfile template when it does not
|
33
|
+
# already exist.
|
34
|
+
#
|
35
|
+
# @see Guard::CLI#init
|
36
|
+
#
|
37
|
+
def create_guardfile
|
38
|
+
if !File.exist?('Guardfile')
|
39
|
+
::Guard::UI.info "Writing new Guardfile to #{ Dir.pwd }/Guardfile"
|
40
|
+
FileUtils.cp(GUARDFILE_TEMPLATE, 'Guardfile')
|
41
|
+
elsif options[:abort_on_existence]
|
42
|
+
::Guard::UI.error "Guardfile already exists at #{ Dir.pwd }/Guardfile"
|
43
|
+
abort
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Adds the Guardfile template of a Guard plugin to an existing Guardfile.
|
48
|
+
#
|
49
|
+
# @see Guard::CLI#init
|
50
|
+
#
|
51
|
+
# @param [String] plugin_name the name of the Guard plugin or template to
|
52
|
+
# initialize
|
53
|
+
#
|
54
|
+
def initialize_template(plugin_name)
|
55
|
+
plugin_util = ::Guard::PluginUtil.new(plugin_name)
|
56
|
+
if plugin_util.plugin_class(fail_gracefully: true)
|
57
|
+
plugin_util.add_to_guardfile
|
58
|
+
|
59
|
+
@options[:guardfile] = File.read('Guardfile') if File.exists?('Guardfile')
|
60
|
+
|
61
|
+
elsif File.exist?(File.join(HOME_TEMPLATES, plugin_name))
|
62
|
+
content = File.read('Guardfile')
|
63
|
+
|
64
|
+
File.open('Guardfile', 'wb') do |f|
|
65
|
+
f.puts(content)
|
66
|
+
f.puts('')
|
67
|
+
f.puts(File.read(File.join(HOME_TEMPLATES, plugin_name)))
|
68
|
+
end
|
69
|
+
|
70
|
+
::Guard::UI.info "#{ plugin_name } template added to Guardfile, feel free to edit it"
|
71
|
+
else
|
72
|
+
const_name = plugin_name.downcase.gsub('-', '')
|
73
|
+
UI.error "Could not load 'guard/#{ plugin_name.downcase }' or '~/.guard/templates/#{ plugin_name.downcase }' or find class Guard::#{ const_name.capitalize }"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Adds the templates of all installed Guard implementations to an
|
78
|
+
# existing Guardfile.
|
79
|
+
#
|
80
|
+
# @see Guard::CLI#init
|
81
|
+
#
|
82
|
+
def initialize_all_templates
|
83
|
+
::Guard::PluginUtil.plugin_names.each { |g| initialize_template(g) }
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
end
|
data/lib/guard/interactor.rb
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
require 'pry'
|
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'
|
11
|
+
|
1
12
|
module Guard
|
2
13
|
|
3
14
|
# The Guard interactor is a Pry REPL with a Guard
|
@@ -5,80 +16,86 @@ module Guard
|
|
5
16
|
#
|
6
17
|
class Interactor
|
7
18
|
|
8
|
-
require 'pry'
|
9
|
-
|
10
|
-
require 'guard'
|
11
|
-
require 'guard/ui'
|
12
|
-
|
13
|
-
require 'guard/commands/all'
|
14
|
-
require 'guard/commands/change'
|
15
|
-
require 'guard/commands/notification'
|
16
|
-
require 'guard/commands/pause'
|
17
|
-
require 'guard/commands/reload'
|
18
|
-
require 'guard/commands/scope'
|
19
|
-
require 'guard/commands/show'
|
20
|
-
|
21
19
|
# The default Ruby script to configure Guard Pry if the option `:guard_rc` is not defined.
|
22
|
-
GUARD_RC
|
20
|
+
GUARD_RC = '~/.guardrc'
|
23
21
|
|
24
22
|
# The default Guard Pry history file if the option `:history_file` is not defined.
|
25
23
|
HISTORY_FILE = '~/.guard_history'
|
26
24
|
|
27
25
|
# List of shortcuts for each interactor command
|
28
26
|
SHORTCUTS = {
|
29
|
-
:
|
30
|
-
:
|
31
|
-
:
|
32
|
-
:
|
33
|
-
:
|
34
|
-
:
|
35
|
-
:
|
36
|
-
:
|
37
|
-
:
|
38
|
-
:
|
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'
|
39
37
|
}
|
40
38
|
|
41
39
|
attr_accessor :thread
|
42
40
|
|
43
|
-
|
41
|
+
# Get the interactor options
|
42
|
+
#
|
43
|
+
# @return [Hash] the options
|
44
|
+
#
|
45
|
+
def self.options
|
46
|
+
@options ||= {}
|
47
|
+
end
|
44
48
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
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
|
52
58
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
@options = options
|
61
|
-
end
|
59
|
+
# Is the interactor enabled?
|
60
|
+
#
|
61
|
+
# @return [Boolean] true if enabled
|
62
|
+
#
|
63
|
+
def self.enabled
|
64
|
+
@enabled || @enabled.nil?
|
65
|
+
end
|
62
66
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
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 = []
|
70
84
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
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
|
77
93
|
end
|
78
94
|
|
95
|
+
[scopes, unknown]
|
79
96
|
end
|
80
97
|
|
81
|
-
#
|
98
|
+
# Initializes the interactor. This configures
|
82
99
|
# Pry and creates some custom commands and aliases
|
83
100
|
# for Guard.
|
84
101
|
#
|
@@ -90,24 +107,58 @@ module Guard
|
|
90
107
|
Pry.config.history.file = File.expand_path(self.class.options[:history_file] || HISTORY_FILE)
|
91
108
|
|
92
109
|
@stty_exists = nil
|
93
|
-
|
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
|
+
if !@thread || !['sleep', 'run'].include?(@thread.status)
|
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'
|
94
143
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
144
|
+
unless Thread.current == @thread
|
145
|
+
::Guard::UI.reset_line
|
146
|
+
::Guard::UI.debug 'Stop interactor'
|
147
|
+
@thread.kill
|
148
|
+
end
|
100
149
|
|
101
|
-
|
150
|
+
_restore_terminal_settings if _stty_exists?
|
102
151
|
end
|
103
152
|
|
153
|
+
private
|
154
|
+
|
104
155
|
# Add Pry hooks:
|
105
156
|
#
|
106
157
|
# * Load `~/.guardrc` within each new Pry session.
|
107
158
|
# * Load project's `.guardrc` within each new Pry session.
|
108
159
|
# * Restore prompt after each evaluation.
|
109
160
|
#
|
110
|
-
def
|
161
|
+
def _add_hooks
|
111
162
|
Pry.config.hooks.add_hook :when_started, :load_guard_rc do
|
112
163
|
(self.class.options[:guard_rc] || GUARD_RC).tap do |p|
|
113
164
|
load p if File.exist?(File.expand_path(p))
|
@@ -119,7 +170,7 @@ module Guard
|
|
119
170
|
load project_guard_rc if File.exist?(project_guard_rc)
|
120
171
|
end
|
121
172
|
|
122
|
-
if
|
173
|
+
if _stty_exists?
|
123
174
|
Pry.config.hooks.add_hook :after_eval, :restore_visibility do
|
124
175
|
system("stty echo 2>#{ DEV_NULL }")
|
125
176
|
end
|
@@ -128,8 +179,8 @@ module Guard
|
|
128
179
|
|
129
180
|
# Replaces reset defined inside of Pry with a reset that
|
130
181
|
# instead restarts guard.
|
131
|
-
|
132
|
-
def
|
182
|
+
#
|
183
|
+
def _replace_reset_command
|
133
184
|
Pry.commands.command "reset", "Reset the Guard to a clean state." do
|
134
185
|
output.puts "Guard reset."
|
135
186
|
exec "guard"
|
@@ -140,7 +191,7 @@ module Guard
|
|
140
191
|
# when the command is empty (just pressing enter on the
|
141
192
|
# beginning of a line).
|
142
193
|
#
|
143
|
-
def
|
194
|
+
def _create_run_all_command
|
144
195
|
Pry.commands.block_command /^$/, 'Hit enter to run all' do
|
145
196
|
Pry.run_command 'all'
|
146
197
|
end
|
@@ -150,7 +201,7 @@ module Guard
|
|
150
201
|
# `help`, `reload`, `change`, `scope`, `notification`, `pause`, `exit` and `quit`,
|
151
202
|
# which will be the first letter of the command.
|
152
203
|
#
|
153
|
-
def
|
204
|
+
def _create_command_aliases
|
154
205
|
SHORTCUTS.each do |command, shortcut|
|
155
206
|
Pry.commands.alias_command shortcut, command.to_s
|
156
207
|
end
|
@@ -161,11 +212,9 @@ module Guard
|
|
161
212
|
# when guard-rspec is available, then a command
|
162
213
|
# `rspec` is created that runs `all rspec`.
|
163
214
|
#
|
164
|
-
def
|
165
|
-
::Guard.
|
166
|
-
|
167
|
-
|
168
|
-
Pry.commands.create_command name, "Run all #{ name }" do
|
215
|
+
def _create_guard_commands
|
216
|
+
::Guard.plugins.each do |guard_plugin|
|
217
|
+
Pry.commands.create_command guard_plugin.name, "Run all #{ guard_plugin.title }" do
|
169
218
|
group 'Guard'
|
170
219
|
|
171
220
|
def process
|
@@ -180,12 +229,11 @@ module Guard
|
|
180
229
|
# when you have a group `frontend`, then a command
|
181
230
|
# `frontend` is created that runs `all frontend`.
|
182
231
|
#
|
183
|
-
def
|
232
|
+
def _create_group_commands
|
184
233
|
::Guard.groups.each do |group|
|
185
|
-
|
186
|
-
next if name == 'default'
|
234
|
+
next if group.name == :default
|
187
235
|
|
188
|
-
Pry.commands.create_command name, "Run all #{
|
236
|
+
Pry.commands.create_command group.name.to_s, "Run all #{ group.title }" do
|
189
237
|
group 'Guard'
|
190
238
|
|
191
239
|
def process
|
@@ -198,71 +246,29 @@ module Guard
|
|
198
246
|
# Configure the pry prompt to see `guard` instead of
|
199
247
|
# `pry`.
|
200
248
|
#
|
201
|
-
def
|
202
|
-
Pry.config.prompt = [
|
203
|
-
proc do |target_self, nest_level, pry|
|
204
|
-
history = pry.input_array.size
|
205
|
-
process = ::Guard.listener.paused? ? 'pause' : 'guard'
|
206
|
-
clip = Pry.view_clip(target_self)
|
207
|
-
level = ":#{ nest_level }" unless nest_level.zero?
|
208
|
-
scope = if !::Guard.scope[:plugins].empty?
|
209
|
-
"{#{ ::Guard.scope[:plugins].join(',') }} "
|
210
|
-
elsif !::Guard.scope[:groups].empty?
|
211
|
-
"{#{ ::Guard.scope[:groups].join(',') }} "
|
212
|
-
else
|
213
|
-
''
|
214
|
-
end
|
215
|
-
|
216
|
-
"[#{ history }] #{ scope }#{ process }(#{ clip })#{ level }> "
|
217
|
-
end,
|
218
|
-
proc do |target_self, nest_level, pry|
|
219
|
-
history = pry.input_array.size
|
220
|
-
process = ::Guard.listener.paused? ? 'pause' : 'guard'
|
221
|
-
clip = Pry.view_clip(target_self)
|
222
|
-
level = ":#{ nest_level }" unless nest_level.zero?
|
223
|
-
scope = if !::Guard.scope[:plugins].empty?
|
224
|
-
"{#{ ::Guard.scope[:plugins].join }} "
|
225
|
-
elsif !::Guard.scope[:groups].empty?
|
226
|
-
"{#{ ::Guard.scope[:groups].join }} "
|
227
|
-
else
|
228
|
-
''
|
229
|
-
end
|
230
|
-
|
231
|
-
"[#{ history }] #{ scope }#{ process }(#{ clip })#{ level }* "
|
232
|
-
end
|
233
|
-
]
|
234
|
-
end
|
235
|
-
|
236
|
-
# Start the line reader in its own thread and
|
237
|
-
# stop Guard on Ctrl-D.
|
238
|
-
#
|
239
|
-
def start
|
240
|
-
return if ENV['GUARD_ENV'] == 'test'
|
241
|
-
|
242
|
-
store_terminal_settings if stty_exists?
|
243
|
-
|
244
|
-
if !@thread || !['sleep', 'run'].include?(@thread.status)
|
245
|
-
::Guard::UI.debug 'Start interactor'
|
246
|
-
|
247
|
-
@thread = Thread.new do
|
248
|
-
Pry.start
|
249
|
-
::Guard.stop
|
250
|
-
end
|
251
|
-
end
|
249
|
+
def _configure_prompt
|
250
|
+
Pry.config.prompt = [_prompt('>'), _prompt('*')]
|
252
251
|
end
|
253
252
|
|
254
|
-
#
|
253
|
+
# Returns a proc that will return itself a string ending with the given
|
254
|
+
# `ending_char` when called.
|
255
255
|
#
|
256
|
-
def
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
256
|
+
def _prompt(ending_char)
|
257
|
+
proc do |target_self, nest_level, pry|
|
258
|
+
history = pry.input_array.size
|
259
|
+
process = ::Guard.listener.paused? ? 'pause' : 'guard'
|
260
|
+
clip = Pry.view_clip(target_self)
|
261
|
+
level = ":#{ nest_level }" unless nest_level.zero?
|
262
|
+
scope = if !::Guard.scope[:plugins].empty?
|
263
|
+
"{#{ ::Guard.scope[:plugins].map(&:title).join(',') }} "
|
264
|
+
elsif !::Guard.scope[:groups].empty?
|
265
|
+
"{#{ ::Guard.scope[:groups].map(&:title).join(',') }} "
|
266
|
+
else
|
267
|
+
''
|
268
|
+
end
|
269
|
+
|
270
|
+
"[#{ history }] #{ scope }#{ process }(#{ clip })#{ level }#{ending_char} "
|
263
271
|
end
|
264
|
-
|
265
|
-
restore_terminal_settings if stty_exists?
|
266
272
|
end
|
267
273
|
|
268
274
|
# Detects whether or not the stty command exists
|
@@ -270,7 +276,7 @@ module Guard
|
|
270
276
|
#
|
271
277
|
# @return [Boolean] the status of stty
|
272
278
|
#
|
273
|
-
def
|
279
|
+
def _stty_exists?
|
274
280
|
@stty_exists ||= system('hash', 'stty') ? true : false if @stty_exists.nil?
|
275
281
|
@stty_exists
|
276
282
|
end
|
@@ -278,37 +284,15 @@ module Guard
|
|
278
284
|
# Stores the terminal settings so we can resore them
|
279
285
|
# when stopping.
|
280
286
|
#
|
281
|
-
def
|
287
|
+
def _store_terminal_settings
|
282
288
|
@stty_save = `stty -g 2>#{ DEV_NULL }`.chomp
|
283
289
|
end
|
284
290
|
|
285
291
|
# Restore terminal settings
|
286
292
|
#
|
287
|
-
def
|
293
|
+
def _restore_terminal_settings
|
288
294
|
system("stty #{ @stty_save } 2>#{ DEV_NULL }") if @stty_save
|
289
295
|
end
|
290
296
|
|
291
|
-
# Converts and validates a plain text scope
|
292
|
-
# to a valid plugin or group scope.
|
293
|
-
#
|
294
|
-
# @param [Array<String>] entries the text scope
|
295
|
-
# @return [Hash, Array<String>] the plugin or group scope, the unknown entries
|
296
|
-
#
|
297
|
-
def self.convert_scope(entries)
|
298
|
-
scopes = { :plugins => [], :groups => [] }
|
299
|
-
unknown = []
|
300
|
-
|
301
|
-
entries.each do |entry|
|
302
|
-
if plugin = ::Guard.guards(entry)
|
303
|
-
scopes[:plugins] << plugin
|
304
|
-
elsif group = ::Guard.groups(entry)
|
305
|
-
scopes[:groups] << group
|
306
|
-
else
|
307
|
-
unknown << entry
|
308
|
-
end
|
309
|
-
end
|
310
|
-
|
311
|
-
[scopes, unknown]
|
312
|
-
end
|
313
297
|
end
|
314
298
|
end
|