git.fiddlerwoaroof.com
Browse code

Cleanup, document, etc.

fiddlerwoaroof authored on 21/02/2016 04:12:41
Showing 5 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,74 @@
1
+A little utility to manage a simple time-sheet file.
2
+
3
+The file-format is this:
4
+
5
+```
6
+-- Someday YYYY-MM-DD
7
+   start@HH:MM[:SS][+-NN(mins|hrs)][,HH:MM[:SS][+-NN(mins|hrs)]]
8
+   Client Name: This is a memo.	
9
+```
10
+
11
+Write now the parser is fairly fragile: it reds what it can and fails silently at the first 
12
+error.  Eventually there'll be better error-handling.
13
+
14
+```
15
+% ./timesheet -h
16
+timesheet, common-lisp version 0:1
17
+  -c --client                     boolean  Sort by client
18
+  -r --reverse                    boolean  Reverse sort
19
+  -s --status                     boolean  Print a summary of the hours worked and the prices
20
+  -h --help                       boolean  show help
21
+```
22
+
23
+```
24
+% ./timesheet -r sample-inputs/test.ts
25
+Thu, 2016/01/04  Client #2    5.00 hrs  Implement prototype and write presentation
26
+Thu, 2016/01/04  Client #1    9.00 hrs  Implement Facebook Connector
27
+Wed, 2016/01/03  Client #2    2.50 hrs  Discussed user requirements and produce specification.
28
+Wed, 2016/01/03  Client #1    6.00 hrs  Delivered prototype, reviewed prototype feedback.
29
+Tue, 2016/01/02  Client #1    8.00 hrs  Prototype for testing user experience.
30
+Mon, 2016/01/01  Client #1    8.00 hrs  Mockup of site layout
31
+```
32
+
33
+```
34
+% ./timesheet -sc sample-inputs/test.ts
35
+Mon, 2016/01/01  Client #1    8.00 hrs  Mockup of site layout
36
+Tue, 2016/01/02  Client #1    8.00 hrs  Prototype for testing user experience.
37
+Wed, 2016/01/03  Client #1    6.00 hrs  Delivered prototype, reviewed prototype feedback.
38
+Thu, 2016/01/04  Client #1    9.00 hrs  Implement Facebook Connector
39
+Wed, 2016/01/03  Client #2    2.50 hrs  Discussed user requirements and produce specification.
40
+Thu, 2016/01/04  Client #2    5.00 hrs  Implement prototype and write presentation
41
+------------------------------------------------------------------------------------------------------------------------
42
+                 Client #1:  31.00 hours @   40.00 $/hr = $1240.00
43
+                 Client #2:   7.50 hours @   40.00 $/hr = $ 300.00
44
+                     Total:  38.50 hours @   40.00 $/hr = $1540.00
45
+```
46
+
47
+```
48
+% ./timesheet -sr sample-inputs/test.ts
49
+Thu, 2016/01/04  Client #2    5.00 hrs  Implement prototype and write presentation
50
+Thu, 2016/01/04  Client #1    9.00 hrs  Implement Facebook Connector
51
+Wed, 2016/01/03  Client #2    2.50 hrs  Discussed user requirements and produce specification.
52
+Wed, 2016/01/03  Client #1    6.00 hrs  Delivered prototype, reviewed prototype feedback.
53
+Tue, 2016/01/02  Client #1    8.00 hrs  Prototype for testing user experience.
54
+Mon, 2016/01/01  Client #1    8.00 hrs  Mockup of site layout
55
+------------------------------------------------------------------------------------------------------------------------
56
+                 Client #1:  31.00 hours @   40.00 $/hr = $1240.00
57
+                 Client #2:   7.50 hours @   40.00 $/hr = $ 300.00
58
+                     Total:  38.50 hours @   40.00 $/hr = $1540.00
59
+```
60
+
61
+```
62
+% ./timesheet -scr sample-inputs/test.ts
63
+Thu, 2016/01/04  Client #2    5.00 hrs  Implement prototype and write presentation
64
+Wed, 2016/01/03  Client #2    2.50 hrs  Discussed user requirements and produce specification.
65
+Thu, 2016/01/04  Client #1    9.00 hrs  Implement Facebook Connector
66
+Wed, 2016/01/03  Client #1    6.00 hrs  Delivered prototype, reviewed prototype feedback.
67
+Tue, 2016/01/02  Client #1    8.00 hrs  Prototype for testing user experience.
68
+Mon, 2016/01/01  Client #1    8.00 hrs  Mockup of site layout
69
+------------------------------------------------------------------------------------------------------------------------
70
+                 Client #1:  31.00 hours @   40.00 $/hr = $1240.00
71
+                 Client #2:   7.50 hours @   40.00 $/hr = $ 300.00
72
+                     Total:  38.50 hours @   40.00 $/hr = $1540.00
73
+```
74
+
0 75
new file mode 100755
1 76
Binary files /dev/null and b/precompiled/timesheet differ
2 77
new file mode 100644
... ...
@@ -0,0 +1,24 @@
1
+-- Monday 2016-01-01
2
+   start@08:00--16:00
3
+   Client #1: Mockup of site layout
4
+
5
+-- Tuesday 2016-01-02
6
+   start@08:00--16:00
7
+   Client #1: Prototype for testing user experience.
8
+
9
+-- Wednesday 2016-01-03
10
+   start@08:00--12:00,15:30--17:00+30min
11
+   Client #1: Delivered prototype, reviewed prototype feedback.
12
+   start@12:30--15:00
13
+   Client #2: Discussed user requirements and produce specification.
14
+
15
+-- Thursday 2016-01-04
16
+   start@08:00--16:54
17
+   Client #1: Implement Facebook Connector
18
+   start@17:00--21:54
19
+   Client #2: Implement prototype and write presentation
20
+
21
+-- Friday 2016-01-05
22
+   start@11:00--16:54
23
+   Client #1: Implement Twitter Connector
24
+
... ...
@@ -10,7 +10,7 @@
10 10
 (defvar *rate*)
11 11
 
12 12
 (defun parse-file (&optional (file *default-time-sheet-file*))
13
-  (with-open-file (s *default-time-sheet-file* :direction :input)
13
+  (with-open-file (s file :direction :input)
14 14
     (let ((dest (make-string (file-length s))))
15 15
       (read-sequence dest s)
16 16
       (caar (smug:run (timesheet.parser::.date-records) dest)))))
... ...
@@ -19,28 +19,28 @@
19 19
   (with-slots (year month day) date-obj
20 20
     (list day month year)))
21 21
 
22
+(defun combine-date-time (time-obj day month year)
23
+  (with-slots (second minute hour) time-obj
24
+    (local-time:encode-timestamp 0 second minute hour
25
+                                 day month year)))
26
+
22 27
 (defun calculate-ranges (ranges year month day)
23
-  (loop for (start-obj end-obj mod) in ranges
24
-        for start = (local-time:encode-timestamp 0 
25
-                                                 (slot-value start-obj 'second)
26
-                                                 (slot-value start-obj 'minute)
27
-                                                 (slot-value start-obj 'hour)
28
-                                                 day month year)
29
-        for end = (local-time:encode-timestamp 0
30
-                                               (slot-value end-obj 'second)
31
-                                               (slot-value end-obj 'minute)
32
-                                               (slot-value end-obj 'hour)
33
-                                               day month year )
34
-        for time-mod = (when time-mod
35
-                         (let ((unit (make-keyword
36
-                                       (string-upcase
37
-                                         (if (string= (slot-value time-mod 'timesheet.parser::unit) "mins")
38
-                                           "minute"
39
-                                           "hour"))))
40
-                               (amount (slot-value time-mod 'timesheet.parser:amount)))
41
-                           (funcall #'local-time-duration:duration unit amount)))
42
-        nconc (list (local-time-duration:timestamp-difference end start)
43
-                    (or time-mod (local-time-duration:duration)))))
28
+  (flet ((time-mod-unit-keyword (time-mod)
29
+           (make-keyword
30
+             (string-upcase
31
+               (if (string= (slot-value time-mod 'unit) "mins")
32
+                 "minute"
33
+                 "hour")))))
34
+    (loop for (start-obj end-obj mod) in ranges
35
+          for start = (combine-date-time start-obj year month day)
36
+          for end = (combine-date-time end-obj year month day)
37
+          for time-mod = (when mod
38
+                           (let ((unit (time-mod-unit-keyword mod))
39
+                                 (amount (slot-value mod 'timesheet.parser:amount)))
40
+                             (funcall #'local-time-duration:duration unit amount)))
41
+          nconc (list
42
+                  (local-time-duration:timestamp-difference end start)
43
+                  (or time-mod (local-time-duration:duration))))))
44 44
 
45 45
 (defun calculate-rounded-ranges (ranges)
46 46
   (flet ((calc-duration-in-15mins (duration)
... ...
@@ -62,13 +62,15 @@
62 62
                                          `(,date
63 63
                                             ,client
64 64
                                             ,(calculate-rounded-ranges
65
-                                               (calculate-ranges ranges year month day))
65
+                                               (calculate-ranges ranges day month year))
66 66
                                             ,memo))))))))
67 67
 
68 68
 (defparameter +pprint-log-option-spec+
69
-  '((("client" #\c) :type boolean :optional t :documentation "sort by client")
70
-    (("reverse" #\r) :type boolean :optional t :documentation "reverse")  
71
-    (("status" #\s) :type boolean :optional t :documentation "status")))
69
+  '((("client" #\c) :type boolean :optional t :documentation "Sort by client")
70
+    (("reverse" #\r) :type boolean :optional t :documentation "Reverse sort")
71
+    (("status" #\s) :type boolean :optional t
72
+                    :documentation "Print a summary of the hours worked and the prices")  
73
+    (("help" #\h) :type boolean :optional t :documentation "show help")))
72 74
 
73 75
 (defparameter *version* "0:1")
74 76
 (defun show-version ()
... ...
@@ -78,32 +80,25 @@
78 80
   (show-version)
79 81
   (command-line-arguments:show-option-help +pprint-log-option-spec+ :sort-names t))
80 82
 
81
-(defun pprint-log (args &key client reverse status help)
82
-  (when help
83
-    (show-help)
84
-    (return-from pprint-log))
83
+(defun sort-by-date (results)
84
+  (stable-sort results #'local-time:timestamp<
85
+               :key (alambda (apply #'local-time:encode-timestamp
86
+                                    (append '(0 0 0 0)
87
+                                            (unroll-date (car it)))))))
88
+
89
+(defun pprint-results (results status)
90
+  (let ((clients (make-hash-table))
91
+        (total-cost 0))
85 92
 
86
-  (let* ((*default-time-sheet-file* (or (cadr args) *default-time-sheet-file*))
87
-         (*print-pretty* t)
88
-         (results (get-log *default-time-sheet-file*))
89
-         (clients (make-hash-table))
90
-         (total-cost 0))
91
-    (setf results (stable-sort results #'local-time:timestamp<
92
-                               :key (alambda (apply #'local-time:encode-timestamp
93
-                                                    (append '(0 0 0 0)
94
-                                                            (unroll-date (car it)))))))
95
-    (when client
96
-      (setf results (stable-sort results #'string-lessp :key #'cadr)))
97
-    (when reverse
98
-      (setf results (nreverse results)))
99
-    (format t "~&~:{~4a ~10<~:(~a~)~> ~7,2F hrs  ~a~%~}" results)
100 93
     (flet ((record-client (client hours)
101 94
              (let ((client (make-keyword (string-upcase client))))
102 95
                (incf (gethash client clients 0) hours))))
96
+      (format t "~&~:{~4a ~10<~:(~a~)~> ~7,2F hrs  ~a~%~}" results)
103 97
       (when status
104 98
         (format t "~120,1,0,'-<~>")
105 99
         (let ((total (format nil "~26<Total~>:~7,2F hours @ ~7,2F $/hr = $~7,2F"
106
-                             (loop for (_ client time ___) in results
100
+                             (loop for (_ client time __) in results
101
+                                   do (progn _ __)
107 102
                                    sum time
108 103
                                    do (record-client client time)
109 104
                                    do (incf total-cost (* time *rate*)))
... ...
@@ -118,14 +113,33 @@
118 113
                       (fix-assoc (hash-table-alist clients))
119 114
                       #'string<
120 115
                       :key (alambda (car it)))))
121
-          (format t total))))))
116
+          (format t total))))))   
117
+
118
+(defun pprint-log (args &key client reverse status help)
119
+  (when help
120
+    (show-help)
121
+    (return-from pprint-log))
122
+
123
+  (flet ((sort-results (results)
124
+           (setf results (sort-by-date results))
125
+           (when client
126
+             (setf results (stable-sort results #'string-lessp :key #'cadr)))
127
+           (when reverse
128
+             (setf results (nreverse results)))
129
+           results))
130
+
131
+    (let* ((*default-time-sheet-file* (or (car args) *default-time-sheet-file*))
132
+           (*print-pretty* t)
133
+           (results (sort-results (get-log *default-time-sheet-file*))))
134
+      (pprint-results results status))))
122 135
 
123 136
 (defun pprint-log-main (argv)
124
-  (setf *default-time-sheet-file* (ubiquitous:defaulted-value "" :timesheet :file))
125
-  (setf *rate* (ubiquitous:defaulted-value 40 :rate))
137
+  (setf *rate* (ubiquitous:defaulted-value 0 :rate)
138
+        *default-time-sheet-file* (ubiquitous:defaulted-value #p"~/time.md" :timesheet :file))
126 139
   (command-line-arguments:handle-command-line
127 140
     +pprint-log-option-spec+
128 141
     'pprint-log
129 142
     :command-line (cdr argv)
130 143
     :name "timesheet"
131 144
     :rest-arity t))
145
+
132 146
new file mode 100755
133 147
Binary files /dev/null and b/utils/buildapp differ