notifiers 1.2.2 → 2.0.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: ddbf316c3d227051cede7c16899601b69b8fe877
4
- data.tar.gz: f28643946a68b7d4bf484086deccdb84c426a4e4
2
+ SHA256:
3
+ metadata.gz: 283300dff237abf0a0ae9bdb960dd674ce1ddc632846087b1449438176a097d7
4
+ data.tar.gz: 899747ad18240c1f05c38ee57d315ccd365cdad7d7b42208c7772b1624b678c2
5
5
  SHA512:
6
- metadata.gz: 05153d76e7ac7dfc4aa74d642fa4cffe12a690983dea8b08b1e83632b44431c1768805b96d704d24fc303b46e6973dcef4ad84efa26a87631866bee6e537730b
7
- data.tar.gz: 3c7a7fbb267d26913bc70e4058af3f61e753493ba32e1bca2a5013aa177878d77421a6ecf7a4f33e3fbbc5e49ac506b5d26803b72188dc858daaa4e6c194818f
6
+ metadata.gz: bd88d8ec60ea149d0dc376f9aca984a097a9a4bf3bde1b5899cd872e7e98c6a47c09a9d02ca1244acb35d1969d5c46b6860801460ac1008689fea3321d74c3b5
7
+ data.tar.gz: f90c615293fd0ca70adf41a291a04ffe26a81cc5c37b81faf06d63091ea4927e15448807ea51db60cc2816df78d0674463bcec188999dfbb53da5217a43c5525
@@ -0,0 +1,28 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [master, main]
6
+ pull_request:
7
+ branches: [master, main]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+
13
+ strategy:
14
+ fail-fast: false
15
+ matrix:
16
+ ruby-version: ['3.2', '3.3', '3.4', 'jruby', 'truffleruby']
17
+
18
+ steps:
19
+ - uses: actions/checkout@v4
20
+
21
+ - name: Set up Ruby ${{ matrix.ruby-version }}
22
+ uses: ruby/setup-ruby@v1
23
+ with:
24
+ ruby-version: ${{ matrix.ruby-version }}
25
+ bundler-cache: true
26
+
27
+ - name: Run tests
28
+ run: bundle exec rspec
data/History.markdown CHANGED
@@ -1,3 +1,24 @@
1
+ # 2.0.0
2
+
3
+ Breaking changes:
4
+
5
+ * Remove Growl support (project retired)
6
+ * Remove Knotify support (KDE3 dcop deprecated)
7
+ * Require Ruby >= 3.0
8
+
9
+ New features:
10
+
11
+ * Add TerminalNotifier for macOS (Notification Center via terminal-notifier)
12
+ * Add Osascript for macOS (built-in AppleScript notifications)
13
+ * Add Dunstify for Linux/BSD (dunst notification daemon)
14
+ * Auto discover now works across all platforms and notifiers
15
+
16
+ Other changes:
17
+
18
+ * Replace Travis CI with GitHub Actions
19
+ * Update RSpec to ~> 3.13
20
+ * Add frozen_string_literal to all files
21
+
1
22
  # 1.2.1
2
23
 
3
24
  * Implementing auto discover, just for Growl now.
data/README.markdown CHANGED
@@ -1,32 +1,85 @@
1
1
  # Notifiers
2
2
 
3
- Use notifications systems like growl, lib-notify in a simple and elegant way. :)
3
+ Cross-platform desktop notifications for macOS and Linux.
4
+
5
+ [![CI](https://github.com/tomas-stefano/notifiers/actions/workflows/ci.yml/badge.svg)](https://github.com/tomas-stefano/notifiers/actions/workflows/ci.yml)
4
6
 
5
7
  ## Install
6
8
 
7
- gem install notifiers
9
+ ```
10
+ gem install notifiers
11
+ ```
12
+
13
+ ## Requirements
14
+
15
+ - Ruby >= 3.0
8
16
 
9
17
  ## Usage
10
18
 
11
- require 'notifiers'
12
- include Notifiers
19
+ ```ruby
20
+ require 'notifiers'
21
+ include Notifiers
22
+ ```
23
+
24
+ ### Auto Discover
25
+
26
+ Automatically detect and use an available notifier for your platform:
27
+
28
+ ```ruby
29
+ auto_discover.title('Hello').message('World!').notify!
30
+ ```
31
+
32
+ ### macOS
33
+
34
+ #### terminal-notifier
35
+
36
+ Requires [terminal-notifier](https://github.com/julienXX/terminal-notifier): `brew install terminal-notifier`
37
+
38
+ ```ruby
39
+ terminal_notifier.title('Hello').message('World!').sound('default').notify!
40
+ terminal_notifier.message('Click me').open('https://example.com').notify!
41
+ ```
42
+
43
+ #### osascript (built-in)
44
+
45
+ Uses AppleScript, no installation required:
46
+
47
+ ```ruby
48
+ osascript.title('Hello').message('World!').sound('Glass').notify!
49
+ osascript.title('Alert').subtitle('Status').message('Done!').notify!
50
+ ```
51
+
52
+ ### Linux / BSD
53
+
54
+ #### notify-send
13
55
 
14
- ### Growl
56
+ Requires libnotify: `apt install libnotify-bin` or equivalent
15
57
 
16
- growl.message('Hi Growl!').image('my_image.png').priority(2).name('my_app').notify!
58
+ ```ruby
59
+ notify_send.title('Hello').message('World!').urgency(:critical).notify!
60
+ notify_send.title('Alert').message('Check this').expire_time(5000).notify!
61
+ ```
17
62
 
18
- ### Lib_Notify
63
+ `lib_notify` is an alias for `notify_send`.
19
64
 
20
- notify_send.image('my_image.png').message('Hi Growl').notify!
65
+ #### dunstify
21
66
 
22
- <b>Obs.: #notify_send is an alias to #lib_notify .</b>
67
+ Requires [dunst](https://dunst-project.org/): `apt install dunst` or equivalent
23
68
 
24
- ### Knotify
69
+ ```ruby
70
+ dunstify.title('Hello').message('World!').urgency(:low).notify!
71
+ dunstify.title('Update').message('Progress').timeout(3000).notify!
72
+ ```
25
73
 
26
- knotify.title('Hello World').message('Hi!').notify!
74
+ ## Supported Notifiers
27
75
 
28
- # Why I created this gem?
76
+ | Notifier | Platform | Command | Installation |
77
+ |----------|----------|---------|--------------|
78
+ | `terminal_notifier` | macOS | `terminal-notifier` | `brew install terminal-notifier` |
79
+ | `osascript` | macOS | `osascript` | Built-in |
80
+ | `notify_send` | Linux/BSD | `notify-send` | `apt install libnotify-bin` |
81
+ | `dunstify` | Linux/BSD | `dunstify` | `apt install dunst` |
29
82
 
30
- ## Only one explanation:
83
+ ## License
31
84
 
32
- ### Because is fun! =)
85
+ MIT
data/TODO.markdown CHANGED
@@ -1,2 +1,5 @@
1
+ # TODO
1
2
 
2
- * Auto Discover the OS and notify as expected.
3
+ * Add support for Windows notifications (powershell/toast)
4
+ * Add notification icons/images support for all notifiers
5
+ * Add callback/action support where available
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Notifiers
2
4
  class Base
3
5
  def self.inherited(subclass)
@@ -14,16 +16,20 @@ module Notifiers
14
16
  false
15
17
  end
16
18
 
17
- def self.darwin?
18
- platform?(/darwin/)
19
- end
20
-
21
19
  def self.platform?(name)
22
20
  RbConfig::CONFIG['host_os'] =~ name or RUBY_PLATFORM =~ name
23
21
  end
24
22
 
25
23
  def self.command?(command)
26
- `which #{command}` and $?.to_i.zero?
24
+ `which #{command}` and success_process_status?
25
+ end
26
+
27
+ def self.process?(process_name)
28
+ `ps -A #{process_name}` and success_process_status?
29
+ end
30
+
31
+ def self.success_process_status?
32
+ $?.to_i.zero?
27
33
  end
28
34
 
29
35
  def notify
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Notifiers
4
+ class Dunstify < Notifiers::Base
5
+ COMMAND = 'dunstify'
6
+
7
+ def self.installed?
8
+ platform?(/(freebsd|linux)/) and command?(COMMAND)
9
+ end
10
+
11
+ def urgency(level)
12
+ @urgency = level.to_s
13
+ self
14
+ end
15
+
16
+ def timeout(milliseconds)
17
+ @timeout = milliseconds
18
+ self
19
+ end
20
+
21
+ def action(action_string)
22
+ @action = action_string
23
+ self
24
+ end
25
+
26
+ def replace(id)
27
+ @replace = id
28
+ self
29
+ end
30
+
31
+ def to_s
32
+ command = COMMAND.dup
33
+ command << " -u '#{@urgency}'" if @urgency
34
+ command << " -t '#{@timeout}'" if @timeout
35
+ command << " -i '#{@icon}'" if @icon
36
+ command << " -r '#{@replace}'" if @replace
37
+ command << " -A '#{@action}'" if @action
38
+ command << " '#{@title}'" if @title
39
+ command << " '#{@message}'" if @message
40
+ command
41
+ end
42
+
43
+ def install_instructions
44
+ 'dunstify is not installed. Install dunst notification daemon for your distribution.'
45
+ end
46
+ end
47
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Notifiers
2
4
  class NotifierNotFound < StandardError
3
5
  end
@@ -1,7 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Notifiers
2
4
  class NotifySend < Notifiers::Base
3
5
  COMMAND = 'notify-send'
4
6
 
7
+ def self.installed?
8
+ platform?(/(freebsd|linux)/) and command?(COMMAND)
9
+ end
10
+
5
11
  def urgency(level)
6
12
  @urgency = level.to_s
7
13
  self
@@ -13,22 +19,29 @@ module Notifiers
13
19
  end
14
20
 
15
21
  def hint(values)
16
- @hint = values.collect.each { |element| element.to_s}.join(':')
22
+ @hint = values.collect.each { |element| element.to_s }.join(':')
23
+ self
24
+ end
25
+
26
+ def category(name)
27
+ @category = name
17
28
  self
18
29
  end
19
30
 
20
31
  def to_s
21
- command = COMMAND.clone
22
- [:hint, :priority, :icon, :urgency].each do |option|
23
- variable = instance_variable_get("@#{option}")
24
- command << " --#{option}=#{variable}" if variable
25
- end
32
+ command = COMMAND.dup
33
+ command << " --urgency=#{@urgency}" if @urgency
26
34
  command << " --expire-time=#{@expire_time}" if @expire_time
27
- [:title, :message].each do |option|
28
- variable = instance_variable_get("@#{option}")
29
- command << " '#{variable}'" if variable
30
- end
35
+ command << " --icon=#{@icon}" if @icon
36
+ command << " --category=#{@category}" if @category
37
+ command << " --hint=#{@hint}" if @hint
38
+ command << " '#{@title}'" if @title
39
+ command << " '#{@message}'" if @message
31
40
  command
32
41
  end
42
+
43
+ def install_instructions
44
+ 'notify-send is not installed. Install libnotify for your distribution.'
45
+ end
33
46
  end
34
47
  end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Notifiers
4
+ # macOS native notifications using osascript (AppleScript).
5
+ #
6
+ # Note: The 'display notification' AppleScript command does not support
7
+ # custom images. The notification will display the application icon of the
8
+ # calling process (e.g., Terminal.app or Ruby). If you need custom image
9
+ # support on macOS, consider using terminal-notifier instead.
10
+ class Osascript < Notifiers::Base
11
+ def self.installed?
12
+ platform?(/darwin/) and command?('osascript')
13
+ end
14
+
15
+ # Override to warn that images are not supported by osascript.
16
+ def image(icon)
17
+ warn '[Notifiers::Osascript] Warning: Custom images are not supported ' \
18
+ 'by osascript display notification. The image will be ignored. ' \
19
+ 'Consider using terminal-notifier for image support.'
20
+ super
21
+ end
22
+
23
+ def subtitle(text)
24
+ @subtitle = text
25
+ self
26
+ end
27
+
28
+ def sound(name)
29
+ @sound = name
30
+ self
31
+ end
32
+
33
+ def to_s
34
+ script = 'display notification'.dup
35
+ script << " \"#{@message}\"" if @message
36
+ script << " with title \"#{@title}\"" if @title
37
+ script << " subtitle \"#{@subtitle}\"" if @subtitle
38
+ script << " sound name \"#{@sound}\"" if @sound
39
+
40
+ "osascript -e '#{script}'"
41
+ end
42
+
43
+ def install_instructions
44
+ ''
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Notifiers
4
+ class TerminalNotifier < Notifiers::Base
5
+ COMMAND = 'terminal-notifier'
6
+
7
+ def self.installed?
8
+ platform?(/darwin/) and command?(COMMAND)
9
+ end
10
+
11
+ def sound(name)
12
+ @sound = name
13
+ self
14
+ end
15
+
16
+ def group(id)
17
+ @group = id
18
+ self
19
+ end
20
+
21
+ def open(url)
22
+ @open = url
23
+ self
24
+ end
25
+
26
+ def execute(command)
27
+ @execute = command
28
+ self
29
+ end
30
+
31
+ def to_s
32
+ command = COMMAND.dup
33
+ command << " -title '#{@title}'" if @title
34
+ command << " -message '#{@message}'" if @message
35
+ command << " -contentImage '#{@icon}'" if @icon
36
+ command << " -sound '#{@sound}'" if @sound
37
+ command << " -group '#{@group}'" if @group
38
+ command << " -open '#{@open}'" if @open
39
+ command << " -execute '#{@execute}'" if @execute
40
+ command
41
+ end
42
+
43
+ def install_instructions
44
+ 'terminal-notifier is not installed. Install with: brew install terminal-notifier'
45
+ end
46
+ end
47
+ end
data/lib/notifiers.rb CHANGED
@@ -1,23 +1,29 @@
1
- [:base, :growl, :knotify, :notify_send, :notifier_not_found].each do |notifier|
1
+ # frozen_string_literal: true
2
+
3
+ %i[base terminal_notifier osascript notify_send dunstify notifier_not_found].each do |notifier|
2
4
  require "notifiers/#{notifier}"
3
5
  end
4
6
 
5
7
  module Notifiers
6
- def growl
7
- Growl.new
8
+ def terminal_notifier
9
+ TerminalNotifier.new
8
10
  end
9
11
 
10
- def knotify
11
- Knotify.new
12
+ def osascript
13
+ Osascript.new
12
14
  end
13
15
 
14
16
  def notify_send
15
17
  NotifySend.new
16
18
  end
17
- alias :lib_notify :notify_send
19
+ alias lib_notify notify_send
20
+
21
+ def dunstify
22
+ Dunstify.new
23
+ end
18
24
 
19
25
  def auto_discover
20
- notifier = Notifiers::Base.subclasses.find { |notifier| notifier.installed? } or raise NotifierNotFound
26
+ notifier = Notifiers::Base.subclasses.find(&:installed?) or raise NotifierNotFound
21
27
 
22
28
  notifier.new
23
29
  end
data/notifiers.gemspec CHANGED
@@ -1,20 +1,21 @@
1
- # -*- encoding: utf-8 -*-
1
+ # frozen_string_literal: true
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "notifiers"
5
- s.version = '1.2.2'
5
+ s.version = '2.0.0'
6
6
  s.platform = Gem::Platform::RUBY
7
7
  s.authors = ["Tomás D'Stefano"]
8
8
  s.email = ["tomasdestefi@gmail.com"]
9
- s.homepage = "http://rubygems.org/gems/notifiers"
10
- s.summary = "Use notifications in a simple and elegant way."
11
- s.description = "Use Growl and Lib-Notify in a simple and clean way."
9
+ s.homepage = "https://rubygems.org/gems/notifiers"
10
+ s.summary = "Cross-platform desktop notifications for macOS and Linux."
11
+ s.description = "Send desktop notifications on macOS (terminal-notifier, osascript) and Linux (notify-send, dunstify) in a simple and clean way."
12
+ s.license = "MIT"
12
13
 
13
- s.required_rubygems_version = ">= 1.3.6"
14
- s.rubyforge_project = "notifiers"
14
+ s.required_ruby_version = ">= 3.0"
15
+ s.required_rubygems_version = ">= 3.0"
15
16
 
16
- s.add_development_dependency('rspec', "~> 2.14")
17
- s.add_development_dependency('bundler', ">= 1.0.0")
17
+ s.add_development_dependency('rspec', "~> 3.13")
18
+ s.add_development_dependency('bundler', ">= 2.0")
18
19
 
19
20
  s.files = `git ls-files`.split("\n")
20
21
  s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  module Notifiers
@@ -7,7 +9,7 @@ module Notifiers
7
9
  end
8
10
 
9
11
  describe '.subclasses' do
10
- it { expect(Base.subclasses).to include(Growl, Knotify, NotifySend) }
12
+ it { expect(Base.subclasses).to include(TerminalNotifier, Osascript, NotifySend, Dunstify) }
11
13
  end
12
14
 
13
15
  describe '.installed?' do
@@ -16,22 +18,6 @@ module Notifiers
16
18
  end
17
19
  end
18
20
 
19
- describe '.darwin?' do
20
- context 'when the ruby platform is darwin' do
21
- it 'returns true' do
22
- expect(Base).to receive(:platform?).with(/darwin/).and_return(true)
23
- expect(Base.darwin?).to be true
24
- end
25
- end
26
-
27
- context 'when the ruby platform is not darwin' do
28
- it 'returns false' do
29
- expect(Base).to receive(:platform?).with(/darwin/).and_return(false)
30
- expect(Base.darwin?).to be false
31
- end
32
- end
33
- end
34
-
35
21
  describe '#notify' do
36
22
  before do
37
23
  expect(base).to receive(:to_s).and_return('example')
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ module Notifiers
6
+ describe Dunstify do
7
+ it_should_behave_like 'a notifier'
8
+
9
+ before do
10
+ @dunstify = dunstify
11
+ end
12
+
13
+ describe '.installed?' do
14
+ context 'when is linux or freebsd platform' do
15
+ before do
16
+ expect(Dunstify).to receive(:platform?).with(/(freebsd|linux)/).and_return(true)
17
+ end
18
+
19
+ context 'with dunstify installed' do
20
+ before do
21
+ expect(Dunstify).to receive(:command?).with('dunstify').and_return(true)
22
+ end
23
+
24
+ it 'returns true' do
25
+ expect(Dunstify).to be_installed
26
+ end
27
+ end
28
+
29
+ context 'without dunstify installed' do
30
+ before do
31
+ expect(Dunstify).to receive(:command?).with('dunstify').and_return(false)
32
+ end
33
+
34
+ it 'returns false' do
35
+ expect(Dunstify).to_not be_installed
36
+ end
37
+ end
38
+ end
39
+
40
+ context 'when is not linux or freebsd platform' do
41
+ before do
42
+ expect(Dunstify).to receive(:platform?).with(/(freebsd|linux)/).and_return(false)
43
+ end
44
+
45
+ it 'returns false' do
46
+ expect(Dunstify).to_not be_installed
47
+ end
48
+ end
49
+ end
50
+
51
+ describe '#image' do
52
+ it 'sets the icon' do
53
+ @dunstify.image('my_image.png')
54
+ expect(@dunstify.instance_variable_get(:@icon)).to eql 'my_image.png'
55
+ end
56
+ end
57
+
58
+ describe '#message' do
59
+ it 'sets the message' do
60
+ @dunstify.message('Hello World!')
61
+ expect(@dunstify.instance_variable_get(:@message)).to eql 'Hello World!'
62
+ end
63
+ end
64
+
65
+ describe '#title' do
66
+ it 'sets the title' do
67
+ @dunstify.title('My App')
68
+ expect(@dunstify.instance_variable_get(:@title)).to eql 'My App'
69
+ end
70
+ end
71
+
72
+ describe '#urgency' do
73
+ it 'sets the urgency to low' do
74
+ @dunstify.urgency(:low)
75
+ expect(@dunstify.instance_variable_get(:@urgency)).to eql 'low'
76
+ end
77
+
78
+ it 'sets the urgency to normal' do
79
+ @dunstify.urgency(:normal)
80
+ expect(@dunstify.instance_variable_get(:@urgency)).to eql 'normal'
81
+ end
82
+
83
+ it 'sets the urgency to critical' do
84
+ @dunstify.urgency(:critical)
85
+ expect(@dunstify.instance_variable_get(:@urgency)).to eql 'critical'
86
+ end
87
+ end
88
+
89
+ describe '#timeout' do
90
+ it 'sets the timeout' do
91
+ @dunstify.timeout(5000)
92
+ expect(@dunstify.instance_variable_get(:@timeout)).to eql 5000
93
+ end
94
+ end
95
+
96
+ describe '#action' do
97
+ it 'sets the action' do
98
+ @dunstify.action('open,Open File')
99
+ expect(@dunstify.instance_variable_get(:@action)).to eql 'open,Open File'
100
+ end
101
+ end
102
+
103
+ describe '#replace' do
104
+ it 'sets the replace id' do
105
+ @dunstify.replace(123)
106
+ expect(@dunstify.instance_variable_get(:@replace)).to eql 123
107
+ end
108
+ end
109
+
110
+ describe '#to_s' do
111
+ it 'constructs the command with title and message' do
112
+ command = @dunstify.title('Test').message('Hello World!').to_s
113
+ expect(command).to eql "dunstify 'Test' 'Hello World!'"
114
+ end
115
+
116
+ it 'constructs the command with urgency and timeout' do
117
+ command = @dunstify.title('Alert').message('Important').urgency(:critical).timeout(10000).to_s
118
+ expect(command).to eql "dunstify -u 'critical' -t '10000' 'Alert' 'Important'"
119
+ end
120
+
121
+ it 'constructs the command with icon' do
122
+ command = @dunstify.title('App').message('Done').image('icon.png').to_s
123
+ expect(command).to eql "dunstify -i 'icon.png' 'App' 'Done'"
124
+ end
125
+
126
+ it 'constructs the command with replace' do
127
+ command = @dunstify.title('Update').message('Progress').replace(42).to_s
128
+ expect(command).to eql "dunstify -r '42' 'Update' 'Progress'"
129
+ end
130
+
131
+ it 'constructs the command with action' do
132
+ command = @dunstify.title('File').message('Click to open').action('open,Open').to_s
133
+ expect(command).to eql "dunstify -A 'open,Open' 'File' 'Click to open'"
134
+ end
135
+ end
136
+
137
+ describe '#install_instructions' do
138
+ it 'returns installation instructions' do
139
+ expect(@dunstify.install_instructions).to eq 'dunstify is not installed. Install dunst notification daemon for your distribution.'
140
+ end
141
+ end
142
+ end
143
+ end