guard 0.8.8 → 0.9.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.
- data/CHANGELOG.md +16 -1
- data/README.md +665 -293
- data/bin/fsevent_watch_guard +0 -0
- data/lib/guard.rb +66 -31
- data/lib/guard/cli.rb +9 -3
- data/lib/guard/dsl.rb +32 -5
- data/lib/guard/dsl_describer.rb +3 -2
- data/lib/guard/guard.rb +2 -2
- data/lib/guard/interactor.rb +179 -48
- data/lib/guard/listener.rb +32 -17
- data/lib/guard/listeners/darwin.rb +5 -9
- data/lib/guard/listeners/linux.rb +6 -10
- data/lib/guard/listeners/windows.rb +4 -2
- data/lib/guard/notifier.rb +171 -258
- data/lib/guard/notifiers/gntp.rb +114 -0
- data/lib/guard/notifiers/growl.rb +98 -0
- data/lib/guard/notifiers/growl_notify.rb +91 -0
- data/lib/guard/notifiers/libnotify.rb +96 -0
- data/lib/guard/notifiers/rb_notifu.rb +101 -0
- data/lib/guard/ui.rb +2 -2
- data/lib/guard/version.rb +1 -1
- data/lib/guard/watcher.rb +1 -1
- data/lib/vendor/darwin/Gemfile +6 -0
- data/lib/vendor/darwin/Guardfile +8 -0
- data/lib/vendor/darwin/LICENSE +20 -0
- data/lib/vendor/darwin/README.rdoc +254 -0
- data/lib/vendor/darwin/Rakefile +21 -0
- data/lib/vendor/darwin/ext/extconf.rb +61 -0
- data/lib/vendor/darwin/ext/fsevent/fsevent_watch.c +226 -0
- data/lib/vendor/darwin/lib/rb-fsevent.rb +2 -0
- data/lib/vendor/darwin/lib/rb-fsevent/fsevent.rb +105 -0
- data/lib/vendor/darwin/lib/rb-fsevent/version.rb +3 -0
- data/lib/vendor/darwin/rb-fsevent.gemspec +24 -0
- data/lib/vendor/darwin/spec/fixtures/folder1/file1.txt +0 -0
- data/lib/vendor/darwin/spec/fixtures/folder1/folder2/file2.txt +0 -0
- data/lib/vendor/darwin/spec/rb-fsevent/fsevent_spec.rb +75 -0
- data/lib/vendor/darwin/spec/spec_helper.rb +24 -0
- data/lib/vendor/linux/MIT-LICENSE +20 -0
- data/lib/vendor/linux/README.md +66 -0
- data/lib/vendor/linux/Rakefile +54 -0
- data/lib/vendor/linux/VERSION +1 -0
- data/lib/vendor/linux/lib/rb-inotify.rb +17 -0
- data/lib/vendor/linux/lib/rb-inotify/event.rb +139 -0
- data/lib/vendor/linux/lib/rb-inotify/native.rb +31 -0
- data/lib/vendor/linux/lib/rb-inotify/native/flags.rb +89 -0
- data/lib/vendor/linux/lib/rb-inotify/notifier.rb +308 -0
- data/lib/vendor/linux/lib/rb-inotify/watcher.rb +83 -0
- data/lib/vendor/linux/rb-inotify.gemspec +53 -0
- data/lib/vendor/windows/Gemfile +4 -0
- data/lib/vendor/windows/README.md +34 -0
- data/lib/vendor/windows/Rakefile +18 -0
- data/lib/vendor/windows/lib/rb-fchange.rb +14 -0
- data/lib/vendor/windows/lib/rb-fchange/event.rb +29 -0
- data/lib/vendor/windows/lib/rb-fchange/native.rb +45 -0
- data/lib/vendor/windows/lib/rb-fchange/native/flags.rb +78 -0
- data/lib/vendor/windows/lib/rb-fchange/notifier.rb +149 -0
- data/lib/vendor/windows/lib/rb-fchange/version.rb +3 -0
- data/lib/vendor/windows/lib/rb-fchange/watcher.rb +99 -0
- data/lib/vendor/windows/rb-fchange.gemspec +34 -0
- data/lib/vendor/windows/spec/fixtures/folder1/file1.txt +0 -0
- data/lib/vendor/windows/spec/fixtures/folder1/folder2/file2.txt +0 -0
- data/lib/vendor/windows/spec/rb-fchange/fchange_spec.rb +119 -0
- data/lib/vendor/windows/spec/spec_helper.rb +21 -0
- metadata +87 -22
- data/lib/guard/version.rbc +0 -180
data/lib/guard/listener.rb
CHANGED
@@ -31,16 +31,17 @@ module Guard
|
|
31
31
|
# @param [Array] args the arguments for the listener
|
32
32
|
# @return [Guard::Listener] the chosen listener
|
33
33
|
#
|
34
|
-
def self.select_and_init(
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
34
|
+
def self.select_and_init(watchdir = Dir.pwd, options = nil)
|
35
|
+
no_vendor = options && options.key?(:no_vendor) ? options[:no_vendor] : false
|
36
|
+
if mac? && Darwin.usable?(no_vendor)
|
37
|
+
Darwin.new(watchdir, options)
|
38
|
+
elsif linux? && Linux.usable?(no_vendor)
|
39
|
+
Linux.new(watchdir, options)
|
40
|
+
elsif windows? && Windows.usable?(no_vendor)
|
41
|
+
Windows.new(watchdir, options)
|
41
42
|
else
|
42
43
|
UI.info 'Using polling (Please help us to support your system better than that).'
|
43
|
-
Polling.new(
|
44
|
+
Polling.new(watchdir, options)
|
44
45
|
end
|
45
46
|
end
|
46
47
|
|
@@ -48,18 +49,23 @@ module Guard
|
|
48
49
|
#
|
49
50
|
# @param [String] directory the root directory to listen to
|
50
51
|
# @option options [Boolean] relativize_paths use only relative paths
|
52
|
+
# @option options [Boolean] watch_all_modifications to enable deleted and moved file listening.
|
51
53
|
# @option options [Array<String>] ignore_paths the paths to ignore by the listener
|
52
54
|
#
|
53
55
|
def initialize(directory = Dir.pwd, options = {})
|
54
|
-
@directory = directory.to_s
|
55
56
|
@sha1_checksums_hash = {}
|
56
57
|
@file_timestamp_hash = {}
|
57
|
-
@relativize_paths = options.fetch(:relativize_paths, true)
|
58
58
|
@changed_files = []
|
59
59
|
@paused = false
|
60
|
+
|
61
|
+
@directory = directory.to_s
|
62
|
+
|
63
|
+
options = options.inject({}) { |h,(k,v)| h[k.to_sym] = v; h }
|
64
|
+
@relativize_paths = options.fetch(:relativize_paths, true)
|
65
|
+
@watch_all_modifications = options.fetch(:watch_all_modifications, false)
|
66
|
+
|
60
67
|
@ignore_paths = DEFAULT_IGNORE_PATHS
|
61
68
|
@ignore_paths |= options[:ignore_paths] if options[:ignore_paths]
|
62
|
-
@watch_all_modifications = options.fetch(:watch_all_modifications, false)
|
63
69
|
|
64
70
|
update_last_event
|
65
71
|
start_reactor
|
@@ -143,7 +149,7 @@ module Guard
|
|
143
149
|
def modified_files(dirs, options = {})
|
144
150
|
last_event = @last_event
|
145
151
|
files = []
|
146
|
-
if
|
152
|
+
if watch_all_modifications?
|
147
153
|
deleted_files = @file_timestamp_hash.collect do |path, ts|
|
148
154
|
unless File.exists?(path)
|
149
155
|
@sha1_checksums_hash.delete(path)
|
@@ -196,10 +202,19 @@ module Guard
|
|
196
202
|
!!@relativize_paths
|
197
203
|
end
|
198
204
|
|
205
|
+
# test if the listener should also watch for deleted and
|
206
|
+
# moved files
|
207
|
+
#
|
208
|
+
# @return [Boolean] whether to watch all file modifications or not
|
209
|
+
#
|
210
|
+
def watch_all_modifications?
|
211
|
+
!!@watch_all_modifications
|
212
|
+
end
|
213
|
+
|
199
214
|
# Populate initial timestamp file hash to watch for deleted or moved files.
|
200
215
|
#
|
201
216
|
def timestamp_files
|
202
|
-
all_files.each {|path| set_file_timestamp_hash(path, file_timestamp(path)) } if
|
217
|
+
all_files.each {|path| set_file_timestamp_hash(path, file_timestamp(path)) } if watch_all_modifications?
|
203
218
|
end
|
204
219
|
|
205
220
|
# Removes the ignored paths from the directory list.
|
@@ -258,7 +273,7 @@ module Guard
|
|
258
273
|
elsif mtime > last_event.to_i
|
259
274
|
set_sha1_checksums_hash(path, sha1_checksum(path))
|
260
275
|
true
|
261
|
-
elsif
|
276
|
+
elsif watch_all_modifications?
|
262
277
|
ts = file_timestamp(path)
|
263
278
|
if ts != @file_timestamp_hash[path]
|
264
279
|
set_file_timestamp_hash(path, ts)
|
@@ -289,7 +304,7 @@ module Guard
|
|
289
304
|
# Set save a files current timestamp
|
290
305
|
#
|
291
306
|
# @param [String] path the file path
|
292
|
-
# @param [
|
307
|
+
# @param [Integer] file_timestamp the files modified timestamp
|
293
308
|
#
|
294
309
|
def set_file_timestamp_hash(path, file_timestamp)
|
295
310
|
@file_timestamp_hash[path] = file_timestamp
|
@@ -306,8 +321,8 @@ module Guard
|
|
306
321
|
|
307
322
|
# Gets a files modified timestamp
|
308
323
|
#
|
309
|
-
# @
|
310
|
-
# @return [
|
324
|
+
# @param [String] path the file path
|
325
|
+
# @return [Integer] file modified timestamp
|
311
326
|
#
|
312
327
|
def file_timestamp(path)
|
313
328
|
File.mtime(path).to_i
|
@@ -29,17 +29,13 @@ module Guard
|
|
29
29
|
#
|
30
30
|
# @return [Boolean] whether usable or not
|
31
31
|
#
|
32
|
-
def self.usable?
|
32
|
+
def self.usable?(no_vendor = false)
|
33
|
+
return false unless RbConfig::CONFIG['target_os'] =~ /darwin/i
|
34
|
+
|
35
|
+
$LOAD_PATH << File.expand_path('../../../vendor/darwin/lib', __FILE__) unless no_vendor
|
33
36
|
require 'rb-fsevent'
|
34
|
-
|
35
|
-
Gem::Version.new(FSEvent::VERSION) < Gem::Version.new('0.4.0'))
|
36
|
-
UI.info 'Please update rb-fsevent (>= 0.4.0)'
|
37
|
-
false
|
38
|
-
else
|
39
|
-
true
|
40
|
-
end
|
37
|
+
true
|
41
38
|
rescue LoadError
|
42
|
-
UI.info 'Please install rb-fsevent gem for Mac OSX FSEvents support'
|
43
39
|
false
|
44
40
|
end
|
45
41
|
|
@@ -32,17 +32,13 @@ module Guard
|
|
32
32
|
#
|
33
33
|
# @return [Boolean] whether usable or not
|
34
34
|
#
|
35
|
-
def self.usable?
|
35
|
+
def self.usable?(no_vendor = false)
|
36
|
+
return false unless RbConfig::CONFIG['target_os'] =~ /linux/i
|
37
|
+
|
38
|
+
$LOAD_PATH << File.expand_path('../../../vendor/linux/lib', __FILE__) unless no_vendor
|
36
39
|
require 'rb-inotify'
|
37
|
-
|
38
|
-
Gem::Version.new(INotify::VERSION.join('.')) < Gem::Version.new('0.8.5'))
|
39
|
-
UI.info 'Please update rb-inotify (>= 0.8.5)'
|
40
|
-
false
|
41
|
-
else
|
42
|
-
true
|
43
|
-
end
|
40
|
+
true
|
44
41
|
rescue LoadError
|
45
|
-
UI.info 'Please install rb-inotify gem for Linux inotify support'
|
46
42
|
false
|
47
43
|
end
|
48
44
|
|
@@ -72,7 +68,7 @@ module Guard
|
|
72
68
|
# @return [Boolean] whether inotify is active or not
|
73
69
|
#
|
74
70
|
def watch_change?
|
75
|
-
|
71
|
+
!!(defined? @watch_change and @watch_change)
|
76
72
|
end
|
77
73
|
|
78
74
|
# Watch for file system changes.
|
@@ -29,11 +29,13 @@ module Guard
|
|
29
29
|
#
|
30
30
|
# @return [Boolean] whether usable or not
|
31
31
|
#
|
32
|
-
def self.usable?
|
32
|
+
def self.usable?(no_vendor = false)
|
33
|
+
return false unless RbConfig::CONFIG['target_os'] =~ /mswin|mingw/i
|
34
|
+
|
35
|
+
$LOAD_PATH << File.expand_path('../../../vendor/windows/lib', __FILE__) unless no_vendor
|
33
36
|
require 'rb-fchange'
|
34
37
|
true
|
35
38
|
rescue LoadError
|
36
|
-
UI.info 'Please install rb-fchange gem for Windows file events support'
|
37
39
|
false
|
38
40
|
end
|
39
41
|
|
data/lib/guard/notifier.rb
CHANGED
@@ -1,290 +1,203 @@
|
|
1
1
|
require 'rbconfig'
|
2
2
|
require 'pathname'
|
3
3
|
require 'guard/ui'
|
4
|
+
require 'guard/notifiers/gntp'
|
5
|
+
require 'guard/notifiers/growl'
|
6
|
+
require 'guard/notifiers/growl_notify'
|
7
|
+
require 'guard/notifiers/libnotify'
|
8
|
+
require 'guard/notifiers/rb_notifu'
|
4
9
|
|
5
10
|
module Guard
|
6
11
|
|
7
|
-
# The notifier
|
12
|
+
# The notifier handles sending messages to different notifiers. Currently the following
|
13
|
+
# libraries are supported:
|
8
14
|
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
15
|
+
# * Ruby GNTP
|
16
|
+
# * Growl
|
17
|
+
# * GrowlNotify
|
18
|
+
# * Libnotify
|
19
|
+
# * rb-notifu
|
20
|
+
#
|
21
|
+
# Please see the documentation of each notifier for more information about the requirements
|
22
|
+
# and configuration possibilities.
|
23
|
+
#
|
24
|
+
# Guard knows four different notification types:
|
25
|
+
#
|
26
|
+
# * success
|
27
|
+
# * pending
|
28
|
+
# * failed
|
29
|
+
# * notify
|
30
|
+
#
|
31
|
+
# The notification type selection is based on the image option that is
|
32
|
+
# sent to {#notify}. Each image type has its own notification type, and
|
33
|
+
# notifications with custom images goes all sent as type `notify`. The
|
34
|
+
# `gntp` and `growl_notify` notifiers are able to register these types
|
35
|
+
# at Growl and allows customization of each notification type.
|
36
|
+
#
|
37
|
+
# Guard can be configured to make use of more than one notifier at once, @see Guard::Dsl
|
12
38
|
#
|
13
39
|
module Notifier
|
40
|
+
extend self
|
41
|
+
|
42
|
+
# List of available notifiers.
|
43
|
+
NOTIFIERS = {
|
44
|
+
:gntp => ::Guard::Notifier::GNTP,
|
45
|
+
:growl => ::Guard::Notifier::Growl,
|
46
|
+
:growl_notify => ::Guard::Notifier::GrowlNotify,
|
47
|
+
:libnotify => ::Guard::Notifier::Libnotify,
|
48
|
+
:notifu => ::Guard::Notifier::Notifu
|
49
|
+
}
|
50
|
+
|
51
|
+
# Get the available notifications.
|
52
|
+
#
|
53
|
+
# @return [Hash] the notifications
|
54
|
+
#
|
55
|
+
def notifications
|
56
|
+
@notifications ||= []
|
57
|
+
end
|
14
58
|
|
15
|
-
#
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
# Turn notifications off.
|
23
|
-
#
|
24
|
-
def turn_off
|
25
|
-
ENV["GUARD_NOTIFY"] = 'false'
|
26
|
-
end
|
27
|
-
|
28
|
-
# Turn notifications on. This tries to load the platform
|
29
|
-
# specific notification library.
|
30
|
-
#
|
31
|
-
# @return [Boolean] whether the notification could be enabled.
|
32
|
-
#
|
33
|
-
def turn_on
|
34
|
-
ENV["GUARD_NOTIFY"] = 'true'
|
35
|
-
case RbConfig::CONFIG['target_os']
|
36
|
-
when /darwin/i
|
37
|
-
require_growl
|
38
|
-
when /linux/i
|
39
|
-
require_libnotify
|
40
|
-
when /mswin|mingw/i
|
41
|
-
require_rbnotifu
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
# Show a message with the system notification.
|
46
|
-
#
|
47
|
-
# @see .image_path
|
48
|
-
#
|
49
|
-
# @param [String] the message to show
|
50
|
-
# @option options [Symbol, String] image the image symbol or path to an image
|
51
|
-
# @option options [String] title the notification title
|
52
|
-
#
|
53
|
-
def notify(message, options = { })
|
54
|
-
if enabled?
|
55
|
-
image = options.delete(:image) || :success
|
56
|
-
title = options.delete(:title) || "Guard"
|
57
|
-
|
58
|
-
case RbConfig::CONFIG['target_os']
|
59
|
-
when /darwin/i
|
60
|
-
notify_mac(title, message, image, options)
|
61
|
-
when /linux/i
|
62
|
-
notify_linux(title, message, image, options)
|
63
|
-
when /mswin|mingw/i
|
64
|
-
notify_windows(title, message, image, options)
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
# Test if the notifications are enabled and available.
|
70
|
-
#
|
71
|
-
# @return [Boolean] whether the notifications are available
|
72
|
-
#
|
73
|
-
def enabled?
|
74
|
-
ENV["GUARD_NOTIFY"] == 'true'
|
75
|
-
end
|
76
|
-
|
77
|
-
private
|
78
|
-
|
79
|
-
# Send a message to Growl either with the `growl` gem or the `growl_notify` gem.
|
80
|
-
#
|
81
|
-
# @param [String] title the notification title
|
82
|
-
# @param [String] message the message to show
|
83
|
-
# @param [Symbol, String] the image to user
|
84
|
-
# @param [Hash] options the growl options
|
85
|
-
#
|
86
|
-
def notify_mac(title, message, image, options = { })
|
87
|
-
require_growl # need for guard-rspec formatter that is called out of guard scope
|
88
|
-
|
89
|
-
notification = { :title => title, :icon => image_path(image) }.merge(options)
|
90
|
-
|
91
|
-
case self.growl_library
|
92
|
-
when :growl_notify
|
93
|
-
notification.delete(:name)
|
94
|
-
|
95
|
-
GrowlNotify.send_notification({
|
96
|
-
:description => message,
|
97
|
-
:application_name => APPLICATION_NAME
|
98
|
-
}.merge(notification))
|
99
|
-
|
100
|
-
when :ruby_gntp
|
101
|
-
icon = "file://#{ notification.delete(:icon) }"
|
102
|
-
|
103
|
-
self.gntp.notify({
|
104
|
-
:name => [:pending, :success, :failed].include?(image) ? image.to_s : 'notify',
|
105
|
-
:text => message,
|
106
|
-
:icon => icon
|
107
|
-
}.merge(notification))
|
59
|
+
# Set the available notifications.
|
60
|
+
#
|
61
|
+
# @param [Array<Hash>] notifications the notifications
|
62
|
+
#
|
63
|
+
def notifications=(notifications)
|
64
|
+
@notifications = notifications
|
65
|
+
end
|
108
66
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
67
|
+
# Turn notifications on. If no notifications are defined
|
68
|
+
# in the `Guardfile` Guard auto detects the first available
|
69
|
+
# library.
|
70
|
+
#
|
71
|
+
def turn_on
|
72
|
+
auto_detect_notification if notifications.empty? && (!::Guard.options || ::Guard.options[:notify])
|
73
|
+
|
74
|
+
if notifications.empty?
|
75
|
+
ENV['GUARD_NOTIFY'] = 'false'
|
76
|
+
else
|
77
|
+
notifications.each do |notification|
|
78
|
+
::Guard::UI.info "Guard uses #{ NOTIFIERS[notification[:name]].to_s.split('::').last } to send notifications."
|
113
79
|
end
|
114
|
-
end
|
115
|
-
|
116
|
-
# Send a message to libnotify.
|
117
|
-
#
|
118
|
-
# @param [String] title the notification title
|
119
|
-
# @param [String] message the message to show
|
120
|
-
# @param [Symbol, String] the image to user
|
121
|
-
# @param [Hash] options the libnotify options
|
122
|
-
#
|
123
|
-
def notify_linux(title, message, image, options = { })
|
124
|
-
require_libnotify # need for guard-rspec formatter that is called out of guard scope
|
125
80
|
|
126
|
-
|
127
|
-
Libnotify.show notification.merge(options)
|
128
|
-
end
|
129
|
-
|
130
|
-
# Send a message to notifu.
|
131
|
-
#
|
132
|
-
# @param [String] title the notification title
|
133
|
-
# @param [String] message the message to show
|
134
|
-
# @param [Symbol, String] the image to user
|
135
|
-
# @param [Hash] options the notifu options
|
136
|
-
#
|
137
|
-
def notify_windows(title, message, image, options = { })
|
138
|
-
require_rbnotifu # need for guard-rspec formatter that is called out of guard scope
|
139
|
-
|
140
|
-
notification = { :message => message, :title => title, :type => image_level(image), :time => 3 }
|
141
|
-
Notifu.show notification.merge(options)
|
142
|
-
end
|
143
|
-
|
144
|
-
# Get the image path for an image symbol.
|
145
|
-
#
|
146
|
-
# Known symbols are:
|
147
|
-
#
|
148
|
-
# - failed
|
149
|
-
# - pending
|
150
|
-
# - success
|
151
|
-
#
|
152
|
-
# @param [Symbol] image the image name
|
153
|
-
# @return [String] the image path
|
154
|
-
#
|
155
|
-
def image_path(image)
|
156
|
-
images_path = Pathname.new(File.dirname(__FILE__)).join('../../images')
|
157
|
-
case image
|
158
|
-
when :failed
|
159
|
-
images_path.join("failed.png").to_s
|
160
|
-
when :pending
|
161
|
-
images_path.join("pending.png").to_s
|
162
|
-
when :success
|
163
|
-
images_path.join("success.png").to_s
|
164
|
-
else
|
165
|
-
# path given
|
166
|
-
image
|
167
|
-
end
|
81
|
+
ENV['GUARD_NOTIFY'] = 'true'
|
168
82
|
end
|
83
|
+
end
|
169
84
|
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
def image_level(image)
|
176
|
-
case image
|
177
|
-
when :failed
|
178
|
-
:error
|
179
|
-
when :pending
|
180
|
-
:warn
|
181
|
-
when :success
|
182
|
-
:info
|
183
|
-
else
|
184
|
-
:info
|
185
|
-
end
|
186
|
-
end
|
85
|
+
# Turn notifications off.
|
86
|
+
#
|
87
|
+
def turn_off
|
88
|
+
ENV['GUARD_NOTIFY'] = 'false'
|
89
|
+
end
|
187
90
|
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
#
|
196
|
-
# On successful loading of any of the libraries, the active library name is
|
197
|
-
# accessible through `.growl_library`.
|
198
|
-
#
|
199
|
-
def require_growl
|
200
|
-
self.growl_library = try_growl_notify || try_ruby_gntp || try_growl
|
91
|
+
# Test if the notifications are on.
|
92
|
+
#
|
93
|
+
# @return [Boolean] whether the notifications are on
|
94
|
+
#
|
95
|
+
def enabled?
|
96
|
+
ENV['GUARD_NOTIFY'] == 'true'
|
97
|
+
end
|
201
98
|
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
99
|
+
# Add a notification library to be used.
|
100
|
+
#
|
101
|
+
# @param [Symbol] name the name of the notifier to use
|
102
|
+
# @param [Boolean] silent disable any error message
|
103
|
+
# @param [Hash] options the notifier options
|
104
|
+
# @return [Boolean] if the notification could be added
|
105
|
+
#
|
106
|
+
def add_notification(name, options = { }, silent = false)
|
107
|
+
return turn_off if name == :off
|
108
|
+
|
109
|
+
if NOTIFIERS.has_key?(name) && NOTIFIERS[name].available?(silent)
|
110
|
+
notifications << { :name => name, :options => options }
|
111
|
+
true
|
112
|
+
else
|
113
|
+
false
|
206
114
|
end
|
115
|
+
end
|
207
116
|
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
117
|
+
# Show a system notification with all configured notifiers.
|
118
|
+
#
|
119
|
+
# @param [String] message the message to show
|
120
|
+
# @option options [Symbol, String] image the image symbol or path to an image
|
121
|
+
# @option options [String] title the notification title
|
122
|
+
#
|
123
|
+
def notify(message, options = { })
|
124
|
+
if enabled?
|
125
|
+
type = notification_type(options[:image] || :success)
|
126
|
+
image = image_path(options.delete(:image) || :success)
|
127
|
+
title = options.delete(:title) || 'Guard'
|
128
|
+
|
129
|
+
notifications.each do |notification|
|
130
|
+
begin
|
131
|
+
NOTIFIERS[notification[:name]].notify(type, title, message, image, options.merge(notification[:options]))
|
132
|
+
rescue Exception => e
|
133
|
+
::Guard::UI.error "Error sending notification with #{ notification[:name] }: #{ e.message }"
|
221
134
|
end
|
222
|
-
|
223
|
-
rescue ::GrowlNotify::GrowlNotFound
|
224
|
-
turn_off
|
225
|
-
UI.info "Please install Growl from http://growl.info"
|
226
135
|
end
|
227
|
-
|
228
|
-
:growl_notify
|
229
|
-
|
230
|
-
rescue LoadError
|
231
|
-
end
|
232
|
-
|
233
|
-
# Try to load the `ruby_gntp` gem and register the available
|
234
|
-
# notification channels.
|
235
|
-
#
|
236
|
-
# @return [Symbol, nil] A symbol with the name of the loaded library
|
237
|
-
#
|
238
|
-
def try_ruby_gntp
|
239
|
-
require 'ruby_gntp'
|
240
|
-
|
241
|
-
self.gntp = GNTP.new(APPLICATION_NAME)
|
242
|
-
self.gntp.register(:notifications => [
|
243
|
-
{ :name => 'notify', :enabled => true },
|
244
|
-
{ :name => 'failed', :enabled => true },
|
245
|
-
{ :name => 'pending', :enabled => true },
|
246
|
-
{ :name => 'success', :enabled => true }
|
247
|
-
])
|
248
|
-
|
249
|
-
:ruby_gntp
|
250
|
-
|
251
|
-
rescue LoadError
|
252
136
|
end
|
137
|
+
end
|
253
138
|
|
254
|
-
|
255
|
-
#
|
256
|
-
# @return [Symbol, nil] A symbol with the name of the loaded library
|
257
|
-
#
|
258
|
-
def try_growl
|
259
|
-
require 'growl'
|
260
|
-
|
261
|
-
:growl
|
262
|
-
|
263
|
-
rescue LoadError
|
264
|
-
end
|
139
|
+
private
|
265
140
|
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
141
|
+
# Auto detect the available notification library. This goes through
|
142
|
+
# the list of supported notification gems and picks the first that
|
143
|
+
# is available.
|
144
|
+
#
|
145
|
+
def auto_detect_notification
|
146
|
+
available = [:growl_notify, :gntp, :growl, :libnotify, :notifu].any? { |notifier| add_notification(notifier, { }, true) }
|
147
|
+
::Guard::UI.info('Guard could not detect any of the supported notification libraries.') unless available
|
148
|
+
end
|
271
149
|
|
272
|
-
|
273
|
-
|
274
|
-
|
150
|
+
# Get the image path for an image symbol for the following
|
151
|
+
# known image types:
|
152
|
+
#
|
153
|
+
# - failed
|
154
|
+
# - pending
|
155
|
+
# - success
|
156
|
+
#
|
157
|
+
# If the image is not a known symbol, it will be returned unmodified.
|
158
|
+
#
|
159
|
+
# @param [Symbol, String] image the image symbol or path to an image
|
160
|
+
# @return [String] the image path
|
161
|
+
#
|
162
|
+
def image_path(image)
|
163
|
+
case image
|
164
|
+
when :failed
|
165
|
+
images_path.join('failed.png').to_s
|
166
|
+
when :pending
|
167
|
+
images_path.join('pending.png').to_s
|
168
|
+
when :success
|
169
|
+
images_path.join('success.png').to_s
|
170
|
+
else
|
171
|
+
image
|
275
172
|
end
|
173
|
+
end
|
276
174
|
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
175
|
+
# Paths where all Guard images are located
|
176
|
+
#
|
177
|
+
# @return [Pathname] the path to the images directory
|
178
|
+
#
|
179
|
+
def images_path
|
180
|
+
@images_path ||= Pathname.new(File.dirname(__FILE__)).join('../../images')
|
181
|
+
end
|
282
182
|
|
283
|
-
|
284
|
-
|
285
|
-
|
183
|
+
# Get the notification type depending on the
|
184
|
+
# image that has been selected for the notification.
|
185
|
+
#
|
186
|
+
# @param [Symbol, String] image the image symbol or path to an image
|
187
|
+
# @return [String] the notification type
|
188
|
+
#
|
189
|
+
def notification_type(image)
|
190
|
+
case image
|
191
|
+
when :failed
|
192
|
+
'failed'
|
193
|
+
when :pending
|
194
|
+
'pending'
|
195
|
+
when :success
|
196
|
+
'success'
|
197
|
+
else
|
198
|
+
'notify'
|
286
199
|
end
|
287
|
-
|
288
200
|
end
|
289
201
|
end
|
202
|
+
|
290
203
|
end
|