guard 2.8.2 → 2.9.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|