guard 2.7.1 → 2.7.2
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/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
|