guard 2.8.2 → 2.9.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 +0 -7
- data/lib/guard.rb +220 -152
- data/lib/guard.rb.orig +213 -155
- data/lib/guard/aruba_adapter.rb +2 -2
- data/lib/guard/cli.rb +8 -13
- data/lib/guard/cli.rb.orig +12 -10
- data/lib/guard/commander.rb +15 -7
- data/lib/guard/commands/all.rb +3 -0
- data/lib/guard/commands/change.rb +3 -0
- data/lib/guard/commands/pause.rb +2 -0
- data/lib/guard/commands/reload.rb +4 -0
- data/lib/guard/commands/scope.rb +3 -0
- data/lib/guard/config.rb +24 -0
- data/lib/guard/deprecated/dsl.rb +45 -0
- data/lib/guard/deprecated/guard.rb +166 -0
- data/lib/guard/deprecated/guardfile.rb +84 -0
- data/lib/guard/dsl.rb +24 -13
- data/lib/guard/dsl.rb.orig +378 -0
- data/lib/guard/dsl_describer.rb +8 -2
- data/lib/guard/dsl_describer.rb.orig +11 -3
- data/lib/guard/guardfile.rb +32 -44
- data/lib/guard/guardfile/evaluator.rb +13 -6
- data/lib/guard/guardfile/generator.rb +4 -3
- data/lib/guard/interactor.rb +7 -3
- data/lib/guard/internals/debugging.rb +1 -0
- data/lib/guard/internals/environment.rb +93 -0
- data/lib/guard/internals/helpers.rb +13 -0
- data/lib/guard/internals/traps.rb +10 -0
- data/lib/guard/jobs/pry_wrapper.rb +4 -3
- data/lib/guard/jobs/sleep.rb +2 -0
- data/lib/guard/metadata.rb +190 -0
- data/lib/guard/notifier.rb +124 -99
- data/lib/guard/notifier.rb.orig +124 -99
- data/lib/guard/notifier/detected.rb +83 -0
- data/lib/guard/notifiers/emacs.rb +2 -1
- data/lib/guard/notifiers/tmux.rb +173 -177
- data/lib/guard/plugin/base.rb +2 -0
- data/lib/guard/plugin_util.rb +26 -32
- data/lib/guard/reevaluator.rb +3 -3
- data/lib/guard/reevaluator.rb.orig +22 -0
- data/lib/guard/runner.rb +1 -0
- data/lib/guard/session.rb +5 -0
- data/lib/guard/sheller.rb +2 -2
- data/lib/guard/templates/Guardfile +4 -0
- data/lib/guard/templates/Guardfile.orig +2 -0
- data/lib/guard/terminal.rb +1 -0
- data/lib/guard/ui.rb +4 -1
- data/lib/guard/version.rb +1 -1
- data/lib/guard/version.rb.orig +1 -1
- data/lib/guard/watcher.rb +3 -1
- data/lib/guard/watcher.rb.orig +122 -0
- data/man/guard.1 +1 -4
- data/man/guard.1.html +1 -4
- metadata +17 -25
- data/lib/guard/commander.rb.orig +0 -103
- data/lib/guard/commands/all.rb.orig +0 -36
- data/lib/guard/commands/reload.rb.orig +0 -34
- data/lib/guard/commands/scope.rb.orig +0 -36
- data/lib/guard/deprecated_methods.rb +0 -72
- data/lib/guard/deprecated_methods.rb.orig +0 -71
- data/lib/guard/deprecator.rb +0 -133
- data/lib/guard/deprecator.rb.orig +0 -206
- data/lib/guard/guard.rb +0 -100
- data/lib/guard/guard.rb.orig +0 -42
- data/lib/guard/guardfile.rb.orig +0 -43
- data/lib/guard/guardfile/evaluator.rb.orig +0 -275
- data/lib/guard/internals/debugging.rb.orig +0 -0
- data/lib/guard/internals/environment.rb.orig +0 -0
- data/lib/guard/internals/tracing.rb.orig +0 -0
- data/lib/guard/notifiers/base.rb.orig +0 -221
- data/lib/guard/notifiers/tmux.rb.orig +0 -339
- data/lib/guard/plugin_util.rb.orig +0 -186
- data/lib/guard/runner.rb.orig +0 -210
- data/lib/guard/setuper.rb +0 -359
- data/lib/guard/setuper.rb.orig +0 -395
- data/lib/guard/ui.rb.orig +0 -278
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2438b30b1e270d58f79c7f2ae9b8e2dce82fd6ad
|
4
|
+
data.tar.gz: 50e9fa2441d8eefc8aa4adb62405765086eaeda3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d87720ec63302aaeeaacd21db3b76bc76768649af94ead543aba9cba5422f3a934db2e3d6172f7e5f3ec5d8a0ac3d7d3a7d4ba275c16adc52acdf51b2f510f4b
|
7
|
+
data.tar.gz: 09427674cac325111ae666ec7043e559c5fd4ec7f96125d9ac929e6858aa962ca40a021541b3de6c67f8eb1e49b29c4a5aede1f98daa42617c73e257381833dd
|
data/README.md
CHANGED
@@ -291,13 +291,6 @@ $ bundle exec guard start -B
|
|
291
291
|
$ bundle exec guard start --no-bundler-warning
|
292
292
|
```
|
293
293
|
|
294
|
-
#### `--show-deprecations`
|
295
|
-
|
296
|
-
This option is deprecated. No, seriously! Deprecations are now always shown.
|
297
|
-
|
298
|
-
(To *really* hide them, set the environment variable `GUARD_GEM_SILENCE_DEPRECATIONS=1`)
|
299
|
-
|
300
|
-
|
301
294
|
#### `-l`/`--latency` option
|
302
295
|
|
303
296
|
Overwrite Listen's default latency, useful when your hard-drive / system is slow.
|
data/lib/guard.rb
CHANGED
@@ -1,210 +1,278 @@
|
|
1
|
-
require "
|
1
|
+
require "thread"
|
2
|
+
require "listen"
|
3
|
+
|
4
|
+
require "guard/config"
|
5
|
+
require "guard/deprecated/guard" unless Guard::Config.new.strict?
|
6
|
+
|
7
|
+
require "guard/internals/debugging"
|
8
|
+
require "guard/internals/traps"
|
9
|
+
require "guard/internals/helpers"
|
10
|
+
|
11
|
+
require "guard/metadata"
|
12
|
+
require "guard/options"
|
2
13
|
|
3
14
|
require "guard/commander"
|
4
|
-
require "guard/deprecated_methods"
|
5
|
-
require "guard/deprecator"
|
6
15
|
require "guard/dsl"
|
7
|
-
require "guard/group"
|
8
|
-
require "guard/guardfile"
|
9
16
|
require "guard/interactor"
|
10
17
|
require "guard/notifier"
|
11
18
|
require "guard/plugin_util"
|
12
19
|
require "guard/runner"
|
13
|
-
require "guard/setuper"
|
14
20
|
require "guard/sheller"
|
15
21
|
require "guard/ui"
|
16
22
|
require "guard/watcher"
|
17
|
-
require "guard/reevaluator"
|
18
23
|
|
19
24
|
# Guard is the main module for all Guard related modules and classes.
|
20
25
|
# Also Guard plugins should use this namespace.
|
21
26
|
#
|
22
27
|
module Guard
|
23
|
-
|
24
|
-
|
25
|
-
extend Commander
|
26
|
-
extend DeprecatedMethods
|
27
|
-
extend Setuper
|
28
|
+
Deprecated::Guard.add_deprecated(self) unless Config.new.strict?
|
28
29
|
|
29
30
|
class << self
|
30
|
-
|
31
|
+
attr_reader :listener
|
31
32
|
|
32
|
-
|
33
|
-
@scope = new_scope
|
34
|
-
@scope.dup.freeze
|
35
|
-
end
|
33
|
+
include Internals::Helpers
|
36
34
|
|
37
|
-
|
38
|
-
fail "::Guard.setup() not called" if @scope.nil?
|
39
|
-
@scope.dup.freeze
|
40
|
-
end
|
41
|
-
attr_reader :runner, :listener
|
42
|
-
|
43
|
-
# Smart accessor for retrieving specific plugins at once.
|
44
|
-
#
|
45
|
-
# @see Guard.plugin
|
46
|
-
# @see Guard.group
|
47
|
-
# @see Guard.groups
|
48
|
-
#
|
49
|
-
# @example Filter plugins by String or Symbol
|
50
|
-
# Guard.plugins('rspec')
|
51
|
-
# Guard.plugins(:rspec)
|
35
|
+
# Initializes the Guard singleton:
|
52
36
|
#
|
53
|
-
#
|
54
|
-
#
|
37
|
+
# * Initialize the internal Guard state;
|
38
|
+
# * Create the interactor
|
39
|
+
# * Select and initialize the file change listener.
|
55
40
|
#
|
56
|
-
# @
|
57
|
-
#
|
41
|
+
# @option options [Boolean] clear if auto clear the UI should be done
|
42
|
+
# @option options [Boolean] notify if system notifications should be shown
|
43
|
+
# @option options [Boolean] debug if debug output should be shown
|
44
|
+
# @option options [Array<String>] group the list of groups to start
|
45
|
+
# @option options [Array<String>] watchdir the directories to watch
|
46
|
+
# @option options [String] guardfile the path to the Guardfile
|
58
47
|
#
|
59
|
-
# @
|
60
|
-
# plugins
|
61
|
-
# @return [Plugin, Array<Plugin>] the filtered plugin(s)
|
48
|
+
# @return [Guard] the Guard singleton
|
62
49
|
#
|
63
|
-
def plugins(filter = nil)
|
64
|
-
@plugins ||= []
|
65
50
|
|
66
|
-
|
51
|
+
# TODO: this method has too many instance variables
|
52
|
+
# and some are mock and leak between tests,
|
53
|
+
# so ideally there should be a guard "instance"
|
54
|
+
# object that can be created anew between tests
|
55
|
+
def setup(opts = {})
|
56
|
+
# NOTE: must be set before anything calls Guard.options
|
57
|
+
reset_options(opts)
|
67
58
|
|
68
|
-
|
69
|
-
|
70
|
-
@plugins.select do |plugin|
|
71
|
-
plugin.name == filter.to_s.downcase.gsub("-", "")
|
72
|
-
end
|
73
|
-
when Regexp
|
74
|
-
@plugins.select do |plugin|
|
75
|
-
plugin.name =~ filter
|
76
|
-
end
|
77
|
-
when Hash
|
78
|
-
@plugins.select do |plugin|
|
79
|
-
filter.all? do |k, v|
|
80
|
-
case k
|
81
|
-
when :name
|
82
|
-
plugin.name == v.to_s.downcase.gsub("-", "")
|
83
|
-
when :group
|
84
|
-
plugin.group.name == v.to_sym
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
59
|
+
# NOTE: must be set before anything calls Guard::UI.debug
|
60
|
+
::Guard::Internals::Debugging.start if options[:debug]
|
89
61
|
|
90
|
-
|
62
|
+
@queue = Queue.new
|
63
|
+
self.watchdirs = Array(options[:watchdir])
|
64
|
+
|
65
|
+
::Guard::UI.reset_and_clear
|
66
|
+
|
67
|
+
_reset_all
|
68
|
+
evaluate_guardfile
|
69
|
+
setup_scope
|
70
|
+
|
71
|
+
@listener = _setup_listener
|
72
|
+
|
73
|
+
::Guard::Notifier.connect(notify: options[:notify])
|
74
|
+
|
75
|
+
traps = Internals::Traps
|
76
|
+
traps.handle("USR1") { async_queue_add([:guard_pause, :paused]) }
|
77
|
+
traps.handle("USR2") { async_queue_add([:guard_pause, :unpaused]) }
|
78
|
+
|
79
|
+
@interactor = ::Guard::Interactor.new(options[:no_interactions])
|
80
|
+
traps.handle("INT") { @interactor.handle_interrupt }
|
81
|
+
|
82
|
+
self
|
91
83
|
end
|
92
84
|
|
93
|
-
|
94
|
-
|
95
|
-
#
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
#
|
101
|
-
# Guard.plugin(:rspec)
|
102
|
-
#
|
103
|
-
# @example Find a plugin by Regexp
|
104
|
-
# Guard.plugin(/rsp.+/)
|
105
|
-
#
|
106
|
-
# @example Find a plugin by Hash
|
107
|
-
# Guard.plugin(name: 'rspec', group: 'backend')
|
85
|
+
attr_reader :interactor
|
86
|
+
|
87
|
+
# Used only by tests (for all I know...)
|
88
|
+
def clear_options
|
89
|
+
@options = nil
|
90
|
+
end
|
91
|
+
|
92
|
+
# Initializes the groups array with the default group(s).
|
108
93
|
#
|
109
|
-
# @
|
110
|
-
# plugin the Guard plugin
|
111
|
-
# @return [Plugin, nil] the plugin found, nil otherwise
|
94
|
+
# @see DEFAULT_GROUPS
|
112
95
|
#
|
113
|
-
def
|
114
|
-
|
96
|
+
def reset_groups
|
97
|
+
@groups = DEFAULT_GROUPS.map { |name| Group.new(name) }
|
115
98
|
end
|
116
99
|
|
117
|
-
#
|
100
|
+
# Initializes the plugins array to an empty array.
|
118
101
|
#
|
119
|
-
# @see Guard.plugin
|
120
102
|
# @see Guard.plugins
|
121
|
-
# @see Guard.group
|
122
103
|
#
|
123
|
-
|
124
|
-
|
125
|
-
|
104
|
+
def reset_plugins
|
105
|
+
@plugins = []
|
106
|
+
end
|
107
|
+
|
108
|
+
attr_reader :watchdirs
|
109
|
+
|
110
|
+
# Stores the scopes defined by the user via the `--group` / `-g` option (to
|
111
|
+
# run only a specific group) or the `--plugin` / `-P` option (to run only a
|
112
|
+
# specific plugin).
|
113
|
+
#
|
114
|
+
# @see CLI#start
|
115
|
+
# @see Dsl#scope
|
126
116
|
#
|
127
|
-
|
128
|
-
|
117
|
+
def setup_scope(scope = {})
|
118
|
+
# TODO: there should be a special Scope class instead
|
119
|
+
scope = _prepare_scope(scope)
|
120
|
+
|
121
|
+
::Guard.scope = {
|
122
|
+
groups: scope[:groups].map { |item| ::Guard.add_group(item) },
|
123
|
+
plugins: scope[:plugins].map { |item| ::Guard.plugin(item) },
|
124
|
+
}
|
125
|
+
end
|
126
|
+
|
127
|
+
# Evaluates the Guardfile content. It displays an error message if no
|
128
|
+
# Guard plugins are instantiated after the Guardfile evaluation.
|
129
129
|
#
|
130
|
-
# @
|
131
|
-
# @return [Array<Group>] the filtered group(s)
|
130
|
+
# @see Guard::Guardfile::Evaluator#evaluate_guardfile
|
132
131
|
#
|
133
|
-
def
|
134
|
-
|
132
|
+
def evaluate_guardfile
|
133
|
+
evaluator = Guard::Guardfile::Evaluator.new(options)
|
134
|
+
evaluator.evaluate_guardfile
|
135
135
|
|
136
|
-
|
136
|
+
# FIXME: temporary hack while due to upcoming refactorings
|
137
|
+
options[:guardfile] = evaluator.guardfile_path
|
137
138
|
|
138
|
-
|
139
|
-
|
140
|
-
@groups.select { |group| group.name == filter.to_sym }
|
141
|
-
when Regexp
|
142
|
-
@groups.select { |group| group.name.to_s =~ filter }
|
143
|
-
else
|
144
|
-
fail "Invalid filter: #{filter.inspect}"
|
145
|
-
end
|
139
|
+
msg = "No plugins found in Guardfile, please add at least one."
|
140
|
+
::Guard::UI.error msg if _pluginless_guardfile?
|
146
141
|
end
|
147
142
|
|
148
|
-
#
|
149
|
-
#
|
150
|
-
|
151
|
-
|
152
|
-
#
|
143
|
+
# @private api
|
144
|
+
# used solely for match_guardfile?
|
145
|
+
attr_reader :guardfile_path
|
146
|
+
|
147
|
+
# Asynchronously trigger changes
|
153
148
|
#
|
154
|
-
#
|
155
|
-
# Guard.group('backend')
|
156
|
-
# Guard.group(:backend)
|
149
|
+
# Currently supported args:
|
157
150
|
#
|
158
|
-
#
|
159
|
-
# Guard.group(/(back|front)end/)
|
151
|
+
# old style hash: {modified: ['foo'], added: ['bar'], removed: []}
|
160
152
|
#
|
161
|
-
#
|
162
|
-
# @return [Group] the group found, nil otherwise
|
153
|
+
# new style signals with args: [:guard_pause, :unpaused ]
|
163
154
|
#
|
164
|
-
def
|
165
|
-
|
155
|
+
def async_queue_add(changes)
|
156
|
+
@queue << changes
|
157
|
+
|
158
|
+
# Putting interactor in background puts guard into foreground
|
159
|
+
# so it can handle change notifications
|
160
|
+
Thread.new { interactor.background }
|
166
161
|
end
|
167
162
|
|
168
|
-
|
169
|
-
|
170
|
-
# @param [String] name the Guard name
|
171
|
-
# @param [Hash] options the plugin options (see Plugin documentation)
|
172
|
-
# @option options [String] group the group to which the plugin belongs
|
173
|
-
# @option options [Array<Watcher>] watchers the list of declared watchers
|
174
|
-
# @option options [Array<Hash>] callbacks the list of callbacks
|
175
|
-
# @return [Plugin] the added Guard plugin
|
176
|
-
# @see Plugin
|
177
|
-
#
|
178
|
-
def add_plugin(name, options = {})
|
179
|
-
instance = ::Guard::PluginUtil.new(name).initialize_plugin(options)
|
180
|
-
@plugins << instance
|
181
|
-
instance
|
163
|
+
def pending_changes?
|
164
|
+
! @queue.empty?
|
182
165
|
end
|
183
166
|
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
@plugins.delete(plugin)
|
167
|
+
def watchdirs=(dirs)
|
168
|
+
dirs = [Dir.pwd] if dirs.empty?
|
169
|
+
@watchdirs = dirs.map { |dir| File.expand_path dir }
|
188
170
|
end
|
189
171
|
|
190
|
-
|
191
|
-
|
192
|
-
#
|
193
|
-
# @option options [Boolean] halt_on_fail if a task execution
|
194
|
-
# should be halted for all Guard plugins in this group if
|
195
|
-
# one Guard throws `:task_has_failed`
|
196
|
-
# @return [Group] the group added (or retrieved from the `@groups`
|
197
|
-
# variable if already present)
|
198
|
-
#
|
199
|
-
# @see Group
|
172
|
+
private
|
173
|
+
|
174
|
+
# Initializes the listener and registers a callback for changes.
|
200
175
|
#
|
201
|
-
def
|
202
|
-
|
203
|
-
|
204
|
-
|
176
|
+
def _setup_listener
|
177
|
+
if options[:listen_on]
|
178
|
+
Listen.on(options[:listen_on], &_listener_callback)
|
179
|
+
else
|
180
|
+
listener_options = {}
|
181
|
+
[:latency, :force_polling, :wait_for_delay].each do |option|
|
182
|
+
listener_options[option] = options[option] if options[option]
|
183
|
+
end
|
184
|
+
listen_args = watchdirs + [listener_options]
|
185
|
+
Listen.to(*listen_args, &_listener_callback)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
# Process the change queue, running tasks within the main Guard thread
|
190
|
+
def _process_queue
|
191
|
+
actions, changes = [], { modified: [], added: [], removed: [] }
|
192
|
+
|
193
|
+
while pending_changes?
|
194
|
+
if (item = @queue.pop).first.is_a?(Symbol)
|
195
|
+
actions << item
|
196
|
+
else
|
197
|
+
item.each { |key, value| changes[key] += value }
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
_run_actions(actions)
|
202
|
+
return if changes.values.all?(&:empty?)
|
203
|
+
Runner.new.run_on_changes(*changes.values)
|
204
|
+
end
|
205
|
+
|
206
|
+
# TODO: Guard::Watch or Guard::Scope should provide this
|
207
|
+
def _scoped_watchers
|
208
|
+
watchers = []
|
209
|
+
Runner.new.send(:_scoped_plugins) { |guard| watchers += guard.watchers }
|
210
|
+
watchers
|
211
|
+
end
|
212
|
+
|
213
|
+
# Check if any of the changes are actually watched for
|
214
|
+
def _relevant_changes?(changes)
|
215
|
+
files = changes.values.flatten(1)
|
216
|
+
watchers = _scoped_watchers
|
217
|
+
watchers.any? { |watcher| files.any? { |file| watcher.match(file) } }
|
218
|
+
end
|
219
|
+
|
220
|
+
def _relative_pathnames(paths)
|
221
|
+
paths.map { |path| _relative_pathname(path) }
|
222
|
+
end
|
223
|
+
|
224
|
+
def _run_actions(actions)
|
225
|
+
actions.each do |action_args|
|
226
|
+
args = action_args.dup
|
227
|
+
namespaced_action = args.shift
|
228
|
+
action = namespaced_action.to_s.sub(/^guard_/, "")
|
229
|
+
if ::Guard.respond_to?(action)
|
230
|
+
::Guard.send(action, *args)
|
231
|
+
else
|
232
|
+
fail "Unknown action: #{action.inspect}"
|
233
|
+
end
|
205
234
|
end
|
235
|
+
end
|
236
|
+
|
237
|
+
def _listener_callback
|
238
|
+
lambda do |modified, added, removed|
|
239
|
+
relative_paths = {
|
240
|
+
modified: _relative_pathnames(modified),
|
241
|
+
added: _relative_pathnames(added),
|
242
|
+
removed: _relative_pathnames(removed)
|
243
|
+
}
|
244
|
+
|
245
|
+
async_queue_add(relative_paths) if _relevant_changes?(relative_paths)
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
def _reset_all
|
250
|
+
reset_groups
|
251
|
+
reset_plugins
|
252
|
+
reset_scope
|
253
|
+
end
|
254
|
+
|
255
|
+
def _pluginless_guardfile?
|
256
|
+
# no Reevaluator means there was no Guardfile configured that could be
|
257
|
+
# reevaluated, so we don't have a pluginless guardfile, because we don't
|
258
|
+
# have a Guardfile to begin with...
|
259
|
+
#
|
260
|
+
# But, if we have a Guardfile, we'll at least have the built-in
|
261
|
+
# Reevaluator, so the following will work:
|
262
|
+
|
263
|
+
# TODO: this is a workaround for tests
|
264
|
+
return true if plugins.empty?
|
265
|
+
|
266
|
+
plugins.map(&:name) == ["reevaluator"]
|
267
|
+
end
|
206
268
|
|
207
|
-
|
269
|
+
def _reset_for_tests
|
270
|
+
@options = nil
|
271
|
+
@queue = nil
|
272
|
+
@watchdirs = nil
|
273
|
+
@listener = nil
|
274
|
+
@interactor = nil
|
275
|
+
@scope = nil
|
208
276
|
end
|
209
277
|
end
|
210
278
|
end
|