notiffany 0.0.2

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