guard 1.4.0 → 2.18.0

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