guard 2.9.2 → 2.10.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 +41 -3
- data/lib/guard.rb +6 -2
- data/lib/guard/deprecated/guard.rb +12 -0
- data/lib/guard/deprecated/guard.rb.orig +178 -0
- data/lib/guard/dsl.rb +25 -14
- data/lib/guard/internals/session.rb +7 -2
- data/lib/guard/internals/session.rb.orig +135 -0
- data/lib/guard/templates/Guardfile +4 -2
- data/lib/guard/ui.rb.orig +274 -0
- data/lib/guard/version.rb +1 -1
- metadata +4 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6996dd69034de1636618026e8606df7f10b2b22b
|
4
|
+
data.tar.gz: c374f6846a61be304447f9518ad72d219ba0b12f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2d4cf024a8ce54ad66c2bd9ba03b46a457924da685ec6987e6ae0c4823e2ebc30fd15627b9dae5b01f7c844158cc420f1396d532c525e4b6d4175feb0167aef2
|
7
|
+
data.tar.gz: fc31605dee865f1371c2e6fca5d71c35ef7f4d1ca5255acf364972f9312785ebb897776e985632d966edc88b58b0d9e2d913b6987a9cc9576943041b0e74f304
|
data/README.md
CHANGED
@@ -198,10 +198,11 @@ $ bundle exec guard --clear
|
|
198
198
|
$ bundle exec guard -c # shortcut
|
199
199
|
```
|
200
200
|
|
201
|
-
You
|
201
|
+
You may prefer to enable clearing in all projects by addin the `clearing`
|
202
|
+
statement (described below) in you `~/.guardrc` instead:
|
202
203
|
|
203
|
-
```
|
204
|
-
|
204
|
+
```ruby
|
205
|
+
clearing :on
|
205
206
|
```
|
206
207
|
|
207
208
|
#### `-n`/`--notify` option
|
@@ -262,6 +263,9 @@ directory - by selecting which ones to actually track.*
|
|
262
263
|
If your watched directories are outside the current one, or if `--watchdirs` isn't working
|
263
264
|
as you expect, be sure to read: [Correctly using watchdirs](https://github.com/guard/guard/wiki/Correctly-using-the---watchdir-option)
|
264
265
|
|
266
|
+
You may find it more convenient to use the `directories` statement (described
|
267
|
+
below) in your Guardfile
|
268
|
+
|
265
269
|
|
266
270
|
#### `-G`/`--guardfile` option
|
267
271
|
|
@@ -641,6 +645,40 @@ plural and the singular option, the plural has precedence.
|
|
641
645
|
|
642
646
|
**Please be sure to call the `scope` method after you've declared your Guard plugins!**
|
643
647
|
|
648
|
+
### directories
|
649
|
+
|
650
|
+
This option limits the directories watch to those given, which can improve
|
651
|
+
responsiveness, performance and help reduce resource usage (CPU, memory) on
|
652
|
+
larger projects.
|
653
|
+
|
654
|
+
```ruby
|
655
|
+
directories %w(app config lib spec features)
|
656
|
+
```
|
657
|
+
|
658
|
+
Note: The `--watchdir` option overrides this. (see `--watchdir` above for extra
|
659
|
+
info).
|
660
|
+
|
661
|
+
Note: Since recursion cannot be diabled on OSX, all other backends were made
|
662
|
+
recursive - so if you want to watch selected directories AND files in the root
|
663
|
+
directory of your project, move them to another directory and create symlinks
|
664
|
+
back, e.g.
|
665
|
+
|
666
|
+
```
|
667
|
+
mkdir config
|
668
|
+
mv Gemfile config
|
669
|
+
ln -s config/Gemfile Gemfile
|
670
|
+
```
|
671
|
+
|
672
|
+
### clearing
|
673
|
+
|
674
|
+
Guard can clear the screen before every action (which some people prefer).
|
675
|
+
|
676
|
+
The this clearing behavior can be set to `:on` or `:off`:
|
677
|
+
|
678
|
+
```ruby
|
679
|
+
clearing :on
|
680
|
+
```
|
681
|
+
|
644
682
|
### notification
|
645
683
|
|
646
684
|
If you don't specify any notification configuration in your `Guardfile`, Guard goes through the list of available
|
data/lib/guard.rb
CHANGED
@@ -57,8 +57,6 @@ module Guard
|
|
57
57
|
|
58
58
|
@queue = Internals::Queue.new(Guard)
|
59
59
|
|
60
|
-
UI.reset_and_clear
|
61
|
-
|
62
60
|
_evaluate(state.session.evaluator_options)
|
63
61
|
|
64
62
|
# NOTE: this should be *after* evaluate so :directories can work
|
@@ -146,6 +144,12 @@ module Guard
|
|
146
144
|
def _evaluate(options)
|
147
145
|
evaluator = Guardfile::Evaluator.new(options)
|
148
146
|
evaluator.evaluate
|
147
|
+
|
148
|
+
# TODO: remove this workaround when options are removed
|
149
|
+
state.session.clearing(state.session.options[:clear])
|
150
|
+
|
151
|
+
UI.reset_and_clear
|
152
|
+
|
149
153
|
msg = "No plugins found in Guardfile, please add at least one."
|
150
154
|
UI.error msg if _pluginless_guardfile?
|
151
155
|
|
@@ -172,6 +172,18 @@ module Guard
|
|
172
172
|
msg = "No plugins found in Guardfile, please add at least one."
|
173
173
|
::Guard::UI.error msg if _pluginless_guardfile?
|
174
174
|
end
|
175
|
+
|
176
|
+
OPTIONS = <<-EOS.gsub(/^\s*/, "")
|
177
|
+
Starting with Guard 2.9.0 Guard.options is deprecated and ideally you
|
178
|
+
should be able to set specific options through an API or a DSL
|
179
|
+
method. Feel free to add feature requests if there's something
|
180
|
+
missing.
|
181
|
+
EOS
|
182
|
+
|
183
|
+
def options
|
184
|
+
UI.deprecation(OPTIONS)
|
185
|
+
::Guard.state.session.options
|
186
|
+
end
|
175
187
|
end
|
176
188
|
end
|
177
189
|
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
require "guard/config"
|
2
|
+
fail "Deprecations disabled (strict mode)" if Guard::Config.new.strict?
|
3
|
+
|
4
|
+
require "guard/ui"
|
5
|
+
require "guard/plugin_util"
|
6
|
+
require "guard/guardfile/evaluator"
|
7
|
+
|
8
|
+
module Guard
|
9
|
+
# @deprecated Every method in this module is deprecated
|
10
|
+
module Deprecated
|
11
|
+
module Guard
|
12
|
+
def self.add_deprecated(klass)
|
13
|
+
klass.send(:extend, ClassMethods)
|
14
|
+
end
|
15
|
+
|
16
|
+
module ClassMethods
|
17
|
+
MORE_INFO_ON_UPGRADING_TO_GUARD_2 = <<-EOS.gsub(/^\s*/, "")
|
18
|
+
For more information on how to upgrade for Guard 2.0, please head
|
19
|
+
over to: https://github.com/guard/guard/wiki/Upgrading-to-Guard-2.0%s
|
20
|
+
EOS
|
21
|
+
|
22
|
+
# @deprecated Use `Guard.plugins(filter)` instead.
|
23
|
+
#
|
24
|
+
# @see https://github.com/guard/guard/wiki/Upgrading-to-Guard-2.0 How to
|
25
|
+
# upgrade for Guard 2.0
|
26
|
+
#
|
27
|
+
GUARDS = <<-EOS.gsub(/^\s*/, "")
|
28
|
+
Starting with Guard 2.0 'Guard.guards(filter)' is deprecated.
|
29
|
+
|
30
|
+
Please use 'Guard.plugins(filter)' instead.
|
31
|
+
|
32
|
+
#{MORE_INFO_ON_UPGRADING_TO_GUARD_2 % "#deprecated-methods"}
|
33
|
+
EOS
|
34
|
+
|
35
|
+
def guards(filter = nil)
|
36
|
+
::Guard::UI.deprecation(GUARDS)
|
37
|
+
plugins(filter)
|
38
|
+
end
|
39
|
+
|
40
|
+
# @deprecated Use `Guard.add_plugin(name, options = {})` instead.
|
41
|
+
#
|
42
|
+
# @see https://github.com/guard/guard/wiki/Upgrading-to-Guard-2.0 How to
|
43
|
+
# upgrade for Guard 2.0
|
44
|
+
#
|
45
|
+
ADD_GUARD = <<-EOS.gsub(/^\s*/, "")
|
46
|
+
Starting with Guard 2.0 'Guard.add_guard(name, options = {})' is
|
47
|
+
deprecated.
|
48
|
+
|
49
|
+
Please use 'Guard.add_plugin(name, options = {})' instead.
|
50
|
+
|
51
|
+
#{MORE_INFO_ON_UPGRADING_TO_GUARD_2 % "#deprecated-methods"}
|
52
|
+
EOS
|
53
|
+
|
54
|
+
def add_guard(*args)
|
55
|
+
::Guard::UI.deprecation(ADD_GUARD)
|
56
|
+
add_plugin(*args)
|
57
|
+
end
|
58
|
+
|
59
|
+
# @deprecated Use
|
60
|
+
# `Guard::PluginUtil.new(name).plugin_class(fail_gracefully:
|
61
|
+
# fail_gracefully)` instead.
|
62
|
+
#
|
63
|
+
# @see https://github.com/guard/guard/wiki/Upgrading-to-Guard-2.0 How to
|
64
|
+
# upgrade for Guard 2.0
|
65
|
+
#
|
66
|
+
GET_GUARD_CLASS = <<-EOS.gsub(/^\s*/, "")
|
67
|
+
Starting with Guard 2.0 'Guard.get_guard_class(name, fail_gracefully
|
68
|
+
= false)' is deprecated and is now always on.
|
69
|
+
|
70
|
+
Please use 'Guard::PluginUtil.new(name).plugin_class(fail_gracefully:
|
71
|
+
fail_gracefully)' instead.
|
72
|
+
|
73
|
+
#{MORE_INFO_ON_UPGRADING_TO_GUARD_2 % "#deprecated-methods"}
|
74
|
+
EOS
|
75
|
+
|
76
|
+
def get_guard_class(name, fail_gracefully = false)
|
77
|
+
UI.deprecation(GET_GUARD_CLASS)
|
78
|
+
PluginUtil.new(name).plugin_class(fail_gracefully: fail_gracefully)
|
79
|
+
end
|
80
|
+
|
81
|
+
# @deprecated Use `Guard::PluginUtil.new(name).plugin_location` instead.
|
82
|
+
#
|
83
|
+
# @see https://github.com/guard/guard/wiki/Upgrading-to-Guard-2.0 How to
|
84
|
+
# upgrade for Guard 2.0
|
85
|
+
#
|
86
|
+
LOCATE_GUARD = <<-EOS.gsub(/^\s*/, "")
|
87
|
+
Starting with Guard 2.0 'Guard.locate_guard(name)' is deprecated.
|
88
|
+
|
89
|
+
Please use 'Guard::PluginUtil.new(name).plugin_location' instead.
|
90
|
+
|
91
|
+
#{MORE_INFO_ON_UPGRADING_TO_GUARD_2 % "#deprecated-methods"}
|
92
|
+
EOS
|
93
|
+
|
94
|
+
def locate_guard(name)
|
95
|
+
UI.deprecation(LOCATE_GUARD)
|
96
|
+
PluginUtil.new(name).plugin_location
|
97
|
+
end
|
98
|
+
|
99
|
+
# @deprecated Use `Guard::PluginUtil.plugin_names` instead.
|
100
|
+
#
|
101
|
+
# @see https://github.com/guard/guard/wiki/Upgrading-to-Guard-2.0 How to
|
102
|
+
# upgrade for Guard 2.0
|
103
|
+
#
|
104
|
+
# Deprecator message for the `Guard.guard_gem_names` method
|
105
|
+
GUARD_GEM_NAMES = <<-EOS.gsub(/^\s*/, "")
|
106
|
+
Starting with Guard 2.0 'Guard.guard_gem_names' is deprecated.
|
107
|
+
|
108
|
+
Please use 'Guard::PluginUtil.plugin_names' instead.
|
109
|
+
|
110
|
+
#{MORE_INFO_ON_UPGRADING_TO_GUARD_2 % "#deprecated-methods"}
|
111
|
+
EOS
|
112
|
+
|
113
|
+
def guard_gem_names
|
114
|
+
UI.deprecation(GUARD_GEM_NAMES)
|
115
|
+
PluginUtil.plugin_names
|
116
|
+
end
|
117
|
+
|
118
|
+
RUNNING = <<-EOS.gsub(/^\s*/, "")
|
119
|
+
Starting with Guard 2.7.1 it was discovered that Guard.running was
|
120
|
+
never initialized or used internally.
|
121
|
+
EOS
|
122
|
+
|
123
|
+
def running
|
124
|
+
UI.deprecation(RUNNING)
|
125
|
+
nil
|
126
|
+
end
|
127
|
+
|
128
|
+
LOCK = <<-EOS.gsub(/^\s*/, "")
|
129
|
+
Starting with Guard 2.7.1 it was discovered that this accessor was
|
130
|
+
never initialized or used internally.
|
131
|
+
EOS
|
132
|
+
def lock
|
133
|
+
UI.deprecation(LOCK)
|
134
|
+
end
|
135
|
+
|
136
|
+
EVALUATOR = <<-EOS.gsub(/^\s*/, "")
|
137
|
+
Starting with Guard 2.8.2 this method shouldn't be used
|
138
|
+
EOS
|
139
|
+
|
140
|
+
def evaluator
|
141
|
+
UI.deprecation(EVALUATOR)
|
142
|
+
options = ::Guard.state.session.evaluator_options
|
143
|
+
::Guard::Guardfile::Evaluator.new(options)
|
144
|
+
end
|
145
|
+
|
146
|
+
RESET_EVALUATOR = <<-EOS.gsub(/^\s*/, "")
|
147
|
+
Starting with Guard 2.8.2 this method shouldn't be used
|
148
|
+
EOS
|
149
|
+
|
150
|
+
def reset_evaluator(_options)
|
151
|
+
UI.deprecation(RESET_EVALUATOR)
|
152
|
+
end
|
153
|
+
|
154
|
+
RUNNER = <<-EOS.gsub(/^\s*/, "")
|
155
|
+
Starting with Guard 2.8.2 this method shouldn't be used
|
156
|
+
EOS
|
157
|
+
|
158
|
+
def runner
|
159
|
+
UI.deprecation(RUNNER)
|
160
|
+
::Guard::Runner.new
|
161
|
+
end
|
162
|
+
|
163
|
+
EVALUATE_GUARDFILE = <<-EOS.gsub(/^\s*/, "")
|
164
|
+
Starting with Guard 2.8.2 this method shouldn't be used
|
165
|
+
EOS
|
166
|
+
|
167
|
+
def evaluate_guardfile
|
168
|
+
UI.deprecation(EVALUATE_GUARDFILE)
|
169
|
+
options = ::Guard.state.session.evaluator_options
|
170
|
+
evaluator = ::Guard::Guardfile::Evaluator.new(options)
|
171
|
+
evaluator.evaluate
|
172
|
+
msg = "No plugins found in Guardfile, please add at least one."
|
173
|
+
::Guard::UI.error msg if _pluginless_guardfile?
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
data/lib/guard/dsl.rb
CHANGED
@@ -379,6 +379,31 @@ module Guard
|
|
379
379
|
raise Error, format(msg, e, backtrace)
|
380
380
|
end
|
381
381
|
|
382
|
+
# Sets the directories to pass to Listen
|
383
|
+
#
|
384
|
+
# @example watch only given directories
|
385
|
+
# directories %w(lib specs)
|
386
|
+
#
|
387
|
+
# @param [Array] directories directories for Listen to watch
|
388
|
+
#
|
389
|
+
def directories(directories)
|
390
|
+
directories.each do |dir|
|
391
|
+
fail "Directory #{dir.inspect} does not exist!" unless Dir.exist?(dir)
|
392
|
+
end
|
393
|
+
Guard.state.session.watchdirs = directories
|
394
|
+
end
|
395
|
+
|
396
|
+
# Sets Guard to clear the screen before every task is run
|
397
|
+
#
|
398
|
+
# @example switching clearing the screen on
|
399
|
+
# clearing(:on)
|
400
|
+
#
|
401
|
+
# @param [Symbol] on ':on' to turn on, ':off' (default) to turn off
|
402
|
+
#
|
403
|
+
def clearing(on)
|
404
|
+
Guard.state.session.clearing(on == :on)
|
405
|
+
end
|
406
|
+
|
382
407
|
private
|
383
408
|
|
384
409
|
def _cleanup_backtrace(backtrace)
|
@@ -404,19 +429,5 @@ module Guard
|
|
404
429
|
end
|
405
430
|
end
|
406
431
|
end
|
407
|
-
|
408
|
-
# Sets the directories to pass to Listen
|
409
|
-
#
|
410
|
-
# @example watch only given directories
|
411
|
-
# directories %w(lib specs)
|
412
|
-
#
|
413
|
-
# @param [Array] directories directories for Listen to watch
|
414
|
-
#
|
415
|
-
def directories(directories)
|
416
|
-
directories.each do |dir|
|
417
|
-
fail "Directory #{dir.inspect} does not exist!" unless Dir.exist?(dir)
|
418
|
-
end
|
419
|
-
Guard.state.session.watchdirs = directories
|
420
|
-
end
|
421
432
|
end
|
422
433
|
end
|
@@ -81,11 +81,16 @@ module Guard
|
|
81
81
|
attr_reader :guardfile_group_scope
|
82
82
|
attr_reader :guardfile_plugin_scope
|
83
83
|
|
84
|
-
|
85
|
-
|
84
|
+
def clearing(on)
|
85
|
+
@clear = on
|
86
|
+
end
|
87
|
+
|
88
|
+
def clearing?
|
86
89
|
@clear
|
87
90
|
end
|
88
91
|
|
92
|
+
alias :clear? :clearing?
|
93
|
+
|
89
94
|
def debug?
|
90
95
|
@debug
|
91
96
|
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
require "guard/internals/plugins"
|
2
|
+
require "guard/internals/groups"
|
3
|
+
|
4
|
+
require "guard/options"
|
5
|
+
|
6
|
+
module Guard
|
7
|
+
# @private api
|
8
|
+
module Internals
|
9
|
+
# TODO: split into a commandline class and session (plugins, groups)
|
10
|
+
# TODO: swap session and metadata
|
11
|
+
# This class contains variables set during
|
12
|
+
# evaluation of the guardfile (and are reset
|
13
|
+
# before reevaluation)
|
14
|
+
class Session
|
15
|
+
attr_reader :options
|
16
|
+
attr_reader :plugins
|
17
|
+
attr_reader :groups
|
18
|
+
|
19
|
+
DEFAULT_OPTIONS = {
|
20
|
+
clear: false,
|
21
|
+
debug: false,
|
22
|
+
no_bundler_warning: false,
|
23
|
+
|
24
|
+
# User defined scopes
|
25
|
+
group: [],
|
26
|
+
plugin: [],
|
27
|
+
|
28
|
+
# Notifier
|
29
|
+
notify: true,
|
30
|
+
|
31
|
+
# Interactor
|
32
|
+
no_interactions: false,
|
33
|
+
|
34
|
+
# Guardfile options:
|
35
|
+
# guardfile_contents
|
36
|
+
guardfile: nil,
|
37
|
+
|
38
|
+
# Listener options
|
39
|
+
# TODO: rename to watchdirs?
|
40
|
+
watchdir: Dir.pwd,
|
41
|
+
latency: nil,
|
42
|
+
force_polling: false,
|
43
|
+
wait_for_delay: nil,
|
44
|
+
listen_on: nil
|
45
|
+
}
|
46
|
+
|
47
|
+
def cmdline_groups
|
48
|
+
@cmdline_groups.dup.freeze
|
49
|
+
end
|
50
|
+
|
51
|
+
def cmdline_plugins
|
52
|
+
@cmdline_plugins.dup.freeze
|
53
|
+
end
|
54
|
+
|
55
|
+
def initialize(new_options)
|
56
|
+
@options = Options.new(new_options, DEFAULT_OPTIONS)
|
57
|
+
|
58
|
+
@plugins = Internals::Plugins.new
|
59
|
+
@groups = Internals::Groups.new
|
60
|
+
|
61
|
+
@cmdline_groups = @options[:group]
|
62
|
+
@cmdline_plugins = @options[:plugin]
|
63
|
+
|
64
|
+
@clear = @options[:clear]
|
65
|
+
@debug = @options[:debug]
|
66
|
+
@watchdirs = Array(@options[:watchdir])
|
67
|
+
@notify = @options[:notify]
|
68
|
+
@interactor_name = @options[:no_interactions] ? :sleep : :pry_wrapper
|
69
|
+
|
70
|
+
@guardfile_plugin_scope = []
|
71
|
+
@guardfile_group_scope = []
|
72
|
+
end
|
73
|
+
|
74
|
+
def guardfile_scope(scope)
|
75
|
+
opts = scope.dup
|
76
|
+
@guardfile_plugin_scope = Array(opts.delete(:plugins))
|
77
|
+
@guardfile_group_scope = Array(opts.delete(:groups))
|
78
|
+
fail "Unknown options: #{opts.inspect}" unless opts.empty?
|
79
|
+
end
|
80
|
+
|
81
|
+
attr_reader :guardfile_group_scope
|
82
|
+
attr_reader :guardfile_plugin_scope
|
83
|
+
|
84
|
+
# TODO: not tested
|
85
|
+
def clear?
|
86
|
+
@clear
|
87
|
+
end
|
88
|
+
|
89
|
+
def debug?
|
90
|
+
@debug
|
91
|
+
end
|
92
|
+
|
93
|
+
def watchdirs
|
94
|
+
@watchdirs_from_guardfile ||= nil
|
95
|
+
@watchdirs_from_guardfile || @watchdirs
|
96
|
+
end
|
97
|
+
|
98
|
+
# set by Dsl with :directories() command
|
99
|
+
def watchdirs=(dirs)
|
100
|
+
dirs = [Dir.pwd] if dirs.empty?
|
101
|
+
@watchdirs_from_guardfile = dirs.map { |dir| File.expand_path dir }
|
102
|
+
end
|
103
|
+
|
104
|
+
def listener_args
|
105
|
+
if options[:listen_on]
|
106
|
+
[:on, options[:listen_on]]
|
107
|
+
else
|
108
|
+
listener_options = {}
|
109
|
+
[:latency, :force_polling, :wait_for_delay].each do |option|
|
110
|
+
listener_options[option] = options[option] if options[option]
|
111
|
+
end
|
112
|
+
expanded_watchdirs = watchdirs.map { |dir| File.expand_path dir }
|
113
|
+
[:to, *expanded_watchdirs, listener_options]
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def evaluator_options
|
118
|
+
opts = { guardfile: options[:guardfile] }
|
119
|
+
# TODO: deprecate :guardfile_contents
|
120
|
+
if options[:guardfile_contents]
|
121
|
+
opts[:contents] = options[:guardfile_contents]
|
122
|
+
end
|
123
|
+
opts
|
124
|
+
end
|
125
|
+
|
126
|
+
def notify_options
|
127
|
+
{ notify: @options[:notify] }
|
128
|
+
end
|
129
|
+
|
130
|
+
def interactor_name
|
131
|
+
@interactor_name
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
# A sample Guardfile
|
2
2
|
# More info at https://github.com/guard/guard#readme
|
3
3
|
|
4
|
-
|
5
|
-
#
|
4
|
+
## Uncomment and set this to only include directories you want to watch
|
6
5
|
# directories %(app lib config test spec feature)
|
6
|
+
|
7
|
+
## Uncomment to clear the screen before every task
|
8
|
+
# clearing :on
|
@@ -0,0 +1,274 @@
|
|
1
|
+
require "lumberjack"
|
2
|
+
|
3
|
+
require "guard/internals/state"
|
4
|
+
|
5
|
+
require "guard/options"
|
6
|
+
|
7
|
+
require "guard/ui/colors"
|
8
|
+
|
9
|
+
require "guard/terminal"
|
10
|
+
|
11
|
+
module Guard
|
12
|
+
# The UI class helps to format messages for the user. Everything that is
|
13
|
+
# logged through this class is considered either as an error message or a
|
14
|
+
# diagnostic message and is written to standard error ($stderr).
|
15
|
+
#
|
16
|
+
# If your Guard plugin does some output that is piped into another process
|
17
|
+
# for further processing, please just write it to STDOUT with `puts`.
|
18
|
+
#
|
19
|
+
module UI
|
20
|
+
include Colors
|
21
|
+
|
22
|
+
class << self
|
23
|
+
# Get the Guard::UI logger instance
|
24
|
+
#
|
25
|
+
def logger
|
26
|
+
@logger ||= begin
|
27
|
+
Lumberjack::Logger.new(
|
28
|
+
options.fetch(:device) { $stderr },
|
29
|
+
options)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Since logger is global, for Aruba in-process to properly
|
34
|
+
# separate output between calls, we need to reset
|
35
|
+
#
|
36
|
+
# We don't use logger=() since it's expected to be a Lumberjack instance
|
37
|
+
def reset_logger
|
38
|
+
@logger = nil
|
39
|
+
end
|
40
|
+
|
41
|
+
# Get the logger options
|
42
|
+
#
|
43
|
+
# @return [Hash] the logger options
|
44
|
+
#
|
45
|
+
def options
|
46
|
+
@options ||= ::Guard::Options.new(
|
47
|
+
level: :info,
|
48
|
+
template: ":time - :severity - :message",
|
49
|
+
time_format: "%H:%M:%S")
|
50
|
+
end
|
51
|
+
|
52
|
+
# Set the logger options
|
53
|
+
#
|
54
|
+
# @param [Hash] options the logger options
|
55
|
+
# @option options [Symbol] level the log level
|
56
|
+
# @option options [String] template the logger template
|
57
|
+
# @option options [String] time_format the time format
|
58
|
+
#
|
59
|
+
# TODO: deprecate?
|
60
|
+
def options=(options)
|
61
|
+
@options = ::Guard::Options.new(options)
|
62
|
+
end
|
63
|
+
|
64
|
+
# Assigns a log level
|
65
|
+
def level=(new_level)
|
66
|
+
logger.level = new_level
|
67
|
+
end
|
68
|
+
|
69
|
+
# Show an info message.
|
70
|
+
#
|
71
|
+
# @param [String] message the message to show
|
72
|
+
# @option options [Boolean] reset whether to clean the output before
|
73
|
+
# @option options [String] plugin manually define the calling plugin
|
74
|
+
#
|
75
|
+
def info(message, options = {})
|
76
|
+
_filtered_logger_message(message, :info, nil, options)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Show a yellow warning message that is prefixed with WARNING.
|
80
|
+
#
|
81
|
+
# @param [String] message the message to show
|
82
|
+
# @option options [Boolean] reset whether to clean the output before
|
83
|
+
# @option options [String] plugin manually define the calling plugin
|
84
|
+
#
|
85
|
+
def warning(message, options = {})
|
86
|
+
_filtered_logger_message(message, :warn, :yellow, options)
|
87
|
+
end
|
88
|
+
|
89
|
+
# Show a red error message that is prefixed with ERROR.
|
90
|
+
#
|
91
|
+
# @param [String] message the message to show
|
92
|
+
# @option options [Boolean] reset whether to clean the output before
|
93
|
+
# @option options [String] plugin manually define the calling plugin
|
94
|
+
#
|
95
|
+
def error(message, options = {})
|
96
|
+
_filtered_logger_message(message, :error, :red, options)
|
97
|
+
end
|
98
|
+
|
99
|
+
# Show a red deprecation message that is prefixed with DEPRECATION.
|
100
|
+
# It has a log level of `warn`.
|
101
|
+
#
|
102
|
+
# @param [String] message the message to show
|
103
|
+
# @option options [Boolean] reset whether to clean the output before
|
104
|
+
# @option options [String] plugin manually define the calling plugin
|
105
|
+
#
|
106
|
+
def deprecation(message, options = {})
|
107
|
+
unless ENV["GUARD_GEM_SILENCE_DEPRECATIONS"] == "1"
|
108
|
+
backtrace = Thread.current.backtrace[1..5].join("\n\t >")
|
109
|
+
msg = format("%s\nDeprecation backtrace: %s", message, backtrace)
|
110
|
+
warning(msg, options)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Show a debug message that is prefixed with DEBUG and a timestamp.
|
115
|
+
#
|
116
|
+
# @param [String] message the message to show
|
117
|
+
# @option options [Boolean] reset whether to clean the output before
|
118
|
+
# @option options [String] plugin manually define the calling plugin
|
119
|
+
#
|
120
|
+
def debug(message, options = {})
|
121
|
+
_filtered_logger_message(message, :debug, :yellow, options)
|
122
|
+
end
|
123
|
+
|
124
|
+
# Reset a line.
|
125
|
+
#
|
126
|
+
def reset_line
|
127
|
+
$stderr.print(color_enabled? ? "\r\e[0m" : "\r\n")
|
128
|
+
end
|
129
|
+
|
130
|
+
# Clear the output if clearable.
|
131
|
+
#
|
132
|
+
def clear(opts = {})
|
133
|
+
return unless Guard.state.session.clear?
|
134
|
+
|
135
|
+
fail "UI not set up!" if @clearable.nil?
|
136
|
+
return unless @clearable || opts[:force]
|
137
|
+
|
138
|
+
@clearable = false
|
139
|
+
Terminal.clear
|
140
|
+
rescue Errno::ENOENT => e
|
141
|
+
warning("Failed to clear the screen: #{e.inspect}")
|
142
|
+
end
|
143
|
+
|
144
|
+
# TODO: arguments: UI uses Guard::options anyway
|
145
|
+
# @private api
|
146
|
+
def reset_and_clear
|
147
|
+
@clearable = false
|
148
|
+
clear(force: true)
|
149
|
+
end
|
150
|
+
|
151
|
+
# Allow the screen to be cleared again.
|
152
|
+
#
|
153
|
+
def clearable
|
154
|
+
@clearable = true
|
155
|
+
end
|
156
|
+
|
157
|
+
# Show a scoped action message.
|
158
|
+
#
|
159
|
+
# @param [String] action the action to show
|
160
|
+
# @param [Hash] scope hash with a guard or a group scope
|
161
|
+
#
|
162
|
+
def action_with_scopes(action, scope)
|
163
|
+
titles = Guard.state.scope.titles(scope)
|
164
|
+
info "#{action} #{titles.join(", ")}"
|
165
|
+
end
|
166
|
+
|
167
|
+
private
|
168
|
+
|
169
|
+
# Filters log messages depending on either the
|
170
|
+
# `:only`` or `:except` option.
|
171
|
+
#
|
172
|
+
# @param [String] plugin the calling plugin name
|
173
|
+
# @yield When the message should be logged
|
174
|
+
# @yieldparam [String] param the calling plugin name
|
175
|
+
#
|
176
|
+
def _filter(plugin)
|
177
|
+
only = options[:only]
|
178
|
+
except = options[:except]
|
179
|
+
plugin ||= calling_plugin_name
|
180
|
+
|
181
|
+
match = !(only || except)
|
182
|
+
match ||= (only && only.match(plugin))
|
183
|
+
match ||= (except && !except.match(plugin))
|
184
|
+
return unless match
|
185
|
+
yield plugin
|
186
|
+
end
|
187
|
+
|
188
|
+
# Display a message of the type `method` and with the color `color_name`
|
189
|
+
# (no color by default) conditionnaly given a `plugin_name`.
|
190
|
+
#
|
191
|
+
# @param [String] plugin_name the calling plugin name
|
192
|
+
# @option options [Boolean] reset whether to clean the output before
|
193
|
+
# @option options [String] plugin manually define the calling plugin
|
194
|
+
#
|
195
|
+
def _filtered_logger_message(message, method, color_name, options = {})
|
196
|
+
message = color(message, color_name) if color_name
|
197
|
+
|
198
|
+
_filter(options[:plugin]) do |plugin|
|
199
|
+
reset_line if options[:reset]
|
200
|
+
logger.send(method, message, plugin)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
# Tries to extract the calling Guard plugin name
|
205
|
+
# from the call stack.
|
206
|
+
#
|
207
|
+
# @param [Integer] depth the stack depth
|
208
|
+
# @return [String] the Guard plugin name
|
209
|
+
#
|
210
|
+
def calling_plugin_name(depth = 2)
|
211
|
+
name = /(guard\/[a-z_]*)(\/[a-z_]*)?.rb:/i.match(caller[depth])
|
212
|
+
return "Guard" unless name
|
213
|
+
name[1].split("/").map do |part|
|
214
|
+
part.split(/[^a-z0-9]/i).map(&:capitalize).join
|
215
|
+
end.join("::")
|
216
|
+
end
|
217
|
+
|
218
|
+
# Checks if color output can be enabled.
|
219
|
+
#
|
220
|
+
# @return [Boolean] whether color is enabled or not
|
221
|
+
#
|
222
|
+
def color_enabled?
|
223
|
+
@color_enabled_initialized ||= false
|
224
|
+
@color_enabled = nil unless @color_enabled_initialized
|
225
|
+
@color_enabled_initialized = true
|
226
|
+
if @color_enabled.nil?
|
227
|
+
if Gem.win_platform?
|
228
|
+
if ENV["ANSICON"]
|
229
|
+
@color_enabled = true
|
230
|
+
else
|
231
|
+
begin
|
232
|
+
require "rubygems" unless ENV["NO_RUBYGEMS"]
|
233
|
+
require "Win32/Console/ANSI"
|
234
|
+
@color_enabled = true
|
235
|
+
rescue LoadError
|
236
|
+
@color_enabled = false
|
237
|
+
info "Run 'gem install win32console' to use color on Windows"
|
238
|
+
end
|
239
|
+
end
|
240
|
+
else
|
241
|
+
@color_enabled = true
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
@color_enabled
|
246
|
+
end
|
247
|
+
|
248
|
+
# Colorizes a text message. See the constant in the UI class for possible
|
249
|
+
# color_options parameters. You can pass optionally :bright, a foreground
|
250
|
+
# color and a background color.
|
251
|
+
#
|
252
|
+
# @example
|
253
|
+
#
|
254
|
+
# color('Hello World', :red, :bright)
|
255
|
+
#
|
256
|
+
# @param [String] text the text to colorize
|
257
|
+
# @param [Array] color_options the color options
|
258
|
+
#
|
259
|
+
def color(text, *color_options)
|
260
|
+
color_code = ""
|
261
|
+
color_options.each do |color_option|
|
262
|
+
color_option = color_option.to_s
|
263
|
+
next if color_option == ""
|
264
|
+
|
265
|
+
unless color_option =~ /\d+/
|
266
|
+
color_option = const_get("ANSI_ESCAPE_#{ color_option.upcase }")
|
267
|
+
end
|
268
|
+
color_code += ";" + color_option
|
269
|
+
end
|
270
|
+
color_enabled? ? "\e[0#{ color_code }m#{ text }\e[0m" : text
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
data/lib/guard/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: guard
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Thibaud Guillaume-Gentil
|
@@ -113,6 +113,7 @@ files:
|
|
113
113
|
- lib/guard/deprecated/dsl.rb
|
114
114
|
- lib/guard/deprecated/evaluator.rb
|
115
115
|
- lib/guard/deprecated/guard.rb
|
116
|
+
- lib/guard/deprecated/guard.rb.orig
|
116
117
|
- lib/guard/deprecated/guardfile.rb
|
117
118
|
- lib/guard/deprecated/watcher.rb
|
118
119
|
- lib/guard/dsl.rb
|
@@ -132,6 +133,7 @@ files:
|
|
132
133
|
- lib/guard/internals/queue.rb
|
133
134
|
- lib/guard/internals/scope.rb
|
134
135
|
- lib/guard/internals/session.rb
|
136
|
+
- lib/guard/internals/session.rb.orig
|
135
137
|
- lib/guard/internals/state.rb
|
136
138
|
- lib/guard/internals/tracing.rb
|
137
139
|
- lib/guard/internals/traps.rb
|
@@ -166,6 +168,7 @@ files:
|
|
166
168
|
- lib/guard/templates/Guardfile.orig
|
167
169
|
- lib/guard/terminal.rb
|
168
170
|
- lib/guard/ui.rb
|
171
|
+
- lib/guard/ui.rb.orig
|
169
172
|
- lib/guard/ui/colors.rb
|
170
173
|
- lib/guard/version.rb
|
171
174
|
- lib/guard/version.rb.orig
|