eyecare 0.1.0 → 0.2.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 +4 -4
- data/README.md +0 -1
- data/eyecare.gemspec +1 -0
- data/lib/eyecare.rb +24 -3
- data/lib/eyecare/alert.rb +13 -8
- data/lib/eyecare/audio.rb +18 -2
- data/lib/eyecare/config.rb +15 -15
- data/lib/eyecare/version.rb +1 -1
- data/test/alert_test.rb +7 -2
- data/test/audio_test.rb +14 -0
- data/test/config_test.rb +5 -5
- data/test/eyecare_test.rb +10 -5
- metadata +19 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8e004ee89fa1ccdaedc3c380870abda32967566f
|
4
|
+
data.tar.gz: 7657db390db6a9d5784df05d69147aee23bf1218
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 861bec7f2f2fdabdfc16109f3c9d12df652bea2b8214b485ffe306e2112b9bf4eed60c3a80dd36c4e9109111daf0055ef51550e4fa7ec6b30770b5bd066ab4b0
|
7
|
+
data.tar.gz: 72ed5653993ecb3e8183213f7f9ff7db3280f5743fa1effbab148fd6b52d0a3824a1d0a9278fb817d11defc1675c2299042d048a27aec8e6809799a34c3a7d22
|
data/README.md
CHANGED
data/eyecare.gemspec
CHANGED
@@ -21,6 +21,7 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.add_dependency 'ffi'
|
22
22
|
spec.add_dependency 'libnotify'
|
23
23
|
spec.add_dependency 'chronic_duration'
|
24
|
+
spec.add_dependency 'activesupport', '~> 4'
|
24
25
|
spec.add_development_dependency 'bundler', '~> 1.5'
|
25
26
|
spec.add_development_dependency 'rake'
|
26
27
|
spec.add_development_dependency 'minitest'
|
data/lib/eyecare.rb
CHANGED
@@ -6,6 +6,22 @@ require 'eyecare/daemon'
|
|
6
6
|
require 'fileutils'
|
7
7
|
require 'ffi'
|
8
8
|
|
9
|
+
class Hash
|
10
|
+
def deep_compact
|
11
|
+
dup.deep_compact!
|
12
|
+
end
|
13
|
+
|
14
|
+
def deep_compact!
|
15
|
+
each do |key, value|
|
16
|
+
if value.respond_to?(:deep_compact)
|
17
|
+
value = value.deep_compact
|
18
|
+
value = nil if value.length == 0
|
19
|
+
end
|
20
|
+
self[key] = value
|
21
|
+
end.compact
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
9
25
|
module Eyecare
|
10
26
|
extend FFI::Library
|
11
27
|
ffi_lib FFI::Library::LIBC
|
@@ -22,7 +38,7 @@ module Eyecare
|
|
22
38
|
attr_reader :config_path
|
23
39
|
|
24
40
|
def run
|
25
|
-
Daemon.start(config[:pid_file]) do
|
41
|
+
Daemon.start(config[:pid_file]) do
|
26
42
|
while true
|
27
43
|
seconds = config[:alert][:interval]
|
28
44
|
while seconds > 0
|
@@ -47,14 +63,19 @@ module Eyecare
|
|
47
63
|
return @config if @config
|
48
64
|
|
49
65
|
config_file = File.expand_path(config_path)
|
50
|
-
|
66
|
+
|
67
|
+
if File.exists?(config_file) && File.file?(config_file) && File.readable?(config_file)
|
68
|
+
@config = Config.load_from_file(config_file)
|
69
|
+
end
|
70
|
+
|
71
|
+
@config ||= Config.new
|
51
72
|
end
|
52
73
|
|
53
74
|
private
|
54
75
|
def proc_name(name)
|
55
76
|
$0 = name
|
56
77
|
return false unless self.respond_to?(:prctl)
|
57
|
-
|
78
|
+
|
58
79
|
name = name.slice(0, 16)
|
59
80
|
ptr = FFI::MemoryPointer.from_string(name)
|
60
81
|
self.prctl(15, ptr.address, 0, 0)
|
data/lib/eyecare/alert.rb
CHANGED
@@ -10,19 +10,22 @@ module Eyecare
|
|
10
10
|
attr_accessor :beep
|
11
11
|
attr_accessor :icon_path
|
12
12
|
|
13
|
-
DEFAULT_MESSAGE
|
14
|
-
DEFAULT_TIMEOUT
|
15
|
-
DEFAULT_BEEP_START
|
16
|
-
DEFAULT_BEEP_END
|
17
|
-
|
13
|
+
DEFAULT_MESSAGE = Config::DEFAULTS[:alert][:message]
|
14
|
+
DEFAULT_TIMEOUT = Config::DEFAULTS[:alert][:timeout]
|
15
|
+
DEFAULT_BEEP_START = Config::DEFAULTS[:alert][:beep][:start]
|
16
|
+
DEFAULT_BEEP_END = Config::DEFAULTS[:alert][:beep][:end]
|
17
|
+
DEFAULT_BEEP_PLAYER = Config::DEFAULTS[:alert][:beep][:player]
|
18
|
+
DEFAULT_ICON_PATH = Config::DEFAULTS[:alert][:icon]
|
18
19
|
|
19
20
|
class Beep
|
20
21
|
attr_accessor :start
|
21
22
|
attr_accessor :end
|
23
|
+
attr_accessor :player
|
22
24
|
|
23
25
|
def initialize(options = {})
|
24
|
-
@
|
25
|
-
@
|
26
|
+
@player = options[:player]
|
27
|
+
@start = Eyecare::Audio.new(options[:start], options[:player])
|
28
|
+
@end = Eyecare::Audio.new(options[:end], options[:player])
|
26
29
|
end
|
27
30
|
|
28
31
|
def play(name)
|
@@ -37,12 +40,14 @@ module Eyecare
|
|
37
40
|
|
38
41
|
beep_start = DEFAULT_BEEP_START
|
39
42
|
beep_end = DEFAULT_BEEP_END
|
43
|
+
beep_player = DEFAULT_BEEP_PLAYER
|
40
44
|
if options[:beep]
|
41
45
|
beep_start = options[:beep][:start] if options[:beep][:start]
|
42
46
|
beep_end = options[:beep][:end] if options[:beep][:end]
|
47
|
+
beep_player = options[:beep][:player] if options[:beep][:player]
|
43
48
|
end
|
44
49
|
|
45
|
-
@beep = Beep.new(start: beep_start, end: beep_end)
|
50
|
+
@beep = Beep.new(start: beep_start, end: beep_end, player: beep_player)
|
46
51
|
self
|
47
52
|
end
|
48
53
|
|
data/lib/eyecare/audio.rb
CHANGED
@@ -1,13 +1,29 @@
|
|
1
1
|
module Eyecare
|
2
2
|
class Audio
|
3
3
|
attr_accessor :filename
|
4
|
-
|
4
|
+
attr_accessor :player
|
5
|
+
|
6
|
+
DEFAULT_PLAYER = 'aplay :file'
|
7
|
+
|
8
|
+
def initialize(filename, player = nil)
|
5
9
|
@filename = filename
|
10
|
+
@player = player ? player : DEFAULT_PLAYER
|
6
11
|
end
|
7
12
|
|
8
13
|
def play
|
9
|
-
|
14
|
+
return unless player
|
15
|
+
pid = spawn(player_cmd + ' > /dev/null 2>&1')
|
10
16
|
Process.detach(pid)
|
11
17
|
end
|
18
|
+
|
19
|
+
private
|
20
|
+
def player_cmd
|
21
|
+
return @player_cmd if @player_cmd
|
22
|
+
@player_cmd = @player ? @player : DEFAULT_PLAYER
|
23
|
+
@player_cmd = @player_cmd.gsub(/:filename/, ':file')
|
24
|
+
.gsub(/:filepath/, ':file')
|
25
|
+
.gsub(/:file_path/, ':file')
|
26
|
+
.gsub(/:file/, filename)
|
27
|
+
end
|
12
28
|
end
|
13
29
|
end
|
data/lib/eyecare/config.rb
CHANGED
@@ -1,18 +1,12 @@
|
|
1
1
|
require 'yaml'
|
2
2
|
require 'chronic_duration'
|
3
|
+
require 'active_support/core_ext/hash/keys'
|
4
|
+
require 'active_support/core_ext/hash/compact'
|
5
|
+
require 'active_support/core_ext/hash/deep_merge'
|
3
6
|
require 'eyecare'
|
4
7
|
|
5
|
-
module Eyecare
|
6
|
-
|
7
|
-
class ::Hash
|
8
|
-
def symbolize_keys
|
9
|
-
self.inject({}) do |h, (k, v)|
|
10
|
-
v = v.symbolize_keys if v.respond_to?(:symbolize_keys)
|
11
|
-
h.merge({ k.to_sym => v })
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
8
|
|
9
|
+
module Eyecare
|
16
10
|
class Config
|
17
11
|
ASSETS_PATH = File.expand_path(File.join(File.dirname(__FILE__), 'assets'))
|
18
12
|
IMAGES_PATH = File.join(ASSETS_PATH, 'images')
|
@@ -25,6 +19,7 @@ module Eyecare
|
|
25
19
|
interval: 20 * 60,
|
26
20
|
icon: File.join(IMAGES_PATH, 'eyecare.png'),
|
27
21
|
beep: {
|
22
|
+
player: "aplay :file",
|
28
23
|
start: File.join(AUDIOS_PATH, 'beep_start.wav'),
|
29
24
|
end: File.join(AUDIOS_PATH, 'beep_end.wav')
|
30
25
|
}
|
@@ -33,12 +28,14 @@ module Eyecare
|
|
33
28
|
pid_file: File.expand_path(File.join('.eyecare', 'eyecare.pid'), '~')
|
34
29
|
}
|
35
30
|
|
31
|
+
attr_reader :options
|
32
|
+
|
36
33
|
def initialize(options = {})
|
37
34
|
@options = DEFAULTS
|
38
|
-
if options.respond_to?(:
|
39
|
-
options = options.
|
35
|
+
if options.respond_to?(:deep_symbolize_keys)
|
36
|
+
options = options.deep_symbolize_keys.deep_compact
|
40
37
|
options = parse_duration_values(options)
|
41
|
-
@options.
|
38
|
+
@options = @options.deep_merge(options)
|
42
39
|
end
|
43
40
|
end
|
44
41
|
|
@@ -59,8 +56,11 @@ module Eyecare
|
|
59
56
|
return options unless options.is_a?(Hash)
|
60
57
|
if options[:alert].is_a?(Hash)
|
61
58
|
[:interval, :timeout].each do |k|
|
62
|
-
|
63
|
-
|
59
|
+
if options[:alert][k]
|
60
|
+
options[:alert][k] = ChronicDuration.parse(options[:alert][k]) if options[:alert][k].is_a?(String)
|
61
|
+
options[:alert][k] = options[:alert][k].to_i
|
62
|
+
options[:alert].delete(k) if options[:alert][k] == 0
|
63
|
+
end
|
64
64
|
end
|
65
65
|
end
|
66
66
|
options
|
data/lib/eyecare/version.rb
CHANGED
data/test/alert_test.rb
CHANGED
@@ -3,10 +3,13 @@ require 'eyecare/alert'
|
|
3
3
|
|
4
4
|
describe Eyecare::Alert do
|
5
5
|
let(:config) do
|
6
|
-
{
|
6
|
+
{
|
7
7
|
message: 'Blink blink',
|
8
8
|
timeout: 40,
|
9
|
-
interval: 1800
|
9
|
+
interval: 1800,
|
10
|
+
beep: {
|
11
|
+
player: 'fooplayer :file'
|
12
|
+
}
|
10
13
|
}
|
11
14
|
end
|
12
15
|
|
@@ -15,6 +18,7 @@ describe Eyecare::Alert do
|
|
15
18
|
alert.message.wont_be_empty
|
16
19
|
alert.message.must_equal Eyecare::Alert::DEFAULT_MESSAGE
|
17
20
|
alert.timeout.must_equal Eyecare::Alert::DEFAULT_TIMEOUT
|
21
|
+
alert.beep.player.must_equal Eyecare::Alert::DEFAULT_BEEP_PLAYER
|
18
22
|
end
|
19
23
|
|
20
24
|
it 'correctly initialized from config hash' do
|
@@ -23,5 +27,6 @@ describe Eyecare::Alert do
|
|
23
27
|
alert.message.wont_be_empty
|
24
28
|
alert.message.must_equal config[:message]
|
25
29
|
alert.timeout.must_equal config[:timeout]
|
30
|
+
alert.beep.player.must_equal config[:beep][:player]
|
26
31
|
end
|
27
32
|
end
|
data/test/audio_test.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'eyecare/audio'
|
3
|
+
|
4
|
+
describe Eyecare::Alert do
|
5
|
+
it "player command is always valid" do
|
6
|
+
audio = Eyecare::Audio.new('foo.wav', 'fooplayer :file')
|
7
|
+
player_cmd = audio.send(:player_cmd)
|
8
|
+
player_cmd.must_equal 'fooplayer foo.wav'
|
9
|
+
|
10
|
+
audio = Eyecare::Audio.new('foo.wav', 'fooplayer :filename')
|
11
|
+
player_cmd = audio.send(:player_cmd)
|
12
|
+
player_cmd.must_equal 'fooplayer foo.wav'
|
13
|
+
end
|
14
|
+
end
|
data/test/config_test.rb
CHANGED
@@ -55,8 +55,8 @@ describe Eyecare::Config do
|
|
55
55
|
%"
|
56
56
|
alert:
|
57
57
|
message: 'This is a test message'
|
58
|
-
timeout:
|
59
|
-
interval:
|
58
|
+
timeout:
|
59
|
+
interval:
|
60
60
|
beep:
|
61
61
|
start: /path/to/beep/start.wav
|
62
62
|
end: /path/to/beep/end.wav
|
@@ -81,8 +81,8 @@ describe Eyecare::Config do
|
|
81
81
|
end
|
82
82
|
|
83
83
|
it 'is malformed' do
|
84
|
-
config = Eyecare::Config.load_from_text('fdaf-fff:fsdafd')
|
85
|
-
assert_default(config)
|
84
|
+
config = Eyecare::Config.load_from_text(YAML.load('fdaf-fff:fsdafd'))
|
85
|
+
assert_default(config)
|
86
86
|
end
|
87
87
|
|
88
88
|
it 'is loaded from file' do
|
@@ -90,7 +90,7 @@ describe Eyecare::Config do
|
|
90
90
|
f = Tempfile.new('config')
|
91
91
|
f.write(config_text)
|
92
92
|
f.close
|
93
|
-
|
93
|
+
|
94
94
|
config = Eyecare::Config.load_from_file(f.path)
|
95
95
|
f.unlink
|
96
96
|
config[:alert][:message].wont_be_empty
|
data/test/eyecare_test.rb
CHANGED
@@ -4,7 +4,12 @@ require 'tempfile'
|
|
4
4
|
describe Eyecare do
|
5
5
|
describe 'config' do
|
6
6
|
it 'is default if config file is missing' do
|
7
|
-
|
7
|
+
stub = Eyecare.dup
|
8
|
+
stub.instance_eval do
|
9
|
+
@config_path = ''
|
10
|
+
end
|
11
|
+
|
12
|
+
config = stub.config
|
8
13
|
config[:alert][:message].wont_be_empty
|
9
14
|
config[:alert][:message].must_equal Eyecare::Config::DEFAULTS[:alert][:message]
|
10
15
|
config[:alert][:timeout].must_equal Eyecare::Config::DEFAULTS[:alert][:timeout]
|
@@ -14,7 +19,7 @@ describe Eyecare do
|
|
14
19
|
|
15
20
|
it 'is loaded from file if file exists' do
|
16
21
|
config_yml = %"
|
17
|
-
alert:
|
22
|
+
alert:
|
18
23
|
message: 'Yadayada'
|
19
24
|
timeout: 10
|
20
25
|
interval: 1000
|
@@ -24,13 +29,13 @@ describe Eyecare do
|
|
24
29
|
config_file.write(config_yml)
|
25
30
|
config_file.close
|
26
31
|
|
27
|
-
|
28
|
-
|
32
|
+
stub = Eyecare.dup
|
33
|
+
stub.instance_eval do
|
29
34
|
@config = nil
|
30
35
|
@config_path = config_file.path
|
31
36
|
end
|
32
37
|
|
33
|
-
config =
|
38
|
+
config = stub.config
|
34
39
|
|
35
40
|
config[:alert][:message].wont_be_empty
|
36
41
|
config[:alert][:message].must_equal 'Yadayada'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: eyecare
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Viorel Craescu
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-04-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ffi
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: activesupport
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '4'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '4'
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: bundler
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -120,6 +134,7 @@ files:
|
|
120
134
|
- lib/eyecare/daemon.rb
|
121
135
|
- lib/eyecare/version.rb
|
122
136
|
- test/alert_test.rb
|
137
|
+
- test/audio_test.rb
|
123
138
|
- test/config_test.rb
|
124
139
|
- test/eyecare_test.rb
|
125
140
|
- test/test_helper.rb
|
@@ -143,12 +158,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
143
158
|
version: '0'
|
144
159
|
requirements: []
|
145
160
|
rubyforge_project:
|
146
|
-
rubygems_version: 2.4.
|
161
|
+
rubygems_version: 2.4.5
|
147
162
|
signing_key:
|
148
163
|
specification_version: 4
|
149
164
|
summary: Protect your eyes
|
150
165
|
test_files:
|
151
166
|
- test/alert_test.rb
|
167
|
+
- test/audio_test.rb
|
152
168
|
- test/config_test.rb
|
153
169
|
- test/eyecare_test.rb
|
154
170
|
- test/test_helper.rb
|