time_tree 2.1.0 → 2.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +8 -8
- data/fixtures/time/jun1.txt +1 -1
- data/fixtures/time/jun2.txt +1 -1
- data/fixtures/time/jun3.txt +1 -1
- data/lib/time_tree/activity_tree.rb +8 -6
- data/lib/time_tree/file_parser.rb +7 -5
- data/lib/time_tree/version.rb +1 -1
- data/spec/activity_tree_spec.rb +22 -4
- data/spec/file_parser_spec.rb +9 -3
- data/spec/integration_spec.rb +3 -3
- metadata +2 -2
data/README.md
CHANGED
@@ -8,26 +8,26 @@ Timetree is a command line utility that prints a tree-like breakdown of time spe
|
|
8
8
|
|
9
9
|
## Time Log Format
|
10
10
|
|
11
|
-
Each day's log should start with a date in YYYY/MM/DD format. Any text following is ignored
|
11
|
+
Each day's log should start with a date in YYYY/MM/DD format. Any text following is ignored. Following this are lines starting with a time in 24 hour format - HHMI, followed by an activity which must contain no spaces, any text following can be free form and is treated as a description. Activities may have nested subcategories to any level separated by forward slashes - these will be printed as a hierarchy by timetree. Use a dash (-) for the activity to be ignored and not reported on - this means a day's log must always end with a time followed by a dash to denote when the previous line's activity finished.
|
12
12
|
|
13
|
-
Blank lines are ignored
|
13
|
+
Blank lines are ignored. Sequences starting with # to the end of the line are ignored as comments.
|
14
14
|
|
15
15
|
Here's an example:
|
16
16
|
|
17
|
-
2013/04/21 A splendid day!
|
17
|
+
2013/04/21 A splendid day! This text after the date will be ignored
|
18
18
|
|
19
|
-
0930 admin
|
20
|
-
0945 development/project1
|
19
|
+
0930 admin This is a description
|
20
|
+
0945 development/project1 Some more descriptive text
|
21
21
|
1005 -
|
22
22
|
1030 developemnt/project2
|
23
23
|
1115 -
|
24
24
|
|
25
|
-
# Did some work in the evening!
|
26
|
-
2230 bugfixing/project3
|
25
|
+
# Did some work in the evening! This is a comment that will be ignored
|
26
|
+
2230 bugfixing/project3 a description # This will be ignored because it's a comment
|
27
27
|
2315 -
|
28
28
|
|
29
29
|
|
30
|
-
A day's log can
|
30
|
+
A day's log can not span across more than one file, but a file may contain multiple day's logs. This gives flexibility, all time may be stored in one big file or there may be multiple files, one for each day or week for example. Multiple files may be stored in a nested folder hierarchy - time tree will recursively search for files, ignoring those starting with . (dot).
|
31
31
|
|
32
32
|
## Usage
|
33
33
|
|
data/fixtures/time/jun1.txt
CHANGED
data/fixtures/time/jun2.txt
CHANGED
data/fixtures/time/jun3.txt
CHANGED
@@ -7,19 +7,21 @@ module TimeTree
|
|
7
7
|
@output = []
|
8
8
|
end
|
9
9
|
|
10
|
-
def load(activities, minutes, level = 0, target = @activities)
|
10
|
+
def load(activities, minutes, description, level = 0, target = @activities)
|
11
11
|
activities.unshift 'All' if level == 0
|
12
12
|
activity = activities.shift
|
13
|
-
target[activity] = {:minutes => 0, :children => {}} unless target[activity]
|
13
|
+
target[activity] = {:minutes => 0, :children => {}, :descriptions => []} unless target[activity]
|
14
14
|
target[activity][:minutes] += minutes
|
15
|
-
|
15
|
+
target[activity][:descriptions] << description if activities.size == 0 && description
|
16
|
+
load(activities, minutes, description, level+1, target[activity][:children]) if activities.any?
|
16
17
|
end
|
17
18
|
|
18
19
|
def process(level = 0, target = activities)
|
19
|
-
target.each do |activity, values|
|
20
|
-
output << "%-25s %4d min (%s)" % ["#{(1..level*2).to_a.map{' '}.join}#{activity}",
|
20
|
+
target.sort.each do |activity, values|
|
21
|
+
output << "%-25s %4d min (%s) %s" % ["#{(1..level*2).to_a.map{' '}.join}#{activity}",
|
21
22
|
values[:minutes],
|
22
|
-
to_hrs_mins(values[:minutes])
|
23
|
+
to_hrs_mins(values[:minutes]),
|
24
|
+
values[:descriptions].uniq.join(' - ')]
|
23
25
|
process(level+1, values[:children]) if values[:children].any?
|
24
26
|
end
|
25
27
|
end
|
@@ -30,6 +30,7 @@ module TimeTree
|
|
30
30
|
@date = date
|
31
31
|
@prev_mins = nil
|
32
32
|
@prev_activities = nil
|
33
|
+
@prev_comment = nil
|
33
34
|
end
|
34
35
|
|
35
36
|
def process_file(path)
|
@@ -65,12 +66,12 @@ module TimeTree
|
|
65
66
|
set_date($1)
|
66
67
|
true
|
67
68
|
|
68
|
-
when /^(\d\d\d\d) +([
|
69
|
+
when /^(\d\d\d\d) +([-\w\/]+) *(.*)$/
|
69
70
|
if minutes = mins($1)
|
70
71
|
unless @prev_mins.nil?
|
71
72
|
if minutes > @prev_mins
|
72
73
|
if @prev_activities != '-' && selected?(@date, @prev_activities)
|
73
|
-
process_line(minutes, @prev_activities)
|
74
|
+
process_line(minutes, @prev_activities, @prev_comment)
|
74
75
|
end
|
75
76
|
else
|
76
77
|
add_error(line, 'time does not advance')
|
@@ -79,7 +80,8 @@ module TimeTree
|
|
79
80
|
end
|
80
81
|
|
81
82
|
@prev_mins = minutes
|
82
|
-
@prev_activities = $2
|
83
|
+
@prev_activities = $2.strip
|
84
|
+
@prev_comment = $3.size > 0 ? $3 : nil
|
83
85
|
true
|
84
86
|
else
|
85
87
|
false
|
@@ -122,9 +124,9 @@ module TimeTree
|
|
122
124
|
|
123
125
|
private
|
124
126
|
|
125
|
-
def process_line(minutes, activities)
|
127
|
+
def process_line(minutes, activities, comment)
|
126
128
|
duration = minutes - @prev_mins
|
127
|
-
@activity_tree.load(activities.split('/'), duration)
|
129
|
+
@activity_tree.load(activities.split('/'), duration, comment)
|
128
130
|
end
|
129
131
|
|
130
132
|
def mins(str)
|
data/lib/time_tree/version.rb
CHANGED
data/spec/activity_tree_spec.rb
CHANGED
@@ -5,12 +5,14 @@ module TimeTree
|
|
5
5
|
let(:tree) { ActivityTree.new }
|
6
6
|
|
7
7
|
before do
|
8
|
-
tree.load(%w{foo bar baz},
|
9
|
-
tree.load(%w{foo bar
|
10
|
-
tree.load(%w{
|
8
|
+
tree.load(%w{foo bar baz}, 9, 'did baz')
|
9
|
+
tree.load(%w{foo bar baz}, 1, nil)
|
10
|
+
tree.load(%w{foo bar bam}, 5, 'did some bam')
|
11
|
+
tree.load(%w{blah}, 11, 'did serious blah')
|
12
|
+
tree.load(%w{blah}, 1, 'did more blah')
|
11
13
|
end
|
12
14
|
|
13
|
-
it "should have 2 root activities" do
|
15
|
+
it "All should have 2 root activities" do
|
14
16
|
tree.activities['All'][:children].size.should == 2
|
15
17
|
end
|
16
18
|
|
@@ -18,6 +20,10 @@ module TimeTree
|
|
18
20
|
tree.activities['All'][:children]['foo'][:minutes].should == 15
|
19
21
|
end
|
20
22
|
|
23
|
+
it "foo should have no descriptions" do
|
24
|
+
tree.activities['All'][:children]['foo'][:descriptions].size.should == 0
|
25
|
+
end
|
26
|
+
|
21
27
|
it "bar should have 15 mins" do
|
22
28
|
tree.activities['All'][:children]['foo'][:children]['bar'][:minutes].should == 15
|
23
29
|
end
|
@@ -26,6 +32,11 @@ module TimeTree
|
|
26
32
|
tree.activities['All'][:children]['foo'][:children]['bar'][:children]['baz'][:minutes].should == 10
|
27
33
|
end
|
28
34
|
|
35
|
+
it "baz should have 1 description" do
|
36
|
+
tree.activities['All'][:children]['foo'][:children]['bar'][:children]['baz'][:descriptions].size.should == 1
|
37
|
+
tree.activities['All'][:children]['foo'][:children]['bar'][:children]['baz'][:descriptions].first.should == 'did baz'
|
38
|
+
end
|
39
|
+
|
29
40
|
it "bam should have 5 mins" do
|
30
41
|
tree.activities['All'][:children]['foo'][:children]['bar'][:children]['bam'][:minutes].should == 5
|
31
42
|
end
|
@@ -34,11 +45,18 @@ module TimeTree
|
|
34
45
|
tree.activities['All'][:children]['blah'][:minutes].should == 12
|
35
46
|
end
|
36
47
|
|
48
|
+
it "blah should have 2 descriptions" do
|
49
|
+
tree.activities['All'][:children]['blah'][:descriptions].size.should == 2
|
50
|
+
tree.activities['All'][:children]['blah'][:descriptions].first.should == 'did serious blah'
|
51
|
+
tree.activities['All'][:children]['blah'][:descriptions].last.should == 'did more blah'
|
52
|
+
end
|
53
|
+
|
37
54
|
it "blah should have no children" do
|
38
55
|
tree.activities['All'][:children]['blah'][:children].size.should == 0
|
39
56
|
end
|
40
57
|
|
41
58
|
it "should print" do
|
59
|
+
tree.process
|
42
60
|
tree.print
|
43
61
|
end
|
44
62
|
end
|
data/spec/file_parser_spec.rb
CHANGED
@@ -42,7 +42,7 @@ module TimeTree
|
|
42
42
|
parser.process_file(fixtures('time.txt')).should be_true
|
43
43
|
end
|
44
44
|
|
45
|
-
it "calls
|
45
|
+
it "calls parse_line for each line of the file" do
|
46
46
|
parser.should_receive(:parse_line).exactly(3).times
|
47
47
|
parser.process_file(fixtures('time.txt'))
|
48
48
|
end
|
@@ -142,10 +142,16 @@ module TimeTree
|
|
142
142
|
end
|
143
143
|
|
144
144
|
it "calls ActivityTree#load after first line" do
|
145
|
-
tree.should_receive(:load).with(%w{adm foo bar}, 1).once
|
146
|
-
parser.parse_line("1634 adm/foo/bar
|
145
|
+
tree.should_receive(:load).with(%w{adm foo bar}, 1, 'blart flange').once
|
146
|
+
parser.parse_line("1634 adm/foo/bar blart flange")
|
147
147
|
parser.parse_line("1635 -")
|
148
148
|
end
|
149
|
+
|
150
|
+
it "handles absent descriptions" do
|
151
|
+
tree.should_receive(:load).with(%w{adm foo bar}, 1, nil).once
|
152
|
+
parser.parse_line("1734 adm/foo/bar")
|
153
|
+
parser.parse_line("1735 -")
|
154
|
+
end
|
149
155
|
|
150
156
|
it "flags invalid times" do
|
151
157
|
parser.parse_line("2435 - df sdfsdg").should be_false
|
data/spec/integration_spec.rb
CHANGED
@@ -11,9 +11,9 @@ module TimeTree
|
|
11
11
|
parser.process_file(fixtures('time'))
|
12
12
|
tree.process
|
13
13
|
tree.output[0].should =~ /All +6 min/
|
14
|
-
tree.output[1].should =~ /jun1stuff +1 min/
|
15
|
-
tree.output[2].should =~ /jun2stuff +2 min/
|
16
|
-
tree.output[3].should =~ /jun3stuff +3 min/
|
14
|
+
tree.output[1].should =~ /jun1stuff +1 min \(0:01\) +jun1/
|
15
|
+
tree.output[2].should =~ /jun2stuff +2 min \(0:02\) +jun2/
|
16
|
+
tree.output[3].should =~ /jun3stuff +3 min \(0:03\) +jun3/
|
17
17
|
tree.output.size.should == 4
|
18
18
|
end
|
19
19
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: time_tree
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.1
|
4
|
+
version: 2.2.1
|
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: 2013-
|
12
|
+
date: 2013-07-03 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|