guard 1.4.0 → 1.5.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.
@@ -14,6 +14,7 @@ module Guard
14
14
  # * rb-notifu
15
15
  # * emacs
16
16
  # * Terminal Notifier
17
+ # * Terminal Title
17
18
  # * Tmux
18
19
  #
19
20
  # Please see the documentation of each notifier for more information about the requirements
@@ -46,22 +47,26 @@ module Guard
46
47
  require 'guard/notifiers/rb_notifu'
47
48
  require 'guard/notifiers/emacs'
48
49
  require 'guard/notifiers/terminal_notifier'
50
+ require 'guard/notifiers/terminal_title'
49
51
  require 'guard/notifiers/tmux'
50
52
 
51
53
  extend self
52
54
 
53
- # List of available notifiers. It needs to be a nested hash instead of
55
+ # List of available notifiers, grouped by functionality. It needs to be a nested hash instead of
54
56
  # a simpler Hash, because it maintains its order on Ruby 1.8.7 also.
55
57
  NOTIFIERS = [
56
- [:growl, ::Guard::Notifier::Growl],
57
- [:gntp, ::Guard::Notifier::GNTP],
58
- [:growl_notify, ::Guard::Notifier::GrowlNotify],
59
- [:libnotify, ::Guard::Notifier::Libnotify],
60
- [:notifysend, ::Guard::Notifier::NotifySend],
61
- [:notifu, ::Guard::Notifier::Notifu],
62
- [:emacs, ::Guard::Notifier::Emacs],
63
- [:terminal_notifier, ::Guard::Notifier::TerminalNotifier],
64
- [:tmux, ::Guard::Notifier::Tmux]
58
+ [
59
+ [:gntp, ::Guard::Notifier::GNTP],
60
+ [:growl, ::Guard::Notifier::Growl],
61
+ [:growl_notify, ::Guard::Notifier::GrowlNotify],
62
+ [:terminal_notifier, ::Guard::Notifier::TerminalNotifier],
63
+ [:libnotify, ::Guard::Notifier::Libnotify],
64
+ [:notifysend, ::Guard::Notifier::NotifySend],
65
+ [:notifu, ::Guard::Notifier::Notifu]
66
+ ],
67
+ [[:emacs, ::Guard::Notifier::Emacs]],
68
+ [[:tmux, ::Guard::Notifier::Tmux]],
69
+ [[:terminal_title, ::Guard::Notifier::TerminalTitle]]
65
70
  ]
66
71
 
67
72
  # Get the available notifications.
@@ -110,6 +115,17 @@ module Guard
110
115
  ENV['GUARD_NOTIFY'] = 'false'
111
116
  end
112
117
 
118
+ # Toggle the system notifications on/off
119
+ #
120
+ def toggle
121
+ if ENV['GUARD_NOTIFY'] == 'true'
122
+ ::Guard::UI.info 'Turn off notifications'
123
+ turn_off
124
+ else
125
+ turn_on
126
+ end
127
+ end
128
+
113
129
  # Test if the notifications are on.
114
130
  #
115
131
  # @return [Boolean] whether the notifications are on
@@ -164,20 +180,26 @@ module Guard
164
180
 
165
181
  # Get the notifier module for the given name.
166
182
  #
167
- # @param [Symbol] the notifier name
183
+ # @param [Symbol] name the notifier name
168
184
  # @return [Module] the notifier module
169
185
  #
170
186
  def get_notifier_module(name)
171
- notifier = NOTIFIERS.detect { |n| n.first == name }
187
+ notifier = NOTIFIERS.flatten(1).detect { |n| n.first == name }
172
188
  notifier ? notifier.last : notifier
173
189
  end
174
190
 
175
191
  # Auto detect the available notification library. This goes through
176
192
  # the list of supported notification gems and picks the first that
177
- # is available.
193
+ # is available in each notification group.
178
194
  #
179
195
  def auto_detect_notification
180
- available = NOTIFIERS.map { |n| n.first }.any? { |notifier| add_notification(notifier, { }, true) }
196
+ available = nil
197
+
198
+ NOTIFIERS.each do |group|
199
+ added = group.map { |n| n.first }.find { |notifier| add_notification(notifier, { }, true) }
200
+ available = available || added
201
+ end
202
+
181
203
  ::Guard::UI.info('Guard could not detect any of the supported notification libraries.') unless available
182
204
  end
183
205
 
@@ -3,14 +3,6 @@ require 'rbconfig'
3
3
  module Guard
4
4
  module Notifier
5
5
 
6
- # Default options for EmacsClient
7
- DEFAULTS = {
8
- :client => 'emacsclient',
9
- :success => 'ForestGreen',
10
- :failed => 'Firebrick',
11
- :default => 'Black',
12
- }
13
-
14
6
  # Send a notification to Emacs with emacsclient (http://www.emacswiki.org/emacs/EmacsClient).
15
7
  #
16
8
  # @example Add the `:emacs` notifier to your `Guardfile`
@@ -19,6 +11,13 @@ module Guard
19
11
  module Emacs
20
12
  extend self
21
13
 
14
+ DEFAULTS = {
15
+ :client => 'emacsclient',
16
+ :success => 'ForestGreen',
17
+ :failed => 'Firebrick',
18
+ :default => 'Black',
19
+ }
20
+
22
21
  # Test if Emacs with running server is available.
23
22
  #
24
23
  # @param [Boolean] silent true if no error messages should be shown
@@ -41,28 +40,33 @@ module Guard
41
40
  # @param [String] message the notification message body
42
41
  # @param [String] image the path to the notification image
43
42
  # @param [Hash] options additional notification library options
44
- # @option options [Boolean] sticky make the notification sticky
43
+ # @option options [String] success the color to use for success notifications (default is 'ForestGreen')
44
+ # @option options [String] failed the color to use for failure notifications (default is 'Firebrick')
45
+ # @option options [String] pending the color to use for pending notifications
46
+ # @option options [String] default the default color to use (default is 'Black')
47
+ # @option options [String] client the client to use for notification (default is 'emacsclient')
45
48
  # @option options [String, Integer] priority specify an int or named key (default is 0)
46
49
  #
47
50
  def notify(type, title, message, image, options = { })
48
- system(%(#{ DEFAULTS[:client] } --eval "(set-face-background 'modeline \\"#{ emacs_color(type) }\\")"))
51
+ options = DEFAULTS.merge options
52
+ color = emacs_color type, options
53
+ system(%(#{ options[:client] } --eval "(set-face-background 'modeline \\"#{ color }\\")"))
49
54
  end
50
55
 
51
56
  # Get the Emacs color for the notification type.
52
57
  # You can configure your own color by overwrite the defaults.
53
58
  #
54
59
  # @param [String] type the notification type
60
+ # @param [Hash] options aditional notification options
61
+ # @option options [String] success the color to use for success notifications (default is 'ForestGreen')
62
+ # @option options [String] failed the color to use for failure notifications (default is 'Firebrick')
63
+ # @option options [String] pending the color to use for pending notifications
64
+ # @option options [String] default the default color to use (default is 'Black')
55
65
  # @return [String] the name of the emacs color
56
66
  #
57
- def emacs_color(type)
58
- case type
59
- when 'success'
60
- DEFAULTS[:success]
61
- when 'failed'
62
- DEFAULTS[:failed]
63
- else
64
- DEFAULTS[:default]
65
- end
67
+ def emacs_color(type, options = {})
68
+ default = options[:default] || DEFAULTS[:default]
69
+ options.fetch(type.to_sym, default)
66
70
  end
67
71
  end
68
72
  end
@@ -0,0 +1,35 @@
1
+ # Module for notifying test result to terminal title
2
+ module Guard
3
+ module Notifier
4
+ module TerminalTitle
5
+ extend self
6
+
7
+ # Test if the notification library is available.
8
+ #
9
+ # @param [Boolean] silent true if no error messages should be shown
10
+ # @return [Boolean] the availability status
11
+ #
12
+ def available?(silent = false)
13
+ true
14
+ end
15
+
16
+ # Show a system notification.
17
+ #
18
+ # @param [String] type the notification type. Either 'success', 'pending', 'failed' or 'notify'
19
+ # @param [String] title the notification title
20
+ # @param [String] message the notification message body
21
+ # @param [String] image the path to the notification image
22
+ # @param [Hash] options additional notification library options
23
+ #
24
+ def notify(type, title, message, image, options = { })
25
+ message.sub!(/^\n/, '')
26
+ message.sub!(/\n.*/m, '')
27
+ set_terminal_title("[#{title}] #{message}")
28
+ end
29
+
30
+ def set_terminal_title(text)
31
+ puts "\e]2;#{text}\a"
32
+ end
33
+ end
34
+ end
35
+ end
@@ -3,20 +3,34 @@ module Guard
3
3
 
4
4
  # Default options for Tmux
5
5
 
6
- # Changes the color of the Tmux status bar
6
+ # Changes the color of the Tmux status bar and optionally
7
+ # shows messages in the status bar.
7
8
  #
8
9
  # @example Add the `:tmux` notifier to your `Guardfile`
9
10
  # notification :tmux
10
11
  #
12
+ # @example Enable text messages
13
+ # notification :tmux, :display_message => true
14
+ #
15
+ # @example Customize the tmux status colored for notifications
16
+ # notification :tmux, :color_location => 'status-right-bg'
17
+ #
11
18
  module Tmux
12
19
  extend self
13
20
 
14
21
  DEFAULTS = {
15
- :client => 'tmux',
16
- :tmux_environment => 'TMUX',
17
- :success => 'green',
18
- :failed => 'red',
19
- :default => 'green'
22
+ :client => 'tmux',
23
+ :tmux_environment => 'TMUX',
24
+ :success => 'green',
25
+ :failed => 'red',
26
+ :pending => 'yellow',
27
+ :default => 'green',
28
+ :timeout => 5,
29
+ :display_message => false,
30
+ :default_message_format => '%s - %s',
31
+ :default_message_color => 'white',
32
+ :line_separator => ' - ',
33
+ :color_location => 'status-left-bg'
20
34
  }
21
35
 
22
36
  # Test if currently running in a Tmux session
@@ -33,19 +47,60 @@ module Guard
33
47
  end
34
48
  end
35
49
 
36
- # Show a system notification.
50
+ # Show a system notification. By default, the Tmux notifier only makes use of a color based
51
+ # notification, changing the background color of the `color_location` to the color defined
52
+ # in either the `success`, `failed`, `pending` or `default`, depending on the notification type.
53
+ # If you also want display a text message, you have to enable it explicit by setting `display_message`
54
+ # to `true`.
37
55
  #
38
56
  # @param [String] type the notification type. Either 'success', 'pending', 'failed' or 'notify'
39
57
  # @param [String] title the notification title
40
58
  # @param [String] message the notification message body
41
59
  # @param [String] image the path to the notification image
42
60
  # @param [Hash] options additional notification library options
43
- # @option options [Boolean] sticky make the notification sticky
44
- # @option options [String, Integer] priority specify an int or named key (default is 0)
61
+ # @option options [String] color_location the location where to draw the color notification
62
+ # @option options [Boolean] display_message whether to display a message or not
45
63
  #
46
64
  def notify(type, title, message, image, options = { })
47
65
  color = tmux_color type, options
48
- system("#{ DEFAULTS[:client] } set -g status-left-bg #{ color }")
66
+ color_location = options[:color_location] || DEFAULTS[:color_location]
67
+ system("#{ DEFAULTS[:client] } set -g #{ color_location } #{ color }")
68
+
69
+ show_message = options[:display_message] || DEFAULTS[:display_message]
70
+ display_message(type, title, message, options) if show_message
71
+ end
72
+
73
+ # Display a message in the status bar of tmux.
74
+ #
75
+ # @param [String] type the notification type. Either 'success', 'pending', 'failed' or 'notify'
76
+ # @param [String] title the notification title
77
+ # @param [String] message the notification message body
78
+ # @param [Hash] options additional notification library options
79
+ # @option options [Integer] timeout the amount of seconds to show the message in the status bar
80
+ # @option options [String] success_message_format a string to use as formatter for the success message.
81
+ # @option options [String] failed_message_format a string to use as formatter for the failed message.
82
+ # @option options [String] pending_message_format a string to use as formatter for the pending message.
83
+ # @option options [String] default_message_format a string to use as formatter when no format per type is defined.
84
+ # @option options [String] success_message_color the success notification foreground color name.
85
+ # @option options [String] failed_message_color the failed notification foreground color name.
86
+ # @option options [String] pending_message_color the pending notification foreground color name.
87
+ # @option options [String] default_message_color a notification foreground color to use when no color per type is defined.
88
+ # @option options [String] line_separator a string to use instead of a line-break.
89
+ #
90
+ def display_message(type, title, message, options = { })
91
+ message_format = options["#{ type }_message_format".to_sym] || options[:default_message_format] || DEFAULTS[:default_message_format]
92
+ message_color = options["#{ type }_message_color".to_sym] || options[:default_message_color] || DEFAULTS[:default_message_color]
93
+ display_time = options[:timeout] || DEFAULTS[:timeout]
94
+ separator = options[:line_separator] || DEFAULTS[:line_separator]
95
+
96
+ color = tmux_color type, options
97
+ formatted_message = message.split("\n").join(separator)
98
+ display_message = message_format % [title, formatted_message]
99
+
100
+ system("#{ DEFAULTS[:client] } set display-time #{ display_time * 1000 }")
101
+ system("#{ DEFAULTS[:client] } set message-fg #{ message_color }")
102
+ system("#{ DEFAULTS[:client] } set message-bg #{ color }")
103
+ system("#{ DEFAULTS[:client] } display-message '#{ display_message }'")
49
104
  end
50
105
 
51
106
  # Get the Tmux color for the notification type.
@@ -60,6 +115,8 @@ module Guard
60
115
  options[:success] || DEFAULTS[:success]
61
116
  when 'failed'
62
117
  options[:failed] || DEFAULTS[:failed]
118
+ when 'pending'
119
+ options[:pending] || DEFAULTS[:pending]
63
120
  else
64
121
  options[:default] || DEFAULTS[:default]
65
122
  end
data/lib/guard/runner.rb CHANGED
@@ -7,6 +7,8 @@ module Guard
7
7
  require 'guard'
8
8
  require 'guard/ui'
9
9
  require 'guard/watcher'
10
+
11
+ require 'lumberjack'
10
12
 
11
13
  # Deprecation message for the `run_on_change` method
12
14
  RUN_ON_CHANGE_DEPRECATION = <<-EOS.gsub(/^\s*/, '')
@@ -47,8 +49,10 @@ module Guard
47
49
  # @see self.run_supervised_task
48
50
  #
49
51
  def run(task, scopes = {})
50
- scoped_guards(scopes) do |guard|
51
- run_supervised_task(guard, task)
52
+ Lumberjack.unit_of_work do
53
+ scoped_guards(scopes) do |guard|
54
+ run_supervised_task(guard, task)
55
+ end
52
56
  end
53
57
  end
54
58
 
data/lib/guard/ui.rb CHANGED
@@ -1,26 +1,53 @@
1
+ require 'lumberjack'
2
+
1
3
  module Guard
2
4
 
3
5
  # The UI class helps to format messages for the user. Everything that is logged
4
6
  # through this class is considered either as an error message or a diagnostic
5
- # message and is written to standard error (STDERR).
7
+ # message and is written to standard error ($stderr).
6
8
  #
7
9
  # If your Guard plugin does some output that is piped into another process for further
8
10
  # processing, please just write it to STDOUT with `puts`.
9
11
  #
10
12
  module UI
13
+
11
14
  class << self
12
15
 
13
- color_enabled = nil
16
+ # Get the Guard::UI logger instance
17
+ #
18
+ def logger
19
+ @logger ||= Lumberjack::Logger.new($stderr, self.options)
20
+ end
21
+
22
+ # Get the logger options
23
+ #
24
+ # @return [Hash] the logger options
25
+ #
26
+ def options
27
+ @options ||= { :level => :info, :template => ':time - :severity - :message', :time_format => '%H:%M:%S' }
28
+ end
29
+
30
+ # Set the logger options
31
+ #
32
+ # @param [Hash] options the logger options
33
+ # @option options [Symbol] level the log level
34
+ # @option options [String] template the logger template
35
+ # @option options [String] time_format the time format
36
+ #
37
+ def options=(options)
38
+ @options = options
39
+ end
14
40
 
15
41
  # Show an info message.
16
42
  #
17
43
  # @param [String] message the message to show
18
44
  # @option options [Boolean] reset whether to clean the output before
45
+ # @option options [String] plugin manually define the calling plugin
19
46
  #
20
47
  def info(message, options = { })
21
- unless ENV['GUARD_ENV'] == 'test'
48
+ filter(options[:plugin]) do |plugin|
22
49
  reset_line if options[:reset]
23
- STDERR.puts color(message) if message != ''
50
+ self.logger.info(message, plugin)
24
51
  end
25
52
  end
26
53
 
@@ -28,11 +55,12 @@ module Guard
28
55
  #
29
56
  # @param [String] message the message to show
30
57
  # @option options [Boolean] reset whether to clean the output before
58
+ # @option options [String] plugin manually define the calling plugin
31
59
  #
32
60
  def warning(message, options = { })
33
- unless ENV['GUARD_ENV'] == 'test'
61
+ filter(options[:plugin]) do |plugin|
34
62
  reset_line if options[:reset]
35
- STDERR.puts color('WARNING: ', :yellow) + message
63
+ self.logger.warn(color(message, :yellow), plugin)
36
64
  end
37
65
  end
38
66
 
@@ -40,23 +68,26 @@ module Guard
40
68
  #
41
69
  # @param [String] message the message to show
42
70
  # @option options [Boolean] reset whether to clean the output before
71
+ # @option options [String] plugin manually define the calling plugin
43
72
  #
44
73
  def error(message, options = { })
45
- unless ENV['GUARD_ENV'] == 'test'
74
+ filter(options[:plugin]) do |plugin|
46
75
  reset_line if options[:reset]
47
- STDERR.puts color('ERROR: ', :red) + message
76
+ self.logger.error(color(message, :red), plugin)
48
77
  end
49
78
  end
50
79
 
51
80
  # Show a red deprecation message that is prefixed with DEPRECATION.
81
+ # It has a log level of `warn`.
52
82
  #
53
83
  # @param [String] message the message to show
54
84
  # @option options [Boolean] reset whether to clean the output before
85
+ # @option options [String] plugin manually define the calling plugin
55
86
  #
56
87
  def deprecation(message, options = { })
57
- unless ENV['GUARD_ENV'] == 'test'
88
+ filter(options[:plugin]) do |plugin|
58
89
  reset_line if options[:reset]
59
- STDERR.puts color('DEPRECATION: ', :red) + message
90
+ self.logger.warn(color(message, :yellow), plugin)
60
91
  end
61
92
  end
62
93
 
@@ -64,18 +95,19 @@ module Guard
64
95
  #
65
96
  # @param [String] message the message to show
66
97
  # @option options [Boolean] reset whether to clean the output before
98
+ # @option options [String] plugin manually define the calling plugin
67
99
  #
68
100
  def debug(message, options = { })
69
- unless ENV['GUARD_ENV'] == 'test'
101
+ filter(options[:plugin]) do |plugin|
70
102
  reset_line if options[:reset]
71
- STDERR.puts color("DEBUG (#{Time.now.strftime('%T')}): ", :yellow) + message if ::Guard.options && ::Guard.options[:debug]
103
+ self.logger.debug(color(message, :yellow), plugin)
72
104
  end
73
105
  end
74
106
 
75
107
  # Reset a line.
76
108
  #
77
109
  def reset_line
78
- STDERR.print(color_enabled? ? "\r\e[0m" : "\r\n")
110
+ $stderr.print(color_enabled? ? "\r\e[0m" : "\r\n")
79
111
  end
80
112
 
81
113
  # Clear the output if clearable.
@@ -107,6 +139,34 @@ module Guard
107
139
  end
108
140
 
109
141
  private
142
+
143
+ # Filters log messages depending on either the
144
+ # `:only`` or `:except` option.
145
+ #
146
+ # @param [String] plugin the calling plugin name
147
+ # @yield When the message should be logged
148
+ # @yieldparam [String] param the calling plugin name
149
+ #
150
+ def filter(plugin)
151
+ only = self.options[:only]
152
+ except = self.options[:except]
153
+ plugin = plugin || calling_plugin_name
154
+
155
+ if (!only && !except) || (only && only.match(plugin)) || (except && !except.match(plugin))
156
+ yield plugin
157
+ end
158
+ end
159
+
160
+ # Tries to extract the calling Guard plugin name
161
+ # from the call stack.
162
+ #
163
+ # @param [Integer] depth the stack depth
164
+ # @return [String] the Guard plugin name
165
+ #
166
+ def calling_plugin_name(depth = 2)
167
+ name = /(guard\/[a-z_]*)(\/[a-z_]*)?.rb:/i.match(caller[depth])
168
+ name ? name[1].split('/').map { |part| part.split(/[^a-z0-9]/i).map { |word| word.capitalize }.join }.join('::') : 'Guard'
169
+ end
110
170
 
111
171
  # Reset a color sequence.
112
172
  #
@@ -161,7 +221,7 @@ module Guard
161
221
  color_options.each do |color_option|
162
222
  color_option = color_option.to_s
163
223
  if color_option != ''
164
- if !(color_option =~ /\d+/)
224
+ unless color_option =~ /\d+/
165
225
  color_option = const_get("ANSI_ESCAPE_#{ color_option.upcase }")
166
226
  end
167
227
  color_code += ';' + color_option