devlog 0.3.2 → 0.3.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.
- checksums.yaml +5 -5
- data/README.md +18 -4
- data/VERSION +1 -1
- data/bin/devlog +7 -0
- data/devlog.gemspec +7 -4
- data/devlog.markdown +47 -0
- data/lib/devlog.rb +177 -6
- data/lib/devlog_settings.rb +8 -4
- data/templates/background.jpg +0 -0
- data/templates/weekly_timesheet.erb.html +71 -0
- data/test/devlog_test.rb +45 -1
- data/test/test_devlogs/test_weekly_devlog.markdown +89 -0
- data/test/test_helper.rb +12 -4
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 152a77a9bf2759dee53158b75e850e5fa7eac445ffc96c1640f63994afa95657
|
4
|
+
data.tar.gz: fa39e2749400e54807d883f106e0a79371633f471d7ad0eb84d54254b4f586d8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3240402228afcfe9dc9d8826f96b0a3e3579604e3d3ff139a66c9f8dc65562d03218ee66886c03fc468c1382b81b3d347f30a513c1a0e486f42f8f4d4b7c927f
|
7
|
+
data.tar.gz: '080462e56cd322f1af89edf7053ff912b8f9cc0a90dc4c36c2d35839a93abdcf45243b5af2dcb724a6f960e826b53312b362a1703ea6f79cd7f38830da184857'
|
data/README.md
CHANGED
@@ -76,19 +76,33 @@ run in current folder and write out info.markdown, copy devlog to README.markdow
|
|
76
76
|
|
77
77
|
`devlog saver`
|
78
78
|
|
79
|
+
write out a weekly timesheet for the current week, using a ERB template producing html + PDF:
|
80
|
+
|
81
|
+
`devlog w`
|
82
|
+
|
83
|
+
writing out the week before the current one (and so on):
|
84
|
+
|
85
|
+
`devlog w 1`
|
86
|
+
|
79
87
|
settings
|
80
88
|
========
|
81
89
|
|
82
|
-
currently only `devlog_file` can be configured. it represents the location of the devlog text file.
|
83
|
-
|
84
90
|
the settings file is called `.devlog.yml`.
|
85
91
|
|
86
92
|
it can be placed into a project folder from where one wants to be able to call `devlog`.
|
87
93
|
|
94
|
+
this way you can keep your devlog.markdown anywhere on disk.
|
95
|
+
|
96
|
+
`devlog_file` represents the location of the devlog text file.
|
97
|
+
`weekly_timesheet_template` represents the location of the ERB weekly timesheet template, if you don't provide one, there's a default.
|
98
|
+
`convert_to_pdf_command` represents the command used to convert the generated html into a signable PDF.
|
99
|
+
|
100
|
+
file paths should be relative to `.devlog.yml`.
|
101
|
+
|
88
102
|
example settings `.devlog.yml`:
|
89
103
|
|
90
104
|
```
|
91
105
|
devlog_file: ../info/devlog.markdown
|
106
|
+
weekly_timesheet_template: ../info/weekly_timesheet.erb.html
|
107
|
+
convert_to_pdf_command: wkhtmltopdf --dpi 400 --viewport-size 600x800 --orientation Landscape
|
92
108
|
```
|
93
|
-
|
94
|
-
the file path should be relative to `.devlog.yml`.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.3.
|
1
|
+
0.3.3
|
data/bin/devlog
CHANGED
@@ -31,11 +31,15 @@ exporting devlog into a book, which can be read top down, like normal books:
|
|
31
31
|
|
32
32
|
#{'devlog'.green} x ~ exports into devlog.txt
|
33
33
|
|
34
|
+
reporting devlog as a timesheet:
|
35
|
+
|
36
|
+
#{'devlog'.green} w ~ export the current weekly timesheet into a html page and convert that into PDF
|
34
37
|
EOF
|
35
38
|
|
36
39
|
# arguments
|
37
40
|
$:.unshift File.join(File.dirname(__FILE__))
|
38
41
|
@in_file_or_cmd = ARGV[0]
|
42
|
+
@argument = ARGV[1] ? ARGV[1].to_i : 0
|
39
43
|
|
40
44
|
def print_backtrace(exception)
|
41
45
|
exception.backtrace.join("\n\t").to_s.blue
|
@@ -51,6 +55,7 @@ def parse_now(devlog_file = 'devlog.markdown', msg = '')
|
|
51
55
|
puts t.validation_string
|
52
56
|
puts t.to_info_string
|
53
57
|
puts is_session_open(devlog_file) ? "\nSession is open...".yellow : "\nNo open session.".green
|
58
|
+
t
|
54
59
|
end
|
55
60
|
|
56
61
|
def export_now(devlog_file = 'devlog.markdown', msg = '')
|
@@ -72,6 +77,8 @@ def dodo
|
|
72
77
|
print_usage
|
73
78
|
elsif @in_file_or_cmd == 'x'
|
74
79
|
export_now(default_devlog_file, "Exporting #{default_devlog_file}...".green)
|
80
|
+
elsif @in_file_or_cmd == 'w'
|
81
|
+
weekly_pdf(parse_now(default_devlog_file, "Parsing #{default_devlog_file}...".green), @argument)
|
75
82
|
elsif @in_file_or_cmd == 'commit'
|
76
83
|
`git commit -am 'devlog';git push`
|
77
84
|
elsif @in_file_or_cmd == 'b'
|
data/devlog.gemspec
CHANGED
@@ -2,16 +2,16 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: devlog 0.3.
|
5
|
+
# stub: devlog 0.3.3 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "devlog".freeze
|
9
|
-
s.version = "0.3.
|
9
|
+
s.version = "0.3.3"
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
12
12
|
s.require_paths = ["lib".freeze]
|
13
13
|
s.authors = ["mihael".freeze]
|
14
|
-
s.date = "
|
14
|
+
s.date = "2019-10-19"
|
15
15
|
s.description = "devlog.markdown time&space extractor".freeze
|
16
16
|
s.email = "kitschmaster@gmail.com".freeze
|
17
17
|
s.executables = ["devlog".freeze]
|
@@ -43,6 +43,8 @@ Gem::Specification.new do |s|
|
|
43
43
|
"sublime_text/devlog.tmbundle/Snippets/tu.tmSnippet",
|
44
44
|
"sublime_text/devlog.tmbundle/info.plist",
|
45
45
|
"sublime_text/tu.py",
|
46
|
+
"templates/background.jpg",
|
47
|
+
"templates/weekly_timesheet.erb.html",
|
46
48
|
"test/devlog_file_test.rb",
|
47
49
|
"test/devlog_settings_test.rb",
|
48
50
|
"test/devlog_test.rb",
|
@@ -56,12 +58,13 @@ Gem::Specification.new do |s|
|
|
56
58
|
"test/test_devlogs/test_settings.yml",
|
57
59
|
"test/test_devlogs/test_single_devlog.markdown",
|
58
60
|
"test/test_devlogs/test_stats_devlog.markdown",
|
61
|
+
"test/test_devlogs/test_weekly_devlog.markdown",
|
59
62
|
"test/test_helper.rb",
|
60
63
|
"tmp/.gitignore"
|
61
64
|
]
|
62
65
|
s.homepage = "http://github.com/mihael/devlog".freeze
|
63
66
|
s.licenses = ["MIT".freeze]
|
64
|
-
s.rubygems_version = "
|
67
|
+
s.rubygems_version = "3.0.6".freeze
|
65
68
|
s.summary = "takes devlog.markdown and gives info".freeze
|
66
69
|
|
67
70
|
if s.respond_to? :specification_version then
|
data/devlog.markdown
CHANGED
@@ -1,3 +1,50 @@
|
|
1
|
+
#23.09.2019 23:08:08 CodingSession::END
|
2
|
+
|
3
|
+
some quick adjustments...
|
4
|
+
|
5
|
+
wkhtmltopdf does not work very well yet. it produces a huge canvas for some reason, making the actual table look miniature until zoomed in.
|
6
|
+
it's not a big issue, ii can open the generated html with safari and make an excellent pdf export.
|
7
|
+
but, why does it do it like that...
|
8
|
+
|
9
|
+
ahm, it seems to produce canvas sized as the current OS resolution, which then on this iMac becomes 5120x2880.
|
10
|
+
|
11
|
+
solved to a degree with: wkhtmltopdf --dpi 400 --viewport-size 600x800 --orientation Portrait
|
12
|
+
|
13
|
+
so now there's two more settings, a settings file might look like:
|
14
|
+
|
15
|
+
devlog_file: info/devlog.markdown
|
16
|
+
weekly_timesheet_template: info/weekly_timesheet.erb.html
|
17
|
+
convert_to_pdf_command: wkhtmltopdf --dpi 400 --viewport-size 600x800 --orientation Landscape
|
18
|
+
|
19
|
+
and that's it. will publish this as 0.3.3 if it turns out to work well.
|
20
|
+
|
21
|
+
#23.09.2019 19:39:39 CodingSession::BEGIN
|
22
|
+
|
23
|
+
#23.09.2019 01:04:21 CodingSession::END
|
24
|
+
|
25
|
+
took me some time to decide how to do this.
|
26
|
+
|
27
|
+
decided to generate a html from the pdf they gave.
|
28
|
+
|
29
|
+
that was easy, but turned out as rubbish, so ii did it manually.
|
30
|
+
|
31
|
+
then decided to populate that html with the data.
|
32
|
+
|
33
|
+
and then decided to use wkhtmltopdf command line utility to convert the html back to pdf.
|
34
|
+
|
35
|
+
have something, and it's configurable by devlogger. will need some more grind and polish.
|
36
|
+
|
37
|
+
#22.09.2019 19:05:17 CodingSession::BEGIN
|
38
|
+
|
39
|
+
#19.09.2019 23:34:08 CodingSession::END
|
40
|
+
|
41
|
+
adding something ii need for a dayjob. at end of period employer wants a timesheet filled out.
|
42
|
+
ii have no intent to do that manually ever again.
|
43
|
+
|
44
|
+
weekly daily report, ...
|
45
|
+
|
46
|
+
#19.09.2019 22:00:17 CodingSession::BEGIN
|
47
|
+
|
1
48
|
#09.01.2018 23:38:01 CodingSession::END
|
2
49
|
|
3
50
|
resolving a security issue reported by github. bumping nokogiri.
|
data/lib/devlog.rb
CHANGED
@@ -226,7 +226,7 @@ module Devlog
|
|
226
226
|
def save_info(devlog_file = 'devlog.markdown', info_file = 'info.markdown')
|
227
227
|
info = parse_devlog_now(devlog_file)
|
228
228
|
if info.has_info?
|
229
|
-
File.open(File.join(File.dirname(devlog_file), info_file), 'w') {|f| f.write(info.to_info_string(
|
229
|
+
File.open(File.join(File.dirname(devlog_file), info_file), 'w') {|f| f.write(info.to_info_string(true)) }
|
230
230
|
else
|
231
231
|
puts "No info present.".red
|
232
232
|
end
|
@@ -294,6 +294,127 @@ module Devlog
|
|
294
294
|
devlog_export_file
|
295
295
|
end
|
296
296
|
|
297
|
+
def weekly_pdf(tajm, weeks_from_now = 0, devlog_file = 'devlog.markdown')
|
298
|
+
require 'erb'
|
299
|
+
devlog_file = settings.devlog_file || devlog_file
|
300
|
+
template = settings.has?(:weekly_timesheet_template) ? settings.weekly_timesheet_template : File.join(Devlog.path, 'templates', 'weekly_timesheet.erb.html')
|
301
|
+
convert_command = settings.has?(:convert_to_pdf_command) ? settings.convert_to_pdf_command : 'wkhtmltopdf'
|
302
|
+
puts "Using weekly template: #{template} #{settings.has?(:weekly_timesheet_template)}".green
|
303
|
+
|
304
|
+
zezzions = tajm.zezzions_for_week(weeks_from_now, DateTime.current)
|
305
|
+
|
306
|
+
if zezzions.any?
|
307
|
+
file_id = zezzions.last.zzbegin.strftime("%Y-%m-%d")
|
308
|
+
pdf = File.join(File.dirname(devlog_file), "sevendays-#{file_id}.pdf")
|
309
|
+
html = File.join(File.dirname(devlog_file), "sevendays-#{file_id}.html")
|
310
|
+
@sevendays = Sevendays.new(zezzions)
|
311
|
+
|
312
|
+
renderer = ERB.new(File.read(template))
|
313
|
+
|
314
|
+
File.open(html,'w') {|f| f.write(renderer.result()) }
|
315
|
+
|
316
|
+
`#{convert_command} #{html} #{pdf}`
|
317
|
+
else
|
318
|
+
'No sessions to render.'.red
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
module SevendaysTotal
|
323
|
+
def total_hours
|
324
|
+
all.inject(0) { |time, zezzion| time + zezzion.session_time }.round(2)
|
325
|
+
end
|
326
|
+
|
327
|
+
def total_hours_string
|
328
|
+
total = total_hours
|
329
|
+
|
330
|
+
return "" if total <= 0
|
331
|
+
|
332
|
+
"#{total}h"
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
class Day
|
337
|
+
attr_accessor :all
|
338
|
+
include SevendaysTotal
|
339
|
+
|
340
|
+
def initialize(day, zezzions)
|
341
|
+
@all = zezzions.sort # sorting by default by zzbegin
|
342
|
+
@day = Sevendays::DAYS.include?(day) ? day : Sevendays::RANDOMDAY
|
343
|
+
end
|
344
|
+
|
345
|
+
def name
|
346
|
+
@day
|
347
|
+
end
|
348
|
+
|
349
|
+
def any?
|
350
|
+
all.any?
|
351
|
+
end
|
352
|
+
|
353
|
+
def begins_at
|
354
|
+
return '' unless any?
|
355
|
+
all.first.zzbegin.strftime('%H:%M')
|
356
|
+
end
|
357
|
+
|
358
|
+
def ends_at
|
359
|
+
return '' unless any?
|
360
|
+
all.last.zzend.strftime("%H:%M")
|
361
|
+
end
|
362
|
+
|
363
|
+
def breaks_at
|
364
|
+
return '' unless any?
|
365
|
+
|
366
|
+
size = all.size
|
367
|
+
|
368
|
+
return "" if size < 2
|
369
|
+
|
370
|
+
breaks = []
|
371
|
+
first = true
|
372
|
+
last = nil
|
373
|
+
|
374
|
+
all.each do |zezzion|
|
375
|
+
if first
|
376
|
+
last = zezzion
|
377
|
+
first = false
|
378
|
+
else
|
379
|
+
breaks << "#{last.zzend.strftime('%H:%M')} -> #{zezzion.zzbegin.strftime('%H:%M')}"
|
380
|
+
last = zezzion
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
384
|
+
breaks.join(', ')
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
class Sevendays
|
389
|
+
attr_accessor :all
|
390
|
+
include Devlog::SevendaysTotal
|
391
|
+
|
392
|
+
DAYS = %i(monday tuesday wednesday thursday friday saturday sunday).freeze
|
393
|
+
RANDOMDAY = 'Random'.freeze
|
394
|
+
|
395
|
+
def initialize(zezzions)
|
396
|
+
@all = zezzions.sort
|
397
|
+
end
|
398
|
+
|
399
|
+
def begins_at
|
400
|
+
all.first.zzbegin.strftime("%Y/%m/%d")
|
401
|
+
end
|
402
|
+
|
403
|
+
def date
|
404
|
+
DateTime.current.strftime("%Y/%m/%d")
|
405
|
+
end
|
406
|
+
|
407
|
+
DAYS.each do |day|
|
408
|
+
attr_accessor day
|
409
|
+
|
410
|
+
define_method(day) do
|
411
|
+
value = Day.new(day, all.select { |zezzion| zezzion.zzbegin.send("#{day.to_s}?") } )
|
412
|
+
instance_variable_set("@__#{day.to_s}", value) unless instance_variable_get("@__#{day.to_s}")&.any?
|
413
|
+
instance_variable_get("@__#{day.to_s}")
|
414
|
+
end
|
415
|
+
end
|
416
|
+
end
|
417
|
+
|
297
418
|
# The parsing object
|
298
419
|
class Parsing
|
299
420
|
# this is the total time, but each session has these same params
|
@@ -379,14 +500,37 @@ module Devlog
|
|
379
500
|
(coding_session_time + com_session_time + payed_time).round(2)
|
380
501
|
end
|
381
502
|
|
382
|
-
# return hours worked for the last X days, from
|
383
|
-
def hours_for_last(days,
|
384
|
-
endTime =
|
385
|
-
selected_zezzions = @zezzions.select { |z| z.zzbegin.to_time <
|
386
|
-
#
|
503
|
+
# return hours worked for the last X days, from current_time
|
504
|
+
def hours_for_last(days, current_time = DateTime.now)
|
505
|
+
endTime = current_time.to_time - days.days
|
506
|
+
selected_zezzions = @zezzions.select { |z| z.zzbegin.to_time < current_time && z.zzend >= endTime }
|
507
|
+
#puts("Selected sessons from #{current_time} to #{endTime}: #{selected_zezzions.size}")
|
387
508
|
selected_zezzions.inject(0) { |time, z| time + z.session_time }.round(2)
|
388
509
|
end
|
389
510
|
|
511
|
+
# from time to time select some zezzions
|
512
|
+
def select_zezzions(from_time, to_time)
|
513
|
+
@zezzions.select { |z| z.zzbegin.to_time > from_time && z.zzend.to_time <= to_time }
|
514
|
+
end
|
515
|
+
|
516
|
+
# returns zezzions recorded during beginning of week and end of week
|
517
|
+
# fromnow - how many weeks into the past
|
518
|
+
def zezzions_for_week(fromnow = 0, current_time = DateTime.current)
|
519
|
+
moment = current_time - (7 * fromnow).days
|
520
|
+
begin_time = moment.beginning_of_week
|
521
|
+
end_time = moment.end_of_week
|
522
|
+
|
523
|
+
select_zezzions(begin_time, end_time)
|
524
|
+
end
|
525
|
+
|
526
|
+
def zezzions_for_month(fromnow = 0, current_time = DateTime.current_time)
|
527
|
+
moment = current_time - (fromnow).months
|
528
|
+
begin_time = moment.beginning_of_month
|
529
|
+
end_time = moment.end_of_month
|
530
|
+
|
531
|
+
select_zezzions(begin_time, end_time)
|
532
|
+
end
|
533
|
+
|
390
534
|
def longest_session
|
391
535
|
@zezzions.max_by(&:session_time)
|
392
536
|
end
|
@@ -463,6 +607,26 @@ module Devlog
|
|
463
607
|
s << ("Longest Session = #{self.longest_session.to_s}\n")
|
464
608
|
s << ("Shortest Session = #{self.shortest_session.to_s}\n")
|
465
609
|
s << ("Last Session = #{self.devlog_end.ago_in_words}, duration: #{self.last_session.session_time.round(3)} [h]")
|
610
|
+
s << ("\n")
|
611
|
+
s << ("Weekly Sessions\n")
|
612
|
+
s << ("\n")
|
613
|
+
sevendays = Sevendays.new(zezzions_for_week)
|
614
|
+
sevendays_total = 0
|
615
|
+
Sevendays::DAYS.each do |day|
|
616
|
+
current_day = sevendays.send(day.to_sym)
|
617
|
+
dayname = day.upcase
|
618
|
+
if current_day.any?
|
619
|
+
current_day_total_hours = current_day.total_hours
|
620
|
+
sevendays_total += current_day_total_hours
|
621
|
+
s << ("#{dayname.upcase}\n")
|
622
|
+
s << ("begins at: #{current_day.begins_at}\n")
|
623
|
+
s << ("breaks: #{current_day.breaks_at}\n")
|
624
|
+
s << ("end_at: #{current_day.ends_at}\n")
|
625
|
+
s << ("sum: #{current_day_total_hours}\n")
|
626
|
+
s << ("\n")
|
627
|
+
end
|
628
|
+
end
|
629
|
+
s << ("Weekly sessions total: #{sevendays_total}\n")
|
466
630
|
end
|
467
631
|
s
|
468
632
|
end
|
@@ -486,6 +650,8 @@ module Devlog
|
|
486
650
|
end
|
487
651
|
|
488
652
|
class Zezzion
|
653
|
+
include Comparable
|
654
|
+
|
489
655
|
COM = 1 # communication session
|
490
656
|
COD = 0 # coding session
|
491
657
|
attr_accessor :zzbegin, :zzend, :zzbegin_title, :zzend_title, :zztype
|
@@ -506,6 +672,10 @@ module Devlog
|
|
506
672
|
@zzend_line_number = 0
|
507
673
|
end
|
508
674
|
|
675
|
+
def <=>(other)
|
676
|
+
zzbegin <=> other.zzbegin
|
677
|
+
end
|
678
|
+
|
509
679
|
# in seconds
|
510
680
|
def time
|
511
681
|
@zzend.to_time - @zzbegin.to_time
|
@@ -516,6 +686,7 @@ module Devlog
|
|
516
686
|
min = self.time / 60
|
517
687
|
hours = min / 60
|
518
688
|
days = hours / 24
|
689
|
+
days
|
519
690
|
end
|
520
691
|
|
521
692
|
# the whole coding session time
|
data/lib/devlog_settings.rb
CHANGED
@@ -8,6 +8,10 @@ module Devlog
|
|
8
8
|
# Allow settings.key besides settings[:key]
|
9
9
|
# If the method name exists as a key within this Hash, fetch it.
|
10
10
|
class Settings < Hash
|
11
|
+
def has?(m)
|
12
|
+
return key?(m) || key?(m.to_s)
|
13
|
+
end
|
14
|
+
|
11
15
|
def method_missing(m, *args, &block)
|
12
16
|
if key?(m)
|
13
17
|
fetch m
|
@@ -29,7 +33,7 @@ module Devlog
|
|
29
33
|
end
|
30
34
|
|
31
35
|
def settings
|
32
|
-
@settings
|
36
|
+
@settings ||= Settings.new
|
33
37
|
end
|
34
38
|
|
35
39
|
# The default is the current folder with devlog.markdown in it.
|
@@ -37,9 +41,9 @@ module Devlog
|
|
37
41
|
|
38
42
|
# Calculate a devlog_file path.
|
39
43
|
def devlog_file_setting
|
40
|
-
return DEVLOG_FILE unless
|
41
|
-
devlog_file_setting =
|
42
|
-
if devlog_file_setting && File.
|
44
|
+
return DEVLOG_FILE unless settings
|
45
|
+
devlog_file_setting = settings['devlog_file']
|
46
|
+
if devlog_file_setting && File.exist?(File.join(Dir.pwd, devlog_file_setting))
|
43
47
|
devlog_file_setting
|
44
48
|
else
|
45
49
|
DEVLOG_FILE
|
Binary file
|
@@ -0,0 +1,71 @@
|
|
1
|
+
<!doctype html>
|
2
|
+
<html>
|
3
|
+
<head><meta http-equiv=Content-Type content="text/html; charset=UTF-8">
|
4
|
+
<style type="text/css">
|
5
|
+
<!--
|
6
|
+
span.cls_005{font-family:Arial,serif;font-size:10.1px;color:rgb(118,112,113);font-weight:normal;font-style:normal;text-decoration: none}
|
7
|
+
div.cls_005{font-family:Arial,serif;font-size:10.1px;color:rgb(118,112,113);font-weight:normal;font-style:normal;text-decoration: none}
|
8
|
+
span.cls_003{font-family:Arial,serif;font-size:11.1px;color:rgb(118,112,113);font-weight:bold;font-style:normal;text-decoration: none}
|
9
|
+
div.cls_003{font-family:Arial,serif;font-size:11.1px;color:rgb(118,112,113);font-weight:bold;font-style:normal;text-decoration: none}
|
10
|
+
span.cls_006{font-family:Arial,serif;font-size:11.1px;color:rgb(118,112,113);font-weight:normal;font-style:normal;text-decoration: none}
|
11
|
+
div.cls_006{font-family:Arial,serif;font-size:11.1px;color:rgb(118,112,113);font-weight:normal;font-style:normal;text-decoration: none}
|
12
|
+
-->
|
13
|
+
|
14
|
+
.time {
|
15
|
+
font-family:Arial,serif;font-size:8px;color:rgb(118,112,113);font-weight:bold;font-style:normal;text-decoration: none
|
16
|
+
}
|
17
|
+
</style>
|
18
|
+
</head>
|
19
|
+
<body style="width:900px;">
|
20
|
+
<div style="position:absolute;left:50%;margin-left:-420px;top:0px;width:841px;height:595px;overflow:hidden">
|
21
|
+
<div style="position:absolute;left:0px;top:0px">
|
22
|
+
<img src="background.jpg" width=841 height=589></div>
|
23
|
+
<div style="position:absolute;left:441.59px;top:158.60px" class="cls_005"><span class="cls_005">Clients Name</span></div>
|
24
|
+
<div style="position:absolute;left:441.59px;top:173.71px" class="cls_005"><span class="cls_005">Contract Number</span></div>
|
25
|
+
<div style="position:absolute;left:441.59px;top:189.07px" class="cls_005"><span class="cls_005">Consultancy Company Name</span></div>
|
26
|
+
<div style="position:absolute;left:53.51px;top:191.72px" class="cls_003"><span class="cls_003">WEEK COMMENCING</span></div>
|
27
|
+
<div style="position:absolute;left:225px;top:193.72px" class="cls_006"><span class="time week-comencing"><%= @sevendays.begins_at %></span></div>
|
28
|
+
|
29
|
+
|
30
|
+
<div style="position:absolute;left:441.59px;top:204.19px" class="cls_005"><span class="cls_005">Consultants Name</span></div>
|
31
|
+
|
32
|
+
|
33
|
+
<!-- The weekly timesheet table -->
|
34
|
+
<div style="position:absolute;left:54.71px;top:234.44px" class="cls_003"><span class="cls_003">DAY</span></div>
|
35
|
+
<div style="position:absolute;left:146.39px;top:234.44px" class="cls_003"><span class="cls_003">START TIME</span></div>
|
36
|
+
<div style="position:absolute;left:252.71px;top:234.44px" class="cls_003"><span class="cls_003">BREAK/S START & FINISH</span></div>
|
37
|
+
<div style="position:absolute;left:578.87px;top:234.44px" class="cls_003"><span class="cls_003">END TIME</span></div>
|
38
|
+
<div style="position:absolute;left:685.19px;top:234.44px" class="cls_003"><span class="cls_003">TOTAL HOURS</span></div>
|
39
|
+
|
40
|
+
<% top = 251 %>
|
41
|
+
<% %w[monday tuesday wednesday thursday friday saturday sunday].each do |day| %>
|
42
|
+
<% current_day = @sevendays.send(day.to_sym) %>
|
43
|
+
<% dayname = day.upcase %>
|
44
|
+
<div style="position:absolute;left:54.71px;top:<%= top.to_s %>px" class="cls_006"><span class="cls_006"><%= dayname %></span></div>
|
45
|
+
<div style="position:absolute;left:146.39px;top:<%= top.to_s %>px" class="cls_006"><span class="time <%= day %> start-time"><%= current_day.begins_at %></span></div>
|
46
|
+
<div style="position:absolute;left:252.7px;top:<%= top.to_s %>px" class="cls_006"><span class="time <%= day %> breaks"><%= current_day.breaks_at %></span></div>
|
47
|
+
<div style="position:absolute;left:578.8px;top:<%= top.to_s %>px" class="cls_006"><span class="time <%= day %> end-time"><%= current_day.ends_at %></span></div>
|
48
|
+
<div style="position:absolute;left:685.19px;top:<%= top.to_s %>px" class="cls_006"><span class="time <%= day %> total-hours"><%= current_day.total_hours %></span></div>
|
49
|
+
<% top += 16 %>
|
50
|
+
<%end%>
|
51
|
+
|
52
|
+
<div style="position:absolute;left:55.43px;top:380.83px" class="cls_006"><span class="cls_006">Notes Regarding Overtime or Expenses:</span></div>
|
53
|
+
<div style="position:absolute;left:60.43px;top:410.83px" class="cls_006"><span class="cls_006"><%= @sevendays.total_hours_string %></span></div>
|
54
|
+
|
55
|
+
<div style="position:absolute;left:54.71px;top:450.43px" class="cls_006"><span class="cls_006">Signed by Consultant</span></div>
|
56
|
+
<div style="position:absolute;left:200.71px;top:450.43px" class="cls_006"><span class="cls_006"></span></div>
|
57
|
+
|
58
|
+
<div style="position:absolute;left:467.03px;top:451.88px" class="cls_006"><span class="cls_006">Signed by Client</span></div>
|
59
|
+
<div style="position:absolute;left:54.71px;top:468.67px" class="cls_006"><span class="cls_006">Print Name</span></div>
|
60
|
+
<div style="position:absolute;left:200.71px;top:468.67px" class="cls_006"><span class="cls_006"></span></div>
|
61
|
+
|
62
|
+
<div style="position:absolute;left:467.03px;top:471.32px" class="cls_006"><span class="cls_006">Job Title</span></div>
|
63
|
+
<div style="position:absolute;left:54.71px;top:488.83px" class="cls_006"><span class="cls_006">Date</span></div>
|
64
|
+
<div style="position:absolute;left:200px;top:488.83px" class="cls_006"><span class="date"><%= @sevendays.date %></span></div>
|
65
|
+
<div style="position:absolute;left:467.03px;top:491.71px" class="cls_006"><span class="cls_006">Print Name</span></div>
|
66
|
+
<div style="position:absolute;left:467.03px;top:511.16px" class="cls_006"><span class="cls_006">Date</span></div>
|
67
|
+
</div>
|
68
|
+
</body>
|
69
|
+
</html>
|
70
|
+
|
71
|
+
|
data/test/devlog_test.rb
CHANGED
@@ -189,7 +189,7 @@ class DevlogTest < Test::Unit::TestCase
|
|
189
189
|
|
190
190
|
def test_devlog_export
|
191
191
|
@exported_devlog = export_devlog_now(File.join(File.dirname(__FILE__), TEST_FILES_PATH, 'test_devlog_export.markdown'))
|
192
|
-
assert(File.
|
192
|
+
assert(File.exist?(@exported_devlog))
|
193
193
|
assert(File.size(@exported_devlog)>0, "file should not be empty")
|
194
194
|
File.open(@exported_devlog, "r") do |f|
|
195
195
|
first = f.readline
|
@@ -207,4 +207,48 @@ class DevlogTest < Test::Unit::TestCase
|
|
207
207
|
def test_default_devlog_file_setting
|
208
208
|
assert(devlog_file_setting == 'devlog.markdown', 'should return default')
|
209
209
|
end
|
210
|
+
|
211
|
+
def test_zezzions_for_week
|
212
|
+
load_devlog_weekly
|
213
|
+
assert(@tajm_weekly.devlog_sessions.size==15, "should be 15, but is #{@tajm_weekly.devlog_sessions.size}")
|
214
|
+
|
215
|
+
zezzions = @tajm_weekly.zezzions_for_week(0, DateTime.new(2019, 9, 11, 18, 0, 0))
|
216
|
+
|
217
|
+
assert(zezzions.size == 4, 'should be 4 but is not')
|
218
|
+
|
219
|
+
zezzions = @tajm_weekly.zezzions_for_week(1, DateTime.new(2019, 9, 11, 18, 0, 0))
|
220
|
+
|
221
|
+
assert(zezzions.size == 10, "should be 10 but is #{zezzions.size}")
|
222
|
+
|
223
|
+
zezzions = @tajm_weekly.zezzions_for_week(2, DateTime.new(2019, 9, 11, 18, 0, 0))
|
224
|
+
|
225
|
+
assert(zezzions.size == 1, "should be 1 but is #{zezzions.size}")
|
226
|
+
|
227
|
+
zezzions = @tajm_weekly.zezzions_for_week(0, DateTime.new(2019, 9, 6, 23, 0, 0))
|
228
|
+
|
229
|
+
assert(zezzions.size == 10, "should be 10 but is #{zezzions.size}")
|
230
|
+
end
|
231
|
+
|
232
|
+
def test_weekly_timesheet_html_generation
|
233
|
+
load_devlog_weekly
|
234
|
+
|
235
|
+
@sevendays = Sevendays.new(@tajm_weekly.zezzions_for_week(0, DateTime.new(2019, 9, 6, 23, 0, 0)))
|
236
|
+
|
237
|
+
assert(@sevendays.monday.begins_at == "08:00", "monday should begin at 08:00 but begins at #{@sevendays.monday.begins_at}")
|
238
|
+
assert(@sevendays.monday.ends_at == "16:00", "monday should end at 16:00 but ends at #{@sevendays.monday.ends_at}")
|
239
|
+
|
240
|
+
assert(@sevendays.tuesday.begins_at == "08:00", "tuesday should begin at 08:00 but begins at #{@sevendays.tuesday.begins_at}")
|
241
|
+
assert(@sevendays.tuesday.ends_at == "22:00", "tuesday should end at 22:00 but ends at #{@sevendays.tuesday.ends_at}")
|
242
|
+
|
243
|
+
assert(@sevendays.friday.begins_at == "08:00", "friday should begin at 08:00 but begins at #{@sevendays.friday.begins_at}")
|
244
|
+
assert(@sevendays.friday.ends_at == "18:00", "friday should end at 18:00 but ends at #{@sevendays.friday.ends_at}")
|
245
|
+
|
246
|
+
assert(@sevendays.begins_at == "2019/09/02", "seven days should begin on 2019/09/02 but beings on #{@sevendays.begins_at}")
|
247
|
+
|
248
|
+
assert(@sevendays.sunday.breaks_at == "", "no breaks on sunday but is: #{@sevendays.sunday.breaks_at}")
|
249
|
+
|
250
|
+
assert(@sevendays.friday.breaks_at == "12:00 -> 14:00", "one break on friday but is: #{@sevendays.friday.breaks_at}")
|
251
|
+
|
252
|
+
assert(@sevendays.tuesday.breaks_at == "12:00 -> 13:00, 15:00 -> 20:00", "two breaks on tuesday but is: #{@sevendays.tuesday.breaks_at}")
|
253
|
+
end
|
210
254
|
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
#11.09.2019 17:00:00 CodingSession::END
|
2
|
+
|
3
|
+
Wednesday
|
4
|
+
|
5
|
+
#11.09.2019 13:00:00 CodingSession::BEGIN
|
6
|
+
|
7
|
+
#11.09.2019 12:00:00 CodingSession::END
|
8
|
+
|
9
|
+
Wednesday
|
10
|
+
|
11
|
+
#11.09.2019 08:00:00 CodingSession::BEGIN
|
12
|
+
|
13
|
+
#10.09.2019 16:00:00 CodingSession::END
|
14
|
+
|
15
|
+
Tuesday
|
16
|
+
|
17
|
+
#10.09.2019 08:00:00 CodingSession::BEGIN
|
18
|
+
|
19
|
+
#09.09.2019 16:00:00 CodingSession::END
|
20
|
+
|
21
|
+
Monday
|
22
|
+
|
23
|
+
#09.09.2019 08:00:00 CodingSession::BEGIN
|
24
|
+
|
25
|
+
#08.09.2019 16:00:00 CodingSession::END
|
26
|
+
|
27
|
+
Sunday
|
28
|
+
|
29
|
+
#08.09.2019 08:00:00 CodingSession::BEGIN
|
30
|
+
|
31
|
+
#07.09.2019 16:00:00 CodingSession::END
|
32
|
+
|
33
|
+
Saturday
|
34
|
+
|
35
|
+
#07.09.2019 08:00:00 CodingSession::BEGIN
|
36
|
+
|
37
|
+
#06.09.2019 18:00:00 CodingSession::END
|
38
|
+
|
39
|
+
Friday
|
40
|
+
|
41
|
+
#06.09.2019 14:00:00 CodingSession::BEGIN
|
42
|
+
|
43
|
+
#06.09.2019 12:00:00 CodingSession::END
|
44
|
+
|
45
|
+
Friday
|
46
|
+
|
47
|
+
#06.09.2019 08:00:00 CodingSession::BEGIN
|
48
|
+
|
49
|
+
#05.09.2019 16:00:00 CodingSession::END
|
50
|
+
|
51
|
+
Thursday
|
52
|
+
|
53
|
+
#05.09.2019 08:00:00 CodingSession::BEGIN
|
54
|
+
|
55
|
+
#04.09.2019 16:00:00 CodingSession::END
|
56
|
+
|
57
|
+
Wednesday
|
58
|
+
|
59
|
+
#04.09.2019 08:00:00 CodingSession::BEGIN
|
60
|
+
|
61
|
+
#03.09.2019 22:00:00 CodingSession::END
|
62
|
+
|
63
|
+
Tuesday 3
|
64
|
+
|
65
|
+
#03.09.2019 20:00:00 CodingSession::BEGIN
|
66
|
+
|
67
|
+
#03.09.2019 15:00:00 CodingSession::END
|
68
|
+
|
69
|
+
Tuesday 2
|
70
|
+
|
71
|
+
#03.09.2019 13:00:00 CodingSession::BEGIN
|
72
|
+
|
73
|
+
#03.09.2019 12:00:00 CodingSession::END
|
74
|
+
|
75
|
+
Tuesday 1
|
76
|
+
|
77
|
+
#03.09.2019 08:00:00 CodingSession::BEGIN
|
78
|
+
|
79
|
+
#02.09.2019 16:00:00 CodingSession::END
|
80
|
+
|
81
|
+
Monday
|
82
|
+
|
83
|
+
#02.09.2019 08:00:00 CodingSession::BEGIN
|
84
|
+
|
85
|
+
#01.09.2019 16:00:00 CodingSession::END
|
86
|
+
|
87
|
+
Sunday
|
88
|
+
|
89
|
+
#01.09.2019 08:00:00 CodingSession::BEGIN
|
data/test/test_helper.rb
CHANGED
@@ -12,6 +12,10 @@ end
|
|
12
12
|
TEST_FILES_PATH = 'test_devlogs'.freeze
|
13
13
|
TEMP_PATH = '../tmp'.freeze
|
14
14
|
|
15
|
+
def parse_test_devlog(filename)
|
16
|
+
parse_devlog_now(File.join(File.dirname(__FILE__), TEST_FILES_PATH, filename))
|
17
|
+
end
|
18
|
+
|
15
19
|
def load_devlog
|
16
20
|
@tajm = parse_devlog_now(File.join(File.dirname(__FILE__), '..', 'devlog.markdown'))
|
17
21
|
puts "#{@tajm.coding_session_time} #{@tajm.com_session_time} #{@tajm.payed_time}"
|
@@ -29,7 +33,7 @@ def load_devlog_now
|
|
29
33
|
end
|
30
34
|
|
31
35
|
def load_devlog_test
|
32
|
-
@tajm_test =
|
36
|
+
@tajm_test = parse_test_devlog('test_devlog.markdown')
|
33
37
|
puts "#{@tajm_test.coding_session_time} #{@tajm_test.com_session_time} #{@tajm_test.payed_time}"
|
34
38
|
assert(@tajm_test.coding_session_time>0, "truth")
|
35
39
|
assert(@tajm_test.com_session_time>0, "love")
|
@@ -37,13 +41,17 @@ def load_devlog_test
|
|
37
41
|
end
|
38
42
|
|
39
43
|
def load_devlog_stat
|
40
|
-
@tajm_stat =
|
44
|
+
@tajm_stat = parse_test_devlog('test_stats_devlog.markdown')
|
41
45
|
end
|
42
46
|
|
43
47
|
def load_devlog_single
|
44
|
-
@tajm_single =
|
48
|
+
@tajm_single = parse_test_devlog('test_single_devlog.markdown')
|
45
49
|
end
|
46
50
|
|
47
51
|
def load_devlog_negative
|
48
|
-
@tajm_negative =
|
52
|
+
@tajm_negative = parse_test_devlog('test_negative_devlog.markdown')
|
53
|
+
end
|
54
|
+
|
55
|
+
def load_devlog_weekly
|
56
|
+
@tajm_weekly = parse_test_devlog('test_weekly_devlog.markdown')
|
49
57
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: devlog
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- mihael
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-10-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -98,6 +98,8 @@ files:
|
|
98
98
|
- sublime_text/devlog.tmbundle/Snippets/tu.tmSnippet
|
99
99
|
- sublime_text/devlog.tmbundle/info.plist
|
100
100
|
- sublime_text/tu.py
|
101
|
+
- templates/background.jpg
|
102
|
+
- templates/weekly_timesheet.erb.html
|
101
103
|
- test/devlog_file_test.rb
|
102
104
|
- test/devlog_settings_test.rb
|
103
105
|
- test/devlog_test.rb
|
@@ -111,6 +113,7 @@ files:
|
|
111
113
|
- test/test_devlogs/test_settings.yml
|
112
114
|
- test/test_devlogs/test_single_devlog.markdown
|
113
115
|
- test/test_devlogs/test_stats_devlog.markdown
|
116
|
+
- test/test_devlogs/test_weekly_devlog.markdown
|
114
117
|
- test/test_helper.rb
|
115
118
|
- tmp/.gitignore
|
116
119
|
homepage: http://github.com/mihael/devlog
|
@@ -132,8 +135,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
132
135
|
- !ruby/object:Gem::Version
|
133
136
|
version: '0'
|
134
137
|
requirements: []
|
135
|
-
|
136
|
-
rubygems_version: 2.5.2
|
138
|
+
rubygems_version: 3.0.6
|
137
139
|
signing_key:
|
138
140
|
specification_version: 4
|
139
141
|
summary: takes devlog.markdown and gives info
|