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.
@@ -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