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
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: dc2bea88badfaf2002b0a1b2ee78fe244f4761b5
|
4
|
+
data.tar.gz: df4e2e90efa30cd30c509d9bbce6f1f8b2165f37
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: afe03258470e5aeee7109879499a0831ad58d1309f9cf2649a03ac53465c83605b67205dbd7ac2d348ade5f05fa640bfa6bde3117cd785e052eea050ded1c973
|
7
|
+
data.tar.gz: 82bc83271bb750d27220ae3a73e3102292fe5659f3c8fee165343a697de1a3084dc545ad3eecf066b4287198a9a3f55e138caec29714e2f1f90d32323a0fe1c0
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in notiffany.gemspec
|
4
|
+
gemspec development_group: :gem_build_tools
|
5
|
+
|
6
|
+
gem "rake", "~> 10.0"
|
7
|
+
gem 'nenv', "~> 0.1"
|
8
|
+
|
9
|
+
group :test do
|
10
|
+
gem "rspec", "~> 3.1"
|
11
|
+
end
|
12
|
+
|
13
|
+
group :development do
|
14
|
+
gem 'guard-rspec', "~> 4.5", require: false
|
15
|
+
end
|
data/Guardfile
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
## Uncomment and set this to only include directories you want to watch
|
5
|
+
# directories %w(app lib config test spec feature)
|
6
|
+
|
7
|
+
## Uncomment to clear the screen before every task
|
8
|
+
# clearing :on
|
9
|
+
|
10
|
+
## Make Guard exit when config is changed so it can be restarted
|
11
|
+
#
|
12
|
+
## Note: if you want Guard to automatically start up again, run guard in a
|
13
|
+
## shell loop, e.g.:
|
14
|
+
#
|
15
|
+
# $ while bundle exec guard; do echo "Restarting Guard..."; done
|
16
|
+
#
|
17
|
+
## Note: if you are using the `directories` clause above and you are not
|
18
|
+
## watching the project directory ('.'), the you will want to move the Guardfile
|
19
|
+
## to a watched dir and symlink it back, e.g.
|
20
|
+
#
|
21
|
+
# $ mkdir config
|
22
|
+
# $ mv Guardfile config/
|
23
|
+
# $ ln -s config/Guardfile .
|
24
|
+
#
|
25
|
+
# and, you'll have to watch "config/Guardfile" instead of "Guardfile"
|
26
|
+
#
|
27
|
+
watch ("Guardfile") do
|
28
|
+
UI.info "Exiting because Guard must be restarted for changes to take effect"
|
29
|
+
exit 0
|
30
|
+
end
|
31
|
+
|
32
|
+
# Note: The cmd option is now required due to the increasing number of ways
|
33
|
+
# rspec may be run, below are examples of the most common uses.
|
34
|
+
# * bundler: 'bundle exec rspec'
|
35
|
+
# * bundler binstubs: 'bin/rspec'
|
36
|
+
# * spring: 'bin/rspec' (This will use spring if running and you have
|
37
|
+
# installed the spring binstubs per the docs)
|
38
|
+
# * zeus: 'zeus rspec' (requires the server to be started separately)
|
39
|
+
# * 'just' rspec: 'rspec'
|
40
|
+
|
41
|
+
guard :rspec, cmd: "bundle exec rspec" do
|
42
|
+
require "guard/rspec/dsl"
|
43
|
+
dsl = Guard::RSpec::Dsl.new(self)
|
44
|
+
|
45
|
+
# Feel free to open issues for suggestions and improvements
|
46
|
+
|
47
|
+
# RSpec files
|
48
|
+
rspec = dsl.rspec
|
49
|
+
watch(rspec.spec_helper) { rspec.spec_dir }
|
50
|
+
watch(rspec.spec_support) { rspec.spec_dir }
|
51
|
+
watch(rspec.spec_files)
|
52
|
+
|
53
|
+
# Ruby files
|
54
|
+
ruby = dsl.ruby
|
55
|
+
dsl.watch_spec_files_for(ruby.lib_files)
|
56
|
+
end
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Cezary Baginski
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
# Notiffany
|
2
|
+
|
3
|
+
Notification library supporting popular notifiers, such as:
|
4
|
+
- Growl
|
5
|
+
- libnotify
|
6
|
+
- TMux
|
7
|
+
- Emacs
|
8
|
+
- rb-notifu
|
9
|
+
- notifysend
|
10
|
+
- gntp
|
11
|
+
- TerminalNotifier
|
12
|
+
|
13
|
+
## Features
|
14
|
+
- most popular notification libraries supported
|
15
|
+
- easy to override options at any level (new(), notify())
|
16
|
+
- using multiple notifiers simultaneously
|
17
|
+
- child processes reuse same configuration
|
18
|
+
|
19
|
+
## Installation
|
20
|
+
|
21
|
+
Add this line to your application's Gemfile:
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
gem 'notiffany'
|
25
|
+
```
|
26
|
+
|
27
|
+
And then execute:
|
28
|
+
|
29
|
+
$ bundle
|
30
|
+
|
31
|
+
Or install it yourself as:
|
32
|
+
|
33
|
+
$ gem install notiffany
|
34
|
+
|
35
|
+
## Usage
|
36
|
+
|
37
|
+
Basic notification
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
notifier = Notiffany.connect(title: "A message")
|
41
|
+
notifier.notify("Hello there!", image: :success)
|
42
|
+
notifier.disconnect # some plugins like TMux and TerminalTitle rely on this
|
43
|
+
```
|
44
|
+
|
45
|
+
Enabling/disabling and on/off
|
46
|
+
|
47
|
+
### disable with option
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
notifier = Notiffany.connect(notify: false)
|
51
|
+
notifier.notify('hello') # does nothing
|
52
|
+
```
|
53
|
+
|
54
|
+
### switch on/off using methods
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
notifier = Notiffany.connect
|
58
|
+
notifier.turn_off
|
59
|
+
notifier.turn_on
|
60
|
+
notifier.toggle
|
61
|
+
```
|
62
|
+
|
63
|
+
## Contributing
|
64
|
+
|
65
|
+
1. Fork it ( https://github.com/[my-github-username]/notiffany/fork )
|
66
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
67
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
68
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
69
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/images/failed.png
ADDED
Binary file
|
data/images/guard.png
ADDED
Binary file
|
data/images/pending.png
ADDED
Binary file
|
data/images/success.png
ADDED
Binary file
|
data/lib/notiffany.rb
ADDED
@@ -0,0 +1,205 @@
|
|
1
|
+
require "yaml"
|
2
|
+
require "rbconfig"
|
3
|
+
require "pathname"
|
4
|
+
require "nenv"
|
5
|
+
require "logger"
|
6
|
+
|
7
|
+
require "notiffany/notifier/detected"
|
8
|
+
|
9
|
+
module Notiffany
|
10
|
+
# The notifier handles sending messages to different notifiers. Currently the
|
11
|
+
# following libraries are supported:
|
12
|
+
#
|
13
|
+
# * Ruby GNTP
|
14
|
+
# * Growl
|
15
|
+
# * Libnotify
|
16
|
+
# * rb-notifu
|
17
|
+
# * emacs
|
18
|
+
# * Terminal Notifier
|
19
|
+
# * Terminal Title
|
20
|
+
# * Tmux
|
21
|
+
#
|
22
|
+
# Please see the documentation of each notifier for more information about
|
23
|
+
# the requirements
|
24
|
+
# and configuration possibilities.
|
25
|
+
#
|
26
|
+
# Notiffany knows four different notification types:
|
27
|
+
#
|
28
|
+
# * success
|
29
|
+
# * pending
|
30
|
+
# * failed
|
31
|
+
# * notify
|
32
|
+
#
|
33
|
+
# The notification type selection is based on the image option that is
|
34
|
+
# sent to {#notify}. Each image type has its own notification type, and
|
35
|
+
# notifications with custom images goes all sent as type `notify`. The
|
36
|
+
# `gntp` notifier is able to register these types
|
37
|
+
# at Growl and allows customization of each notification type.
|
38
|
+
#
|
39
|
+
# Notiffany can be configured to make use of more than one notifier at once.
|
40
|
+
#
|
41
|
+
def self.connect(options = {})
|
42
|
+
Notifier.new(options)
|
43
|
+
end
|
44
|
+
|
45
|
+
class Notifier
|
46
|
+
DEFAULTS = { notify: true }
|
47
|
+
|
48
|
+
NOTIFICATIONS_DISABLED = "Notifications disabled by GUARD_NOTIFY" +
|
49
|
+
" environment variable"
|
50
|
+
|
51
|
+
USING_NOTIFIER = "Notiffany is using %s to send notifications."
|
52
|
+
|
53
|
+
ONLY_NOTIFY = "Only notify() is available from a child process"
|
54
|
+
|
55
|
+
# List of available notifiers, grouped by functionality
|
56
|
+
SUPPORTED = [
|
57
|
+
{
|
58
|
+
gntp: GNTP,
|
59
|
+
growl: Growl,
|
60
|
+
terminal_notifier: TerminalNotifier,
|
61
|
+
libnotify: Libnotify,
|
62
|
+
notifysend: NotifySend,
|
63
|
+
notifu: Notifu
|
64
|
+
},
|
65
|
+
{ emacs: Emacs },
|
66
|
+
{ tmux: Tmux },
|
67
|
+
{ terminal_title: TerminalTitle },
|
68
|
+
{ file: File }
|
69
|
+
]
|
70
|
+
|
71
|
+
Env = Nenv::Builder.build do
|
72
|
+
create_method(:notify?) { |data| data != "false" }
|
73
|
+
create_method(:notify_pid) { |data| data && Integer(data) }
|
74
|
+
create_method(:notify_pid=)
|
75
|
+
create_method(:notify_active?)
|
76
|
+
create_method(:notify_active=)
|
77
|
+
end
|
78
|
+
|
79
|
+
class NotServer < RuntimeError
|
80
|
+
end
|
81
|
+
|
82
|
+
def initialize(opts)
|
83
|
+
@env_namespace = opts.fetch(:namespace, "notiffany")
|
84
|
+
@logger = opts.fetch(:logger) do
|
85
|
+
Logger.new($stderr).tap { |l| l.level = Logger::WARN }
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
@detected = Detected.new(SUPPORTED, @env_namespace, @logger)
|
90
|
+
return if _client?
|
91
|
+
|
92
|
+
_env.notify_pid = $$
|
93
|
+
|
94
|
+
fail "Already connected" if active?
|
95
|
+
|
96
|
+
options = DEFAULTS.merge(opts)
|
97
|
+
return unless enabled? && options[:notify]
|
98
|
+
|
99
|
+
notifiers = opts.fetch(:notifiers, {})
|
100
|
+
if notifiers.any?
|
101
|
+
notifiers.each do |name, notifier_options|
|
102
|
+
@detected.add(name, notifier_options)
|
103
|
+
end
|
104
|
+
else
|
105
|
+
@detected.detect
|
106
|
+
end
|
107
|
+
|
108
|
+
turn_on
|
109
|
+
rescue Detected::NoneAvailableError => e
|
110
|
+
@logger.info e.to_s
|
111
|
+
end
|
112
|
+
|
113
|
+
def disconnect
|
114
|
+
if _client?
|
115
|
+
@detected = nil
|
116
|
+
return
|
117
|
+
end
|
118
|
+
|
119
|
+
turn_off if active?
|
120
|
+
@detected.reset unless @detected.nil?
|
121
|
+
_env.notify_pid = nil
|
122
|
+
@detected = nil
|
123
|
+
end
|
124
|
+
|
125
|
+
# Turn notifications on.
|
126
|
+
#
|
127
|
+
# @param [Hash] options the turn_on options
|
128
|
+
# @option options [Boolean] silent disable any logging
|
129
|
+
#
|
130
|
+
def turn_on(options = {})
|
131
|
+
_check_server!
|
132
|
+
return unless enabled?
|
133
|
+
|
134
|
+
fail "Already active!" if active?
|
135
|
+
|
136
|
+
silent = options[:silent]
|
137
|
+
|
138
|
+
@detected.available.each do |obj|
|
139
|
+
@logger.debug(format(USING_NOTIFIER, obj.title)) unless silent
|
140
|
+
obj.turn_on if obj.respond_to?(:turn_on)
|
141
|
+
end
|
142
|
+
|
143
|
+
_env.notify_active = true
|
144
|
+
end
|
145
|
+
|
146
|
+
# Turn notifications off.
|
147
|
+
def turn_off
|
148
|
+
_check_server!
|
149
|
+
|
150
|
+
fail "Not active!" unless active?
|
151
|
+
|
152
|
+
@detected.available.each do |obj|
|
153
|
+
obj.turn_off if obj.respond_to?(:turn_off)
|
154
|
+
end
|
155
|
+
|
156
|
+
_env.notify_active = false
|
157
|
+
end
|
158
|
+
|
159
|
+
# Test if the notifications can be enabled based on ENV['GUARD_NOTIFY']
|
160
|
+
def enabled?
|
161
|
+
_env.notify?
|
162
|
+
end
|
163
|
+
|
164
|
+
# Test if notifiers are currently turned on
|
165
|
+
def active?
|
166
|
+
_env.notify_active?
|
167
|
+
end
|
168
|
+
|
169
|
+
# Show a system notification with all configured notifiers.
|
170
|
+
#
|
171
|
+
# @param [String] message the message to show
|
172
|
+
# @option opts [Symbol, String] image the image symbol or path to an image
|
173
|
+
# @option opts [String] title the notification title
|
174
|
+
#
|
175
|
+
def notify(message, message_opts = {})
|
176
|
+
if _client?
|
177
|
+
return unless enabled?
|
178
|
+
else
|
179
|
+
return unless active?
|
180
|
+
end
|
181
|
+
|
182
|
+
@detected.available.each do |notifier|
|
183
|
+
notifier.notify(message, message_opts.dup)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def available
|
188
|
+
@detected.available
|
189
|
+
end
|
190
|
+
|
191
|
+
private
|
192
|
+
|
193
|
+
def _env
|
194
|
+
@environment ||= Env.new(@env_namespace)
|
195
|
+
end
|
196
|
+
|
197
|
+
def _check_server!
|
198
|
+
_client? && fail(NotServer, ONLY_NOTIFY)
|
199
|
+
end
|
200
|
+
|
201
|
+
def _client?
|
202
|
+
(pid = _env.notify_pid) && (pid != $$)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require "rbconfig"
|
2
|
+
|
3
|
+
module Notiffany
|
4
|
+
class Notifier
|
5
|
+
class Base
|
6
|
+
HOSTS = {
|
7
|
+
darwin: "Mac OS X",
|
8
|
+
linux: "Linux",
|
9
|
+
freebsd: "FreeBSD",
|
10
|
+
openbsd: "OpenBSD",
|
11
|
+
sunos: "SunOS",
|
12
|
+
solaris: "Solaris",
|
13
|
+
mswin: "Windows",
|
14
|
+
mingw: "Windows",
|
15
|
+
cygwin: "Windows"
|
16
|
+
}
|
17
|
+
|
18
|
+
ERROR_ADD_GEM_AND_RUN_BUNDLE = "Please add \"gem '%s'\" to your Gemfile "\
|
19
|
+
"and run your app with \"bundle exec\"."
|
20
|
+
|
21
|
+
class UnavailableError < RuntimeError
|
22
|
+
def initialize(reason)
|
23
|
+
super
|
24
|
+
@reason = reason
|
25
|
+
end
|
26
|
+
|
27
|
+
def message
|
28
|
+
@reason
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class RequireFailed < UnavailableError
|
33
|
+
def initialize(gem_name)
|
34
|
+
super ERROR_ADD_GEM_AND_RUN_BUNDLE % gem_name
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class UnsupportedPlatform < UnavailableError
|
39
|
+
def initialize
|
40
|
+
super "Unsupported platform #{RbConfig::CONFIG["host_os"].inspect}"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
attr_reader :options
|
45
|
+
|
46
|
+
def initialize(opts = {})
|
47
|
+
options = opts.dup
|
48
|
+
options.delete(:silent)
|
49
|
+
@options =
|
50
|
+
{ title: "Notiffany" }.
|
51
|
+
merge(self.class.const_get(:DEFAULTS)).
|
52
|
+
merge(options).freeze
|
53
|
+
|
54
|
+
@images_path = Pathname.new(__FILE__).dirname + "../../../images"
|
55
|
+
|
56
|
+
_check_host_supported
|
57
|
+
_require_gem
|
58
|
+
_check_available(@options)
|
59
|
+
end
|
60
|
+
|
61
|
+
def title
|
62
|
+
self.class.to_s[/.+::(\w+)$/, 1]
|
63
|
+
end
|
64
|
+
|
65
|
+
def name
|
66
|
+
title.gsub(/([a-z])([A-Z])/, '\1_\2').downcase
|
67
|
+
end
|
68
|
+
|
69
|
+
def notify(message, opts = {})
|
70
|
+
new_opts = _notify_options(opts).freeze
|
71
|
+
_perform_notify(message, new_opts)
|
72
|
+
end
|
73
|
+
|
74
|
+
def _image_path(image)
|
75
|
+
images = [:failed, :pending, :success, :guard]
|
76
|
+
images.include?(image) ? @images_path.join("#{image}.png").to_s : image
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
# Override if necessary
|
82
|
+
def _gem_name
|
83
|
+
name
|
84
|
+
end
|
85
|
+
|
86
|
+
# Override if necessary
|
87
|
+
def _supported_hosts
|
88
|
+
:all
|
89
|
+
end
|
90
|
+
|
91
|
+
# Override
|
92
|
+
def _check_available(_options)
|
93
|
+
fail NotImplementedError
|
94
|
+
end
|
95
|
+
|
96
|
+
# Override
|
97
|
+
def _perform_notify(_message, _opts)
|
98
|
+
fail NotImplementedError
|
99
|
+
end
|
100
|
+
|
101
|
+
def _notification_type(image)
|
102
|
+
[:failed, :pending, :success].include?(image) ? image : :notify
|
103
|
+
end
|
104
|
+
|
105
|
+
def _notify_options(overrides = {})
|
106
|
+
opts = @options.merge(overrides)
|
107
|
+
img_type = opts.fetch(:image, :success)
|
108
|
+
opts[:type] ||= _notification_type(img_type)
|
109
|
+
opts[:image] = _image_path(img_type)
|
110
|
+
opts
|
111
|
+
end
|
112
|
+
|
113
|
+
def _check_host_supported
|
114
|
+
return if _supported_hosts == :all
|
115
|
+
expr = /#{_supported_hosts * '|'}/
|
116
|
+
fail UnsupportedPlatform unless expr.match(RbConfig::CONFIG["host_os"])
|
117
|
+
end
|
118
|
+
|
119
|
+
def _require_gem
|
120
|
+
Kernel.require _gem_name unless _gem_name.nil?
|
121
|
+
rescue LoadError, NameError
|
122
|
+
fail RequireFailed, _gem_name
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|