beans 0.2.1
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 +15 -0
- data/Rakefile +38 -0
- data/bin/beans +71 -0
- data/bin/beans-server +9 -0
- data/bin/beansd +7 -0
- data/lib/beans.rb +9 -0
- data/lib/beans/bean_counter.rb +26 -0
- data/lib/beans/bean_server.rb +47 -0
- data/lib/beans/config.rb +51 -0
- data/lib/beans/dispatcher.rb +13 -0
- data/lib/beans/images/bean-icon.png +0 -0
- data/lib/beans/notification.rb +17 -0
- data/lib/beans/stopwatch.rb +113 -0
- data/lib/beans/version.rb +10 -0
- metadata +101 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
Yjg4NWM1NmM0OGIzNDRiMjc1NWNlNzg0YjY3NWMwOGM3MGYxMDBmNw==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
NmY4OTIzNzJjZDIwNTU3MTM1MDU0YzcxZDRiM2U2Y2IxYjIyYzM0Yg==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
ZjI0NjUwODEwMTdlYjQ2ZDBhMmU4NTY5ZGUwZDZiMmY5OTdiYzM1MWQxOTRh
|
10
|
+
YTRjNDVmOWM2ZDA0ODhmNmE3ZmNhYWRkZWVhY2Y1NDQ2MWQwMWIxMzE1Nzdi
|
11
|
+
YTVmODFkYWQzNTQyM2RhMzgyMDlmMjQ2YzM1ZDE2ODliYzA1NDc=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
NTQzNzQ1MDg4YzZjYWRhOTBiZTM5M2RhOGJjZWFiNzY1ZWE2NTQzNTJiZDk3
|
14
|
+
OTU3N2RiMDJhNDNiYTNjZTEyN2NjYWFhZjUyYjc2OTllYTBjOWZjZTRhNDFm
|
15
|
+
YzlhNDYwNjE5ZDgzZmZmZDFmOTYyYTVlNTg5MGNiMDQ1ZDAzNTA=
|
data/Rakefile
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
begin
|
3
|
+
require 'bundler/setup'
|
4
|
+
rescue LoadError
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
6
|
+
end
|
7
|
+
begin
|
8
|
+
require 'rdoc/task'
|
9
|
+
rescue LoadError
|
10
|
+
require 'rdoc/rdoc'
|
11
|
+
require 'rake/rdoctask'
|
12
|
+
RDoc::Task = Rake::RDocTask
|
13
|
+
end
|
14
|
+
|
15
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
16
|
+
rdoc.rdoc_dir = 'rdoc'
|
17
|
+
rdoc.title = 'beans'
|
18
|
+
rdoc.options << '--line-numbers'
|
19
|
+
rdoc.rdoc_files.include('README.rdoc')
|
20
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
|
26
|
+
Bundler::GemHelper.install_tasks
|
27
|
+
|
28
|
+
require 'rake/testtask'
|
29
|
+
|
30
|
+
Rake::TestTask.new(:test) do |t|
|
31
|
+
t.libs << 'lib'
|
32
|
+
t.libs << 'test'
|
33
|
+
t.pattern = 'test/**/*_test.rb'
|
34
|
+
t.verbose = false
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
task :default => :test
|
data/bin/beans
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'beans'
|
4
|
+
|
5
|
+
if ARGV.include? '-n'
|
6
|
+
multiplier = ARGV[ARGV.index('-n')+1].to_f
|
7
|
+
end
|
8
|
+
multiplier ||= 1.0
|
9
|
+
|
10
|
+
if ARGV.include? '-i'
|
11
|
+
interval = ARGV[ARGV.index('-i')+1].to_f
|
12
|
+
end
|
13
|
+
interval ||= 0.25
|
14
|
+
|
15
|
+
|
16
|
+
if ARGV.include? '-t'
|
17
|
+
|
18
|
+
begin
|
19
|
+
|
20
|
+
s = Beans::BeanCounter.new
|
21
|
+
|
22
|
+
while true do
|
23
|
+
$stdout.printf "\r$%.02f", s.query.to_f*multiplier
|
24
|
+
sleep(interval)
|
25
|
+
end
|
26
|
+
|
27
|
+
rescue Interrupt
|
28
|
+
$stdout.printf "\n"
|
29
|
+
|
30
|
+
rescue Errno::ECONNREFUSED
|
31
|
+
$stderr.puts "Unable to connect to beans server! Are you sure it's running on port #{Beans::Config.port}?"
|
32
|
+
|
33
|
+
rescue Errno::EPIPE
|
34
|
+
$stderr.printf "\nLost connection with beans server!\n"
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
elsif ARGV.include? 'start' or ARGV.include? 'stop' or ARGV.include? 'reset'
|
39
|
+
|
40
|
+
s = Beans::BeanCounter.new
|
41
|
+
case ARGV[0].strip.downcase
|
42
|
+
when 'start'
|
43
|
+
s.query('start')
|
44
|
+
when 'stop'
|
45
|
+
s.query('stop')
|
46
|
+
when 'reset'
|
47
|
+
s.query('reset')
|
48
|
+
end
|
49
|
+
|
50
|
+
else
|
51
|
+
|
52
|
+
begin
|
53
|
+
s = Beans::BeanCounter.new
|
54
|
+
$stdout.printf "$%.02f\n", s.query.to_f
|
55
|
+
|
56
|
+
rescue Errno::ECONNREFUSED
|
57
|
+
begin
|
58
|
+
# Presumably there's no server running, so let's just count some beans.
|
59
|
+
s = Beans::Stopwatch.new
|
60
|
+
s.start
|
61
|
+
|
62
|
+
while true do
|
63
|
+
$stdout.printf "\r$%.02f", s.query('dollars')*multiplier
|
64
|
+
sleep(interval)
|
65
|
+
end
|
66
|
+
rescue Interrupt
|
67
|
+
$stdout.printf "\n"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
data/bin/beans-server
ADDED
data/bin/beansd
ADDED
data/lib/beans.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
module Beans
|
2
|
+
class BeanCounter
|
3
|
+
|
4
|
+
def initialize(opts={})
|
5
|
+
opts[:port] ||= Config.port
|
6
|
+
@port = opts[:port]
|
7
|
+
end
|
8
|
+
|
9
|
+
def open
|
10
|
+
@socket = TCPSocket.new('127.0.0.1', @port)
|
11
|
+
end
|
12
|
+
|
13
|
+
def query( query='dollars' )
|
14
|
+
self.open
|
15
|
+
@socket.puts query
|
16
|
+
response = @socket.gets
|
17
|
+
self.close
|
18
|
+
response
|
19
|
+
end
|
20
|
+
|
21
|
+
def close
|
22
|
+
@socket.close
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'socket'
|
2
|
+
|
3
|
+
module Beans
|
4
|
+
class BeanServer
|
5
|
+
|
6
|
+
def initialize(opts={})
|
7
|
+
opts[:port] ||= Config.port
|
8
|
+
@server = TCPServer.new(opts[:port])
|
9
|
+
end
|
10
|
+
|
11
|
+
=begin
|
12
|
+
def in_background_loop &block
|
13
|
+
Thread.start do
|
14
|
+
loop do
|
15
|
+
begin
|
16
|
+
block.call
|
17
|
+
rescue StandardError => e
|
18
|
+
$stderr.puts "#{e.exception}: #{e.message}"
|
19
|
+
$stderr.puts e.backtrace
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
=end
|
25
|
+
|
26
|
+
def respond &block
|
27
|
+
|
28
|
+
#puts "Listening for bean counters on port #{opts[:port]}..."
|
29
|
+
|
30
|
+
loop do
|
31
|
+
Thread.start(@server.accept) do |client|
|
32
|
+
begin
|
33
|
+
response = block.call( client.gets )
|
34
|
+
client.puts response
|
35
|
+
client.close
|
36
|
+
rescue StandardError => e
|
37
|
+
$stderr.puts "#{e.exception}: #{e.message}"
|
38
|
+
$stderr.puts e.backtrace
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
data/lib/beans/config.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Beans
|
4
|
+
class Config
|
5
|
+
|
6
|
+
class <<self
|
7
|
+
def config
|
8
|
+
@config ||= YAML.load(open(ENV['HOME']+'/.beans.yml'))
|
9
|
+
end
|
10
|
+
|
11
|
+
def salary
|
12
|
+
config['salary']
|
13
|
+
end
|
14
|
+
|
15
|
+
def per
|
16
|
+
config['per']
|
17
|
+
end
|
18
|
+
|
19
|
+
def salary_per_year
|
20
|
+
case per.downcase
|
21
|
+
when 'year'
|
22
|
+
salary
|
23
|
+
when 'month'
|
24
|
+
salary*12
|
25
|
+
when 'hour'
|
26
|
+
salary*hours_per_week*52
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def hours_per_week
|
31
|
+
config['hours_per_week']
|
32
|
+
end
|
33
|
+
|
34
|
+
def port
|
35
|
+
config['port']
|
36
|
+
end
|
37
|
+
|
38
|
+
def dollars_per_second
|
39
|
+
seconds_per_week = hours_per_week*3600.0
|
40
|
+
weeks_per_year = 52.0
|
41
|
+
salary_per_year / weeks_per_year / seconds_per_week
|
42
|
+
end
|
43
|
+
|
44
|
+
def seconds_between_notifications
|
45
|
+
config['notify_every'] || 1800
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
Binary file
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'ruby-growl'
|
2
|
+
|
3
|
+
LIBDIR=File.dirname(__FILE__)
|
4
|
+
|
5
|
+
module Beans
|
6
|
+
class Notification
|
7
|
+
|
8
|
+
def initialize( m1, m2 )
|
9
|
+
|
10
|
+
@growl = Growl.new('localhost', 'beans')
|
11
|
+
|
12
|
+
@growl.add_notification 'beans', 'beans', File.read(File.join(LIBDIR,'/images/bean-icon.png'))
|
13
|
+
@growl.notify 'beans', m1, m2
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
module Beans
|
2
|
+
class Stopwatch
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
self.reset
|
6
|
+
end
|
7
|
+
|
8
|
+
def reset
|
9
|
+
t = Time.now
|
10
|
+
@first_started_at = nil
|
11
|
+
@last_notification_at = t
|
12
|
+
@previously_elapsed_time = 0.0
|
13
|
+
@last_stopped_at = t
|
14
|
+
@last_started_at = nil
|
15
|
+
@running = false
|
16
|
+
end
|
17
|
+
|
18
|
+
def start
|
19
|
+
if stopped?
|
20
|
+
t = Time.now
|
21
|
+
|
22
|
+
@first_started_at ||= t
|
23
|
+
|
24
|
+
@last_started_at = t
|
25
|
+
@running = true
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def stop
|
31
|
+
if running?
|
32
|
+
t = Time.now
|
33
|
+
|
34
|
+
@previously_elapsed_time ||= 0
|
35
|
+
@previously_elapsed_time += (t-@last_started_at).to_f
|
36
|
+
|
37
|
+
@last_stopped_at = t
|
38
|
+
@running = false
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
def stopped?
|
45
|
+
!@running
|
46
|
+
end
|
47
|
+
|
48
|
+
def running?
|
49
|
+
@running
|
50
|
+
end
|
51
|
+
|
52
|
+
def seconds_elapsed
|
53
|
+
if @last_started_at.nil?
|
54
|
+
0.0
|
55
|
+
else
|
56
|
+
s = @previously_elapsed_time
|
57
|
+
s += (Time.now-@last_started_at).to_f unless stopped?
|
58
|
+
s
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def minutes_elapsed
|
63
|
+
seconds_elapsed / 60.0
|
64
|
+
end
|
65
|
+
|
66
|
+
def hours_elapsed
|
67
|
+
minutes_elapsed / 60.0
|
68
|
+
end
|
69
|
+
|
70
|
+
def days_elapsed
|
71
|
+
hours_elapsed/24.0
|
72
|
+
end
|
73
|
+
|
74
|
+
def dollars_elapsed
|
75
|
+
seconds_elapsed * Config.dollars_per_second
|
76
|
+
end
|
77
|
+
|
78
|
+
def query(unit)
|
79
|
+
self.send( "#{unit.strip}_elapsed" )
|
80
|
+
end
|
81
|
+
|
82
|
+
def next_notification_at
|
83
|
+
@last_notification_at + Config.seconds_between_notifications
|
84
|
+
end
|
85
|
+
|
86
|
+
def seconds_to_next_notification
|
87
|
+
next_notification_at - Time.now
|
88
|
+
end
|
89
|
+
|
90
|
+
def nice_elapsed_time
|
91
|
+
if (s=seconds_elapsed) < 60
|
92
|
+
"#{sprintf("%i",s)} seconds"
|
93
|
+
elsif (m=minutes_elapsed) < 60
|
94
|
+
"#{sprintf("%i",m)} minutes"
|
95
|
+
elsif (h=hours_elapsed) < 24
|
96
|
+
"#{sprintf("%.1f",h)} hours"
|
97
|
+
else
|
98
|
+
"#{sprintf("%.1f",days_elapsed)} days"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
|
103
|
+
def notify
|
104
|
+
@last_notification_at = Time.now
|
105
|
+
return false if @first_started_at.nil?
|
106
|
+
Beans::Notification.new(
|
107
|
+
sprintf( "$%.02f", dollars_elapsed),
|
108
|
+
"over #{nice_elapsed_time} since #{@first_started_at.strftime( "%-I:%M %p")}."
|
109
|
+
)
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
end
|
metadata
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: beans
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ricky Reusser
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-11-11 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: daemons
|
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'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: ruby-growl
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ! '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: sqlite3
|
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'
|
55
|
+
description: A daemonized stopwatch with growl notifications so you don't forget.
|
56
|
+
email:
|
57
|
+
- rsreusser@gmail.com
|
58
|
+
executables:
|
59
|
+
- beans
|
60
|
+
- beans-server
|
61
|
+
- beansd
|
62
|
+
extensions: []
|
63
|
+
extra_rdoc_files: []
|
64
|
+
files:
|
65
|
+
- lib/beans/bean_counter.rb
|
66
|
+
- lib/beans/bean_server.rb
|
67
|
+
- lib/beans/config.rb
|
68
|
+
- lib/beans/dispatcher.rb
|
69
|
+
- lib/beans/images/bean-icon.png
|
70
|
+
- lib/beans/notification.rb
|
71
|
+
- lib/beans/stopwatch.rb
|
72
|
+
- lib/beans/version.rb
|
73
|
+
- lib/beans.rb
|
74
|
+
- Rakefile
|
75
|
+
- bin/beans
|
76
|
+
- bin/beans-server
|
77
|
+
- bin/beansd
|
78
|
+
homepage: https://github.com/rreusser/beans
|
79
|
+
licenses: []
|
80
|
+
metadata: {}
|
81
|
+
post_install_message:
|
82
|
+
rdoc_options: []
|
83
|
+
require_paths:
|
84
|
+
- lib
|
85
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ! '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - ! '>='
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
requirements: []
|
96
|
+
rubyforge_project:
|
97
|
+
rubygems_version: 2.1.10
|
98
|
+
signing_key:
|
99
|
+
specification_version: 4
|
100
|
+
summary: A small utility to convert time (yours) to money (theirs)
|
101
|
+
test_files: []
|