eyecare 0.0.2 → 0.1.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
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