notiffany 0.0.2

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