notiffany 0.0.2
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.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/.rspec +3 -0
- data/.travis.yml +13 -0
- data/Gemfile +15 -0
- data/Guardfile +56 -0
- data/LICENSE.txt +22 -0
- data/README.md +69 -0
- data/Rakefile +13 -0
- data/images/failed.png +0 -0
- data/images/guard.png +0 -0
- data/images/pending.png +0 -0
- data/images/success.png +0 -0
- data/lib/notiffany.rb +6 -0
- data/lib/notiffany/notifier.rb +205 -0
- data/lib/notiffany/notifier/base.rb +126 -0
- data/lib/notiffany/notifier/detected.rb +113 -0
- data/lib/notiffany/notifier/emacs.rb +107 -0
- data/lib/notiffany/notifier/file.rb +44 -0
- data/lib/notiffany/notifier/gntp.rb +91 -0
- data/lib/notiffany/notifier/growl.rb +81 -0
- data/lib/notiffany/notifier/libnotify.rb +54 -0
- data/lib/notiffany/notifier/notifysend.rb +84 -0
- data/lib/notiffany/notifier/rb_notifu.rb +89 -0
- data/lib/notiffany/notifier/terminal_notifier.rb +59 -0
- data/lib/notiffany/notifier/terminal_title.rb +39 -0
- data/lib/notiffany/notifier/tmux.rb +355 -0
- data/lib/notiffany/version.rb +3 -0
- data/notiffany.gemspec +28 -0
- metadata +114 -0
@@ -0,0 +1,113 @@
|
|
1
|
+
require "nenv"
|
2
|
+
|
3
|
+
require_relative "emacs"
|
4
|
+
require_relative "file"
|
5
|
+
require_relative "gntp"
|
6
|
+
require_relative "growl"
|
7
|
+
require_relative "libnotify"
|
8
|
+
require_relative "notifysend"
|
9
|
+
require_relative "rb_notifu"
|
10
|
+
require_relative "terminal_notifier"
|
11
|
+
require_relative "terminal_title"
|
12
|
+
require_relative "tmux"
|
13
|
+
|
14
|
+
module Notiffany
|
15
|
+
class Notifier
|
16
|
+
# @private api
|
17
|
+
|
18
|
+
# TODO: use a socket instead of passing env variables to child processes
|
19
|
+
# (currently probably only used by guard-cucumber anyway)
|
20
|
+
YamlEnvStorage = Nenv::Builder.build do
|
21
|
+
create_method(:notifiers=) { |data| YAML::dump(data) }
|
22
|
+
create_method(:notifiers) { |data| data ? YAML::load(data) : [] }
|
23
|
+
end
|
24
|
+
|
25
|
+
# @private api
|
26
|
+
class Detected
|
27
|
+
NO_SUPPORTED_NOTIFIERS = "Notiffany could not detect any of the"\
|
28
|
+
" supported notification libraries."
|
29
|
+
|
30
|
+
class NoneAvailableError < RuntimeError
|
31
|
+
end
|
32
|
+
|
33
|
+
class UnknownNotifier < RuntimeError
|
34
|
+
def initialize(name)
|
35
|
+
super
|
36
|
+
@name = name
|
37
|
+
end
|
38
|
+
|
39
|
+
def name
|
40
|
+
@name
|
41
|
+
end
|
42
|
+
|
43
|
+
def message
|
44
|
+
"Unknown notifier: #{@name.inspect}"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def initialize(supported, env_namespace, logger)
|
49
|
+
@supported = supported
|
50
|
+
@environment = YamlEnvStorage.new(env_namespace)
|
51
|
+
@logger = logger
|
52
|
+
end
|
53
|
+
|
54
|
+
def reset
|
55
|
+
@environment.notifiers = nil
|
56
|
+
end
|
57
|
+
|
58
|
+
def detect
|
59
|
+
return unless _data.empty?
|
60
|
+
@supported.each do |group|
|
61
|
+
group.detect do |name, _|
|
62
|
+
begin
|
63
|
+
add(name, {})
|
64
|
+
true
|
65
|
+
rescue Notifier::Base::UnavailableError => e
|
66
|
+
@logger.debug "Notiffany: #{name} not available (#{e.message})."
|
67
|
+
false
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
fail NoneAvailableError, NO_SUPPORTED_NOTIFIERS if _data.empty?
|
73
|
+
end
|
74
|
+
|
75
|
+
def available
|
76
|
+
@available ||= _data.map do |entry|
|
77
|
+
_to_module(entry[:name]).new(entry[:options])
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def add(name, opts)
|
82
|
+
@available = nil
|
83
|
+
all = @environment.notifiers
|
84
|
+
|
85
|
+
# Silently skip if it's already available, because otherwise
|
86
|
+
# we'd have to do :turn_off, then configure, then :turn_on
|
87
|
+
names = all.map(&:first).map(&:last)
|
88
|
+
unless names.include?(name)
|
89
|
+
fail UnknownNotifier, name unless (klass = _to_module(name))
|
90
|
+
|
91
|
+
klass.new(opts) # raises if unavailable
|
92
|
+
@environment.notifiers = all << { name: name, options: opts }
|
93
|
+
end
|
94
|
+
|
95
|
+
# Just overwrite the options (without turning the notifier off or on),
|
96
|
+
# so those options will be passed in next calls to notify()
|
97
|
+
all.each { |item| item[:options] = opts if item[:name] == name }
|
98
|
+
end
|
99
|
+
|
100
|
+
def _to_module(name)
|
101
|
+
@supported.each do |group|
|
102
|
+
next unless (notifier = group.detect { |n, _| n == name })
|
103
|
+
return notifier.last
|
104
|
+
end
|
105
|
+
nil
|
106
|
+
end
|
107
|
+
|
108
|
+
def _data
|
109
|
+
@environment.notifiers || []
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
require "notiffany/notifier/base"
|
2
|
+
require "shellany/sheller"
|
3
|
+
|
4
|
+
module Notiffany
|
5
|
+
class Notifier
|
6
|
+
# Send a notification to Emacs with emacsclient
|
7
|
+
# (http://www.emacswiki.org/emacs/EmacsClient).
|
8
|
+
#
|
9
|
+
class Emacs < Base
|
10
|
+
DEFAULTS = {
|
11
|
+
client: "emacsclient",
|
12
|
+
success: "ForestGreen",
|
13
|
+
failed: "Firebrick",
|
14
|
+
default: "Black",
|
15
|
+
fontcolor: "White",
|
16
|
+
}
|
17
|
+
|
18
|
+
class Client
|
19
|
+
def initialize(options)
|
20
|
+
@client = options[:client]
|
21
|
+
end
|
22
|
+
|
23
|
+
def available?
|
24
|
+
emacs_eval("'1'")
|
25
|
+
end
|
26
|
+
|
27
|
+
def notify(color, bgcolor)
|
28
|
+
elisp = <<-EOF.gsub(/\s+/, " ").strip
|
29
|
+
(set-face-attribute 'mode-line nil
|
30
|
+
:background "#{bgcolor}"
|
31
|
+
:foreground "#{color}")
|
32
|
+
EOF
|
33
|
+
emacs_eval(elisp)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def emacs_eval(code)
|
39
|
+
Shellany::Sheller.run(@client, "--eval", code)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def _gem_name
|
46
|
+
nil
|
47
|
+
end
|
48
|
+
|
49
|
+
def _check_available(options)
|
50
|
+
return if Client.new(options).available?
|
51
|
+
fail UnavailableError, "Emacs client failed"
|
52
|
+
end
|
53
|
+
|
54
|
+
# Shows a system notification.
|
55
|
+
#
|
56
|
+
# @param [String] type the notification type. Either 'success',
|
57
|
+
# 'pending', 'failed' or 'notify'
|
58
|
+
# @param [String] title the notification title
|
59
|
+
# @param [String] message the notification message body
|
60
|
+
# @param [String] image the path to the notification image
|
61
|
+
# @param [Hash] opts additional notification library options
|
62
|
+
# @option opts [String] success the color to use for success
|
63
|
+
# notifications (default is 'ForestGreen')
|
64
|
+
# @option opts [String] failed the color to use for failure
|
65
|
+
# notifications (default is 'Firebrick')
|
66
|
+
# @option opts [String] pending the color to use for pending
|
67
|
+
# notifications
|
68
|
+
# @option opts [String] default the default color to use (default is
|
69
|
+
# 'Black')
|
70
|
+
# @option opts [String] client the client to use for notification
|
71
|
+
# (default is 'emacsclient')
|
72
|
+
# @option opts [String, Integer] priority specify an int or named key
|
73
|
+
# (default is 0)
|
74
|
+
#
|
75
|
+
def _perform_notify(_message, opts = {})
|
76
|
+
color = _emacs_color(opts[:type], opts)
|
77
|
+
fontcolor = _emacs_color(:fontcolor, opts)
|
78
|
+
Client.new(opts).notify(fontcolor, color)
|
79
|
+
end
|
80
|
+
|
81
|
+
# Get the Emacs color for the notification type.
|
82
|
+
# You can configure your own color by overwrite the defaults.
|
83
|
+
#
|
84
|
+
# @param [String] type the notification type
|
85
|
+
# @param [Hash] options aditional notification options
|
86
|
+
#
|
87
|
+
# @option options [String] success the color to use for success
|
88
|
+
# notifications (default is 'ForestGreen')
|
89
|
+
#
|
90
|
+
# @option options [String] failed the color to use for failure
|
91
|
+
# notifications (default is 'Firebrick')
|
92
|
+
#
|
93
|
+
# @option options [String] pending the color to use for pending
|
94
|
+
# notifications
|
95
|
+
#
|
96
|
+
# @option options [String] default the default color to use (default is
|
97
|
+
# 'Black')
|
98
|
+
#
|
99
|
+
# @return [String] the name of the emacs color
|
100
|
+
#
|
101
|
+
def _emacs_color(type, options = {})
|
102
|
+
default = options.fetch(:default, DEFAULTS[:default])
|
103
|
+
options.fetch(type.to_sym, default)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require "notiffany/notifier/base"
|
2
|
+
|
3
|
+
module Notiffany
|
4
|
+
class Notifier
|
5
|
+
# Writes notifications to a file.
|
6
|
+
#
|
7
|
+
class File < Base
|
8
|
+
DEFAULTS = { format: "%s\n%s\n%s\n" }
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
# @param [Hash] opts some options
|
13
|
+
# @option opts [Boolean] path the path to a file where notification
|
14
|
+
# message will be written
|
15
|
+
#
|
16
|
+
def _check_available(opts = {})
|
17
|
+
fail UnavailableError, "No :path option given" unless opts[:path]
|
18
|
+
end
|
19
|
+
|
20
|
+
# Writes the notification to a file. By default it writes type, title,
|
21
|
+
# and message separated by newlines.
|
22
|
+
#
|
23
|
+
# @param [String] message the notification message body
|
24
|
+
# @param [Hash] opts additional notification library options
|
25
|
+
# @option opts [String] type the notification type. Either 'success',
|
26
|
+
# 'pending', 'failed' or 'notify'
|
27
|
+
# @option opts [String] title the notification title
|
28
|
+
# @option opts [String] image the path to the notification image
|
29
|
+
# @option opts [String] format printf style format for file contents
|
30
|
+
# @option opts [String] path the path of where to write the file
|
31
|
+
#
|
32
|
+
def _perform_notify(message, opts = {})
|
33
|
+
fail UnavailableError, "No :path option given" unless opts[:path]
|
34
|
+
|
35
|
+
format = opts[:format]
|
36
|
+
::File.write(opts[:path], format % [opts[:type], opts[:title], message])
|
37
|
+
end
|
38
|
+
|
39
|
+
def _gem_name
|
40
|
+
nil
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require "notiffany/notifier/base"
|
2
|
+
|
3
|
+
module Notiffany
|
4
|
+
class Notifier
|
5
|
+
# System notifications using the
|
6
|
+
# [ruby_gntp](https://github.com/snaka/ruby_gntp) gem.
|
7
|
+
#
|
8
|
+
# This gem is available for OS X, Linux and Windows and sends system
|
9
|
+
# notifications to the following system notification frameworks through the
|
10
|
+
#
|
11
|
+
# [Growl Network Transport
|
12
|
+
# Protocol](http://www.growlforwindows.com/gfw/help/gntp.aspx):
|
13
|
+
#
|
14
|
+
# * [Growl](http://growl.info)
|
15
|
+
# * [Growl for Windows](http://www.growlforwindows.com)
|
16
|
+
# * [Growl for Linux](http://mattn.github.com/growl-for-linux)
|
17
|
+
# * [Snarl](https://sites.google.com/site/snarlapp)
|
18
|
+
class GNTP < Base
|
19
|
+
DEFAULTS = {
|
20
|
+
sticky: false
|
21
|
+
}
|
22
|
+
|
23
|
+
# Default options for the ruby gtnp client.
|
24
|
+
CLIENT_DEFAULTS = {
|
25
|
+
host: "127.0.0.1",
|
26
|
+
password: "",
|
27
|
+
port: 23053
|
28
|
+
}
|
29
|
+
|
30
|
+
def _supported_hosts
|
31
|
+
%w(darwin linux freebsd openbsd sunos solaris mswin mingw cygwin)
|
32
|
+
end
|
33
|
+
|
34
|
+
def _gem_name
|
35
|
+
"ruby_gntp"
|
36
|
+
end
|
37
|
+
|
38
|
+
def _check_available(_opts)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Shows a system notification.
|
42
|
+
#
|
43
|
+
# @param [String] message the notification message body
|
44
|
+
# @param [Hash] opts additional notification library options
|
45
|
+
# @option opts [String] type the notification type. Either 'success',
|
46
|
+
# 'pending', 'failed' or 'notify'
|
47
|
+
# @option opts [String] title the notification title
|
48
|
+
# @option opts [String] image the path to the notification image
|
49
|
+
# @option opts [String] host the hostname or IP address to which to send
|
50
|
+
# a remote notification
|
51
|
+
# @option opts [String] password the password used for remote
|
52
|
+
# notifications
|
53
|
+
# @option opts [Integer] port the port to send a remote notification
|
54
|
+
# @option opts [Boolean] sticky make the notification sticky
|
55
|
+
#
|
56
|
+
def _perform_notify(message, opts = {})
|
57
|
+
opts = {
|
58
|
+
name: opts[:type].to_s,
|
59
|
+
text: message,
|
60
|
+
icon: opts[:image]
|
61
|
+
}.merge(opts)
|
62
|
+
|
63
|
+
_gntp_client(opts).notify(opts)
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def _gntp_client(opts = {})
|
69
|
+
@_client ||= begin
|
70
|
+
gntp = ::GNTP.new(
|
71
|
+
"Notiffany",
|
72
|
+
opts.fetch(:host) { CLIENT_DEFAULTS[:host] },
|
73
|
+
opts.fetch(:password) { CLIENT_DEFAULTS[:password] },
|
74
|
+
opts.fetch(:port) { CLIENT_DEFAULTS[:port] }
|
75
|
+
)
|
76
|
+
|
77
|
+
gntp.register(
|
78
|
+
app_icon: _image_path(:guard),
|
79
|
+
notifications: [
|
80
|
+
{ name: "notify", enabled: true },
|
81
|
+
{ name: "failed", enabled: true },
|
82
|
+
{ name: "pending", enabled: true },
|
83
|
+
{ name: "success", enabled: true }
|
84
|
+
]
|
85
|
+
)
|
86
|
+
gntp
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require "notiffany/notifier/base"
|
2
|
+
|
3
|
+
module Notiffany
|
4
|
+
class Notifier
|
5
|
+
# System notifications using the
|
6
|
+
# [growl](https://github.com/visionmedia/growl) gem.
|
7
|
+
#
|
8
|
+
# This gem is available for OS X and sends system notifications to
|
9
|
+
# [Growl](http://growl.info) through the
|
10
|
+
# [GrowlNotify](http://growl.info/downloads) executable.
|
11
|
+
#
|
12
|
+
# The `growlnotify` executable must be installed manually or by using
|
13
|
+
# [Homebrew](http://mxcl.github.com/homebrew/).
|
14
|
+
#
|
15
|
+
# Sending notifications with this notifier will not show the different
|
16
|
+
# notifications in the Growl preferences. Use the :gntp notifier if you
|
17
|
+
# want to customize each notification type in Growl.
|
18
|
+
#
|
19
|
+
# @example Install `growlnotify` with Homebrew
|
20
|
+
# brew install growlnotify
|
21
|
+
#
|
22
|
+
# @example Add the `growl` gem to your `Gemfile`
|
23
|
+
# group :development
|
24
|
+
# gem 'growl'
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# @example Add the `:growl` notifier to your `Guardfile`
|
28
|
+
# notification :growl
|
29
|
+
#
|
30
|
+
# @example Add the `:growl_notify` notifier with configuration options to
|
31
|
+
# your `Guardfile` notification :growl, sticky: true, host: '192.168.1.5',
|
32
|
+
# password: 'secret'
|
33
|
+
#
|
34
|
+
class Growl < Base
|
35
|
+
INSTALL_GROWLNOTIFY = "Please install the 'growlnotify' executable'\
|
36
|
+
' (available by installing the 'growl' gem)."
|
37
|
+
|
38
|
+
# Default options for the growl notifications.
|
39
|
+
DEFAULTS = {
|
40
|
+
sticky: false,
|
41
|
+
priority: 0
|
42
|
+
}
|
43
|
+
|
44
|
+
def _supported_hosts
|
45
|
+
%w(darwin)
|
46
|
+
end
|
47
|
+
|
48
|
+
def _check_available(_opts = {})
|
49
|
+
fail UnavailableError, INSTALL_GROWLNOTIFY unless ::Growl.installed?
|
50
|
+
end
|
51
|
+
|
52
|
+
# Shows a system notification.
|
53
|
+
#
|
54
|
+
# The documented options are for GrowlNotify 1.3, but the older options
|
55
|
+
# are also supported. Please see `growlnotify --help`.
|
56
|
+
#
|
57
|
+
# Priority can be one of the following named keys: `Very Low`,
|
58
|
+
# `Moderate`, `Normal`, `High`, `Emergency`. It can also be an integer
|
59
|
+
# between -2 and 2.
|
60
|
+
#
|
61
|
+
# @param [String] message the notification message body
|
62
|
+
# @param [Hash] opts additional notification library options
|
63
|
+
# @option opts [String] type the notification type. Either 'success',
|
64
|
+
# 'pending', 'failed' or 'notify'
|
65
|
+
# @option opts [String] title the notification title
|
66
|
+
# @option opts [String] image the path to the notification image
|
67
|
+
# @option opts [Boolean] sticky make the notification sticky
|
68
|
+
# @option opts [String, Integer] priority specify an int or named key
|
69
|
+
# (default is 0)
|
70
|
+
# @option opts [String] host the hostname or IP address to which to
|
71
|
+
# send a remote notification
|
72
|
+
# @option opts [String] password the password used for remote
|
73
|
+
# notifications
|
74
|
+
#
|
75
|
+
def _perform_notify(message, opts = {})
|
76
|
+
opts = { name: "Notiffany" }.merge(opts)
|
77
|
+
::Growl.notify(message, opts)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require "notiffany/notifier/base"
|
2
|
+
|
3
|
+
module Notiffany
|
4
|
+
class Notifier
|
5
|
+
# System notifications using the
|
6
|
+
# [libnotify](https://github.com/splattael/libnotify) gem.
|
7
|
+
#
|
8
|
+
# This gem is available for Linux, FreeBSD, OpenBSD and Solaris and sends
|
9
|
+
# system notifications to
|
10
|
+
# Gnome [libnotify](http://developer.gnome.org/libnotify):
|
11
|
+
#
|
12
|
+
class Libnotify < Base
|
13
|
+
DEFAULTS = {
|
14
|
+
transient: false,
|
15
|
+
append: true,
|
16
|
+
timeout: 3
|
17
|
+
}
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def _supported_hosts
|
22
|
+
%w(linux freebsd openbsd sunos solaris)
|
23
|
+
end
|
24
|
+
|
25
|
+
def _check_available(_opts = {})
|
26
|
+
end
|
27
|
+
|
28
|
+
# Shows a system notification.
|
29
|
+
#
|
30
|
+
# @param [String] message the notification message body
|
31
|
+
# @param [Hash] opts additional notification library options
|
32
|
+
# @option opts [String] type the notification type. Either 'success',
|
33
|
+
# 'pending', 'failed' or 'notify'
|
34
|
+
# @option opts [String] title the notification title
|
35
|
+
# @option opts [String] image the path to the notification image
|
36
|
+
# @option opts [Boolean] transient keep the notifications around after
|
37
|
+
# display
|
38
|
+
# @option opts [Boolean] append append onto existing notification
|
39
|
+
# @option opts [Number, Boolean] timeout the number of seconds to display
|
40
|
+
# (1.5 (s), 1000 (ms), false)
|
41
|
+
#
|
42
|
+
def _perform_notify(message, opts = {})
|
43
|
+
opts = opts.merge(
|
44
|
+
summary: opts[:title],
|
45
|
+
icon_path: opts[:image],
|
46
|
+
body: message,
|
47
|
+
urgency: opts[:urgency] || (opts[:type] == "failed" ? :normal : :low)
|
48
|
+
)
|
49
|
+
|
50
|
+
::Libnotify.show(opts)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|