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,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: dc2bea88badfaf2002b0a1b2ee78fe244f4761b5
4
+ data.tar.gz: df4e2e90efa30cd30c509d9bbce6f1f8b2165f37
5
+ SHA512:
6
+ metadata.gz: afe03258470e5aeee7109879499a0831ad58d1309f9cf2649a03ac53465c83605b67205dbd7ac2d348ade5f05fa640bfa6bde3117cd785e052eea050ded1c973
7
+ data.tar.gz: 82bc83271bb750d27220ae3a73e3102292fe5659f3c8fee165343a697de1a3084dc545ad3eecf066b4287198a9a3f55e138caec29714e2f1f90d32323a0fe1c0
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1,13 @@
1
+ language: ruby
2
+ bundler_args: --without development
3
+ rvm:
4
+ - 1.9.3
5
+ - 2.0.0
6
+ - 2.1.5
7
+ - ruby-head
8
+ - jruby
9
+ - rbx-2
10
+ matrix:
11
+ allow_failures:
12
+ - rvm: rbx
13
+ - rvm: jruby
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
@@ -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
@@ -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.
@@ -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
@@ -0,0 +1,13 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'nenv'
4
+
5
+ default_tasks = []
6
+
7
+ require 'rspec/core/rake_task'
8
+ default_tasks << RSpec::Core::RakeTask.new(:spec) do |t|
9
+ t.verbose = Nenv.ci?
10
+ end
11
+
12
+ task default: default_tasks.map(&:name)
13
+
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,6 @@
1
+ require "notiffany/version"
2
+ require "notiffany/notifier"
3
+
4
+ module Notiffany
5
+ # Your code goes here...
6
+ end
@@ -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