punched 0.2.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.travis.yml +3 -2
- data/Gemfile +1 -0
- data/README.md +1 -1
- data/bin/punched +25 -8
- data/lib/punchcard.rb +27 -6
- data/spec/punchcard_spec.rb +2 -3
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: d45242bb8b8cbb631b9a5c933d404ca960c54912c21f7d5d67709785252e9fc1
|
4
|
+
data.tar.gz: 8da01d442a353abdba95f800c2f34b3f231ca51ee315b54e6405b3c71bc96935
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a590849b3b356ae0e1ed80cf77e5415f25c125662964b718d45688497d3f227cab309bd59f251aaf83c2f0634305f4f62a242430c008919df3ac76b0a830118f
|
7
|
+
data.tar.gz: c8749fa2a658eeb19db42d03ca6266bef9177eb9e601c5c80864abe937ba5c8fd564ea049a2d485855bc811a2907e99c04b5eda6d527f7252a60455a2d3681f3
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# Punchcard
|
2
2
|
## Minimal time tracking tool for cli
|
3
3
|
|
4
|
-
[![Build Status](https://
|
4
|
+
[![Build Status](https://img.shields.io/travis/pstaender/punched.svg?branch=v1.0.0&style=flat-square)](https://travis-ci.org/pstaender/punched)
|
5
5
|
|
6
6
|
### Requirements
|
7
7
|
|
data/bin/punched
CHANGED
@@ -1,13 +1,17 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
|
3
4
|
require 'punchcard'
|
5
|
+
require 'csv'
|
6
|
+
require 'markdown-tables'
|
7
|
+
require 'date'
|
4
8
|
|
5
9
|
#
|
6
10
|
# CLI Wrapper
|
7
11
|
#
|
8
12
|
|
9
13
|
def available_actions
|
10
|
-
PunchCard.new(nil).public_methods(false).reject { |item| item.to_s.end_with?('=') || item.to_s == 'project' }.sort
|
14
|
+
PunchCard.new(nil).public_methods(false).reject { |item| item.to_s.end_with?('=') || item.to_s == 'project' }.concat([:all]).sort
|
11
15
|
end
|
12
16
|
|
13
17
|
def action_available? action
|
@@ -24,11 +28,13 @@ def usage
|
|
24
28
|
end
|
25
29
|
|
26
30
|
def all action
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
31
|
+
available_formats = %w(csv plain md)
|
32
|
+
unless available_formats.include?(action)
|
33
|
+
raise "Format #{action} is not supported. Possible formats are: #{available_formats.join(',')}"
|
34
|
+
end
|
35
|
+
labels = ["project","status","last active on","total duration","hourly rate","earnings"]
|
36
|
+
data = Dir[PunchCard::SETTINGS_DIR+'/*'].map { |file|
|
37
|
+
data = CSV.parse(`ruby #{__FILE__} csv '#{File.basename(file)}'`).first
|
32
38
|
last_activity = !data[2].empty? ? DateTime.parse(data[2]).to_time.to_i : 0
|
33
39
|
data.push(last_activity)
|
34
40
|
data
|
@@ -36,11 +42,22 @@ def all action
|
|
36
42
|
a.last <=> b.last
|
37
43
|
}.reverse.map { |row|
|
38
44
|
row[0...-1]
|
39
|
-
}
|
45
|
+
}
|
46
|
+
|
47
|
+
case action
|
48
|
+
when 'md'
|
49
|
+
puts MarkdownTables.make_table(labels, data, is_rows: true, align: ['l'])
|
50
|
+
when 'csv'
|
51
|
+
puts labels.to_csv
|
52
|
+
puts data.map(&:to_csv).join
|
53
|
+
when 'plain'
|
54
|
+
table = MarkdownTables.make_table(labels, data, is_rows: true, align: ['l'])
|
55
|
+
puts MarkdownTables.plain_text(table)
|
56
|
+
end
|
40
57
|
end
|
41
58
|
|
42
59
|
if ARGV.first == 'all'
|
43
|
-
all ARGV[1]
|
60
|
+
all ARGV[1] || 'plain'
|
44
61
|
exit
|
45
62
|
elsif ARGV.first && ['-h', '--help', 'help'].include?(ARGV.first)
|
46
63
|
puts usage
|
data/lib/punchcard.rb
CHANGED
@@ -1,17 +1,18 @@
|
|
1
1
|
# (c) 2017-2018 by philipp staender
|
2
2
|
|
3
3
|
require 'date'
|
4
|
+
require 'time'
|
4
5
|
|
5
|
-
class PunchCardError < StandardError
|
6
|
+
class PunchCardError < StandardError
|
6
7
|
end
|
7
8
|
|
8
9
|
class PunchCard
|
9
10
|
|
10
11
|
SETTINGS_DIR = ENV['PUNCHCARD_DIR'] || File.expand_path('~/.punchcard')
|
11
12
|
HOURLY_RATE_PATTERN = /^\s*(\d+)([^\d]+)*\s*/i
|
12
|
-
TIME_POINT_PATTERN = /^(\d
|
13
|
+
TIME_POINT_PATTERN = /^((\d+|.+?\s[\+\-]\d{4}?\s*)(\-)*(\d+|\s.+\d?)*)$/
|
13
14
|
META_KEY_PATTERN = /^([a-zA-Z0-9]+)\:\s*(.*)$/
|
14
|
-
VERSION = '0.
|
15
|
+
VERSION = '1.0.0'
|
15
16
|
|
16
17
|
attr_accessor :project
|
17
18
|
|
@@ -220,11 +221,11 @@ class PunchCard
|
|
220
221
|
end
|
221
222
|
|
222
223
|
def start_time= time
|
223
|
-
append_new_line time
|
224
|
+
append_new_line timestamp_to_time(time)
|
224
225
|
end
|
225
226
|
|
226
227
|
def end_time= time
|
227
|
-
replace_last_line "#{start_time}
|
228
|
+
replace_last_line "#{timestamp_to_time(start_time)} - #{timestamp_to_time(time)}"
|
228
229
|
end
|
229
230
|
|
230
231
|
def end_time
|
@@ -237,7 +238,23 @@ class PunchCard
|
|
237
238
|
|
238
239
|
def line_to_time_points line
|
239
240
|
matches = line.match(TIME_POINT_PATTERN)
|
240
|
-
|
241
|
+
|
242
|
+
time_points = matches ? [string_to_timestamp(matches[2]), string_to_timestamp(matches[4])] : nil
|
243
|
+
if time_points && time_points.reject(&:nil?).empty?
|
244
|
+
nil
|
245
|
+
else
|
246
|
+
time_points
|
247
|
+
end
|
248
|
+
|
249
|
+
end
|
250
|
+
|
251
|
+
def string_to_timestamp(str)
|
252
|
+
return str if str.nil?
|
253
|
+
str.strip!
|
254
|
+
# This is some legacy... previous versions stored timestamp,
|
255
|
+
# but now punched stores date-time strings for better readability.
|
256
|
+
# So we have to convert timestamp and date-time format into timestamp here
|
257
|
+
str =~ /^\d+$/ ? str.to_i : (str =~ /^\d{4}\-\d/ ? Time.parse(str).to_i : nil)
|
241
258
|
end
|
242
259
|
|
243
260
|
def last_entry
|
@@ -248,6 +265,10 @@ class PunchCard
|
|
248
265
|
Time.now.to_i
|
249
266
|
end
|
250
267
|
|
268
|
+
def timestamp_to_time(timestamp)
|
269
|
+
Time.at(timestamp)
|
270
|
+
end
|
271
|
+
|
251
272
|
def read_project_data
|
252
273
|
title = nil
|
253
274
|
meta_data = []
|
data/spec/punchcard_spec.rb
CHANGED
@@ -55,10 +55,9 @@ describe PunchCard do
|
|
55
55
|
end
|
56
56
|
|
57
57
|
it 'should track a project time' do
|
58
|
-
timestamp = Time.now.to_i
|
59
58
|
start_and_stop
|
60
59
|
expect(my_project_file.lines.first.strip).to eq('My Project')
|
61
|
-
expect(my_project_file.lines.last.strip).to match(
|
60
|
+
expect(my_project_file.lines.last.strip).to match(/^\d+-\d+-\d+ .+? - \d+-\d+-\d+ /)
|
62
61
|
end
|
63
62
|
|
64
63
|
it 'should calculate tracked total time' do
|
@@ -116,7 +115,7 @@ describe PunchCard do
|
|
116
115
|
project_a.stop
|
117
116
|
sleep 2
|
118
117
|
project_b.stop
|
119
|
-
expect(project_b.total.to_i - project_a.total.to_i).to be_between(2,
|
118
|
+
expect(project_b.total.to_i - project_a.total.to_i).to be_between(2,4)
|
120
119
|
end
|
121
120
|
|
122
121
|
it 'should load latest project by wildcard' do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: punched
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Philipp Staender
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-12-13 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Minimal time tracking tool for cli
|
14
14
|
email:
|
@@ -47,7 +47,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
47
47
|
version: '0'
|
48
48
|
requirements: []
|
49
49
|
rubyforge_project: punched
|
50
|
-
rubygems_version: 2.
|
50
|
+
rubygems_version: 2.7.8
|
51
51
|
signing_key:
|
52
52
|
specification_version: 4
|
53
53
|
summary: Punchcard Timetracker
|