guard 1.4.0 → 2.18.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.
Files changed (89) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1 -677
  3. data/LICENSE +4 -2
  4. data/README.md +91 -753
  5. data/bin/_guard-core +11 -0
  6. data/bin/guard +108 -3
  7. data/lib/guard/aruba_adapter.rb +59 -0
  8. data/lib/guard/cli/environments/bundler.rb +22 -0
  9. data/lib/guard/cli/environments/evaluate_only.rb +35 -0
  10. data/lib/guard/cli/environments/valid.rb +69 -0
  11. data/lib/guard/cli.rb +129 -128
  12. data/lib/guard/commander.rb +104 -0
  13. data/lib/guard/commands/all.rb +37 -0
  14. data/lib/guard/commands/change.rb +31 -0
  15. data/lib/guard/commands/notification.rb +26 -0
  16. data/lib/guard/commands/pause.rb +29 -0
  17. data/lib/guard/commands/reload.rb +36 -0
  18. data/lib/guard/commands/scope.rb +38 -0
  19. data/lib/guard/commands/show.rb +24 -0
  20. data/lib/guard/config.rb +18 -0
  21. data/lib/guard/deprecated/dsl.rb +45 -0
  22. data/lib/guard/deprecated/evaluator.rb +39 -0
  23. data/lib/guard/deprecated/guard.rb +328 -0
  24. data/lib/guard/deprecated/guardfile.rb +84 -0
  25. data/lib/guard/deprecated/watcher.rb +27 -0
  26. data/lib/guard/dsl.rb +332 -363
  27. data/lib/guard/dsl_describer.rb +132 -122
  28. data/lib/guard/dsl_reader.rb +51 -0
  29. data/lib/guard/group.rb +34 -14
  30. data/lib/guard/guardfile/evaluator.rb +232 -0
  31. data/lib/guard/guardfile/generator.rb +128 -0
  32. data/lib/guard/guardfile.rb +24 -60
  33. data/lib/guard/interactor.rb +31 -255
  34. data/lib/guard/internals/debugging.rb +68 -0
  35. data/lib/guard/internals/groups.rb +40 -0
  36. data/lib/guard/internals/helpers.rb +13 -0
  37. data/lib/guard/internals/plugins.rb +53 -0
  38. data/lib/guard/internals/queue.rb +51 -0
  39. data/lib/guard/internals/scope.rb +121 -0
  40. data/lib/guard/internals/session.rb +180 -0
  41. data/lib/guard/internals/state.rb +25 -0
  42. data/lib/guard/internals/tracing.rb +33 -0
  43. data/lib/guard/internals/traps.rb +10 -0
  44. data/lib/guard/jobs/base.rb +21 -0
  45. data/lib/guard/jobs/pry_wrapper.rb +336 -0
  46. data/lib/guard/jobs/sleep.rb +26 -0
  47. data/lib/guard/notifier.rb +46 -212
  48. data/lib/guard/options.rb +22 -0
  49. data/lib/guard/plugin.rb +303 -0
  50. data/lib/guard/plugin_util.rb +191 -0
  51. data/lib/guard/rake_task.rb +42 -0
  52. data/lib/guard/runner.rb +80 -140
  53. data/lib/guard/templates/Guardfile +14 -0
  54. data/lib/guard/terminal.rb +13 -0
  55. data/lib/guard/ui/colors.rb +56 -0
  56. data/lib/guard/ui/config.rb +70 -0
  57. data/lib/guard/ui/logger.rb +30 -0
  58. data/lib/guard/ui.rb +163 -128
  59. data/lib/guard/version.rb +1 -2
  60. data/lib/guard/watcher/pattern/deprecated_regexp.rb +45 -0
  61. data/lib/guard/watcher/pattern/match_result.rb +18 -0
  62. data/lib/guard/watcher/pattern/matcher.rb +33 -0
  63. data/lib/guard/watcher/pattern/pathname_path.rb +15 -0
  64. data/lib/guard/watcher/pattern/simple_path.rb +23 -0
  65. data/lib/guard/watcher/pattern.rb +24 -0
  66. data/lib/guard/watcher.rb +52 -95
  67. data/lib/guard.rb +108 -376
  68. data/lib/tasks/releaser.rb +116 -0
  69. data/man/guard.1 +12 -9
  70. data/man/guard.1.html +18 -12
  71. metadata +148 -77
  72. data/images/guard.png +0 -0
  73. data/lib/guard/guard.rb +0 -156
  74. data/lib/guard/hook.rb +0 -120
  75. data/lib/guard/interactors/coolline.rb +0 -64
  76. data/lib/guard/interactors/helpers/completion.rb +0 -32
  77. data/lib/guard/interactors/helpers/terminal.rb +0 -46
  78. data/lib/guard/interactors/readline.rb +0 -94
  79. data/lib/guard/interactors/simple.rb +0 -19
  80. data/lib/guard/notifiers/emacs.rb +0 -69
  81. data/lib/guard/notifiers/gntp.rb +0 -118
  82. data/lib/guard/notifiers/growl.rb +0 -99
  83. data/lib/guard/notifiers/growl_notify.rb +0 -92
  84. data/lib/guard/notifiers/libnotify.rb +0 -96
  85. data/lib/guard/notifiers/notifysend.rb +0 -84
  86. data/lib/guard/notifiers/rb_notifu.rb +0 -102
  87. data/lib/guard/notifiers/terminal_notifier.rb +0 -66
  88. data/lib/guard/notifiers/tmux.rb +0 -69
  89. data/lib/guard/version.rbc +0 -130
data/lib/guard/ui.rb CHANGED
@@ -1,62 +1,112 @@
1
- module Guard
1
+ require "guard/ui/colors"
2
+ require "guard/ui/config"
3
+
4
+ require "guard/terminal"
5
+ require "forwardable"
6
+
7
+ # TODO: rework this class from the bottom-up
8
+ # - remove dependency on Session and Scope
9
+ # - extract into a separate gem
10
+ # - change UI to class
2
11
 
3
- # The UI class helps to format messages for the user. Everything that is logged
4
- # through this class is considered either as an error message or a diagnostic
5
- # message and is written to standard error (STDERR).
12
+ module Guard
13
+ # The UI class helps to format messages for the user. Everything that is
14
+ # logged through this class is considered either as an error message or a
15
+ # diagnostic message and is written to standard error ($stderr).
6
16
  #
7
- # If your Guard plugin does some output that is piped into another process for further
8
- # processing, please just write it to STDOUT with `puts`.
17
+ # If your Guard plugin does some output that is piped into another process
18
+ # for further processing, please just write it to STDOUT with `puts`.
9
19
  #
10
20
  module UI
21
+ include Colors
22
+
11
23
  class << self
24
+ # Get the Guard::UI logger instance
25
+ #
26
+ def logger
27
+ @logger ||=
28
+ begin
29
+ require "lumberjack"
30
+ Lumberjack::Logger.new(options.device, options.logger_config)
31
+ end
32
+ end
12
33
 
13
- color_enabled = nil
34
+ # Since logger is global, for Aruba in-process to properly
35
+ # separate output between calls, we need to reset
36
+ #
37
+ # We don't use logger=() since it's expected to be a Lumberjack instance
38
+ def reset_logger
39
+ @logger = nil
40
+ end
41
+
42
+ # Get the logger options
43
+ #
44
+ # @return [Hash] the logger options
45
+ #
46
+ def options
47
+ @options ||= Config.new
48
+ end
49
+
50
+ # Set the logger options
51
+ #
52
+ # @param [Hash] options the logger options
53
+ # @option options [Symbol] level the log level
54
+ # @option options [String] template the logger template
55
+ # @option options [String] time_format the time format
56
+ #
57
+ # TODO: deprecate?
58
+ def options=(options)
59
+ @options = Config.new(options)
60
+ end
61
+
62
+ # Assigns a log level
63
+ def level=(new_level)
64
+ options.logger_config.level = new_level
65
+ @logger.level = new_level if @logger
66
+ end
14
67
 
15
68
  # Show an info message.
16
69
  #
17
70
  # @param [String] message the message to show
18
71
  # @option options [Boolean] reset whether to clean the output before
72
+ # @option options [String] plugin manually define the calling plugin
19
73
  #
20
- def info(message, options = { })
21
- unless ENV['GUARD_ENV'] == 'test'
22
- reset_line if options[:reset]
23
- STDERR.puts color(message) if message != ''
24
- end
74
+ def info(message, options = {})
75
+ _filtered_logger_message(message, :info, nil, options)
25
76
  end
26
77
 
27
78
  # Show a yellow warning message that is prefixed with WARNING.
28
79
  #
29
80
  # @param [String] message the message to show
30
81
  # @option options [Boolean] reset whether to clean the output before
82
+ # @option options [String] plugin manually define the calling plugin
31
83
  #
32
- def warning(message, options = { })
33
- unless ENV['GUARD_ENV'] == 'test'
34
- reset_line if options[:reset]
35
- STDERR.puts color('WARNING: ', :yellow) + message
36
- end
84
+ def warning(message, options = {})
85
+ _filtered_logger_message(message, :warn, :yellow, options)
37
86
  end
38
87
 
39
88
  # Show a red error message that is prefixed with ERROR.
40
89
  #
41
90
  # @param [String] message the message to show
42
91
  # @option options [Boolean] reset whether to clean the output before
92
+ # @option options [String] plugin manually define the calling plugin
43
93
  #
44
- def error(message, options = { })
45
- unless ENV['GUARD_ENV'] == 'test'
46
- reset_line if options[:reset]
47
- STDERR.puts color('ERROR: ', :red) + message
48
- end
94
+ def error(message, options = {})
95
+ _filtered_logger_message(message, :error, :red, options)
49
96
  end
50
97
 
51
98
  # Show a red deprecation message that is prefixed with DEPRECATION.
99
+ # It has a log level of `warn`.
52
100
  #
53
101
  # @param [String] message the message to show
54
102
  # @option options [Boolean] reset whether to clean the output before
103
+ # @option options [String] plugin manually define the calling plugin
55
104
  #
56
- def deprecation(message, options = { })
57
- unless ENV['GUARD_ENV'] == 'test'
58
- reset_line if options[:reset]
59
- STDERR.puts color('DEPRECATION: ', :red) + message
105
+ def deprecation(message, options = {})
106
+ unless ENV["GUARD_GEM_SILENCE_DEPRECATIONS"] == "1"
107
+ backtrace = Thread.current.backtrace[1..5].join("\n\t >")
108
+ msg = format("%s\nDeprecation backtrace: %s", message, backtrace)
109
+ warning(msg, options)
60
110
  end
61
111
  end
62
112
 
@@ -64,27 +114,37 @@ module Guard
64
114
  #
65
115
  # @param [String] message the message to show
66
116
  # @option options [Boolean] reset whether to clean the output before
117
+ # @option options [String] plugin manually define the calling plugin
67
118
  #
68
- def debug(message, options = { })
69
- unless ENV['GUARD_ENV'] == 'test'
70
- reset_line if options[:reset]
71
- STDERR.puts color("DEBUG (#{Time.now.strftime('%T')}): ", :yellow) + message if ::Guard.options && ::Guard.options[:debug]
72
- end
119
+ def debug(message, options = {})
120
+ _filtered_logger_message(message, :debug, :yellow, options)
73
121
  end
74
122
 
75
123
  # Reset a line.
76
124
  #
77
125
  def reset_line
78
- STDERR.print(color_enabled? ? "\r\e[0m" : "\r\n")
126
+ $stderr.print(color_enabled? ? "\r\e[0m" : "\r\n")
79
127
  end
80
128
 
81
129
  # Clear the output if clearable.
82
130
  #
83
- def clear(options = {})
84
- if ::Guard.options[:clear] && (@clearable || options[:force])
85
- @clearable = false
86
- system('clear;')
87
- end
131
+ def clear(opts = {})
132
+ return unless Guard.state.session.clear?
133
+
134
+ fail "UI not set up!" if @clearable.nil?
135
+ return unless @clearable || opts[:force]
136
+
137
+ @clearable = false
138
+ Terminal.clear
139
+ rescue Errno::ENOENT => e
140
+ warning("Failed to clear the screen: #{e.inspect}")
141
+ end
142
+
143
+ # TODO: arguments: UI uses Guard::options anyway
144
+ # @private api
145
+ def reset_and_clear
146
+ @clearable = false
147
+ clear(force: true)
88
148
  end
89
149
 
90
150
  # Allow the screen to be cleared again.
@@ -96,26 +156,58 @@ module Guard
96
156
  # Show a scoped action message.
97
157
  #
98
158
  # @param [String] action the action to show
99
- # @param [Hash] scopes hash with a guard or a group scope
159
+ # @param [Hash] scope hash with a guard or a group scope
100
160
  #
101
- def action_with_scopes(action, scopes)
102
- scope_message ||= scopes[:guard]
103
- scope_message ||= scopes[:group]
104
- scope_message ||= 'all'
105
-
106
- info "#{action} #{scope_message}"
161
+ def action_with_scopes(action, scope)
162
+ titles = Guard.state.scope.titles(scope)
163
+ info "#{action} #{titles.join(', ')}"
107
164
  end
108
165
 
109
166
  private
110
167
 
111
- # Reset a color sequence.
168
+ # Filters log messages depending on either the
169
+ # `:only`` or `:except` option.
112
170
  #
113
- # @deprecated
114
- # @param [String] text the text
171
+ # @param [String] plugin the calling plugin name
172
+ # @yield When the message should be logged
173
+ # @yieldparam [String] param the calling plugin name
115
174
  #
116
- def reset_color(text)
117
- deprecation('UI.reset_color(text) is deprecated, please use color(text, ' ') instead.')
118
- color(text, '')
175
+ def _filter(plugin)
176
+ only = options.only
177
+ except = options.except
178
+ plugin ||= _calling_plugin_name
179
+
180
+ match = !(only || except)
181
+ match ||= (only && only.match(plugin))
182
+ match ||= (except && !except.match(plugin))
183
+ return unless match
184
+ yield plugin
185
+ end
186
+
187
+ # @private
188
+ def _filtered_logger_message(message, method, color_name, options = {})
189
+ message = color(message, color_name) if color_name
190
+
191
+ _filter(options[:plugin]) do
192
+ reset_line if options[:reset]
193
+ logger.send(method, message)
194
+ end
195
+ end
196
+
197
+ # Tries to extract the calling Guard plugin name
198
+ # from the call stack.
199
+ #
200
+ # @param [Integer] depth the stack depth
201
+ # @return [String] the Guard plugin name
202
+ #
203
+ def _calling_plugin_name
204
+ name = caller.lazy.map do |line|
205
+ %r{(?<!guard\/lib)\/(guard\/[a-z_]*)(/[a-z_]*)?.rb:}i.match(line)
206
+ end.reject(&:nil?).take(1).force.first
207
+ return "Guard" unless name || (name && name[1] == "guard/lib")
208
+ name[1].split("/").map do |part|
209
+ part.split(/[^a-z0-9]/i).map(&:capitalize).join
210
+ end.join("::")
119
211
  end
120
212
 
121
213
  # Checks if color output can be enabled.
@@ -123,26 +215,22 @@ module Guard
123
215
  # @return [Boolean] whether color is enabled or not
124
216
  #
125
217
  def color_enabled?
126
- if @color_enabled.nil?
127
- if RbConfig::CONFIG['target_os'] =~ /mswin|mingw/i
128
- if ENV['ANSICON']
129
- @color_enabled = true
130
- else
131
- begin
132
- require 'rubygems' unless ENV['NO_RUBYGEMS']
133
- require 'Win32/Console/ANSI'
134
- @color_enabled = true
135
- rescue LoadError
136
- @color_enabled = false
137
- info "You must 'gem install win32console' to use color on Windows"
138
- end
139
- end
140
- else
141
- @color_enabled = true
218
+ @color_enabled_initialized ||= false
219
+ @color_enabled = nil unless @color_enabled_initialized
220
+ @color_enabled_initialized = true
221
+ return @color_enabled unless @color_enabled.nil?
222
+ return (@color_enabled = true) unless Gem.win_platform?
223
+ return (@color_enabled = true) if ENV["ANSICON"]
224
+
225
+ @color_enabled =
226
+ begin
227
+ require "rubygems" unless ENV["NO_RUBYGEMS"]
228
+ require "Win32/Console/ANSI"
229
+ true
230
+ rescue LoadError
231
+ info "Run 'gem install win32console' to use color on Windows"
232
+ false
142
233
  end
143
- end
144
-
145
- @color_enabled
146
234
  end
147
235
 
148
236
  # Colorizes a text message. See the constant in the UI class for possible
@@ -157,71 +245,18 @@ module Guard
157
245
  # @param [Array] color_options the color options
158
246
  #
159
247
  def color(text, *color_options)
160
- color_code = ''
248
+ color_code = ""
161
249
  color_options.each do |color_option|
162
250
  color_option = color_option.to_s
163
- if color_option != ''
164
- if !(color_option =~ /\d+/)
165
- color_option = const_get("ANSI_ESCAPE_#{ color_option.upcase }")
166
- end
167
- color_code += ';' + color_option
251
+ next if color_option == ""
252
+
253
+ unless color_option =~ /\d+/
254
+ color_option = const_get("ANSI_ESCAPE_#{ color_option.upcase }")
168
255
  end
256
+ color_code += ";" + color_option
169
257
  end
170
258
  color_enabled? ? "\e[0#{ color_code }m#{ text }\e[0m" : text
171
259
  end
172
-
173
260
  end
174
-
175
- # Brighten the color
176
- ANSI_ESCAPE_BRIGHT = '1'
177
-
178
- # Black foreground color
179
- ANSI_ESCAPE_BLACK = '30'
180
-
181
- # Red foreground color
182
- ANSI_ESCAPE_RED = '31'
183
-
184
- # Green foreground color
185
- ANSI_ESCAPE_GREEN = '32'
186
-
187
- # Yellow foreground color
188
- ANSI_ESCAPE_YELLOW = '33'
189
-
190
- # Blue foreground color
191
- ANSI_ESCAPE_BLUE = '34'
192
-
193
- # Magenta foreground color
194
- ANSI_ESCAPE_MAGENTA = '35'
195
-
196
- # Cyan foreground color
197
- ANSI_ESCAPE_CYAN = '36'
198
-
199
- # White foreground color
200
- ANSI_ESCAPE_WHITE = '37'
201
-
202
- # Black background color
203
- ANSI_ESCAPE_BGBLACK = '40'
204
-
205
- # Red background color
206
- ANSI_ESCAPE_BGRED = '41'
207
-
208
- # Green background color
209
- ANSI_ESCAPE_BGGREEN = '42'
210
-
211
- # Yellow background color
212
- ANSI_ESCAPE_BGYELLOW = '43'
213
-
214
- # Blue background color
215
- ANSI_ESCAPE_BGBLUE = '44'
216
-
217
- # Magenta background color
218
- ANSI_ESCAPE_BGMAGENTA = '45'
219
-
220
- # Cyan background color
221
- ANSI_ESCAPE_BGCYAN = '46'
222
-
223
- # White background color
224
- ANSI_ESCAPE_BGWHITE = '47'
225
-
226
261
  end
227
262
  end
data/lib/guard/version.rb CHANGED
@@ -1,4 +1,3 @@
1
1
  module Guard
2
- # The current gem version of Guard
3
- VERSION = '1.4.0'
2
+ VERSION = "2.18.0"
4
3
  end
@@ -0,0 +1,45 @@
1
+ require_relative "matcher"
2
+
3
+ module Guard
4
+ class Watcher
5
+ class Pattern
6
+ # TODO: remove before Guard 3.x
7
+ class DeprecatedRegexp
8
+ def initialize(pattern)
9
+ @original_pattern = pattern
10
+ end
11
+
12
+ def self.convert(pattern)
13
+ Matcher.new(Regexp.new(pattern))
14
+ end
15
+
16
+ def deprecated?
17
+ regexp = /(^(\^))|(>?(\\\.)|(\.\*))|(\(.*\))|(\[.*\])|(\$$)/
18
+ @original_pattern.is_a?(String) && regexp.match(@original_pattern)
19
+ end
20
+
21
+ def self.show_deprecation(pattern)
22
+ @warning_printed ||= false
23
+
24
+ unless @warning_printed
25
+ msg = "*" * 20 + "\nDEPRECATION WARNING!\n" + "*" * 20
26
+ msg += <<-MSG
27
+ You have a string in your Guardfile watch patterns that seem to
28
+ represent a Regexp.
29
+
30
+ Guard matches String with == and Regexp with Regexp#match.
31
+
32
+ You should either use plain String (without Regexp special
33
+ characters) or real Regexp.
34
+ MSG
35
+ UI.deprecation(msg)
36
+ @warning_printed = true
37
+ end
38
+
39
+ new_regexp = Regexp.new(pattern).inspect
40
+ UI.info "\"#{pattern}\" will be converted to #{new_regexp}\n"
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,18 @@
1
+ module Guard
2
+ class Watcher
3
+ class Pattern
4
+ class MatchResult
5
+ def initialize(match_result, original_value)
6
+ @match_result = match_result
7
+ @original_value = original_value
8
+ end
9
+
10
+ def [](index)
11
+ return @match_result[index] if index.is_a?(Symbol)
12
+ return @original_value if index.zero?
13
+ @match_result.to_a[index]
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,33 @@
1
+ module Guard
2
+ class Watcher
3
+ class Pattern
4
+ class Matcher
5
+ attr_reader :matcher
6
+
7
+ def initialize(obj)
8
+ @matcher = obj
9
+ end
10
+
11
+ # Compare with other matcher
12
+ # @param other [Guard::Watcher::Pattern::Matcher]
13
+ # other matcher for comparing
14
+ # @return [true, false] equal or not
15
+ def ==(other)
16
+ matcher == other.matcher
17
+ end
18
+
19
+ def match(string_or_pathname)
20
+ @matcher.match(normalized(string_or_pathname))
21
+ end
22
+
23
+ private
24
+
25
+ def normalized(string_or_pathname)
26
+ path = Pathname.new(string_or_pathname).cleanpath
27
+ return path.to_s if @matcher.is_a?(Regexp)
28
+ path
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,15 @@
1
+ require_relative "simple_path"
2
+
3
+ module Guard
4
+ class Watcher
5
+ class Pattern
6
+ class PathnamePath < SimplePath
7
+ protected
8
+
9
+ def normalize(string_or_pathname)
10
+ Pathname.new(string_or_pathname).cleanpath
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,23 @@
1
+ module Guard
2
+ class Watcher
3
+ class Pattern
4
+ class SimplePath
5
+ def initialize(string_or_pathname)
6
+ @path = normalize(string_or_pathname)
7
+ end
8
+
9
+ def match(string_or_pathname)
10
+ cleaned = normalize(string_or_pathname)
11
+ return nil unless @path == cleaned
12
+ [cleaned]
13
+ end
14
+
15
+ protected
16
+
17
+ def normalize(string_or_pathname)
18
+ Pathname.new(string_or_pathname).cleanpath.to_s
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,24 @@
1
+ require "guard/ui"
2
+
3
+ require_relative "pattern/match_result"
4
+ require_relative "pattern/matcher"
5
+ require_relative "pattern/deprecated_regexp"
6
+ require_relative "pattern/simple_path"
7
+ require_relative "pattern/pathname_path"
8
+
9
+ module Guard
10
+ class Watcher
11
+ class Pattern
12
+ def self.create(pattern)
13
+ if DeprecatedRegexp.new(pattern).deprecated?
14
+ DeprecatedRegexp.show_deprecation(pattern)
15
+ return DeprecatedRegexp.convert(pattern)
16
+ end
17
+
18
+ return PathnamePath.new(pattern) if pattern.is_a?(Pathname)
19
+ return SimplePath.new(pattern) if pattern.is_a?(String)
20
+ Matcher.new(pattern)
21
+ end
22
+ end
23
+ end
24
+ end