trak 0.0.3 → 0.0.4
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.
- data/CHANGELOG.md +15 -0
- data/README.md +8 -34
- data/bin/trak +178 -0
- data/lib/trak.rb +78 -147
- metadata +2 -3
- data/lib/trak/trak.rb +0 -92
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,20 @@
|
|
1
1
|
# Change log
|
2
2
|
|
3
|
+
## v0.0.4 (2012-05-01)
|
4
|
+
|
5
|
+
Changed:
|
6
|
+
|
7
|
+
* (ca1da2d): Use TRAK_DEBUG environment var instead of --debug
|
8
|
+
* (d00089a): Moved todos into github issue tracker
|
9
|
+
* (5cb50db): Fix for report format
|
10
|
+
|
11
|
+
Closed:
|
12
|
+
|
13
|
+
* (a6669ca): #11 - Refactor command-line specific code into bin/trak +
|
14
|
+
refactor Trak module
|
15
|
+
* (f5fd613): Add -h|--help switch. Fixes #6
|
16
|
+
* (a113869): Added version info. Fixes #7
|
17
|
+
|
3
18
|
## v0.0.3 (2012-04-30)
|
4
19
|
|
5
20
|
Changed:
|
data/README.md
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
# Trak: track chunks of time from the command line
|
2
2
|
|
3
|
-
Trak, v0.0.
|
3
|
+
Trak, v0.0.4 (May 1, 2012)
|
4
4
|
Written by Adam Sharp
|
5
5
|
|
6
6
|
## Notice
|
7
7
|
|
8
|
-
Trak was recently
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
Trak was recently a Perl script. It has been ported to Ruby, but the
|
9
|
+
code really looks like it's taken a beating and is definitely NOT what I
|
10
|
+
want it to ultimately look like. Much more ruby-fying to happen yet, as
|
11
|
+
well as support for the excellent
|
12
12
|
[Chronic](https://github.com/mojombo/chronic) gem for natural language
|
13
13
|
date parsing in the pipeline.
|
14
14
|
|
@@ -19,8 +19,8 @@ Stay tuned.
|
|
19
19
|
|
20
20
|
## Description
|
21
21
|
|
22
|
-
Trak is a utility
|
23
|
-
|
22
|
+
Trak is a utility that allows you to quickly make a record of how much
|
23
|
+
time you've spent on various tasks throughout the day.
|
24
24
|
|
25
25
|
Work logs are stored in `/Users/yourusername/Documents/Tracker/` with
|
26
26
|
the format `YEAR-MONTH-DAY-time-log.txt`.
|
@@ -62,7 +62,7 @@ Where:
|
|
62
62
|
You can use either
|
63
63
|
|
64
64
|
$ trak 30 "Foo bar"
|
65
|
-
|
65
|
+
|
66
66
|
or
|
67
67
|
|
68
68
|
$ trak 30 Foo bar
|
@@ -78,29 +78,3 @@ These are all valid commands:
|
|
78
78
|
$ trak 30min Rewrite trak documentation # => 30 minutes
|
79
79
|
$ trak 4hours Refactor trak # => 4 hours
|
80
80
|
$ trak 15 Lunch # => 15 minutes
|
81
|
-
|
82
|
-
## To do
|
83
|
-
|
84
|
-
* Proper handling of incorrectly formatted dates
|
85
|
-
* Write a report that gives a weekly breakdown given a date in that week
|
86
|
-
* Add a `-h` usage/help switch
|
87
|
-
* Make the personal time search more configurable by putting keywords to
|
88
|
-
search in an array
|
89
|
-
* Have the different types of reports, and keywords for those reports,
|
90
|
-
completely stored in a configuration file. The last category in the
|
91
|
-
file is the default report. Because keywords for custom reports would
|
92
|
-
work on a whitelist system, everything that doesn't match goes into
|
93
|
-
the default. For example:
|
94
|
-
|
95
|
-
# Personal
|
96
|
-
lunch
|
97
|
-
uni
|
98
|
-
news
|
99
|
-
# Default
|
100
|
-
Work
|
101
|
-
|
102
|
-
* Have the keywords in the configuration file actually be regexes. When
|
103
|
-
reading the config file, any empty lines or whitespace are ignored.
|
104
|
-
* Give an estimate of completion time, with a configurable default for
|
105
|
-
the length of the work day. Also take into account the default length
|
106
|
-
of lunch break (configurable) if lunch hasn't yet been logged.
|
data/bin/trak
CHANGED
@@ -1,2 +1,180 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
require 'trollop'
|
2
3
|
require 'trak'
|
4
|
+
require 'trak/exit'
|
5
|
+
require 'trak/core_ext/time'
|
6
|
+
|
7
|
+
# place where data is stored
|
8
|
+
datadir = "#{ENV['HOME']}/Documents/Tracker/"
|
9
|
+
%x[mkdir -p #{datadir}]
|
10
|
+
|
11
|
+
# define command line options
|
12
|
+
opts = Trollop::options do
|
13
|
+
version "trak version 0.0.4"
|
14
|
+
banner <<-BANNER
|
15
|
+
Trak: log chunks of time from the command line
|
16
|
+
Usage:
|
17
|
+
trak [-d|--date] <time> <message> # tracking mode
|
18
|
+
trak [-d|--date] [-r|--report] # reporting mode
|
19
|
+
trak [-d|--date] -e|--edit # opens time log in EDITOR
|
20
|
+
|
21
|
+
Tracking time:
|
22
|
+
The <time> argument is the amount of time spent on the task, in
|
23
|
+
minutes. Append "h" for hours, e.g., 1.5h. Examples:
|
24
|
+
|
25
|
+
$ trak 15 email # minimum 15 minutes
|
26
|
+
$ trak 25 lunch # rounded to nearest 15m, i.e. 30
|
27
|
+
$ trak 1.5h bug 2345 # everything after <time> is the message
|
28
|
+
|
29
|
+
Reporting:
|
30
|
+
The -r|--report option is optional, just typing `trak` with no
|
31
|
+
arguments will cause Trak to print a report for today. Use -d|--date
|
32
|
+
to print the report for another day.
|
33
|
+
|
34
|
+
Dates:
|
35
|
+
Trak currently accepts dates in the format YYYY-MM-DD. All modes
|
36
|
+
accept the date argument (defaults to today).
|
37
|
+
|
38
|
+
See http://github.com/sharplet/trak for more information.
|
39
|
+
|
40
|
+
Options:
|
41
|
+
BANNER
|
42
|
+
opt :date, "Specify the date of the log to work with",
|
43
|
+
:type => String, :short => "-d"
|
44
|
+
opt :report, "Print a report for the specified date", :short => "-l"
|
45
|
+
opt :edit, "Open the log for the specified date in EDITOR"
|
46
|
+
end
|
47
|
+
|
48
|
+
# all valid options have been processed, so figure out which mode
|
49
|
+
# we're in...
|
50
|
+
#
|
51
|
+
# if we found a -r or -l option, ignore everything else
|
52
|
+
Trak::breakpoint
|
53
|
+
if opts[:report]
|
54
|
+
MODE = 'report'
|
55
|
+
# now check if the user wants edit mode
|
56
|
+
elsif opts[:edit]
|
57
|
+
MODE = 'edit'
|
58
|
+
# if there are still unprocessed args (that didn't look like switches),
|
59
|
+
# we're in insert mode
|
60
|
+
elsif ARGV.length > 0
|
61
|
+
MODE = 'insert'
|
62
|
+
# if all else fails, there were probably no args to begin with, so we're
|
63
|
+
# in report mode
|
64
|
+
else
|
65
|
+
MODE = 'report'
|
66
|
+
end
|
67
|
+
|
68
|
+
today = Time.now.strftime '%F'
|
69
|
+
|
70
|
+
# did the user supply a date argument that isn't today?
|
71
|
+
if opts[:date] && opts[:date] != today
|
72
|
+
fdate = opts[:date]
|
73
|
+
# otherwise use today's date, formatted, and set date_arg to be false
|
74
|
+
else
|
75
|
+
fdate = today
|
76
|
+
opts[:date] = nil
|
77
|
+
end
|
78
|
+
|
79
|
+
# set the output file name
|
80
|
+
filename = "#{datadir}#{fdate}-time-log.txt"
|
81
|
+
|
82
|
+
if MODE == 'report'
|
83
|
+
if File.exist? filename
|
84
|
+
# open the file and get it as an array
|
85
|
+
begin
|
86
|
+
file = File.open(filename).readlines.map &:chomp
|
87
|
+
rescue
|
88
|
+
Exit::exit_err "#{__FILE__}: #{$!}"
|
89
|
+
end
|
90
|
+
|
91
|
+
# The keys for each hash are the titles of the various tasks logged.
|
92
|
+
# The values are the total time spent on the task.
|
93
|
+
work = {}
|
94
|
+
personal = {}
|
95
|
+
|
96
|
+
# find the start time for the day we're reporting on
|
97
|
+
startTime = file.first.split[1]
|
98
|
+
|
99
|
+
# process each line of the file
|
100
|
+
file[1..file.size].each do |line|
|
101
|
+
minutes, text = line.split(': ')
|
102
|
+
unless text =~ /personal|uni|lunch|home/
|
103
|
+
work[text] = 0 unless work.include? text
|
104
|
+
work[text] += minutes.to_i
|
105
|
+
else
|
106
|
+
personal[text] = 0 unless personal.include? text
|
107
|
+
personal[text] += minutes.to_i
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# print the report
|
112
|
+
if opts[:date]
|
113
|
+
puts "# Logged work for #{fdate}"
|
114
|
+
else
|
115
|
+
puts "# Today's logged work"
|
116
|
+
end
|
117
|
+
|
118
|
+
workTotal = Trak::printSubReport(work, "Work")
|
119
|
+
personalTotal = Trak::printSubReport(personal, "Personal")
|
120
|
+
|
121
|
+
newTimeString = Trak::to12HourTime(Trak::newTimeWithMinutes(startTime, workTotal + personalTotal))
|
122
|
+
print "Hours logged until #{newTimeString} (since #{Trak::to12HourTime(startTime)}). "
|
123
|
+
|
124
|
+
# if we're reporting for today, print the current time
|
125
|
+
puts (!opts[:date]) ? "Currently #{Trak::to12HourTime(Time.now.strftime(Trak::TIME_FORMAT_24HOUR))}." : nil
|
126
|
+
else
|
127
|
+
if opts[:date]
|
128
|
+
STDERR.puts "No time log for #{fdate}. Track some time first."
|
129
|
+
else
|
130
|
+
STDERR.puts "No time log for today. Track some time first.\n"
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
elsif MODE == 'edit'
|
135
|
+
if File.exist? filename
|
136
|
+
if ENV['EDITOR']
|
137
|
+
exec "#{ENV['EDITOR']} #{filename}"
|
138
|
+
else
|
139
|
+
exec "open", filename
|
140
|
+
end
|
141
|
+
exit
|
142
|
+
else
|
143
|
+
Exit::exit_err "#{__FILE__}: #{filename} does not exist or unable to open."
|
144
|
+
end
|
145
|
+
|
146
|
+
elsif MODE == 'insert'
|
147
|
+
if opts[:date]
|
148
|
+
puts "WARNING: Adding time to a day other than today is not recommended."
|
149
|
+
print "Continue? (y/n) "
|
150
|
+
input = STDIN.readline.chomp
|
151
|
+
unless input =~ /^y(es)?/i
|
152
|
+
Exit::exit_err "Timelog update cancelled."
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# process arguments
|
157
|
+
Trak::breakpoint
|
158
|
+
minutes = Trak::processTimeArgument ARGV.shift
|
159
|
+
message = ARGV.join(" ")
|
160
|
+
|
161
|
+
# open the output file
|
162
|
+
first_time = !File.exist?(filename)
|
163
|
+
Trak::breakpoint
|
164
|
+
begin
|
165
|
+
File.open filename, 'a', :autoclose => true do |file|
|
166
|
+
if first_time
|
167
|
+
Trak::breakpoint
|
168
|
+
currentTimeInMinutes = Time.now.to_minutes
|
169
|
+
startTime = Trak::minutesToTime((currentTimeInMinutes - minutes).round_to_nearest 15)
|
170
|
+
file.puts "#{fdate} #{startTime}"
|
171
|
+
end
|
172
|
+
file.puts "#{minutes}: #{message}"
|
173
|
+
end
|
174
|
+
rescue
|
175
|
+
Exit::exit_err "Couldn't open #{filename}: #{$!}"
|
176
|
+
end
|
177
|
+
|
178
|
+
else
|
179
|
+
Exit::exit_err "Couldn't determine the correct mode (I was given '#{MODE}'): #{$!}"
|
180
|
+
end
|
data/lib/trak.rb
CHANGED
@@ -1,166 +1,97 @@
|
|
1
|
-
|
1
|
+
module Trak
|
2
|
+
require 'trak/core_ext/blank'
|
3
|
+
require 'trak/core_ext/round_to_nearest'
|
4
|
+
require 'debugger'
|
2
5
|
|
3
|
-
|
4
|
-
|
5
|
-
# $ trak 1h work really hard on trak
|
6
|
-
#
|
7
|
-
# format:
|
8
|
-
# - First arg is how much time spent
|
9
|
-
# - Second arg is a description
|
6
|
+
TIME_FORMAT_12HOUR = "%l:%M %p"
|
7
|
+
TIME_FORMAT_24HOUR = "%k:%M"
|
10
8
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
require 'trak/trak'
|
15
|
-
require 'trak/exit'
|
16
|
-
require 'trak/core_ext/time'
|
17
|
-
|
18
|
-
# place where data is stored
|
19
|
-
datadir = "#{ENV['HOME']}/Documents/Tracker/"
|
20
|
-
%x[mkdir -p #{datadir}]
|
21
|
-
|
22
|
-
# define command line options
|
23
|
-
opts = Trollop::options do
|
24
|
-
opt :report, "Reporting mode", :short => "-l"
|
25
|
-
opt :edit, "Edit mode"
|
26
|
-
opt :date, "The date", :type => String, :short => "-d"
|
27
|
-
opt :debug, "Debugging mode", :short => "-i"
|
28
|
-
end
|
29
|
-
|
30
|
-
$g_opts = opts
|
31
|
-
def debug(steps = 1)
|
32
|
-
debugger(steps) if $g_opts[:debug]
|
33
|
-
end
|
34
|
-
|
35
|
-
# all valid options have been processed, so figure out which mode
|
36
|
-
# we're in...
|
37
|
-
#
|
38
|
-
# if we found a -r or -l option, ignore everything else
|
39
|
-
if opts[:report]
|
40
|
-
MODE = 'report'
|
41
|
-
# now check if the user wants edit mode
|
42
|
-
elsif opts[:edit]
|
43
|
-
MODE = 'edit'
|
44
|
-
# if there are still unprocessed args (that didn't look like switches),
|
45
|
-
# we're in insert mode
|
46
|
-
elsif ARGV.length > 0
|
47
|
-
MODE = 'insert'
|
48
|
-
# if all else fails, there were probably no args to begin with, so we're
|
49
|
-
# in report mode
|
50
|
-
else
|
51
|
-
MODE = 'report'
|
52
|
-
end
|
53
|
-
|
54
|
-
today = Time.now.strftime '%F'
|
9
|
+
def self.breakpoint(steps = 1)
|
10
|
+
debugger(steps) if ENV['TRAK_DEBUG'] == "1"
|
11
|
+
end
|
55
12
|
|
56
|
-
#
|
57
|
-
|
58
|
-
|
59
|
-
#
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
13
|
+
# expects a hash of tasks mapped to time spent, and a sub-report name
|
14
|
+
# (e.g., work, personal)
|
15
|
+
# prints a formatted sub-report
|
16
|
+
# returns the total hours worked
|
17
|
+
def self.printSubReport(report_hash, report_title)
|
18
|
+
total = 0
|
19
|
+
unless report_hash.empty?
|
20
|
+
count = 0
|
21
|
+
report_out = ""
|
22
|
+
report_hash.each do |title, minutes|
|
23
|
+
total += minutes.to_i
|
24
|
+
count += 1
|
25
|
+
report_out += "=> #{timeString(minutes)}: #{title}"
|
26
|
+
report_out += "\n" unless count == report_hash.size
|
27
|
+
end
|
28
|
+
puts "# #{report_title} time (#{timeString(total)})"
|
29
|
+
puts report_out
|
30
|
+
end
|
31
|
+
total
|
32
|
+
end
|
64
33
|
|
65
|
-
|
66
|
-
|
34
|
+
def self.time_with_hours_minutes(*hm)
|
35
|
+
dmy = Time.now.to_a[3..5].reverse
|
36
|
+
Time.new(*dmy, *hm)
|
37
|
+
end
|
67
38
|
|
68
|
-
|
69
|
-
if
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
# The keys for each hash are the titles of the various tasks logged.
|
78
|
-
# The values are the total time spent on the task.
|
79
|
-
work = {}
|
80
|
-
personal = {}
|
81
|
-
|
82
|
-
# find the start time for the day we're reporting on
|
83
|
-
startTime = file.first.split[1]
|
84
|
-
|
85
|
-
# process each line of the file
|
86
|
-
file[1..file.size].each do |line|
|
87
|
-
minutes, text = line.split(': ')
|
88
|
-
unless text =~ /personal|uni|lunch|home/
|
89
|
-
work[text] = 0 unless work.include? text
|
90
|
-
work[text] += minutes.to_i
|
91
|
-
else
|
92
|
-
personal[text] = 0 unless personal.include? text
|
93
|
-
personal[text] += minutes.to_i
|
39
|
+
# expects a number of minutes
|
40
|
+
# if less than 60 returns the number with an "m"
|
41
|
+
# otherwise converts to hours and adds an "h"
|
42
|
+
def self.timeString(minutes)
|
43
|
+
if minutes >= 60
|
44
|
+
hours = minutes/60.0
|
45
|
+
if hours % 1 == 0
|
46
|
+
hours = hours.to_i
|
94
47
|
end
|
95
|
-
|
96
|
-
|
97
|
-
# print the report
|
98
|
-
if opts[:date]
|
99
|
-
puts "# Logged work for #{fdate}"
|
48
|
+
"#{hours}h"
|
100
49
|
else
|
101
|
-
|
102
|
-
end
|
103
|
-
|
104
|
-
workTotal = Trak::printSubReport(work, "Work")
|
105
|
-
personalTotal = Trak::printSubReport(personal, "Personal")
|
106
|
-
|
107
|
-
newTimeString = Trak::to12HourTime(Trak::newTimeWithMinutes(startTime, workTotal + personalTotal))
|
108
|
-
puts "Hours logged until #{newTimeString} (since #{Trak::to12HourTime(startTime)}). "
|
109
|
-
|
110
|
-
# if we're reporting for today, print the current time
|
111
|
-
puts "Currently #{Trak::to12HourTime(Time.now.strftime(Trak::TIME_FORMAT_24HOUR))}." unless opts[:date]
|
112
|
-
else
|
113
|
-
if opts[:date]
|
114
|
-
STDERR.puts "No time log for #{fdate}. Track some time first."
|
115
|
-
else
|
116
|
-
STDERR.puts "No time log for today. Track some time first.\n"
|
50
|
+
"#{minutes}m"
|
117
51
|
end
|
118
52
|
end
|
119
53
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
exec "#{ENV['EDITOR']} #{filename}"
|
124
|
-
else
|
125
|
-
exec "open", filename
|
126
|
-
end
|
127
|
-
exit
|
128
|
-
else
|
129
|
-
Exit::exit_err "#{__FILE__}: #{filename} does not exist or unable to open."
|
54
|
+
def self.newTimeWithMinutes(start_time, minutes)
|
55
|
+
hm = start_time.split ':'
|
56
|
+
Time.at(time_with_hours_minutes(*hm).to_i + minutes.to_i*60).strftime(TIME_FORMAT_24HOUR).strip
|
130
57
|
end
|
131
58
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
input = STDIN.readline.chomp
|
137
|
-
unless input =~ /^y(es)?/i
|
138
|
-
Exit::exit_err "Timelog update cancelled."
|
59
|
+
def self.to12HourTime(time)
|
60
|
+
unless time.blank?
|
61
|
+
hm = time.split ':'
|
62
|
+
time_with_hours_minutes(*hm).strftime(TIME_FORMAT_12HOUR).strip
|
139
63
|
end
|
140
64
|
end
|
141
|
-
|
142
|
-
#
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
if
|
153
|
-
|
154
|
-
|
155
|
-
startTime = Trak::minutesToTime((currentTimeInMinutes - minutes).round_to_nearest 15)
|
156
|
-
file.puts "#{fdate} #{startTime}"
|
65
|
+
|
66
|
+
# expects a single argument - the time argument in the format ##m or ##h
|
67
|
+
# if argument has no m/h qualifier, assume m
|
68
|
+
# returns a number of minutes
|
69
|
+
def self.processTimeArgument(time_string)
|
70
|
+
if time_string =~ /^(\d*\.?\d+)((m|min|minute|minutes)|(h|hr|hour|hours))?$/i
|
71
|
+
time = $1.to_f
|
72
|
+
modifier = $2
|
73
|
+
minutes = (modifier =~ /h.*/) ? time * 60 : time
|
74
|
+
|
75
|
+
# check enough time has been logged
|
76
|
+
if minutes < 15
|
77
|
+
STDERR.puts "You must log at least 15 minutes."
|
78
|
+
exit 1
|
157
79
|
end
|
158
|
-
|
80
|
+
|
81
|
+
minutes.round_to_nearest 15
|
82
|
+
else
|
83
|
+
STDERR.puts "Incorrectly formatted argument."
|
84
|
+
exit 1
|
159
85
|
end
|
160
|
-
rescue
|
161
|
-
Exit::exit_err "Couldn't open #{filename}: #{$!}"
|
162
86
|
end
|
163
87
|
|
164
|
-
|
165
|
-
|
88
|
+
# expects an integer
|
89
|
+
def self.minutesToTime(minutes)
|
90
|
+
time_with_hours_minutes(minutes / 60, minutes % 60).strftime(TIME_FORMAT_24HOUR).strip
|
91
|
+
end
|
92
|
+
|
93
|
+
# expects an integer which is the amount of minutes logged
|
94
|
+
def self.startTimeInMinutes(minutes)
|
95
|
+
Time.now.to_minutes.round_to_nearest(15) - minutes
|
96
|
+
end
|
166
97
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: trak
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-05-01 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: trollop
|
@@ -53,7 +53,6 @@ files:
|
|
53
53
|
- lib/trak/core_ext/round_to_nearest.rb
|
54
54
|
- lib/trak/core_ext/time.rb
|
55
55
|
- lib/trak/exit.rb
|
56
|
-
- lib/trak/trak.rb
|
57
56
|
- lib/trak.rb
|
58
57
|
- bin/trak
|
59
58
|
- CHANGELOG.md
|
data/lib/trak/trak.rb
DELETED
@@ -1,92 +0,0 @@
|
|
1
|
-
require "trak/core_ext/blank"
|
2
|
-
require "trak/core_ext/round_to_nearest"
|
3
|
-
|
4
|
-
module Trak
|
5
|
-
TIME_FORMAT_12HOUR = "%l:%M %p"
|
6
|
-
TIME_FORMAT_24HOUR = "%k:%M"
|
7
|
-
|
8
|
-
# expects a hash of tasks mapped to time spent, and a sub-report name
|
9
|
-
# (e.g., work, personal)
|
10
|
-
# prints a formatted sub-report
|
11
|
-
# returns the total hours worked
|
12
|
-
def self.printSubReport(report_hash, report_title)
|
13
|
-
total = 0
|
14
|
-
unless report_hash.empty?
|
15
|
-
count = 0
|
16
|
-
report_out = ""
|
17
|
-
report_hash.each do |title, minutes|
|
18
|
-
total += minutes.to_i
|
19
|
-
count += 1
|
20
|
-
report_out += "=> #{timeString(minutes)}: #{title}"
|
21
|
-
report_out += "\n" unless count == report_hash.size
|
22
|
-
end
|
23
|
-
puts "# #{report_title} time (#{timeString(total)})"
|
24
|
-
puts report_out
|
25
|
-
end
|
26
|
-
total
|
27
|
-
end
|
28
|
-
|
29
|
-
def self.time_with_hours_minutes(*hm)
|
30
|
-
dmy = Time.now.to_a[3..5].reverse
|
31
|
-
Time.new(*dmy, *hm)
|
32
|
-
end
|
33
|
-
|
34
|
-
# expects a number of minutes
|
35
|
-
# if less than 60 returns the number with an "m"
|
36
|
-
# otherwise converts to hours and adds an "h"
|
37
|
-
def self.timeString(minutes)
|
38
|
-
if minutes >= 60
|
39
|
-
hours = minutes/60.0
|
40
|
-
if hours % 1 == 0
|
41
|
-
hours = hours.to_i
|
42
|
-
end
|
43
|
-
"#{hours}h"
|
44
|
-
else
|
45
|
-
"#{minutes}m"
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def self.newTimeWithMinutes(start_time, minutes)
|
50
|
-
hm = start_time.split ':'
|
51
|
-
Time.at(time_with_hours_minutes(*hm).to_i + minutes.to_i*60).strftime(TIME_FORMAT_24HOUR).strip
|
52
|
-
end
|
53
|
-
|
54
|
-
def self.to12HourTime(time)
|
55
|
-
unless time.blank?
|
56
|
-
hm = time.split ':'
|
57
|
-
time_with_hours_minutes(*hm).strftime(TIME_FORMAT_12HOUR).strip
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
# expects a single argument - the time argument in the format ##m or ##h
|
62
|
-
# if argument has no m/h qualifier, assume m
|
63
|
-
# returns a number of minutes
|
64
|
-
def self.processTimeArgument(time_string)
|
65
|
-
if time_string =~ /^(\d*\.?\d+)((m|min|minute|minutes)|(h|hr|hour|hours))?$/i
|
66
|
-
time = $1.to_f
|
67
|
-
modifier = $2
|
68
|
-
minutes = (modifier =~ /h.*/) ? time * 60 : time
|
69
|
-
|
70
|
-
# check enough time has been logged
|
71
|
-
if minutes < 15
|
72
|
-
STDERR.puts "You must log at least 15 minutes."
|
73
|
-
exit 1
|
74
|
-
end
|
75
|
-
|
76
|
-
minutes.round_to_nearest 15
|
77
|
-
else
|
78
|
-
STDERR.puts "Incorrectly formatted argument."
|
79
|
-
exit 1
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
# expects an integer
|
84
|
-
def self.minutesToTime(minutes)
|
85
|
-
time_with_hours_minutes(minutes / 60, minutes % 60).strftime(TIME_FORMAT_24HOUR).strip
|
86
|
-
end
|
87
|
-
|
88
|
-
# expects an integer which is the amount of minutes logged
|
89
|
-
def self.startTimeInMinutes(minutes)
|
90
|
-
Time.now.to_minutes.round_to_nearest(15) - minutes
|
91
|
-
end
|
92
|
-
end
|