guard 2.10.0 → 2.10.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6996dd69034de1636618026e8606df7f10b2b22b
4
- data.tar.gz: c374f6846a61be304447f9518ad72d219ba0b12f
3
+ metadata.gz: 100b160735c5c331821d9fa8119bb168ed5f907e
4
+ data.tar.gz: d677f7e1a7491ff72654d415d7c571f028fbef52
5
5
  SHA512:
6
- metadata.gz: 2d4cf024a8ce54ad66c2bd9ba03b46a457924da685ec6987e6ae0c4823e2ebc30fd15627b9dae5b01f7c844158cc420f1396d532c525e4b6d4175feb0167aef2
7
- data.tar.gz: fc31605dee865f1371c2e6fca5d71c35ef7f4d1ca5255acf364972f9312785ebb897776e985632d966edc88b58b0d9e2d913b6987a9cc9576943041b0e74f304
6
+ metadata.gz: 0dcad099ca8bd1dca2486e078233215366c4236b8a1b0b465336d020667e041bd16e75df106efeef75a6013fcdb9601fdd35bd28eac8130c4eb3a910694004a3
7
+ data.tar.gz: 835a20ae288b6c660d9cb058eeba5b2c25f999bc3790c0dfb0ccf48a7816eff2405fe82e26cc9884b2397f02a610ba73f848c63bf89eb478fd94aae632ff31f7
data/lib/guard.rb CHANGED
@@ -60,8 +60,15 @@ module Guard
60
60
  _evaluate(state.session.evaluator_options)
61
61
 
62
62
  # NOTE: this should be *after* evaluate so :directories can work
63
+ # TODO: move listener setup to session?
63
64
  @listener = Listen.send(*state.session.listener_args, &_listener_callback)
64
65
 
66
+ ignores = state.session.guardfile_ignore
67
+ @listener.ignore(ignores) unless ignores.empty?
68
+
69
+ ignores = state.session.guardfile_ignore_bang
70
+ @listener.ignore!(ignores) unless ignores.empty?
71
+
65
72
  Notifier.connect(state.session.notify_options)
66
73
 
67
74
  traps = Internals::Traps
@@ -86,9 +93,11 @@ module Guard
86
93
  #
87
94
  # Currently supported args:
88
95
  #
89
- # old style hash: {modified: ['foo'], added: ['bar'], removed: []}
96
+ # @example Old style hash:
97
+ # async_queue_add(modified: ['foo'], added: ['bar'], removed: [])
90
98
  #
91
- # new style signals with args: [:guard_pause, :unpaused ]
99
+ # @example New style signals with args:
100
+ # async_queue_add([:guard_pause, :unpaused ])
92
101
  #
93
102
  def async_queue_add(changes)
94
103
  @queue << changes
data/lib/guard.rb.orig CHANGED
@@ -8,11 +8,13 @@ require "guard/internals/debugging"
8
8
  require "guard/internals/traps"
9
9
  require "guard/internals/helpers"
10
10
 
11
- require "guard/metadata"
12
- require "guard/options"
11
+ require "guard/internals/queue"
12
+ require "guard/internals/state"
13
13
 
14
+ require "guard/options"
14
15
  require "guard/commander"
15
16
  require "guard/dsl"
17
+ require "guard/group"
16
18
  require "guard/interactor"
17
19
  require "guard/notifier"
18
20
  require "guard/plugin_util"
@@ -20,6 +22,7 @@ require "guard/runner"
20
22
  require "guard/sheller"
21
23
  require "guard/ui"
22
24
  require "guard/watcher"
25
+ require "guard/guardfile/evaluator"
23
26
 
24
27
  # Guard is the main module for all Guard related modules and classes.
25
28
  # Also Guard plugins should use this namespace.
@@ -30,6 +33,9 @@ module Guard
30
33
  class << self
31
34
  attr_reader :listener
32
35
 
36
+ # @private api
37
+ attr_reader :queue
38
+
33
39
  include Internals::Helpers
34
40
 
35
41
  # Initializes the Guard singleton:
@@ -46,103 +52,52 @@ module Guard
46
52
  # @option options [String] guardfile the path to the Guardfile
47
53
  #
48
54
  # @return [Guard] the Guard singleton
49
- #
55
+ def setup(cmdline_options = {})
56
+ init(cmdline_options)
50
57
 
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)
58
+ @queue = Internals::Queue.new(Guard)
58
59
 
59
- # NOTE: must be set before anything calls Guard::UI.debug
60
- ::Guard::Internals::Debugging.start if options[:debug]
60
+ _evaluate(state.session.evaluator_options)
61
61
 
62
- @queue = Queue.new
63
- self.watchdirs = Array(options[:watchdir])
62
+ # NOTE: this should be *after* evaluate so :directories can work
63
+ # TODO: move listener setup to session?
64
+ @listener = Listen.send(*state.session.listener_args, &_listener_callback)
64
65
 
65
- ::Guard::UI.reset_and_clear
66
+ ignores = state.session.guardfile_ignore
67
+ @listener.ignore(ignores) unless ignores.empty?
66
68
 
67
- @listener = _setup_listener
69
+ ignores = state.session.guardfile_ignore_bang
70
+ @listener.ignore!(ignores) unless ignores.empty?
68
71
 
69
- _reset_all
70
- evaluate_guardfile
71
- setup_scope
72
-
73
- ::Guard::Notifier.connect(notify: options[:notify])
72
+ Notifier.connect(state.session.notify_options)
74
73
 
75
74
  traps = Internals::Traps
76
75
  traps.handle("USR1") { async_queue_add([:guard_pause, :paused]) }
77
76
  traps.handle("USR2") { async_queue_add([:guard_pause, :unpaused]) }
78
77
 
79
- @interactor = ::Guard::Interactor.new(options[:no_interactions])
78
+ @interactor = Interactor.new(state.session.interactor_name == :sleep)
80
79
  traps.handle("INT") { @interactor.handle_interrupt }
81
80
 
82
81
  self
83
82
  end
84
83
 
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).
93
- #
94
- # @see DEFAULT_GROUPS
95
- #
96
- def reset_groups
97
- @groups = DEFAULT_GROUPS.map { |name| Group.new(name) }
98
- end
99
-
100
- # Initializes the plugins array to an empty array.
101
- #
102
- # @see Guard.plugins
103
- #
104
- def reset_plugins
105
- @plugins = []
84
+ def init(cmdline_options)
85
+ @state = Internals::State.new(cmdline_options)
106
86
  end
107
87
 
108
- attr_reader :watchdirs
88
+ attr_reader :state
109
89
 
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
116
- #
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
- #
130
- # @see Guard::Guardfile::Evaluator#evaluate_guardfile
131
- #
132
- def evaluate_guardfile
133
- evaluator = Guard::Guardfile::Evaluator.new(options)
134
- evaluator.evaluate_guardfile
135
- msg = "No plugins found in Guardfile, please add at least one."
136
- ::Guard::UI.error msg if _pluginless_guardfile?
137
- end
90
+ attr_reader :interactor
138
91
 
139
92
  # Asynchronously trigger changes
140
93
  #
141
94
  # Currently supported args:
142
95
  #
143
- # old style hash: {modified: ['foo'], added: ['bar'], removed: []}
96
+ # @example Old style hash:
97
+ # async_queue_add(modified: ['foo'], added: ['bar'], removed: [])
144
98
  #
145
- # new style signals with args: [:guard_pause, :unpaused ]
99
+ # @example New style signals with args:
100
+ # async_queue_add([:guard_pause, :unpaused ])
146
101
  #
147
102
  def async_queue_add(changes)
148
103
  @queue << changes
@@ -152,60 +107,17 @@ module Guard
152
107
  Thread.new { interactor.background }
153
108
  end
154
109
 
155
- def pending_changes?
156
- ! @queue.empty?
157
- end
158
-
159
- def watchdirs=(dirs)
160
- dirs = [Dir.pwd] if dirs.empty?
161
- @watchdirs = dirs.map { |dir| File.expand_path dir }
162
- end
163
-
164
110
  private
165
111
 
166
- # Initializes the listener and registers a callback for changes.
167
- #
168
- def _setup_listener
169
- if options[:listen_on]
170
- Listen.on(options[:listen_on], &_listener_callback)
171
- else
172
- listener_options = {}
173
- [:latency, :force_polling, :wait_for_delay].each do |option|
174
- listener_options[option] = options[option] if options[option]
175
- end
176
- listen_args = watchdirs + [listener_options]
177
- Listen.to(*listen_args, &_listener_callback)
178
- end
179
- end
180
-
181
- # Process the change queue, running tasks within the main Guard thread
182
- def _process_queue
183
- actions, changes = [], { modified: [], added: [], removed: [] }
184
-
185
- while pending_changes?
186
- if (item = @queue.pop).first.is_a?(Symbol)
187
- actions << item
188
- else
189
- item.each { |key, value| changes[key] += value }
190
- end
191
- end
192
-
193
- _run_actions(actions)
194
- return if changes.values.all?(&:empty?)
195
- Runner.new.run_on_changes(*changes.values)
196
- end
197
-
198
- # TODO: Guard::Watch or Guard::Scope should provide this
199
- def _scoped_watchers
200
- watchers = []
201
- Runner.new.send(:_scoped_plugins) { |guard| watchers += guard.watchers }
202
- watchers
203
- end
204
-
205
112
  # Check if any of the changes are actually watched for
113
+ # TODO: why iterate twice? reuse this info when running tasks
206
114
  def _relevant_changes?(changes)
115
+ # TODO: no coverage!
207
116
  files = changes.values.flatten(1)
208
- watchers = _scoped_watchers
117
+ scope = Guard.state.scope
118
+ watchers = scope.grouped_plugins.map do |_group, plugins|
119
+ plugins.map(&:watchers).flatten
120
+ end.flatten
209
121
  watchers.any? { |watcher| files.any? { |file| watcher.match(file) } }
210
122
  end
211
123
 
@@ -213,19 +125,6 @@ module Guard
213
125
  paths.map { |path| _relative_pathname(path) }
214
126
  end
215
127
 
216
- def _run_actions(actions)
217
- actions.each do |action_args|
218
- args = action_args.dup
219
- namespaced_action = args.shift
220
- action = namespaced_action.to_s.sub(/^guard_/, "")
221
- if ::Guard.respond_to?(action)
222
- ::Guard.send(action, *args)
223
- else
224
- fail "Unknown action: #{action.inspect}"
225
- end
226
- end
227
- end
228
-
229
128
  def _listener_callback
230
129
  lambda do |modified, added, removed|
231
130
  relative_paths = {
@@ -238,12 +137,7 @@ module Guard
238
137
  end
239
138
  end
240
139
 
241
- def _reset_all
242
- reset_groups
243
- reset_plugins
244
- reset_scope
245
- end
246
-
140
+ # TODO: obsoleted? (move to Dsl?)
247
141
  def _pluginless_guardfile?
248
142
  # no Reevaluator means there was no Guardfile configured that could be
249
143
  # reevaluated, so we don't have a pluginless guardfile, because we don't
@@ -252,20 +146,29 @@ module Guard
252
146
  # But, if we have a Guardfile, we'll at least have the built-in
253
147
  # Reevaluator, so the following will work:
254
148
 
255
- # TODO: this is a workaround for tests
256
- return true if plugins.empty?
257
-
258
- plugins.map(&:name) == ["reevaluator"]
149
+ plugins = state.session.plugins.all
150
+ plugins.empty? || plugins.map(&:name) == ["reevaluator"]
259
151
  end
260
152
 
261
- def _reset_for_tests
262
- @options = nil
263
- @queue = nil
264
- @watchdirs = nil
265
- @watchdirs = nil
266
- @listener = nil
267
- @interactor = nil
268
- @scope = nil
153
+ def _evaluate(options)
154
+ evaluator = Guardfile::Evaluator.new(options)
155
+ evaluator.evaluate
156
+
157
+ # TODO: remove this workaround when options are removed
158
+ state.session.clearing(state.session.options[:clear])
159
+
160
+ UI.reset_and_clear
161
+
162
+ msg = "No plugins found in Guardfile, please add at least one."
163
+ UI.error msg if _pluginless_guardfile?
164
+
165
+ if evaluator.inline?
166
+ UI.info("Using inline Guardfile.")
167
+ elsif evaluator.custom?
168
+ UI.info("Using Guardfile at #{ evaluator.path }.")
169
+ end
170
+ rescue Guardfile::Evaluator::NoPluginsError => e
171
+ UI.error(e.message)
269
172
  end
270
173
  end
271
174
  end
data/lib/guard/dsl.rb CHANGED
@@ -5,8 +5,6 @@ require "guard/ui"
5
5
  require "guard/watcher"
6
6
 
7
7
  require "guard/deprecated/dsl" unless Guard::Config.new.strict?
8
-
9
- # TODO: only for listener
10
8
  require "guard"
11
9
 
12
10
  module Guard
@@ -75,6 +73,7 @@ module Guard
75
73
  # @see Guard::Notifier for available notifier and its options.
76
74
  #
77
75
  def notification(notifier, options = {})
76
+ # TODO: remove dependency on Notifier (let session handle this)
78
77
  Notifier.add(notifier.to_sym, options.merge(silent: false))
79
78
  end
80
79
 
@@ -90,6 +89,7 @@ module Guard
90
89
  # options
91
90
  #
92
91
  def interactor(options)
92
+ # TODO: remove dependency on Interactor (let session handle this)
93
93
  case options
94
94
  when :off
95
95
  Interactor.enabled = false
@@ -132,6 +132,7 @@ module Guard
132
132
 
133
133
  if block_given?
134
134
  groups.each do |group|
135
+ # TODO: let groups be added *after* evaluation
135
136
  Guard.state.session.groups.add(group, options)
136
137
  end
137
138
 
@@ -181,6 +182,7 @@ module Guard
181
182
  groups = @current_groups && @current_groups.last || [:default]
182
183
  groups.each do |group|
183
184
  opts = @plugin_options.merge(group: group)
185
+ # TODO: let plugins be added *after* evaluation
184
186
  Guard.state.session.plugins.add(name, opts)
185
187
  end
186
188
 
@@ -227,11 +229,10 @@ module Guard
227
229
  # `run_on_additions`, `run_on_modifications` and `run_on_removals` plugin
228
230
  # method.
229
231
  #
230
- # @example Define a callback that'll be called before the `reload` action.
232
+ # @example Add callback before the `reload` action.
231
233
  # callback(:reload_begin) { puts "Let's reload!" }
232
234
  #
233
- # @example Define a callback that'll be called before the `start` and
234
- # `stop` actions.
235
+ # @example Add callback before the `start` and `stop` actions.
235
236
  #
236
237
  # my_lambda = lambda do |plugin, event, *args|
237
238
  # puts "Let's #{event} #{plugin} with #{args}!"
@@ -264,8 +265,8 @@ module Guard
264
265
  # @param [Regexp] regexps a pattern (or list of patterns) for ignoring paths
265
266
  #
266
267
  def ignore(*regexps)
267
- # TODO: instead, use Guard.reconfigure(ignore: regexps) or something
268
- Guard.listener.ignore(regexps) if Guard.listener
268
+ # TODO: use guardfile results class
269
+ Guard.state.session.guardfile_ignore = regexps
269
270
  end
270
271
 
271
272
  # TODO: deprecate
@@ -281,8 +282,11 @@ module Guard
281
282
  def ignore!(*regexps)
282
283
  @ignore_regexps ||= []
283
284
  @ignore_regexps << regexps
284
- Guard.listener.ignore!(@ignore_regexps) if Guard.listener
285
+ # TODO: use guardfile results class
286
+ Guard.state.session.guardfile_ignore_bang = @ignore_regexps
285
287
  end
288
+
289
+ # TODO: deprecate
286
290
  alias filter! ignore!
287
291
 
288
292
  # Configures the Guard logger.
@@ -366,6 +370,7 @@ module Guard
366
370
  # @param [Hash] scopes the scope for the groups and plugins
367
371
  #
368
372
  def scope(scope = {})
373
+ # TODO: use a Guardfile::Results class
369
374
  Guard.state.session.guardfile_scope(scope)
370
375
  end
371
376
 
@@ -26,10 +26,10 @@ module Guard
26
26
  # {Notifier} for more information about the supported libraries.
27
27
  #
28
28
  # A more advanced DSL use is the {#callback} keyword that allows you to
29
- # execute arbitrary code before or after any of the {Plugin::Base#start},
30
- # {Plugin::Base#stop}, {Plugin::Base#reload}, {Plugin::Base#run_all},
31
- # {Plugin::Base#run_on_changes}, {Plugin::Base#run_on_additions},
32
- # {Plugin::Base#run_on_modifications} and {Plugin::Base#run_on_removals}
29
+ # execute arbitrary code before or after any of the {Plugin#start},
30
+ # {Plugin#stop}, {Plugin#reload}, {Plugin#run_all},
31
+ # {Plugin#run_on_changes}, {Plugin#run_on_additions},
32
+ # {Plugin#run_on_modifications} and {Plugin#run_on_removals}
33
33
  # Guard plugins method.
34
34
  # You can even insert more hooks inside these methods. Please [checkout the
35
35
  # Wiki page](https://github.com/guard/guard/wiki/Hooks-and-callbacks) for
@@ -50,6 +50,10 @@ module Guard
50
50
  class Dsl
51
51
  Deprecated::Dsl.add_deprecated(self) unless Config.new.strict?
52
52
 
53
+ # Wrap exceptions during parsing Guardfile
54
+ class Error < RuntimeError
55
+ end
56
+
53
57
  WARN_INVALID_LOG_LEVEL = "Invalid log level `%s` ignored. "\
54
58
  "Please use either :debug, :info, :warn or :error."
55
59
 
@@ -88,9 +92,9 @@ module Guard
88
92
  def interactor(options)
89
93
  case options
90
94
  when :off
91
- ::Guard::Interactor.enabled = false
95
+ Interactor.enabled = false
92
96
  when Hash
93
- ::Guard::Interactor.options = options
97
+ Interactor.options = options
94
98
  end
95
99
  end
96
100
 
@@ -128,7 +132,7 @@ module Guard
128
132
 
129
133
  if block_given?
130
134
  groups.each do |group|
131
- ::Guard.add_group(group, options)
135
+ Guard.state.session.groups.add(group, options)
132
136
  end
133
137
 
134
138
  @current_groups ||= []
@@ -138,7 +142,7 @@ module Guard
138
142
 
139
143
  @current_groups.pop
140
144
  else
141
- ::Guard::UI.error \
145
+ UI.error \
142
146
  "No Guard plugins found in the group '#{ groups.join(", ") }',"\
143
147
  " please add at least one."
144
148
  end
@@ -176,7 +180,8 @@ module Guard
176
180
  @current_groups ||= []
177
181
  groups = @current_groups && @current_groups.last || [:default]
178
182
  groups.each do |group|
179
- ::Guard.add_plugin(name, @plugin_options.merge(group: group))
183
+ opts = @plugin_options.merge(group: group)
184
+ Guard.state.session.plugins.add(name, opts)
180
185
  end
181
186
 
182
187
  @plugin_options = nil
@@ -214,7 +219,7 @@ module Guard
214
219
  @plugin_options ||= nil
215
220
  return guard(:plugin) { watch(pattern, &action) } unless @plugin_options
216
221
 
217
- @plugin_options[:watchers] << ::Guard::Watcher.new(pattern, action)
222
+ @plugin_options[:watchers] << Watcher.new(pattern, action)
218
223
  end
219
224
 
220
225
  # Defines a callback to execute arbitrary code before or after any of
@@ -222,11 +227,10 @@ module Guard
222
227
  # `run_on_additions`, `run_on_modifications` and `run_on_removals` plugin
223
228
  # method.
224
229
  #
225
- # @example Define a callback that'll be called before the `reload` action.
230
+ # @example Add callback before the `reload` action.
226
231
  # callback(:reload_begin) { puts "Let's reload!" }
227
232
  #
228
- # @example Define a callback that'll be called before the `start` and
229
- # `stop` actions.
233
+ # @example Add callback before the `start` and `stop` actions.
230
234
  #
231
235
  # my_lambda = lambda do |plugin, event, *args|
232
236
  # puts "Let's #{event} #{plugin} with #{args}!"
@@ -237,8 +241,6 @@ module Guard
237
241
  # @param [Array] args the callback arguments
238
242
  # @yield a callback block
239
243
  #
240
- # @see Guard::Hooker
241
- #
242
244
  def callback(*args, &block)
243
245
  @plugin_options ||= nil
244
246
  fail "callback must be called within a guard block" unless @plugin_options
@@ -262,8 +264,10 @@ module Guard
262
264
  #
263
265
  def ignore(*regexps)
264
266
  # TODO: instead, use Guard.reconfigure(ignore: regexps) or something
265
- ::Guard.listener.ignore(regexps) if ::Guard.listener
267
+ Guard.listener.ignore(regexps) if Guard.listener
266
268
  end
269
+
270
+ # TODO: deprecate
267
271
  alias filter ignore
268
272
 
269
273
  # Replaces ignored paths globally
@@ -276,7 +280,7 @@ module Guard
276
280
  def ignore!(*regexps)
277
281
  @ignore_regexps ||= []
278
282
  @ignore_regexps << regexps
279
- ::Guard.listener.ignore!(@ignore_regexps) if ::Guard.listener
283
+ Guard.listener.ignore!(@ignore_regexps) if Guard.listener
280
284
  end
281
285
  alias filter! ignore!
282
286
 
@@ -341,7 +345,7 @@ module Guard
341
345
  options[name] = Regexp.new(list.join("|"), Regexp::IGNORECASE)
342
346
  end
343
347
 
344
- ::Guard::UI.options.merge!(options)
348
+ UI.options.merge!(options)
345
349
  end
346
350
 
347
351
  # Sets the default scope on startup
@@ -361,18 +365,68 @@ module Guard
361
365
  # @param [Hash] scopes the scope for the groups and plugins
362
366
  #
363
367
  def scope(scope = {})
364
- ::Guard.setup_scope(scope)
368
+ Guard.state.session.guardfile_scope(scope)
369
+ end
370
+
371
+ def evaluate(contents, filename, lineno) # :nodoc
372
+ instance_eval(contents, filename.to_s, lineno)
373
+ rescue StandardError, ScriptError => e
374
+ prefix = "\n\t(dsl)> "
375
+ cleaned_backtrace = _cleanup_backtrace(e.backtrace)
376
+ backtrace = "#{prefix}#{cleaned_backtrace.join(prefix)}"
377
+ msg = "Invalid Guardfile, original error is: \n\n%s, \nbacktrace: %s"
378
+ raise Error, format(msg, e, backtrace)
365
379
  end
366
380
 
367
- # Sets the directories to pass to Listen (watchdirs)
381
+ # Sets the directories to pass to Listen
368
382
  #
369
383
  # @example watch only given directories
370
384
  # directories %w(lib specs)
371
385
  #
372
- # @param [Array] directories to watch
386
+ # @param [Array] directories directories for Listen to watch
387
+ #
388
+ def directories(directories)
389
+ directories.each do |dir|
390
+ fail "Directory #{dir.inspect} does not exist!" unless Dir.exist?(dir)
391
+ end
392
+ Guard.state.session.watchdirs = directories
393
+ end
394
+
395
+ # Sets Guard to clear the screen before every task is run
396
+ #
397
+ # @example switching clearing the screen on
398
+ # clearing(:on)
373
399
  #
374
- def directories(dirs)
375
- ::Guard.watchdirs = dirs
400
+ # @param [Symbol] on ':on' to turn on, ':off' (default) to turn off
401
+ #
402
+ def clearing(on)
403
+ Guard.state.session.clearing(on == :on)
404
+ end
405
+
406
+ private
407
+
408
+ def _cleanup_backtrace(backtrace)
409
+ dirs = { File.realpath(Dir.pwd) => ".", }
410
+
411
+ gem_env = ENV["GEM_HOME"] || ""
412
+ dirs[gem_env] = "$GEM_HOME" unless gem_env.empty?
413
+
414
+ gem_paths = (ENV["GEM_PATH"] || "").split(File::PATH_SEPARATOR)
415
+ gem_paths.each_with_index do |path, index|
416
+ dirs[path] = "$GEM_PATH[#{index}]"
417
+ end
418
+
419
+ backtrace.dup.map do |raw_line|
420
+ path = nil
421
+ symlinked_path = raw_line.split(":").first
422
+ begin
423
+ path = raw_line.sub(symlinked_path, File.realpath(symlinked_path))
424
+ dirs.detect { |dir, name| path.sub!(File.realpath(dir), name) }
425
+ path
426
+ rescue Errno::ENOENT
427
+ path || symlinked_path
428
+ end
429
+ end
376
430
  end
377
431
  end
378
432
  end