eyecare 0.0.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 55b305b029d0e5f457a4f2038edfe8b46c828492
4
- data.tar.gz: 26da6af224ac7e03d6b4f9fdb01010fc2fb3071c
3
+ metadata.gz: 28fe112827d32de770483d3b5eaf9636b18c8ee6
4
+ data.tar.gz: 744a0290be6f3433f9df56f3fb25fac29af2812d
5
5
  SHA512:
6
- metadata.gz: f7157b76deb6ff0afe1fa3c4d1cc20667e270e8c678eab2299086d2d9f25a9c03200460eb0cee53c99cd0ff5ee8bcd86e75a91821001d02912b08c8f0b31f590
7
- data.tar.gz: 0a7edbd62afd773c072614c63292d42878998f9442f1e7d02e70a84eaa1b97803eaa03165377c894a3a25da1c9e93dc4f0bde33aca0ed3417370353b183922cd
6
+ metadata.gz: 5306596df896dc1155036bc56a26e9e6ce36f5e5e17fcca1940614dd7b58ff747a7f71fcdd85e71aad34c8dd5a57c3c109d8b8a86866e102d8a936ff4f6281d8
7
+ data.tar.gz: 1aa7b04e93905f680e4ffff061a11d709a193a40a837a0b50ba4fc95371f6ddf46e68e5f3ad4b60aee672b76d1e157523291f1912a152bc9f764ac54a068cd1f
data/README.md CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  Reminds you to look away to avoid computer eye strain.
4
4
  It is recommended to look away from your screen for 20 seconds every 20 minutes.
5
+ This might only work on Ubuntu!
5
6
 
6
7
  ## Installation
7
8
 
@@ -9,12 +10,24 @@ It is recommended to look away from your screen for 20 seconds every 20 minutes.
9
10
 
10
11
  ## Usage
11
12
 
12
- $ eyecare
13
+ $ eyecare start
14
+ $ eyecare stop
13
15
 
14
- Create a config file ~/.eyecare.
16
+ The app will run as a daemon and pid file will be saved into ~/.eyecare/eyecare.pid
17
+ To see how much time left till next notification:
18
+
19
+ $ ps aux | grep Eyecare
20
+
21
+
22
+ Create a config file ~/.eyecare/config.yml
15
23
 
16
24
  Config options are:
17
25
 
18
- alert.message = 'Your message here'
19
- alert.timeout = 20 # timeout in seconds
20
- alert.interval = 20 * 60 # show up every 20 minutes
26
+ alert:
27
+ message: 'Yor message here'
28
+ timeout: 20 seconds
29
+ interval: 20 minutes
30
+ icon: /path/to/icon.png
31
+ beep:
32
+ start: /path/to/audio.wav
33
+ end: /path/to/audio.wav
data/bin/eyecare CHANGED
@@ -3,4 +3,12 @@
3
3
  require 'eyecare'
4
4
 
5
5
  # runs as daemon
6
- Eyecare::run!
6
+ command = ARGV.shift
7
+ command ||= 'start'
8
+
9
+ if command == 'start'
10
+ Eyecare.run
11
+ else
12
+ Eyecare.stop
13
+ end
14
+
data/eyecare.gemspec CHANGED
@@ -18,7 +18,9 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ['lib']
20
20
 
21
+ spec.add_dependency 'ffi'
21
22
  spec.add_dependency 'libnotify'
23
+ spec.add_dependency 'chronic_duration'
22
24
  spec.add_development_dependency 'bundler', '~> 1.5'
23
25
  spec.add_development_dependency 'rake'
24
26
  spec.add_development_dependency 'minitest'
data/lib/eyecare/alert.rb CHANGED
@@ -1,25 +1,55 @@
1
1
  require 'libnotify'
2
2
  require 'singleton'
3
+ require 'eyecare/config'
3
4
 
4
5
  module Eyecare
5
6
  class Alert
6
7
  include Singleton
7
8
  attr_accessor :message
8
9
  attr_accessor :timeout
10
+ attr_accessor :beep
11
+ attr_accessor :icon_path
9
12
 
10
- DEFAULT_MESSAGE = 'Look away'
11
- DEFAULT_TIMEOUT = 20
13
+ DEFAULT_MESSAGE = Config::DEFAULTS[:alert][:message]
14
+ DEFAULT_TIMEOUT = Config::DEFAULTS[:alert][:timeout]
15
+ DEFAULT_BEEP_START = File.join(Config::AUDIOS_PATH, 'beep_start.wav')
16
+ DEFAULT_BEEP_END = File.join(Config::AUDIOS_PATH, 'beep_end.wav')
17
+ DEFAULT_ICON_PATH = Config::DEFAULTS[:alert][:icon]
18
+
19
+ class Beep
20
+ attr_accessor :start
21
+ attr_accessor :end
22
+
23
+ def initialize(options = {})
24
+ @start = Eyecare::Audio.new(options[:start])
25
+ @end = Eyecare::Audio.new(options[:end])
26
+ end
27
+
28
+ def play(name)
29
+ self.send(name).play if [:start, :end].include?(name)
30
+ end
31
+ end
12
32
 
13
33
  def init(options = {})
14
34
  @message = options.fetch(:message, DEFAULT_MESSAGE)
15
35
  @timeout = options.fetch(:timeout, DEFAULT_TIMEOUT)
36
+ @icon_path = options.fetch(:icon, DEFAULT_ICON_PATH)
37
+
38
+ beep_start = DEFAULT_BEEP_START
39
+ beep_end = DEFAULT_BEEP_END
40
+ if options[:beep]
41
+ beep_start = options[:beep][:start] if options[:beep][:start]
42
+ beep_end = options[:beep][:end] if options[:beep][:end]
43
+ end
44
+
45
+ @beep = Beep.new(start: beep_start, end: beep_end)
16
46
  self
17
47
  end
18
48
 
19
49
  def show
20
- beep_start
50
+ beep.play(:start)
21
51
  notification.show!
22
- run_after(self.timeout) { beep_end }
52
+ run_after(self.timeout) { beep.play(:end) }
23
53
  end
24
54
 
25
55
  private
@@ -27,35 +57,14 @@ module Eyecare
27
57
  self.init
28
58
  end
29
59
 
30
- def icon_path
31
- File.join(Eyecare::IMAGES_PATH, 'eyecare.png')
32
- end
33
-
34
- def beep_start
35
- play_audio('beep_start.wav')
36
- end
37
-
38
- def beep_end
39
- play_audio('beep_end.wav')
40
- end
41
-
42
- def play_audio(filename)
43
- audio_path = File.join(Eyecare::AUDIOS_PATH, filename)
44
- pid = spawn("aplay #{audio_path} > /dev/null 2>&1")
45
- Process.detach(pid)
46
- end
47
-
48
60
  def run_after(timeout, &block)
49
- pid = fork do
50
- sleep(timeout)
51
- yield
52
- end
53
- Process.detach(pid)
61
+ sleep(timeout)
62
+ yield
54
63
  end
55
64
 
56
65
  def notification
57
66
  Libnotify.new do |s|
58
- s.summary = 'Eye Care'
67
+ s.summary = 'Eyecare'
59
68
  s.body = self.message
60
69
  s.timeout = self.timeout
61
70
  s.urgency = :normal
@@ -64,6 +73,3 @@ module Eyecare
64
73
  end
65
74
  end
66
75
  end
67
-
68
- #puts Eyecare::ASSETS_PATH
69
- #Eyecare::Alert.new.show
@@ -0,0 +1,13 @@
1
+ module Eyecare
2
+ class Audio
3
+ attr_accessor :filename
4
+ def initialize(filename)
5
+ @filename = filename
6
+ end
7
+
8
+ def play
9
+ pid = spawn("aplay #{filename} > /dev/null 2>&1")
10
+ Process.detach(pid)
11
+ end
12
+ end
13
+ end
@@ -1,43 +1,69 @@
1
+ require 'yaml'
2
+ require 'chronic_duration'
3
+ require 'eyecare'
4
+
1
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
+
2
16
  class Config
3
- attr_accessor :alert
17
+ ASSETS_PATH = File.expand_path(File.join(File.dirname(__FILE__), 'assets'))
18
+ IMAGES_PATH = File.join(ASSETS_PATH, 'images')
19
+ AUDIOS_PATH = File.join(ASSETS_PATH, 'audios')
20
+
21
+ DEFAULTS = {
22
+ alert: {
23
+ message: 'Look away',
24
+ timeout: 20,
25
+ interval: 20 * 60,
26
+ icon: File.join(IMAGES_PATH, 'eyecare.png'),
27
+ beep: {
28
+ start: File.join(AUDIOS_PATH, 'beep_start.wav'),
29
+ end: File.join(AUDIOS_PATH, 'beep_end.wav')
30
+ }
31
+ },
4
32
 
5
- def initialize
6
- @alert = Alert.new
7
- yield self if block_given?
33
+ pid_file: File.expand_path(File.join('.eyecare', 'eyecare.pid'), '~')
34
+ }
35
+
36
+ def initialize(options = {})
37
+ @options = DEFAULTS
38
+ if options.respond_to?(:symbolize_keys)
39
+ options = options.symbolize_keys
40
+ options = parse_duration_values(options)
41
+ @options.merge!(options)
42
+ end
8
43
  end
9
44
 
10
45
  def self.load_from_file(filename)
11
- load_from_text(File.open(filename).read)
46
+ self.new(YAML.load_file(File.open(filename)))
12
47
  end
13
48
 
14
49
  def self.load_from_text(text)
15
- config = self.new
16
- config.instance_eval do eval(text) end
17
- config
18
- end
19
-
20
- def to_h
21
- { alert: alert.to_hash }
50
+ self.new(YAML.load(text))
22
51
  end
23
- end
24
-
25
- class Eyecare::Config::Alert
26
- attr_accessor :message
27
- attr_accessor :timeout
28
- attr_accessor :interval
29
52
 
30
- def initialize
31
- @timeout = 20
32
- @interval = 20 * 60
53
+ def [](key)
54
+ @options[key]
33
55
  end
34
56
 
35
- def to_h
36
- h = {}
37
- h[:message] = self.message if self.message
38
- h[:timeout] = self.timeout if self.timeout
39
- h[:interval] = self.interval if self.interval
40
- h
57
+ private
58
+ def parse_duration_values(options)
59
+ return options unless options.is_a?(Hash)
60
+ if options[:alert].is_a?(Hash)
61
+ [:interval, :timeout].each do |k|
62
+ options[:alert][k] = ChronicDuration.parse(options[:alert][k]) if options[:alert][k].is_a?(String)
63
+ options[:alert][k] = options[:alert][k].to_i
64
+ end
65
+ end
66
+ options
41
67
  end
42
68
  end
43
69
  end
@@ -0,0 +1,101 @@
1
+ module Eyecare
2
+ class Daemon
3
+ attr_accessor :pid_file
4
+ attr_accessor :out
5
+ attr_accessor :err
6
+
7
+ def initialize(options = {})
8
+ options = Hash[pid_file: options] if options.is_a?(String)
9
+ @pid_file = options[:pid_file]
10
+ end
11
+
12
+ def self.start(options = {}, &block)
13
+ return false unless block_given?
14
+ daemon = self.new(options)
15
+
16
+ begin
17
+ daemon.send(:cleanup) if daemon.stale_pid?
18
+ if daemon.started?
19
+ puts 'Already started'
20
+ return false
21
+ end
22
+
23
+ print 'Starting...'
24
+ Process.daemon(nil, true)
25
+ daemon.send(:write_pid)
26
+
27
+ trap('INT') { exit(0) }
28
+ at_exit { daemon.send(:cleanup) }
29
+ rescue StandardError => e
30
+ puts 'Error: Start failed'
31
+ puts e.message
32
+ end
33
+
34
+ puts "OK\n"
35
+ yield
36
+ end
37
+
38
+ def self.stop(daemon)
39
+ daemon = Daemon.new(pid_file: daemon) if daemon.is_a?(String)
40
+
41
+ begin
42
+ unless daemon.started?
43
+ puts 'Not started or pid file is missing'
44
+ return false
45
+ end
46
+
47
+ print 'Stopping...'
48
+ pid = daemon.pid
49
+ return false unless daemon.running?
50
+ Process.kill('INT', pid)
51
+ puts 'OK'
52
+ rescue StandardError => e
53
+ puts 'Error: Stop failed'
54
+ puts e.inspect
55
+ end
56
+ end
57
+
58
+ def started?
59
+ File.file?(pid_file)
60
+ end
61
+
62
+ def stale_pid?
63
+ !process_running?(read_pid) rescue false
64
+ end
65
+
66
+ def pid
67
+ read_pid rescue 0
68
+ end
69
+
70
+ def running?
71
+ process_running?(pid)
72
+ end
73
+
74
+ private
75
+ def process_running?(pid)
76
+ return false unless pid && pid != 0
77
+ system("kill -s 0 #{pid}")
78
+ end
79
+
80
+ def cleanup
81
+ File.unlink(pid_file) rescue false
82
+ end
83
+
84
+ def read_pid
85
+ pid = nil
86
+ File.open(pid_file, 'r') do |f|
87
+ pid = f.read
88
+ end
89
+ pid.to_i
90
+ end
91
+
92
+ def write_pid
93
+ FileUtils.mkdir_p(File.dirname(pid_file))
94
+
95
+ pid = Process.pid
96
+ File.open(pid_file, 'w') do |f|
97
+ f.write(pid)
98
+ end
99
+ end
100
+ end
101
+ end
@@ -1,3 +1,3 @@
1
1
  module Eyecare
2
- VERSION = "0.0.2"
2
+ VERSION = "0.1.0"
3
3
  end
data/lib/eyecare.rb CHANGED
@@ -1,40 +1,65 @@
1
1
  require "eyecare/version"
2
2
  require 'eyecare/alert'
3
+ require 'eyecare/audio'
3
4
  require 'eyecare/config'
5
+ require 'eyecare/daemon'
6
+ require 'fileutils'
7
+ require 'ffi'
4
8
 
5
9
  module Eyecare
6
- ASSETS_PATH = File.expand_path(File.join(File.dirname(__FILE__), 'eyecare', 'assets'))
7
- IMAGES_PATH = File.join(ASSETS_PATH, 'images')
8
- AUDIOS_PATH = File.join(ASSETS_PATH, 'audios')
10
+ extend FFI::Library
11
+ ffi_lib FFI::Library::LIBC
12
+
13
+ begin
14
+ attach_function :prctl, [ :ulong, :ulong, :ulong, :ulong ], :int
15
+ rescue FFI::NotFoundError
16
+ # We couldn't find the method
17
+ end
18
+
19
+ @config_path = File.expand_path('~/.eyecare/config.yml')
9
20
 
10
21
  class << self
11
- def run!
12
- Process.daemon
13
- while true
14
- sleep(config.alert.interval)
15
- alert.show
16
- end
17
- end
22
+ attr_reader :config_path
18
23
 
19
24
  def run
20
- fork do
21
- sleep(config.alert.interval)
22
- alert.show
25
+ Daemon.start(config[:pid_file]) do
26
+ while true
27
+ seconds = config[:alert][:interval]
28
+ while seconds > 0
29
+ proc_name('Eyecare - %s' % ChronicDuration.output(seconds, :format => :short))
30
+ seconds -= 1
31
+ sleep(1)
32
+ end
33
+ alert.show
34
+ end
23
35
  end
24
36
  end
25
37
 
26
- private
38
+ def stop
39
+ Daemon.stop(config[:pid_file])
40
+ end
41
+
27
42
  def alert
28
- Alert.instance.init(config.alert.to_h)
43
+ Alert.instance.init(config[:alert])
29
44
  end
30
45
 
31
46
  def config
32
47
  return @config if @config
33
- config_file = File.expand_path('~/.eyecare')
34
- if File.file?(config_file)
35
- @config = Config.load_from_file(config_file)
36
- end
48
+
49
+ config_file = File.expand_path(config_path)
50
+ @config = Config.load_from_file(config_file) rescue Config.new
37
51
  end
38
- end
39
52
 
53
+ private
54
+ def proc_name(name)
55
+ $0 = name
56
+ return false unless self.respond_to?(:prctl)
57
+
58
+ name = name.slice(0, 16)
59
+ ptr = FFI::MemoryPointer.from_string(name)
60
+ self.prctl(15, ptr.address, 0, 0)
61
+ ensure
62
+ ptr.free if ptr
63
+ end
64
+ end
40
65
  end
data/test/alert_test.rb CHANGED
@@ -3,17 +3,21 @@ require 'eyecare/alert'
3
3
 
4
4
  describe Eyecare::Alert do
5
5
  let(:config) do
6
- { message: 'Blink blink', timeout: 40 }
6
+ {
7
+ message: 'Blink blink',
8
+ timeout: 40,
9
+ interval: 1800
10
+ }
7
11
  end
8
12
 
9
- it 'is defaulted is when no config' do
13
+ it 'defaults when no config' do
10
14
  alert = Eyecare::Alert.send(:new)
11
15
  alert.message.wont_be_empty
12
16
  alert.message.must_equal Eyecare::Alert::DEFAULT_MESSAGE
13
17
  alert.timeout.must_equal Eyecare::Alert::DEFAULT_TIMEOUT
14
18
  end
15
19
 
16
- it 'is correctly initialized from config hash' do
20
+ it 'correctly initialized from config hash' do
17
21
  alert = Eyecare::Alert.send(:new).init(config)
18
22
 
19
23
  alert.message.wont_be_empty
data/test/config_test.rb CHANGED
@@ -2,46 +2,126 @@ require 'test_helper'
2
2
  require 'eyecare/config'
3
3
 
4
4
  describe Eyecare::Config do
5
- it 'is initialize by a block' do
6
- config = Eyecare::Config.new do |c|
7
- c.alert.message = 'This is a test'
8
- c.alert.timeout = 40
9
- c.alert.interval = 30 * 60
10
- end
5
+ def assert_default(config)
6
+ config[:alert][:message].wont_be_empty
7
+ config[:alert][:message].must_equal Eyecare::Config::DEFAULTS[:alert][:message]
8
+ config[:alert][:timeout].must_equal Eyecare::Config::DEFAULTS[:alert][:timeout]
9
+ config[:alert][:interval].must_equal Eyecare::Config::DEFAULTS[:alert][:interval]
10
+ config[:alert][:beep][:start].must_equal Eyecare::Config::DEFAULTS[:alert][:beep][:start]
11
+ config[:alert][:beep][:end].must_equal Eyecare::Config::DEFAULTS[:alert][:beep][:end]
12
+ config[:pid_file].must_equal Eyecare::Config::DEFAULTS[:pid_file]
13
+ end
11
14
 
12
- config.alert.message.wont_be_empty
13
- config.alert.timeout.must_equal 40
14
- config.alert.interval.must_equal 30 * 60
15
+ let(:config_text) do
16
+ %"
17
+ alert:
18
+ message: 'This is a test message'
19
+ timeout: 40
20
+ interval: 1800
21
+ beep:
22
+ start: /path/to/beep/start.wav
23
+ end: /path/to/beep/end.wav
24
+ pid_file: /path/to/my/pid/file.pid
25
+ "
15
26
  end
16
27
 
17
- it 'is loaded from text' do
18
- text = %"
19
- alert.message = 'This is a test message'
20
- alert.timeout = 40
21
- alert.interval = 30 * 60
28
+ let(:friendly_config_text) do
29
+ %"
30
+ alert:
31
+ message: 'This is a test message'
32
+ timeout: 30 seconds
33
+ interval: 50 minutes
34
+ beep:
35
+ start: /path/to/beep/start.wav
36
+ end: /path/to/beep/end.wav
37
+ pid_file: /path/to/my/pid/file.pid
22
38
  "
23
- config = Eyecare::Config.load_from_text(text)
24
- config.alert.message.wont_be_empty
25
- config.alert.timeout.must_equal 40
26
- config.alert.interval.must_equal 30 * 60
27
39
  end
28
40
 
29
- it 'is loaded from file' do
30
- text = %"
31
- alert.message = 'This is a test message'
32
- alert.timeout = 60
33
- alert.interval = 40 * 60
41
+ let(:friendly_config_text_wrong) do
42
+ %"
43
+ alert:
44
+ message: 'This is a test message'
45
+ timeout: test
46
+ interval: blah
47
+ beep:
48
+ start: /path/to/beep/start.wav
49
+ end: /path/to/beep/end.wav
50
+ pid_file: /path/to/my/pid/file.pid
51
+ "
52
+ end
53
+
54
+ let(:config_text_missing_values) do
55
+ %"
56
+ alert:
57
+ message: 'This is a test message'
58
+ timeout:
59
+ interval:
60
+ beep:
61
+ start: /path/to/beep/start.wav
62
+ end: /path/to/beep/end.wav
63
+ pid_file: /path/to/my/pid/file.pid
34
64
  "
65
+ end
66
+
67
+ it 'is loaded from text' do
68
+ config = Eyecare::Config.load_from_text(config_text)
69
+ config[:alert][:message].wont_be_empty
70
+ config[:alert][:message].must_equal 'This is a test message'
71
+ config[:alert][:timeout].must_equal 40
72
+ config[:alert][:interval].must_equal 30 * 60
73
+ config[:alert][:beep][:start].must_equal '/path/to/beep/start.wav'
74
+ config[:alert][:beep][:end].must_equal '/path/to/beep/end.wav'
75
+ config[:pid_file].must_equal '/path/to/my/pid/file.pid'
76
+ end
77
+
78
+ it 'is empty' do
79
+ config = Eyecare::Config.load_from_text('')
80
+ assert_default(config)
81
+ end
82
+
83
+ it 'is malformed' do
84
+ config = Eyecare::Config.load_from_text('fdaf-fff:fsdafd')
85
+ assert_default(config)
86
+ end
87
+
88
+ it 'is loaded from file' do
35
89
  require 'tempfile'
36
90
  f = Tempfile.new('config')
37
- f.write(text)
91
+ f.write(config_text)
38
92
  f.close
39
93
 
40
94
  config = Eyecare::Config.load_from_file(f.path)
41
95
  f.unlink
42
- config.alert.message.wont_be_empty
43
- config.alert.timeout.must_equal 60
44
- config.alert.interval.must_equal 40 * 60
96
+ config[:alert][:message].wont_be_empty
97
+ config[:alert][:message].must_equal 'This is a test message'
98
+ config[:alert][:timeout].must_equal 40
99
+ config[:alert][:interval].must_equal 30 * 60
100
+ config[:alert][:beep][:start].must_equal '/path/to/beep/start.wav'
101
+ config[:alert][:beep][:end].must_equal '/path/to/beep/end.wav'
102
+ config[:pid_file].must_equal '/path/to/my/pid/file.pid'
45
103
  end
46
- end
47
104
 
105
+ it 'friendly config is parsed correctly' do
106
+ config = Eyecare::Config.load_from_text(friendly_config_text)
107
+ config[:alert][:message].must_equal 'This is a test message'
108
+ config[:alert][:interval].must_equal 60 * 50
109
+ config[:alert][:timeout].must_equal 30
110
+ config[:alert][:beep][:start].must_equal '/path/to/beep/start.wav'
111
+ config[:alert][:beep][:end].must_equal '/path/to/beep/end.wav'
112
+ end
113
+
114
+ it 'friendly config is has wrong values' do
115
+ config = Eyecare::Config.load_from_text(friendly_config_text_wrong)
116
+ config[:alert][:message].must_equal 'This is a test message'
117
+ config[:alert][:interval].must_equal Eyecare::Config::DEFAULTS[:alert][:interval]
118
+ config[:alert][:timeout].must_equal Eyecare::Config::DEFAULTS[:alert][:timeout]
119
+ end
120
+
121
+ it 'has missing values' do
122
+ config = Eyecare::Config.load_from_text(config_text_missing_values)
123
+ config[:alert][:message].must_equal 'This is a test message'
124
+ config[:alert][:interval].must_equal Eyecare::Config::DEFAULTS[:alert][:interval]
125
+ config[:alert][:timeout].must_equal Eyecare::Config::DEFAULTS[:alert][:timeout]
126
+ end
127
+ end
@@ -0,0 +1,45 @@
1
+ require 'test_helper'
2
+ require 'tempfile'
3
+
4
+ describe Eyecare do
5
+ describe 'config' do
6
+ it 'is default if config file is missing' do
7
+ config = Eyecare.config
8
+ config[:alert][:message].wont_be_empty
9
+ config[:alert][:message].must_equal Eyecare::Config::DEFAULTS[:alert][:message]
10
+ config[:alert][:timeout].must_equal Eyecare::Config::DEFAULTS[:alert][:timeout]
11
+ config[:alert][:interval].must_equal Eyecare::Config::DEFAULTS[:alert][:interval]
12
+ config[:pid_file].must_equal Eyecare::Config::DEFAULTS[:pid_file]
13
+ end
14
+
15
+ it 'is loaded from file if file exists' do
16
+ config_yml = %"
17
+ alert:
18
+ message: 'Yadayada'
19
+ timeout: 10
20
+ interval: 1000
21
+ pid_file: '/path/to/pid/file.pid'
22
+ "
23
+ config_file = Tempfile.new('config')
24
+ config_file.write(config_yml)
25
+ config_file.close
26
+
27
+ EyecareStub = Eyecare.dup
28
+ EyecareStub.instance_eval do
29
+ @config = nil
30
+ @config_path = config_file.path
31
+ end
32
+
33
+ config = EyecareStub.config
34
+
35
+ config[:alert][:message].wont_be_empty
36
+ config[:alert][:message].must_equal 'Yadayada'
37
+ config[:alert][:timeout].must_equal 10
38
+ config[:alert][:interval].must_equal 1000
39
+ config[:pid_file].must_equal '/path/to/pid/file.pid'
40
+
41
+ config_file.unlink
42
+ end
43
+ end
44
+ end
45
+
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: eyecare
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.1.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: 2014-07-05 00:00:00.000000000 Z
11
+ date: 2014-07-19 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ffi
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: libnotify
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -24,6 +38,20 @@ dependencies:
24
38
  - - ">="
25
39
  - !ruby/object:Gem::Version
26
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: chronic_duration
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
27
55
  - !ruby/object:Gem::Dependency
28
56
  name: bundler
29
57
  requirement: !ruby/object:Gem::Requirement
@@ -87,10 +115,13 @@ files:
87
115
  - lib/eyecare/assets/audios/beep_start.wav
88
116
  - lib/eyecare/assets/images/eye.png
89
117
  - lib/eyecare/assets/images/eyecare.png
118
+ - lib/eyecare/audio.rb
90
119
  - lib/eyecare/config.rb
120
+ - lib/eyecare/daemon.rb
91
121
  - lib/eyecare/version.rb
92
122
  - test/alert_test.rb
93
123
  - test/config_test.rb
124
+ - test/eyecare_test.rb
94
125
  - test/test_helper.rb
95
126
  homepage: ''
96
127
  licenses:
@@ -112,11 +143,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
112
143
  version: '0'
113
144
  requirements: []
114
145
  rubyforge_project:
115
- rubygems_version: 2.2.2
146
+ rubygems_version: 2.4.1
116
147
  signing_key:
117
148
  specification_version: 4
118
149
  summary: Protect your eyes
119
150
  test_files:
120
151
  - test/alert_test.rb
121
152
  - test/config_test.rb
153
+ - test/eyecare_test.rb
122
154
  - test/test_helper.rb