guard 2.7.1 → 2.7.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/guard/dsl_describer.rb +3 -1
- data/lib/guard/dsl_describer.rb.orig +180 -0
- data/lib/guard/plugin_util.rb +5 -1
- data/lib/guard/reevaluator.rb +8 -0
- data/lib/guard/runner.rb +1 -0
- data/lib/guard/setuper.rb +2 -1
- data/lib/guard/ui.rb +5 -2
- data/lib/guard/version.rb +1 -1
- data/lib/guard/version.rb.orig +1 -1
- metadata +3 -13
- data/bin/fsevent_watch_guard +0 -0
- data/lib/guard.rb.orig +0 -210
- data/lib/guard/interactor.rb.orig +0 -90
- data/lib/guard/jobs/stdin.rb.orig +0 -46
- data/lib/guard/notifiers/emacs.rb.orig +0 -103
- data/lib/guard/setuper.rb.orig +0 -384
- data/lib/guard/sheller.rb.orig +0 -107
- data/lib/guard/tags +0 -442
- data/lib/guard/terminal.rb.orig +0 -0
- data/lib/guard/ui.rb.orig +0 -264
- data/lib/guard/watcher.rb.orig +0 -119
@@ -1,90 +0,0 @@
|
|
1
|
-
require "guard/ui"
|
2
|
-
|
3
|
-
require "guard/jobs/sleep"
|
4
|
-
require "guard/jobs/pry_wrapper"
|
5
|
-
require "guard/jobs/stdin"
|
6
|
-
|
7
|
-
module Guard
|
8
|
-
class Interactor
|
9
|
-
# Initializes the interactor. This configures
|
10
|
-
# Pry and creates some custom commands and aliases
|
11
|
-
# for Guard.
|
12
|
-
#
|
13
|
-
def initialize(no_interaction = false)
|
14
|
-
@interactive = !no_interaction && self.class.enabled?
|
15
|
-
|
16
|
-
|
17
|
-
# TODO: restore
|
18
|
-
# job_klass = interactive? ? Jobs::PryWrapper : Jobs::Sleep
|
19
|
-
job_klass = Jobs::StdinJob
|
20
|
-
|
21
|
-
@idle_job = job_klass.new(self.class.options)
|
22
|
-
end
|
23
|
-
|
24
|
-
def interactive?
|
25
|
-
@interactive
|
26
|
-
end
|
27
|
-
|
28
|
-
# Run in foreground and wait until interrupted or closed
|
29
|
-
def foreground
|
30
|
-
idle_job.foreground
|
31
|
-
end
|
32
|
-
|
33
|
-
# Remove interactor so other tasks can run in foreground
|
34
|
-
def background
|
35
|
-
idle_job.background
|
36
|
-
end
|
37
|
-
|
38
|
-
def handle_interrupt
|
39
|
-
idle_job.handle_interrupt
|
40
|
-
end
|
41
|
-
|
42
|
-
class << self
|
43
|
-
def options
|
44
|
-
@options ||= {}
|
45
|
-
end
|
46
|
-
|
47
|
-
# Pass options to interactor's job when it's created
|
48
|
-
attr_writer :options
|
49
|
-
|
50
|
-
# TODO: allow custom user idle jobs, e.g. [:pry, :sleep, :exit, ...]
|
51
|
-
def enabled?
|
52
|
-
@enabled || @enabled.nil?
|
53
|
-
end
|
54
|
-
|
55
|
-
alias_method :enabled, :enabled?
|
56
|
-
|
57
|
-
# TODO: handle switching interactors during runtime?
|
58
|
-
attr_writer :enabled
|
59
|
-
|
60
|
-
# Converts and validates a plain text scope
|
61
|
-
# to a valid plugin or group scope.
|
62
|
-
#
|
63
|
-
# @param [Array<String>] entries the text scope
|
64
|
-
# @return [Hash, Array<String>] the plugin or group scope, the unknown
|
65
|
-
# entries
|
66
|
-
#
|
67
|
-
# TODO: call this from within action, not within interactor command
|
68
|
-
def convert_scope(entries)
|
69
|
-
scopes = { plugins: [], groups: [] }
|
70
|
-
unknown = []
|
71
|
-
|
72
|
-
entries.each do |entry|
|
73
|
-
if plugin = ::Guard.plugin(entry)
|
74
|
-
scopes[:plugins] << plugin
|
75
|
-
elsif group = ::Guard.group(entry)
|
76
|
-
scopes[:groups] << group
|
77
|
-
else
|
78
|
-
unknown << entry
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
[scopes, unknown]
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
private
|
87
|
-
|
88
|
-
attr_reader :idle_job
|
89
|
-
end
|
90
|
-
end
|
@@ -1,46 +0,0 @@
|
|
1
|
-
require "guard/jobs/base"
|
2
|
-
|
3
|
-
module Guard
|
4
|
-
module Jobs
|
5
|
-
class StdinJob
|
6
|
-
def initialize(options)
|
7
|
-
@mode = :stopped
|
8
|
-
@sleeping = false
|
9
|
-
end
|
10
|
-
|
11
|
-
def foreground
|
12
|
-
output "Guard is idle" # needed for child-process cucumber tests
|
13
|
-
|
14
|
-
line = $stdin.readline.chomp
|
15
|
-
return :exit if line == "exit"
|
16
|
-
|
17
|
-
m = /^sleep (?<seconds>\d+)$/.match(line)
|
18
|
-
return @mode unless m
|
19
|
-
|
20
|
-
seconds = Integer(m[:seconds][/\d+/])
|
21
|
-
@sleeping = true
|
22
|
-
sleep seconds
|
23
|
-
@sleeping = false
|
24
|
-
@mode
|
25
|
-
rescue EOFError, Interrupt
|
26
|
-
@sleeping = false
|
27
|
-
:exit
|
28
|
-
end
|
29
|
-
|
30
|
-
def background
|
31
|
-
Thread.main.wakeup if @sleeping
|
32
|
-
end
|
33
|
-
|
34
|
-
def handle_interrupt
|
35
|
-
@mode = :exit
|
36
|
-
end
|
37
|
-
|
38
|
-
private
|
39
|
-
|
40
|
-
def output(text)
|
41
|
-
$stdout.puts text
|
42
|
-
$stdout.flush
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
@@ -1,103 +0,0 @@
|
|
1
|
-
require "guard/notifiers/base"
|
2
|
-
|
3
|
-
module Guard
|
4
|
-
module Notifier
|
5
|
-
# Send a notification to Emacs with emacsclient
|
6
|
-
# (http://www.emacswiki.org/emacs/EmacsClient).
|
7
|
-
#
|
8
|
-
# @example Add the `:emacs` notifier to your `Guardfile`
|
9
|
-
# notification :emacs
|
10
|
-
#
|
11
|
-
class Emacs < Base
|
12
|
-
DEFAULTS = {
|
13
|
-
client: "emacsclient",
|
14
|
-
success: "ForestGreen",
|
15
|
-
failed: "Firebrick",
|
16
|
-
default: "Black",
|
17
|
-
fontcolor: "White",
|
18
|
-
}
|
19
|
-
|
20
|
-
def self.available?(opts = {})
|
21
|
-
super && _emacs_client_available?(opts)
|
22
|
-
end
|
23
|
-
|
24
|
-
# @private
|
25
|
-
#
|
26
|
-
# @return [Boolean] whether or not the emacs client is available
|
27
|
-
#
|
28
|
-
def self._emacs_client_available?(opts)
|
29
|
-
client_name = opts.fetch(:client, DEFAULTS[:client])
|
30
|
-
cmd = "#{client_name} --eval '1' 2> #{DEV_NULL} || echo 'N/A'"
|
31
|
-
stdout = Sheller.stdout(cmd)
|
32
|
-
!%w(N/A 'N/A').include?(stdout.chomp!)
|
33
|
-
end
|
34
|
-
|
35
|
-
# Shows a system notification.
|
36
|
-
#
|
37
|
-
# @param [String] type the notification type. Either 'success',
|
38
|
-
# 'pending', 'failed' or 'notify'
|
39
|
-
# @param [String] title the notification title
|
40
|
-
# @param [String] message the notification message body
|
41
|
-
# @param [String] image the path to the notification image
|
42
|
-
# @param [Hash] opts additional notification library options
|
43
|
-
# @option opts [String] success the color to use for success
|
44
|
-
# notifications (default is 'ForestGreen')
|
45
|
-
# @option opts [String] failed the color to use for failure
|
46
|
-
# notifications (default is 'Firebrick')
|
47
|
-
# @option opts [String] pending the color to use for pending
|
48
|
-
# notifications
|
49
|
-
# @option opts [String] default the default color to use (default is
|
50
|
-
# 'Black')
|
51
|
-
# @option opts [String] client the client to use for notification
|
52
|
-
# (default is 'emacsclient')
|
53
|
-
# @option opts [String, Integer] priority specify an int or named key
|
54
|
-
# (default is 0)
|
55
|
-
#
|
56
|
-
def notify(message, opts = {})
|
57
|
-
super
|
58
|
-
|
59
|
-
opts = DEFAULTS.merge(opts)
|
60
|
-
color = emacs_color(opts[:type], opts)
|
61
|
-
fontcolor = emacs_color(:fontcolor, opts)
|
62
|
-
elisp = <<-EOF.gsub(/\s+/, " ").strip
|
63
|
-
(set-face-attribute 'mode-line nil
|
64
|
-
:background "#{color}"
|
65
|
-
:foreground "#{fontcolor}")
|
66
|
-
EOF
|
67
|
-
|
68
|
-
_run_cmd(opts[:client], "--eval", elisp)
|
69
|
-
end
|
70
|
-
|
71
|
-
# Get the Emacs color for the notification type.
|
72
|
-
# You can configure your own color by overwrite the defaults.
|
73
|
-
#
|
74
|
-
# @param [String] type the notification type
|
75
|
-
# @param [Hash] options aditional notification options
|
76
|
-
#
|
77
|
-
# @option options [String] success the color to use for success
|
78
|
-
# notifications (default is 'ForestGreen')
|
79
|
-
#
|
80
|
-
# @option options [String] failed the color to use for failure
|
81
|
-
# notifications (default is 'Firebrick')
|
82
|
-
#
|
83
|
-
# @option options [String] pending the color to use for pending
|
84
|
-
# notifications
|
85
|
-
#
|
86
|
-
# @option options [String] default the default color to use (default is
|
87
|
-
# 'Black')
|
88
|
-
#
|
89
|
-
# @return [String] the name of the emacs color
|
90
|
-
#
|
91
|
-
def emacs_color(type, options = {})
|
92
|
-
default = options.fetch(:default, DEFAULTS[:default])
|
93
|
-
options.fetch(type.to_sym, default)
|
94
|
-
end
|
95
|
-
|
96
|
-
private
|
97
|
-
|
98
|
-
def _run_cmd(cmd, *args)
|
99
|
-
Sheller.run(cmd, *args)
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
data/lib/guard/setuper.rb.orig
DELETED
@@ -1,384 +0,0 @@
|
|
1
|
-
require "thread"
|
2
|
-
require "listen"
|
3
|
-
require "guard/options"
|
4
|
-
|
5
|
-
module Guard
|
6
|
-
# Sets up initial variables and options
|
7
|
-
module Setuper
|
8
|
-
DEFAULT_OPTIONS = {
|
9
|
-
clear: false,
|
10
|
-
notify: true,
|
11
|
-
debug: false,
|
12
|
-
group: [],
|
13
|
-
plugin: [],
|
14
|
-
watchdir: nil,
|
15
|
-
guardfile: nil,
|
16
|
-
no_interactions: false,
|
17
|
-
no_bundler_warning: false,
|
18
|
-
show_deprecations: false,
|
19
|
-
latency: nil,
|
20
|
-
force_polling: false,
|
21
|
-
wait_for_delay: nil,
|
22
|
-
listen_on: nil
|
23
|
-
}
|
24
|
-
DEFAULT_GROUPS = [:default, :common]
|
25
|
-
|
26
|
-
# Initializes the Guard singleton:
|
27
|
-
#
|
28
|
-
# * Initialize the internal Guard state;
|
29
|
-
# * Create the interactor
|
30
|
-
# * Select and initialize the file change listener.
|
31
|
-
#
|
32
|
-
# @option options [Boolean] clear if auto clear the UI should be done
|
33
|
-
# @option options [Boolean] notify if system notifications should be shown
|
34
|
-
# @option options [Boolean] debug if debug output should be shown
|
35
|
-
# @option options [Array<String>] group the list of groups to start
|
36
|
-
# @option options [Array<String>] watchdir the directories to watch
|
37
|
-
# @option options [String] guardfile the path to the Guardfile
|
38
|
-
#
|
39
|
-
# @return [Guard] the Guard singleton
|
40
|
-
#
|
41
|
-
|
42
|
-
# TODO: this method has too many instance variables
|
43
|
-
# and some are mock and leak between tests,
|
44
|
-
# so ideally there should be a guard "instance"
|
45
|
-
# object that can be created anew between tests
|
46
|
-
def setup(opts = {})
|
47
|
-
reset_options(opts)
|
48
|
-
reset_evaluator(opts)
|
49
|
-
|
50
|
-
@queue = Queue.new
|
51
|
-
@runner = ::Guard::Runner.new
|
52
|
-
@watchdirs = _setup_watchdirs
|
53
|
-
|
54
|
-
::Guard::UI.clear(force: true)
|
55
|
-
|
56
|
-
_setup_debug if options[:debug]
|
57
|
-
@listener = _setup_listener
|
58
|
-
_setup_signal_traps
|
59
|
-
|
60
|
-
_load_guardfile
|
61
|
-
@interactor = _setup_interactor
|
62
|
-
self
|
63
|
-
end
|
64
|
-
|
65
|
-
attr_reader :options, :interactor
|
66
|
-
|
67
|
-
# Used only by tests (for all I know...)
|
68
|
-
def clear_options
|
69
|
-
@options = nil
|
70
|
-
end
|
71
|
-
|
72
|
-
# Initializes the groups array with the default group(s).
|
73
|
-
#
|
74
|
-
# @see DEFAULT_GROUPS
|
75
|
-
#
|
76
|
-
def reset_groups
|
77
|
-
@groups = DEFAULT_GROUPS.map { |name| Group.new(name) }
|
78
|
-
end
|
79
|
-
|
80
|
-
# Initializes the plugins array to an empty array.
|
81
|
-
#
|
82
|
-
# @see Guard.plugins
|
83
|
-
#
|
84
|
-
def reset_plugins
|
85
|
-
@plugins = []
|
86
|
-
end
|
87
|
-
|
88
|
-
# Initializes the scope hash to `{ groups: [], plugins: [] }`.
|
89
|
-
#
|
90
|
-
# @see Guard.setup_scope
|
91
|
-
#
|
92
|
-
def reset_scope
|
93
|
-
# calls Guard.scope=() to set the instance variable directly, as opposed
|
94
|
-
# to Guard.scope()
|
95
|
-
::Guard.scope = { groups: [], plugins: [] }
|
96
|
-
end
|
97
|
-
|
98
|
-
# Used to merge CLI options with Setuper defaults
|
99
|
-
def reset_options(new_options)
|
100
|
-
@options = ::Guard::Options.new(new_options, DEFAULT_OPTIONS)
|
101
|
-
end
|
102
|
-
|
103
|
-
# TODO: code smell - too many reset_* methods
|
104
|
-
def reset_evaluator(new_options)
|
105
|
-
@evaluator = ::Guard::Guardfile::Evaluator.new(new_options)
|
106
|
-
end
|
107
|
-
|
108
|
-
def save_scope
|
109
|
-
# This actually replaces scope from command line,
|
110
|
-
# so scope set by 'scope' Pry command will be reset
|
111
|
-
@saved_scope = _prepare_scope(::Guard.scope)
|
112
|
-
end
|
113
|
-
|
114
|
-
def restore_scope
|
115
|
-
::Guard.setup_scope(@saved_scope)
|
116
|
-
end
|
117
|
-
|
118
|
-
attr_reader :watchdirs
|
119
|
-
|
120
|
-
# Stores the scopes defined by the user via the `--group` / `-g` option (to
|
121
|
-
# run only a specific group) or the `--plugin` / `-P` option (to run only a
|
122
|
-
# specific plugin).
|
123
|
-
#
|
124
|
-
# @see CLI#start
|
125
|
-
# @see Dsl#scope
|
126
|
-
#
|
127
|
-
def setup_scope(scope = {})
|
128
|
-
# TODO: there should be a special Scope class instead
|
129
|
-
scope = _prepare_scope(scope)
|
130
|
-
|
131
|
-
::Guard.scope = {
|
132
|
-
groups: scope[:groups].map { |item| ::Guard.add_group(item) },
|
133
|
-
plugins: scope[:plugins].map { |item| ::Guard.plugin(item) },
|
134
|
-
}
|
135
|
-
end
|
136
|
-
|
137
|
-
# Evaluates the Guardfile content. It displays an error message if no
|
138
|
-
# Guard plugins are instantiated after the Guardfile evaluation.
|
139
|
-
#
|
140
|
-
# @see Guard::Guardfile::Evaluator#evaluate_guardfile
|
141
|
-
#
|
142
|
-
def evaluate_guardfile
|
143
|
-
evaluator.evaluate_guardfile
|
144
|
-
msg = "No plugins found in Guardfile, please add at least one."
|
145
|
-
::Guard::UI.error msg unless _pluginless_guardfile?
|
146
|
-
end
|
147
|
-
|
148
|
-
# Asynchronously trigger changes
|
149
|
-
#
|
150
|
-
# Currently supported args:
|
151
|
-
#
|
152
|
-
# old style hash: {modified: ['foo'], added: ['bar'], removed: []}
|
153
|
-
#
|
154
|
-
# new style signals with args: [:guard_pause, :unpaused ]
|
155
|
-
#
|
156
|
-
def async_queue_add(changes)
|
157
|
-
@queue << changes
|
158
|
-
|
159
|
-
# Putting interactor in background puts guard into foreground
|
160
|
-
# so it can handle change notifications
|
161
|
-
Thread.new { interactor.background }
|
162
|
-
end
|
163
|
-
|
164
|
-
def pending_changes?
|
165
|
-
! @queue.empty?
|
166
|
-
end
|
167
|
-
|
168
|
-
def add_builtin_plugins(guardfile)
|
169
|
-
return unless guardfile
|
170
|
-
|
171
|
-
pattern = _relative_pathname(guardfile).to_s
|
172
|
-
watcher = ::Guard::Watcher.new(pattern)
|
173
|
-
::Guard.add_plugin(:reevaluator, watchers: [watcher], group: :common)
|
174
|
-
end
|
175
|
-
|
176
|
-
private
|
177
|
-
|
178
|
-
# Sets up various debug behaviors:
|
179
|
-
#
|
180
|
-
# * Abort threads on exception;
|
181
|
-
# * Set the logging level to `:debug`;
|
182
|
-
# * Modify the system and ` methods to log themselves before being executed
|
183
|
-
#
|
184
|
-
# @see #_debug_command_execution
|
185
|
-
#
|
186
|
-
def _setup_debug
|
187
|
-
Thread.abort_on_exception = true
|
188
|
-
::Guard::UI.options[:level] = :debug
|
189
|
-
_debug_command_execution
|
190
|
-
end
|
191
|
-
|
192
|
-
# Initializes the listener and registers a callback for changes.
|
193
|
-
#
|
194
|
-
def _setup_listener
|
195
|
-
if options[:listen_on]
|
196
|
-
Listen.on(options[:listen_on], &_listener_callback)
|
197
|
-
else
|
198
|
-
listener_options = {}
|
199
|
-
[:latency, :force_polling, :wait_for_delay].each do |option|
|
200
|
-
listener_options[option] = options[option] if options[option]
|
201
|
-
end
|
202
|
-
listen_args = watchdirs + [listener_options]
|
203
|
-
Listen.to(*listen_args, &_listener_callback)
|
204
|
-
end
|
205
|
-
end
|
206
|
-
|
207
|
-
# Process the change queue, running tasks within the main Guard thread
|
208
|
-
def _process_queue
|
209
|
-
actions, changes = [], { modified: [], added: [], removed: [] }
|
210
|
-
|
211
|
-
while pending_changes?
|
212
|
-
if (item = @queue.pop).first.is_a?(Symbol)
|
213
|
-
actions << item
|
214
|
-
else
|
215
|
-
item.each { |key, value| changes[key] += value }
|
216
|
-
end
|
217
|
-
end
|
218
|
-
|
219
|
-
_run_actions(actions)
|
220
|
-
runner.run_on_changes(*changes.values)
|
221
|
-
end
|
222
|
-
|
223
|
-
# Sets up traps to catch signals used to control Guard.
|
224
|
-
#
|
225
|
-
# Currently two signals are caught:
|
226
|
-
# - `USR1` which pauses listening to changes.
|
227
|
-
# - `USR2` which resumes listening to changes.
|
228
|
-
# - 'INT' which is delegated to Pry if active, otherwise stops Guard.
|
229
|
-
#
|
230
|
-
def _setup_signal_traps
|
231
|
-
return if defined?(JRUBY_VERSION)
|
232
|
-
|
233
|
-
if Signal.list.keys.include?("USR1")
|
234
|
-
Signal.trap("USR1") { async_queue_add([:guard_pause, :paused]) }
|
235
|
-
end
|
236
|
-
|
237
|
-
if Signal.list.keys.include?("USR2")
|
238
|
-
Signal.trap("USR2") { async_queue_add([:guard_pause, :unpaused]) }
|
239
|
-
end
|
240
|
-
|
241
|
-
return unless Signal.list.keys.include?("INT")
|
242
|
-
Signal.trap("INT") { interactor.handle_interrupt }
|
243
|
-
end
|
244
|
-
|
245
|
-
# Enables or disables the notifier based on user's configurations.
|
246
|
-
#
|
247
|
-
def _setup_notifier
|
248
|
-
if options[:notify] && ENV["GUARD_NOTIFY"] != "false"
|
249
|
-
::Guard::Notifier.turn_on
|
250
|
-
else
|
251
|
-
::Guard::Notifier.turn_off
|
252
|
-
end
|
253
|
-
end
|
254
|
-
|
255
|
-
# Adds a command logger in debug mode. This wraps common command
|
256
|
-
# execution functions and logs the executed command before execution.
|
257
|
-
#
|
258
|
-
def _debug_command_execution
|
259
|
-
Kernel.send(:alias_method, :original_system, :system)
|
260
|
-
Kernel.send(:define_method, :system) do |command, *args|
|
261
|
-
::Guard::UI.debug "Command execution: #{ command } #{ args.join(" ") }"
|
262
|
-
Kernel.send :original_system, command, *args
|
263
|
-
end
|
264
|
-
|
265
|
-
Kernel.send(:alias_method, :original_backtick, :'`')
|
266
|
-
Kernel.send(:define_method, :'`') do |command|
|
267
|
-
::Guard::UI.debug "Command execution: #{ command }"
|
268
|
-
Kernel.send :original_backtick, command
|
269
|
-
end
|
270
|
-
end
|
271
|
-
|
272
|
-
# TODO: Guard::Watch or Guard::Scope should provide this
|
273
|
-
def _scoped_watchers
|
274
|
-
watchers = []
|
275
|
-
runner.send(:_scoped_plugins) { |guard| watchers += guard.watchers }
|
276
|
-
watchers
|
277
|
-
end
|
278
|
-
|
279
|
-
# Check if any of the changes are actually watched for
|
280
|
-
def _relevant_changes?(changes)
|
281
|
-
files = changes.values.flatten(1)
|
282
|
-
watchers = _scoped_watchers
|
283
|
-
watchers.any? { |watcher| files.any? { |file| watcher.match(file) } }
|
284
|
-
end
|
285
|
-
|
286
|
-
def _relative_pathname(path)
|
287
|
-
full_path = Pathname(path)
|
288
|
-
full_path.relative_path_from(Pathname.pwd)
|
289
|
-
rescue ArgumentError
|
290
|
-
full_path
|
291
|
-
end
|
292
|
-
|
293
|
-
def _relative_pathnames(paths)
|
294
|
-
paths.map { |path| _relative_pathname(path) }
|
295
|
-
end
|
296
|
-
|
297
|
-
def _run_actions(actions)
|
298
|
-
actions.each do |action_args|
|
299
|
-
args = action_args.dup
|
300
|
-
namespaced_action = args.shift
|
301
|
-
action = namespaced_action.to_s.sub(/^guard_/, "")
|
302
|
-
if ::Guard.respond_to?(action)
|
303
|
-
::Guard.send(action, *args)
|
304
|
-
else
|
305
|
-
fail "Unknown action: #{action.inspect}"
|
306
|
-
end
|
307
|
-
end
|
308
|
-
end
|
309
|
-
|
310
|
-
def _setup_watchdirs
|
311
|
-
dirs = Array(options[:watchdir])
|
312
|
-
dirs.empty? ? [Dir.pwd] : dirs.map { |dir| File.expand_path dir }
|
313
|
-
end
|
314
|
-
|
315
|
-
def _listener_callback
|
316
|
-
lambda do |modified, added, removed|
|
317
|
-
relative_paths = {
|
318
|
-
modified: _relative_pathnames(modified),
|
319
|
-
added: _relative_pathnames(added),
|
320
|
-
removed: _relative_pathnames(removed)
|
321
|
-
}
|
322
|
-
|
323
|
-
async_queue_add(relative_paths) if _relevant_changes?(relative_paths)
|
324
|
-
end
|
325
|
-
end
|
326
|
-
|
327
|
-
def _reset_all
|
328
|
-
reset_groups
|
329
|
-
reset_plugins
|
330
|
-
reset_scope
|
331
|
-
end
|
332
|
-
|
333
|
-
def _setup_interactor
|
334
|
-
::Guard::Interactor.new(options[:no_interactions])
|
335
|
-
end
|
336
|
-
|
337
|
-
def _load_guardfile
|
338
|
-
_reset_all
|
339
|
-
evaluate_guardfile
|
340
|
-
setup_scope
|
341
|
-
_setup_notifier
|
342
|
-
end
|
343
|
-
|
344
|
-
def _prepare_scope(scope)
|
345
|
-
fail "Guard::setup() not called!" if options.nil?
|
346
|
-
plugins = Array(options[:plugin])
|
347
|
-
plugins = Array(scope[:plugins] || scope[:plugin]) if plugins.empty?
|
348
|
-
|
349
|
-
# Convert objects to names
|
350
|
-
plugins.map! { |p| p.respond_to?(:name) ? p.name : p }
|
351
|
-
|
352
|
-
groups = Array(options[:group])
|
353
|
-
groups = Array(scope[:groups] || scope[:group]) if groups.empty?
|
354
|
-
|
355
|
-
# Convert objects to names
|
356
|
-
groups.map! { |g| g.respond_to?(:name) ? g.name : g }
|
357
|
-
|
358
|
-
{ plugins: plugins, groups: groups }
|
359
|
-
end
|
360
|
-
|
361
|
-
def _pluginless_guardfile?
|
362
|
-
# no Reevaluator means there was no Guardfile configured that could be
|
363
|
-
# reevaluated, so we don't have a pluginless guardfile, because we don't
|
364
|
-
# have a Guardfile to begin with...
|
365
|
-
#
|
366
|
-
# But, if we have a Guardfile, we'll at least have the built-in
|
367
|
-
# Reevaluator, so the following will work:
|
368
|
-
|
369
|
-
plugins.map(&:name) != ["reevaluator"]
|
370
|
-
end
|
371
|
-
|
372
|
-
def _reset_for_tests
|
373
|
-
@options = nil
|
374
|
-
@queue = nil
|
375
|
-
@runner = nil
|
376
|
-
@evaluator = nil
|
377
|
-
@watchdirs = nil
|
378
|
-
@watchdirs = nil
|
379
|
-
@listener = nil
|
380
|
-
@interactor = nil
|
381
|
-
@scope = nil
|
382
|
-
end
|
383
|
-
end
|
384
|
-
end
|