logstats 0.0.2 → 0.0.3
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/.gitignore +3 -0
- data/CHANGELOG +6 -2
- data/lib/logstats/haml/helpers.rb +36 -12
- data/lib/logstats/template.haml +26 -13
- data/lib/logstats/version.rb +1 -1
- data/lib/logstats/worklog.rb +31 -9
- metadata +3 -6
- data/.rvmrc +0 -7
- data/examples/example.haml +0 -128
- data/watchr/all.watchr +0 -1
data/.gitignore
CHANGED
data/CHANGELOG
CHANGED
@@ -1,4 +1,8 @@
|
|
1
|
+
0.0.3 (08Dec2011)
|
2
|
+
BUGFIX: Update to correctly distinguish between billable (with project code) and non-billable (without project code).
|
3
|
+
Added basic "% billable" statistic, and total time for the period. Default display is now billable.
|
4
|
+
Tweaked styles to work better with the additional data.
|
1
5
|
0.0.2 (08Dec2011)
|
2
|
-
BUGFIX: Failed to calculate today's time when there wasn't an open task
|
6
|
+
BUGFIX: Failed to calculate today's time when there wasn't an open task.
|
3
7
|
0.0.1 (08Dec2011)
|
4
|
-
Initial Release
|
8
|
+
Initial Release.
|
@@ -9,6 +9,9 @@ module Helpers
|
|
9
9
|
o=[]
|
10
10
|
o << "<span class=\"hour\">#{hrs}</span> hr" if hrs.to_i > 0
|
11
11
|
o << "<span class=\"minute\">#{min}</span> min" if min.to_i > 0
|
12
|
+
if o.size == 0 then
|
13
|
+
o << "<span class=\"none\">NONE :(</span>"
|
14
|
+
end
|
12
15
|
o.join(' ')
|
13
16
|
end
|
14
17
|
|
@@ -19,8 +22,40 @@ module Helpers
|
|
19
22
|
"<span class=\"#{options[:class]}\">#{self.time_to_html(seconds)}</span>"
|
20
23
|
end
|
21
24
|
|
25
|
+
def self.threshold_met?(seconds, period)
|
26
|
+
(self.threshold_for_period(period) - seconds) < 0
|
27
|
+
end
|
28
|
+
|
22
29
|
def self.remaining_tag(seconds_so_far, period)
|
23
|
-
|
30
|
+
seconds=self.threshold_for_period(period) - seconds_so_far
|
31
|
+
|
32
|
+
css_class=[ 'remaining ']
|
33
|
+
if seconds < 0 then
|
34
|
+
content=self.time_to_html(seconds.abs) + ' over!'
|
35
|
+
css_class << 'met'
|
36
|
+
else
|
37
|
+
content=self.time_to_html(seconds) + ' remaining'
|
38
|
+
end
|
39
|
+
"<div class=\"#{css_class.join(' ')}\">#{content}</div>"
|
40
|
+
end
|
41
|
+
|
42
|
+
# Outputs some basic productivity statistics
|
43
|
+
def self.productivity_tag(data)
|
44
|
+
o=[]
|
45
|
+
css_classes=[ 'productivity' ]
|
46
|
+
|
47
|
+
if data[:total] > 0 then
|
48
|
+
o << self.time_to_html(data[:total]) if data[:total] > 0
|
49
|
+
percent=((data[:billable] / data[:total]) * 100).ceil
|
50
|
+
o << "#{percent}% billable"
|
51
|
+
end
|
52
|
+
|
53
|
+
"<div class=\"#{css_classes.join(' ')}\">#{o.join(' | ')}</div>"
|
54
|
+
end
|
55
|
+
|
56
|
+
# Returns the threshold number of seconds that need to be attained each period
|
57
|
+
def self.threshold_for_period(period)
|
58
|
+
case period
|
24
59
|
when :day
|
25
60
|
# 5 hrs per day
|
26
61
|
5 * 3600
|
@@ -30,17 +65,6 @@ module Helpers
|
|
30
65
|
else
|
31
66
|
raise "Unknown period: #{period}"
|
32
67
|
end
|
33
|
-
|
34
|
-
seconds=seconds_required - seconds_so_far
|
35
|
-
|
36
|
-
css_class=[ 'remaining ']
|
37
|
-
if seconds.nil? || seconds < 0 then
|
38
|
-
content=self.time_to_html(seconds.abs) + ' over!'
|
39
|
-
css_class << 'met'
|
40
|
-
else
|
41
|
-
content=self.time_to_html(seconds) + ' remaining'
|
42
|
-
end
|
43
|
-
"<div class=\"#{css_class.join(' ')}\">(#{content})</div>"
|
44
68
|
end
|
45
69
|
end
|
46
70
|
end
|
data/lib/logstats/template.haml
CHANGED
@@ -46,23 +46,30 @@
|
|
46
46
|
:padding 0
|
47
47
|
|
48
48
|
.duration
|
49
|
-
:font-size 200%
|
50
49
|
:color $text_faded_color
|
51
50
|
:line-height 40px
|
51
|
+
:font-variant small-caps
|
52
|
+
:font-size 150%
|
52
53
|
|
53
54
|
span
|
54
55
|
:color $text_color
|
56
|
+
// 1.5x bigger than the HR/MIN
|
57
|
+
:font-size 150%
|
55
58
|
|
56
59
|
.met
|
57
60
|
:color $success_color
|
58
61
|
|
62
|
+
.remaining
|
63
|
+
:color $success_color
|
64
|
+
|
59
65
|
.duration
|
60
66
|
:color $success_faded_color
|
61
67
|
|
62
68
|
span
|
63
69
|
:color $success_color
|
64
70
|
|
65
|
-
|
71
|
+
.remaining
|
72
|
+
:color red
|
66
73
|
|
67
74
|
.recent, .history
|
68
75
|
:width 200px
|
@@ -86,6 +93,9 @@
|
|
86
93
|
:padding 5px
|
87
94
|
:border-left 1px solid $border_color
|
88
95
|
|
96
|
+
.duration
|
97
|
+
:line-height 35px
|
98
|
+
|
89
99
|
.today, .week
|
90
100
|
:border-bottom 1px solid $border-color
|
91
101
|
|
@@ -96,28 +106,31 @@
|
|
96
106
|
.current
|
97
107
|
%h1 Current Task
|
98
108
|
- if current then
|
99
|
-
= duration_tag(current)
|
109
|
+
= duration_tag(current[:total])
|
100
110
|
- else
|
101
111
|
N/A
|
102
112
|
.today
|
103
|
-
%h1 Projects
|
113
|
+
%h1 Today's Projects
|
104
114
|
%ul.projects
|
105
115
|
- today[:projects].each do |project, time|
|
106
116
|
%li
|
107
|
-
%span.project= project
|
117
|
+
%span.project= project || "Misc."
|
108
118
|
= duration_tag(time)
|
109
119
|
.history
|
110
|
-
.today{ :class => (today[:
|
120
|
+
.today{ :class => (threshold_met?(today[:billable], :day) ? 'met' : nil )}
|
111
121
|
%h1 Today
|
112
|
-
= duration_tag(today[:
|
113
|
-
= remaining_tag(today[:
|
122
|
+
= duration_tag(today[:billable])
|
123
|
+
= remaining_tag(today[:billable], :day)
|
124
|
+
= productivity_tag(today)
|
114
125
|
|
115
|
-
.week{ :class => (week[:
|
126
|
+
.week{ :class => (threshold_met?(week[:billable], :week) ? 'met' : nil )}
|
116
127
|
%h1 Week
|
117
|
-
= duration_tag(week[:
|
118
|
-
= remaining_tag(week[:
|
128
|
+
= duration_tag(week[:billable])
|
129
|
+
= remaining_tag(week[:billable], :week)
|
130
|
+
= productivity_tag(week)
|
119
131
|
.month
|
120
132
|
%h1 Month
|
121
|
-
= duration_tag(month[:
|
133
|
+
= duration_tag(month[:billable])
|
122
134
|
.average
|
123
|
-
|
135
|
+
#{time_to_html(month[:average])} / day avg.
|
136
|
+
= productivity_tag(month)
|
data/lib/logstats/version.rb
CHANGED
data/lib/logstats/worklog.rb
CHANGED
@@ -55,19 +55,21 @@ class WorkLog < TailFromSentinel::Base
|
|
55
55
|
when DATE_SENTINEL_REGEX
|
56
56
|
# It's a date marker - set current_time
|
57
57
|
current_time=Time.parse(WorkLog.parse_sentinel($1,$2,$3).reverse.join('-'))
|
58
|
-
days[current_time]={ :total => 0, :projects => {} }
|
58
|
+
days[current_time]={ :total => 0, :billable => 0, :projects => {} }
|
59
59
|
|
60
60
|
when WORKLOG_RECORD_REGEX
|
61
61
|
# It's a worklog record - parse it, and add it to the relevant buckets
|
62
62
|
duration, project=parse_worklog_record(current_time, $1, $2, $3, $4, $5)
|
63
63
|
|
64
64
|
days[current_time][:total] += duration
|
65
|
+
days[current_time][:billable] += duration if project
|
65
66
|
days[current_time][:projects][project] ||= 0
|
66
67
|
days[current_time][:projects][project] += duration
|
67
68
|
|
68
69
|
when OPEN_WORKLOG_RECORD_REGEX
|
69
70
|
duration, project=parse_worklog_record(current_time, $1, $2, $3)
|
70
|
-
days[:current]=duration
|
71
|
+
days[:current]={ :total => duration, :billable => 0 }
|
72
|
+
days[:current][:billable] = duration if project
|
71
73
|
|
72
74
|
when /^\s*$/
|
73
75
|
# Blank line - ignore
|
@@ -92,7 +94,7 @@ class WorkLog < TailFromSentinel::Base
|
|
92
94
|
if msg.match(/^([A-Z0-9]{3})/) then
|
93
95
|
project=$1
|
94
96
|
else
|
95
|
-
project=
|
97
|
+
project=false
|
96
98
|
end
|
97
99
|
[ duration, project ]
|
98
100
|
end
|
@@ -100,14 +102,19 @@ class WorkLog < TailFromSentinel::Base
|
|
100
102
|
def compile_day_data(days)
|
101
103
|
stats={ :current => days[:current],
|
102
104
|
:today => { :total => 0,
|
105
|
+
:billable => 0,
|
103
106
|
:projects => { }
|
104
107
|
},
|
105
108
|
:week => { :total => 0,
|
109
|
+
:billable => 0,
|
106
110
|
:average => 0,
|
111
|
+
:average_billable => 0,
|
107
112
|
:projects => { }
|
108
113
|
},
|
109
114
|
:month => { :total => 0,
|
115
|
+
:billable => 0,
|
110
116
|
:average => 0,
|
117
|
+
:average_billable => 0,
|
111
118
|
:days_logged => 0,
|
112
119
|
:projects => { }
|
113
120
|
}
|
@@ -124,25 +131,40 @@ class WorkLog < TailFromSentinel::Base
|
|
124
131
|
|
125
132
|
if time_to_date(time).cweek == today.cweek then
|
126
133
|
stats[:week][:total] += data[:total]
|
134
|
+
stats[:week][:billable] += data[:billable]
|
127
135
|
stats[:week][:average] = (stats[:week][:total] / time_to_date(time).wday.to_f)
|
136
|
+
stats[:week][:average_billable] = (stats[:week][:billable] / time_to_date(time).wday.to_f)
|
128
137
|
data[:projects].each do |project, duration|
|
129
|
-
|
130
|
-
|
138
|
+
if project then
|
139
|
+
stats[:week][:projects][project] ||= 0
|
140
|
+
stats[:week][:projects][project] += duration
|
141
|
+
end
|
131
142
|
end
|
132
143
|
end
|
133
144
|
|
134
145
|
# Everything is included in this month
|
135
146
|
stats[:month][:total] += data[:total]
|
147
|
+
stats[:month][:billable] += data[:billable]
|
136
148
|
stats[:month][:days_logged] += 1
|
137
149
|
stats[:month][:average] = (stats[:month][:total] / stats[:month][:days_logged])
|
150
|
+
stats[:month][:average_billable] = (stats[:month][:billable] / stats[:month][:days_logged])
|
138
151
|
data[:projects].each do |project, duration|
|
139
|
-
|
140
|
-
|
152
|
+
if project then
|
153
|
+
stats[:month][:projects][project] ||= 0
|
154
|
+
stats[:month][:projects][project] += duration
|
155
|
+
end
|
141
156
|
end
|
142
157
|
end
|
143
158
|
|
144
|
-
|
145
|
-
|
159
|
+
# Now add in the current task, if it is present
|
160
|
+
if days[:current] then
|
161
|
+
stats[:today][:total] += days[:current][:total]
|
162
|
+
stats[:today][:billable] += days[:current][:billable]
|
163
|
+
stats[:week][:total] += days[:current][:total]
|
164
|
+
stats[:week][:billable] += days[:current][:billable]
|
165
|
+
stats[:month][:total] += days[:current][:total]
|
166
|
+
stats[:month][:billable] += days[:current][:billable]
|
167
|
+
end
|
146
168
|
|
147
169
|
return stats
|
148
170
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logstats
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 25
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 3
|
10
|
+
version: 0.0.3
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Jason Stirk
|
@@ -61,21 +61,18 @@ extra_rdoc_files: []
|
|
61
61
|
|
62
62
|
files:
|
63
63
|
- .gitignore
|
64
|
-
- .rvmrc
|
65
64
|
- CHANGELOG
|
66
65
|
- Gemfile
|
67
66
|
- Gemfile.lock
|
68
67
|
- README
|
69
68
|
- Rakefile
|
70
69
|
- bin/logstats
|
71
|
-
- examples/example.haml
|
72
70
|
- lib/logstats.rb
|
73
71
|
- lib/logstats/haml/helpers.rb
|
74
72
|
- lib/logstats/template.haml
|
75
73
|
- lib/logstats/version.rb
|
76
74
|
- lib/logstats/worklog.rb
|
77
75
|
- logstats.gemspec
|
78
|
-
- watchr/all.watchr
|
79
76
|
has_rdoc: true
|
80
77
|
homepage: http://github.com/jstirk/logstats
|
81
78
|
licenses: []
|
data/.rvmrc
DELETED
data/examples/example.haml
DELETED
@@ -1,128 +0,0 @@
|
|
1
|
-
!!!
|
2
|
-
%html
|
3
|
-
%head
|
4
|
-
%title Log Stats @ 2011-01-18 07:09
|
5
|
-
%style
|
6
|
-
:sass
|
7
|
-
$background_color_light: #454342
|
8
|
-
$background_color_dark: #333335
|
9
|
-
$text_color: white
|
10
|
-
$link_color: #a9c743
|
11
|
-
$border_color: #272b3b
|
12
|
-
|
13
|
-
body
|
14
|
-
:font-size 62.5%
|
15
|
-
:font-family Helvetica, sans-serif
|
16
|
-
:background $background_color_light
|
17
|
-
:color $text_color
|
18
|
-
|
19
|
-
#logstats
|
20
|
-
:width 400px
|
21
|
-
:height 241px
|
22
|
-
:background $background_color_dark
|
23
|
-
:border 1px solid $border_color
|
24
|
-
:text-align center
|
25
|
-
|
26
|
-
h1
|
27
|
-
:font-size 120%
|
28
|
-
:text-decoration underline
|
29
|
-
:font-variant small-caps
|
30
|
-
:text-align center
|
31
|
-
:margin 0 0 10px 0
|
32
|
-
:padding 0
|
33
|
-
|
34
|
-
ul
|
35
|
-
:list-style-type none
|
36
|
-
:margin 0
|
37
|
-
:padding 0
|
38
|
-
:text-align left
|
39
|
-
|
40
|
-
li
|
41
|
-
:margin 0
|
42
|
-
:padding 0
|
43
|
-
|
44
|
-
.duration
|
45
|
-
:font-size 200%
|
46
|
-
:color #cacaca
|
47
|
-
|
48
|
-
span
|
49
|
-
:color $text_color
|
50
|
-
|
51
|
-
.remaining, .average
|
52
|
-
:margin-top 5px
|
53
|
-
|
54
|
-
.recent, .history
|
55
|
-
:width 200px
|
56
|
-
:float left
|
57
|
-
|
58
|
-
.recent
|
59
|
-
.current, .today
|
60
|
-
:padding 5px
|
61
|
-
|
62
|
-
.current
|
63
|
-
:height 50px
|
64
|
-
:border-bottom 1px solid $border-color
|
65
|
-
|
66
|
-
.history
|
67
|
-
.today, .week, .month
|
68
|
-
:height 70px
|
69
|
-
:padding 5px
|
70
|
-
:border-left 1px solid $border_color
|
71
|
-
|
72
|
-
.today, .week
|
73
|
-
:border-bottom 1px solid $border-color
|
74
|
-
|
75
|
-
|
76
|
-
%body
|
77
|
-
#logstats
|
78
|
-
.recent
|
79
|
-
.current
|
80
|
-
%h1 Current
|
81
|
-
%span.duration
|
82
|
-
%span.minute 45
|
83
|
-
min
|
84
|
-
.today
|
85
|
-
%h1 Projects
|
86
|
-
%ul.projects
|
87
|
-
%li
|
88
|
-
%span.project MB1
|
89
|
-
%span.duration
|
90
|
-
%span.hour 1
|
91
|
-
hr
|
92
|
-
%span.minute 57
|
93
|
-
min
|
94
|
-
%li
|
95
|
-
%span.project MY1
|
96
|
-
%span.duration
|
97
|
-
%span.hour 2
|
98
|
-
hr
|
99
|
-
%span.minute 30
|
100
|
-
min
|
101
|
-
.history
|
102
|
-
.today
|
103
|
-
%h1 Today
|
104
|
-
%span.duration
|
105
|
-
%span.hour 5
|
106
|
-
hr
|
107
|
-
%span.minute 57
|
108
|
-
min
|
109
|
-
.remaining
|
110
|
-
(target met!)
|
111
|
-
.week
|
112
|
-
%h1 Week
|
113
|
-
%span.duration
|
114
|
-
%span.hour 5
|
115
|
-
hr
|
116
|
-
%span.minute 57
|
117
|
-
min
|
118
|
-
.remaining
|
119
|
-
(20 hr 3 min remaining)
|
120
|
-
.month
|
121
|
-
%h1 Month
|
122
|
-
%span.duration
|
123
|
-
%span.hour 35
|
124
|
-
hr
|
125
|
-
%span.minute 57
|
126
|
-
min
|
127
|
-
.average
|
128
|
-
(6 hr 12 min average)
|
data/watchr/all.watchr
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
watch( 'examples/.*\.haml' ) {|md| system("haml #{md[0]} #{md[0].gsub(/haml$/,'html')}") }
|