eyecare 0.1.0 → 0.2.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: 28fe112827d32de770483d3b5eaf9636b18c8ee6
4
- data.tar.gz: 744a0290be6f3433f9df56f3fb25fac29af2812d
3
+ metadata.gz: 8e004ee89fa1ccdaedc3c380870abda32967566f
4
+ data.tar.gz: 7657db390db6a9d5784df05d69147aee23bf1218
5
5
  SHA512:
6
- metadata.gz: 5306596df896dc1155036bc56a26e9e6ce36f5e5e17fcca1940614dd7b58ff747a7f71fcdd85e71aad34c8dd5a57c3c109d8b8a86866e102d8a936ff4f6281d8
7
- data.tar.gz: 1aa7b04e93905f680e4ffff061a11d709a193a40a837a0b50ba4fc95371f6ddf46e68e5f3ad4b60aee672b76d1e157523291f1912a152bc9f764ac54a068cd1f
6
+ metadata.gz: 861bec7f2f2fdabdfc16109f3c9d12df652bea2b8214b485ffe306e2112b9bf4eed60c3a80dd36c4e9109111daf0055ef51550e4fa7ec6b30770b5bd066ab4b0
7
+ data.tar.gz: 72ed5653993ecb3e8183213f7f9ff7db3280f5743fa1effbab148fd6b52d0a3824a1d0a9278fb817d11defc1675c2299042d048a27aec8e6809799a34c3a7d22
data/README.md CHANGED
@@ -2,7 +2,6 @@
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!
6
5
 
7
6
  ## Installation
8
7
 
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
- @config = Config.load_from_file(config_file) rescue Config.new
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 = 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]
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
- @start = Eyecare::Audio.new(options[:start])
25
- @end = Eyecare::Audio.new(options[:end])
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
- def initialize(filename)
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
- pid = spawn("aplay #{filename} > /dev/null 2>&1")
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
@@ -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?(:symbolize_keys)
39
- options = options.symbolize_keys
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.merge!(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
- options[:alert][k] = ChronicDuration.parse(options[:alert][k]) if options[:alert][k].is_a?(String)
63
- options[:alert][k] = options[:alert][k].to_i
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
@@ -1,3 +1,3 @@
1
1
  module Eyecare
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
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
@@ -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
- config = Eyecare.config
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
- EyecareStub = Eyecare.dup
28
- EyecareStub.instance_eval do
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 = EyecareStub.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.1.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: 2014-07-19 00:00:00.000000000 Z
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.1
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