guard 2.10.0 → 2.10.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,83 +0,0 @@
1
- require "guard/internals/environment"
2
-
3
- require_relative "../notifiers/emacs"
4
- require_relative "../notifiers/file_notifier"
5
- require_relative "../notifiers/gntp"
6
- require_relative "../notifiers/growl"
7
- require_relative "../notifiers/libnotify"
8
- require_relative "../notifiers/notifysend"
9
- require_relative "../notifiers/rb_notifu"
10
- require_relative "../notifiers/terminal_notifier"
11
- require_relative "../notifiers/terminal_title"
12
- require_relative "../notifiers/tmux"
13
-
14
- module Guard
15
- module Notifier
16
- # @private api
17
- class Detected
18
- NO_SUPPORTED_NOTIFIERS = "Guard could not detect any of the supported" +
19
- " notification libraries."
20
-
21
- class NoneAvailableError < RuntimeError
22
- end
23
-
24
- def initialize(supported)
25
- @supported = supported
26
- @environment = Internals::Environment.new("GUARD").tap do |env|
27
- env.create_method(:notifiers=) { |data| YAML::dump(data) }
28
- env.create_method(:notifiers) { |data| data ? YAML::load(data) : [] }
29
- end
30
- end
31
-
32
- def reset
33
- @environment.notifiers = nil
34
- end
35
-
36
- def detect
37
- return unless _data.empty?
38
- @supported.each do |group|
39
- group.detect { |name, _| add(name, silent: true) }
40
- end
41
-
42
- fail NoneAvailableError, NO_SUPPORTED_NOTIFIERS if _data.empty?
43
- end
44
-
45
- def available
46
- _data.map { |entry| [_to_module(entry[:name]), entry[:options]] }
47
- end
48
-
49
- def add(name, opts)
50
- klass = _to_module(name)
51
- return false unless klass
52
-
53
- all = @environment.notifiers
54
-
55
- # Silently skip if it's already available, because otherwise
56
- # we'd have to do :turn_off, then configure, then :turn_on
57
- names = all.map(&:first).map(&:last)
58
- unless names.include?(name)
59
- return false unless klass.available?(opts)
60
- @environment.notifiers = all << { name: name, options: opts }
61
- true
62
- end
63
-
64
- # Just overwrite the options (without turning the notifier off or on),
65
- # so those options will be passed in next calls to notify()
66
- all.each { |item| item[:options] = opts if item[:name] == name }
67
- true
68
- end
69
-
70
- def _to_module(name)
71
- @supported.each do |group|
72
- next unless (notifier = group.detect { |n, _| n == name })
73
- return notifier.last
74
- end
75
- nil
76
- end
77
-
78
- def _data
79
- @environment.notifiers || []
80
- end
81
- end
82
- end
83
- end
@@ -1,300 +0,0 @@
1
- module Guard
2
- # Base class from which every Guard plugin implementation must inherit.
3
- #
4
- # Guard will trigger the {#start}, {#stop}, {#reload}, {#run_all} and
5
- # {#run_on_changes} ({#run_on_additions}, {#run_on_modifications} and
6
- # {#run_on_removals}) task methods depending on user interaction and file
7
- # modification.
8
- #
9
- # {#run_on_changes} could be implemented to handle all the changes task case
10
- # (additions, modifications, removals) in once, or each task can be
11
- # implemented separately with a specific behavior.
12
- #
13
- # In each of these Guard task methods you have to implement some work when
14
- # you want to support this kind of task. The return value of each Guard task
15
- # method is not evaluated by Guard, but it'll be passed to the "_end" hook
16
- # for further evaluation. You can throw `:task_has_failed` to indicate that
17
- # your Guard plugin method was not successful, and successive Guard plugin
18
- # tasks will be aborted when the group has set the `:halt_on_fail` option.
19
- #
20
- # @see Guard::Group
21
- #
22
- # @example Throw :task_has_failed
23
- #
24
- # def run_all
25
- # if !runner.run(['all'])
26
- # throw :task_has_failed
27
- # end
28
- # end
29
- #
30
- # Each Guard plugin should provide a template Guardfile located within the Gem
31
- # at `lib/guard/guard-name/templates/Guardfile`.
32
- #
33
- # Watchers for a Guard plugin should return a file path or an array of files
34
- # paths to Guard, but if your Guard plugin wants to allow any return value
35
- # from a watcher, you can set the `any_return` option to true.
36
- #
37
- # If one of those methods raises an exception other than `:task_has_failed`,
38
- # the `Guard::GuardName` instance will be removed from the active Guard
39
- # plugins.
40
- #
41
- class Plugin
42
- TEMPLATE_FORMAT = "%s/lib/guard/%s/templates/Guardfile"
43
-
44
- require "guard/ui"
45
-
46
- # Get all callbacks registered for all Guard plugins present in the
47
- # Guardfile.
48
- #
49
- def self.callbacks
50
- @callbacks ||= Hash.new { |hash, key| hash[key] = [] }
51
- end
52
-
53
- # Add a callback.
54
- #
55
- # @param [Block] listener the listener to notify
56
- # @param [Guard::Plugin] guard_plugin the Guard plugin to add the callback
57
- # @param [Array<Symbol>] events the events to register
58
- #
59
- def self.add_callback(listener, guard_plugin, events)
60
- Array(events).each do |event|
61
- callbacks[[guard_plugin, event]] << listener
62
- end
63
- end
64
-
65
- # Notify a callback.
66
- #
67
- # @param [Guard::Plugin] guard_plugin the Guard plugin to add the callback
68
- # @param [Symbol] event the event to trigger
69
- # @param [Array] args the arguments for the listener
70
- #
71
- def self.notify(guard_plugin, event, *args)
72
- callbacks[[guard_plugin, event]].each do |listener|
73
- listener.call(guard_plugin, event, *args)
74
- end
75
- end
76
-
77
- # Reset all callbacks.
78
- #
79
- # TODO: remove (not used anywhere)
80
- def self.reset_callbacks!
81
- @callbacks = nil
82
- end
83
-
84
- # When event is a Symbol, {#hook} will generate a hook name
85
- # by concatenating the method name from where {#hook} is called
86
- # with the given Symbol.
87
- #
88
- # @example Add a hook with a Symbol
89
- #
90
- # def run_all
91
- # hook :foo
92
- # end
93
- #
94
- # Here, when {Guard::Plugin::Base#run_all} is called, {#hook} will notify
95
- # callbacks registered for the "run_all_foo" event.
96
- #
97
- # When event is a String, {#hook} will directly turn the String
98
- # into a Symbol.
99
- #
100
- # @example Add a hook with a String
101
- #
102
- # def run_all
103
- # hook "foo_bar"
104
- # end
105
- #
106
- # When {Guard::Plugin::Base#run_all} is called, {#hook} will notify
107
- # callbacks registered for the "foo_bar" event.
108
- #
109
- # @param [Symbol, String] event the name of the Guard event
110
- # @param [Array] args the parameters are passed as is to the callbacks
111
- # registered for the given event.
112
- #
113
- def hook(event, *args)
114
- hook_name = if event.is_a? Symbol
115
- calling_method = caller[0][/`([^']*)'/, 1]
116
- "#{ calling_method }_#{ event }"
117
- else
118
- event
119
- end
120
-
121
- UI.debug "Hook :#{ hook_name } executed for #{ self.class }"
122
-
123
- self.class.notify(self, hook_name.to_sym, *args)
124
- end
125
-
126
- attr_accessor :group, :watchers, :callbacks, :options
127
-
128
- # Returns the non-namespaced class name of the plugin
129
- #
130
- #
131
- # @example Non-namespaced class name for Guard::RSpec
132
- # Guard::RSpec.non_namespaced_classname
133
- # #=> "RSpec"
134
- #
135
- # @return [String]
136
- #
137
- def self.non_namespaced_classname
138
- to_s.sub("Guard::", "")
139
- end
140
-
141
- # Returns the non-namespaced name of the plugin
142
- #
143
- #
144
- # @example Non-namespaced name for Guard::RSpec
145
- # Guard::RSpec.non_namespaced_name
146
- # #=> "rspec"
147
- #
148
- # @return [String]
149
- #
150
- def self.non_namespaced_name
151
- non_namespaced_classname.downcase
152
- end
153
-
154
- # Specify the source for the Guardfile template.
155
- # Each Guard plugin can redefine this method to add its own logic.
156
- #
157
- # @param [String] plugin_location the plugin location
158
- #
159
- def self.template(plugin_location)
160
- File.read TEMPLATE_FORMAT % [plugin_location, non_namespaced_name]
161
- end
162
-
163
- # Called once when Guard starts. Please override initialize method to
164
- # init stuff.
165
- #
166
- # @raise [:task_has_failed] when start has failed
167
- # @return [Object] the task result
168
- #
169
- # @!method start
170
-
171
- # Called when `stop|quit|exit|s|q|e + enter` is pressed (when Guard
172
- # quits).
173
- #
174
- # @raise [:task_has_failed] when stop has failed
175
- # @return [Object] the task result
176
- #
177
- # @!method stop
178
-
179
- # Called when `reload|r|z + enter` is pressed.
180
- # This method should be mainly used for "reload" (really!) actions like
181
- # reloading passenger/spork/bundler/...
182
- #
183
- # @raise [:task_has_failed] when reload has failed
184
- # @return [Object] the task result
185
- #
186
- # @!method reload
187
-
188
- # Called when just `enter` is pressed
189
- # This method should be principally used for long action like running all
190
- # specs/tests/...
191
- #
192
- # @raise [:task_has_failed] when run_all has failed
193
- # @return [Object] the task result
194
- #
195
- # @!method run_all
196
-
197
- # Default behaviour on file(s) changes that the Guard plugin watches.
198
- #
199
- # @param [Array<String>] paths the changes files or paths
200
- # @raise [:task_has_failed] when run_on_changes has failed
201
- # @return [Object] the task result
202
- #
203
- # @!method run_on_changes(paths)
204
-
205
- # Called on file(s) additions that the Guard plugin watches.
206
- #
207
- # @param [Array<String>] paths the changes files or paths
208
- # @raise [:task_has_failed] when run_on_additions has failed
209
- # @return [Object] the task result
210
- #
211
- # @!method run_on_additions(paths)
212
-
213
- # Called on file(s) modifications that the Guard plugin watches.
214
- #
215
- # @param [Array<String>] paths the changes files or paths
216
- # @raise [:task_has_failed] when run_on_modifications has failed
217
- # @return [Object] the task result
218
- #
219
- # @!method run_on_modifications(paths)
220
-
221
- # Called on file(s) removals that the Guard plugin watches.
222
- #
223
- # @param [Array<String>] paths the changes files or paths
224
- # @raise [:task_has_failed] when run_on_removals has failed
225
- # @return [Object] the task result
226
- #
227
- # @!method run_on_removals(paths)
228
-
229
- # Returns the plugin's name (without "guard-").
230
- #
231
- # @example Name for Guard::RSpec
232
- # Guard::RSpec.new.name
233
- # #=> "rspec"
234
- #
235
- # @return [String]
236
- #
237
- def name
238
- @name ||= self.class.non_namespaced_name
239
- end
240
-
241
- # Returns the plugin's class name without the Guard:: namespace.
242
- #
243
- # @example Title for Guard::RSpec
244
- # Guard::RSpec.new.title
245
- # #=> "RSpec"
246
- #
247
- # @return [String]
248
- #
249
- def title
250
- @title ||= self.class.non_namespaced_classname
251
- end
252
-
253
- # String representation of the plugin.
254
- #
255
- # @example String representation of an instance of the Guard::RSpec plugin
256
- #
257
- # Guard::RSpec.new.title
258
- # #=> "#<Guard::RSpec @name=rspec @group=#<Guard::Group @name=default
259
- # @options={}> @watchers=[] @callbacks=[] @options={all_after_pass:
260
- # true}>"
261
- #
262
- # @return [String] the string representation
263
- #
264
- def to_s
265
- "#<#{self.class} @name=#{name} @group=#{group} @watchers=#{watchers}"\
266
- " @callbacks=#{callbacks} @options=#{options}>"
267
- end
268
-
269
- private
270
-
271
- # Initializes a Guard plugin.
272
- # Don't do any work here, especially as Guard plugins get initialized even
273
- # if they are not in an active group!
274
- #
275
- # @param [Hash] options the Guard plugin options
276
- # @option options [Array<Guard::Watcher>] watchers the Guard plugin file
277
- # watchers
278
- # @option options [Symbol] group the group this Guard plugin belongs to
279
- # @option options [Boolean] any_return allow any object to be returned from
280
- # a watcher
281
- #
282
- def initialize(options = {})
283
- group_name = options.delete(:group) { :default }
284
- @group = Guard.state.session.groups.add(group_name)
285
- @watchers = options.delete(:watchers) { [] }
286
- @callbacks = options.delete(:callbacks) { [] }
287
- @options = options
288
- _register_callbacks
289
- end
290
-
291
- # Add all the Guard::Plugin's callbacks to the global @callbacks array
292
- # that's used by Guard to know which callbacks to notify.
293
- #
294
- def _register_callbacks
295
- callbacks.each do |callback|
296
- Hooker.add_callback(callback[:listener], self, callback[:events])
297
- end
298
- end
299
- end
300
- end
@@ -1,22 +0,0 @@
1
- require "guard/plugin"
2
- require "guard/guardfile/evaluator"
3
-
4
- module Guard
5
- class Reevaluator < Plugin
6
- def run_on_modifications(files)
7
- STDERR.puts files.inspect
8
- return unless ::Guard::Watcher.match_guardfile?(files)
9
- ::Guard.save_scope
10
- Guard::Guardfile::Evaluator.new.reevaluate_guardfile
11
- rescue ScriptError, StandardError => e
12
- ::Guard::UI.warning("Failed to reevaluate file: #{e}")
13
-
14
- options = { watchers: [::Guard::Watcher.new("Guardfile")] }
15
- ::Guard.add_plugin(:reevaluator, options)
16
-
17
- throw :task_has_failed
18
- ensure
19
- ::Guard.restore_scope
20
- end
21
- end
22
- end
@@ -1,2 +0,0 @@
1
- # A sample Guardfile
2
- # More info at https://github.com/guard/guard#readme
data/lib/guard/ui.rb.orig DELETED
@@ -1,274 +0,0 @@
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