punched 1.2.0 → 1.3.1
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 +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +1 -5
- data/README.md +43 -27
- data/bin/punched +84 -30
- data/lib/punchcard.rb +45 -16
- data/punched.gemspec +1 -2
- data/spec/punchcard_spec.rb +18 -0
- metadata +7 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e95894483cb39658bf8b2df9eddece40e114f5afc4c62e8705c5de00345ee3cd
|
4
|
+
data.tar.gz: 32431041a7583350ff2f4dd4e1f90c104cae6f100838caf708560a4f9fac5e8a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6d56bd82d7e3e745a0d6c712e3f68af52e65a8df0e0430e68bea264138d36d60a0cef92fcf039ba183307e85e3aab59793525d030c1441fa2709982b742373f7
|
7
|
+
data.tar.gz: c99e60f4b12a4848feec37f5454ce1c6b343e5d083821276aa7cb12f050406533b560c02250788736c956e401f05f604afc2ab0c63272a542016623c17f5f0fb
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -17,49 +17,45 @@
|
|
17
17
|
|
18
18
|
### Usage
|
19
19
|
|
20
|
-
#### Start Project
|
20
|
+
#### Start and stop a Project
|
21
21
|
|
22
22
|
```sh
|
23
|
-
$ punched
|
23
|
+
$ punched toggle punchcard_programming
|
24
|
+
'punchcard_programming' started (00:00:00 total)
|
24
25
|
```
|
25
26
|
|
26
|
-
|
27
|
-
|
28
|
-
Save keystrokes by using wildcard. The first last active project, which matches the pattern (case insensitive) will be selected:
|
27
|
+
To stop:
|
29
28
|
|
30
29
|
```sh
|
31
|
-
$ punched
|
30
|
+
$ punched toggle punchcard_programming
|
31
|
+
'punchcard_programming' stopped (00:01:25 total)
|
32
32
|
```
|
33
33
|
|
34
|
-
|
34
|
+
To be more explicit, you can also use `start` and `stop` instead of `toggle`.
|
35
35
|
|
36
|
-
|
37
|
-
$ punched stop "Punch*"
|
38
|
-
```
|
39
|
-
|
40
|
-
#### Toggle
|
36
|
+
#### Wildcard
|
41
37
|
|
42
|
-
|
38
|
+
Save keystrokes by using wildcard. The first last active project, which matches the (case insensitive) pattern will be selected:
|
43
39
|
|
44
40
|
```sh
|
45
|
-
$ punched toggle
|
41
|
+
$ punched toggle 'punched*'
|
46
42
|
```
|
47
43
|
|
48
44
|
#### Status
|
49
45
|
|
50
46
|
```sh
|
51
|
-
$ punched status
|
47
|
+
$ punched status punched_programming
|
52
48
|
|
53
|
-
|
49
|
+
punched_programming
|
54
50
|
01:10:09
|
55
51
|
```
|
56
52
|
|
57
53
|
#### List details
|
58
54
|
|
59
55
|
```sh
|
60
|
-
$ punched details
|
56
|
+
$ punched details punched_programming
|
61
57
|
|
62
|
-
|
58
|
+
punched_programming (stopped)
|
63
59
|
|
64
60
|
00:00:08 2017-05-07 08:16:06 - 2017-05-07 08:16:14
|
65
61
|
00:04:35 2017-05-07 08:22:02 - 2017-05-07 08:26:37
|
@@ -68,26 +64,44 @@ Toggle between start and stop:
|
|
68
64
|
01:10:04 (total)
|
69
65
|
```
|
70
66
|
|
67
|
+
#### Filtering
|
68
|
+
|
69
|
+
You can filter your spend time with `startAt` and `endAt`:
|
70
|
+
|
71
|
+
```sh
|
72
|
+
$ punched totalsum myproject --startAt=15.05.2020
|
73
|
+
$ punched totalsum myproject --startAt=15.05.2020 --endAt=30.05.2020
|
74
|
+
$ punched all plain --startAt=15.05.2020 --endAt=30.05.2020
|
75
|
+
```
|
76
|
+
|
71
77
|
#### Set Hourly Rate
|
72
78
|
|
73
79
|
```sh
|
74
|
-
$ punched set
|
80
|
+
$ punched set punched_programming hourlyRate 250€
|
81
|
+
{"hourlyRate":"250€"}
|
75
82
|
```
|
76
83
|
|
77
|
-
####
|
84
|
+
#### Sum spended time on project(s)
|
85
|
+
|
86
|
+
`total` returns the total spend time in seconds:
|
78
87
|
|
79
88
|
```sh
|
80
|
-
$ punched total
|
89
|
+
$ punched total punched_programming
|
90
|
+
13505
|
81
91
|
```
|
82
92
|
|
83
|
-
|
93
|
+
`totalsum` calculates human readable spended time on project(s) (wildcard is used by default):
|
84
94
|
|
85
95
|
```sh
|
86
|
-
$ punched
|
96
|
+
$ punched totalsum punched_programming
|
97
|
+
02:05:06
|
87
98
|
```
|
88
99
|
|
100
|
+
Use `startAt` and/or `endAt` to set a time range:
|
101
|
+
|
89
102
|
```sh
|
90
|
-
$ punched
|
103
|
+
$ punched totalsum punched_programming --startAt=2020-05-01 --endAt=2020-05-03
|
104
|
+
01:02:36
|
91
105
|
```
|
92
106
|
|
93
107
|
#### Help
|
@@ -107,14 +121,14 @@ List all available actions:
|
|
107
121
|
|========================================|=========|=====================|================|=============|==========|
|
108
122
|
| project | status | last active on | total duration | hourly rate | earnings |
|
109
123
|
|========================================|=========|=====================|================|=============|==========|
|
110
|
-
|
|
124
|
+
| website | stopped | 2017-05-07 15:50:00 | 00:04:40 | 95.0 € | 380.00 € |
|
111
125
|
|----------------------------------------|---------|---------------------|----------------|-------------|----------|
|
112
|
-
|
|
126
|
+
| punchcard_programming | stopped | 2017-07-11 12:47:42 | 01:10:04 | | |
|
113
127
|
|========================================|=========|=====================|================|=============|==========|
|
114
128
|
|
115
129
|
```
|
116
130
|
|
117
|
-
To use `md` or `csv` as output format:
|
131
|
+
To use `plain`, `md` or `csv` as output format:
|
118
132
|
|
119
133
|
```sh
|
120
134
|
$ punched all csv
|
@@ -126,6 +140,8 @@ To use `md` or `csv` as output format:
|
|
126
140
|
|
127
141
|
You can use `all` with any other action as well, e.g. `punched all stop` to stop all running projects.
|
128
142
|
|
143
|
+
Here you can also filter your spend time with `startAt` and `endAt`, respectively.
|
144
|
+
|
129
145
|
### Store projects files in a custom folder and sync them between computers
|
130
146
|
|
131
147
|
By default, PunchCard will store the data in `~/.punchcard/`. Define your custom destination with:
|
data/bin/punched
CHANGED
@@ -2,9 +2,8 @@
|
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
THIS_FILE = File.symlink?(__FILE__) ? File.readlink(__FILE__) : __FILE__
|
5
|
-
|
6
5
|
begin
|
7
|
-
require File.expand_path(File.dirname(THIS_FILE) + '/../lib/punchcard')
|
6
|
+
require File.expand_path(File.dirname(THIS_FILE) + '/../lib/punchcard.rb')
|
8
7
|
rescue LoadError
|
9
8
|
require 'punchcard'
|
10
9
|
end
|
@@ -15,19 +14,19 @@ require 'date'
|
|
15
14
|
require 'json'
|
16
15
|
|
17
16
|
class UnknownActionError < StandardError; end
|
18
|
-
|
17
|
+
class InvalidAllArgument < StandardError; end
|
19
18
|
#
|
20
19
|
# CLI Wrapper
|
21
20
|
#
|
22
21
|
|
23
22
|
def available_actions
|
24
|
-
PunchCard.new(nil).public_methods(false).reject
|
23
|
+
PunchCard.new(nil).public_methods(false).reject do |item|
|
25
24
|
item.to_s.end_with?('=') || item.to_s == 'project'
|
26
|
-
|
25
|
+
end.concat(global_available_actions).sort
|
27
26
|
end
|
28
27
|
|
29
28
|
def global_available_actions
|
30
|
-
[
|
29
|
+
%i[all totalsum]
|
31
30
|
end
|
32
31
|
|
33
32
|
def action_available?(action)
|
@@ -43,48 +42,58 @@ def usage
|
|
43
42
|
"Usage: #{File.basename(__FILE__)} #{available_actions.join('|')} 'Name of my project'"
|
44
43
|
end
|
45
44
|
|
46
|
-
def
|
47
|
-
available_formats = %w[csv plain md]
|
48
|
-
unless available_formats.include?(action)
|
49
|
-
raise "Format #{action} is not supported. Possible formats are: #{available_formats.join(',')}"
|
50
|
-
end
|
51
|
-
|
52
|
-
labels = ['project', 'status', 'last active on', 'total duration', 'hourly rate', 'earnings']
|
45
|
+
def list_all_projects(format)
|
53
46
|
data = call_punchcards_by_pattern('*', 'csv').map do |csv_string|
|
54
47
|
csv_data = CSV.parse(csv_string)[0]
|
55
|
-
last_activity = !csv_data[2].empty? ?
|
48
|
+
last_activity = !csv_data[2].empty? ? Time.parse(csv_data[2]).to_i : 0
|
56
49
|
csv_data.push(last_activity)
|
57
50
|
csv_data
|
58
51
|
end.sort_by(&:last).reverse.map do |row|
|
59
52
|
row[0...-1]
|
60
53
|
end
|
61
|
-
|
62
54
|
return puts('No record(s) so far') if data.empty?
|
63
55
|
|
64
|
-
|
56
|
+
puts convert_project_data(format, data)
|
57
|
+
end
|
58
|
+
|
59
|
+
def convert_project_data(format, data)
|
60
|
+
labels = ['project', 'status', 'last active on', 'total duration', 'hourly rate', 'earnings']
|
61
|
+
case format
|
65
62
|
when 'md'
|
66
|
-
|
63
|
+
MarkdownTables.make_table(labels, data, is_rows: true, align: ['l'])
|
67
64
|
when 'csv'
|
68
|
-
|
69
|
-
puts data.map(&:to_csv).join
|
65
|
+
"#{labels.to_csv}\n#{data.map(&:to_csv).join}"
|
70
66
|
when 'plain'
|
71
67
|
table = MarkdownTables.make_table(labels, data, is_rows: true, align: ['l'])
|
72
|
-
|
68
|
+
MarkdownTables.plain_text(table)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def all(action)
|
73
|
+
available_formats = %w[csv plain md]
|
74
|
+
if available_formats.include?(action)
|
75
|
+
list_all_projects(action)
|
76
|
+
elsif action_available?(action)
|
77
|
+
puts call_punchcards_by_pattern('*', action).to_a.join("\n")
|
78
|
+
else
|
79
|
+
suppurted_arguments = (available_formats + available_actions).reject {|n| n.to_s == 'all' }.uniq
|
80
|
+
raise InvalidAllArgument, "'#{action}' is not supported\nSupported formats and actions: #{suppurted_arguments.join(',')}"
|
73
81
|
end
|
74
82
|
end
|
75
83
|
|
76
|
-
def call_punchcard(selected_action
|
84
|
+
def call_punchcard(selected_action:, project_name:, arguments:)
|
77
85
|
if action_available?(selected_action)
|
78
86
|
if !project_name && selected_action != 'list'
|
79
87
|
exit_with_error!("2nd argument has to be the project name, e.g.:\n#{usage}")
|
80
88
|
end
|
81
89
|
punch_card = PunchCard.new project_name
|
82
90
|
begin
|
83
|
-
arguments
|
84
|
-
|
85
|
-
|
91
|
+
if arguments.nil? || arguments.empty?
|
92
|
+
punch_card.public_send(selected_action.to_s)
|
93
|
+
elsif arguments.is_a?(Hash)
|
94
|
+
punch_card.public_send(selected_action.to_s, **arguments)
|
86
95
|
else
|
87
|
-
|
96
|
+
punch_card.public_send(selected_action.to_s, *arguments)
|
88
97
|
end
|
89
98
|
rescue PunchCardError => e
|
90
99
|
exit_with_error! "Error: #{e.message}"
|
@@ -94,10 +103,47 @@ def call_punchcard(selected_action, project_name)
|
|
94
103
|
end
|
95
104
|
end
|
96
105
|
|
106
|
+
def cli_argument_by_name(name)
|
107
|
+
value = ARGV.filter { |arg| arg.start_with?("--#{name}=") }&.first
|
108
|
+
value = value.split('=')[1] unless value.nil?
|
109
|
+
if block_given? && !value.nil? && !value.empty?
|
110
|
+
yield value
|
111
|
+
else
|
112
|
+
value
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
97
116
|
def call_punchcards_by_pattern(pattern, action)
|
98
|
-
|
99
|
-
|
100
|
-
|
117
|
+
path_patterns = [
|
118
|
+
"#{PunchCard::SETTINGS_DIR}/#{pattern}*",
|
119
|
+
"#{PunchCard::SETTINGS_DIR}/*#{pattern}*"
|
120
|
+
]
|
121
|
+
arguments = {}
|
122
|
+
if %w(csv plain md total).include?(action)
|
123
|
+
arguments = {
|
124
|
+
start_at: cli_argument_by_name('startAt') { |v| Date.parse(v) },
|
125
|
+
end_at: cli_argument_by_name('endAt') { |v| Date.parse(v) }
|
126
|
+
}
|
127
|
+
end
|
128
|
+
found = []
|
129
|
+
path_patterns.each do |path_pattern|
|
130
|
+
found = Dir[path_pattern].map do |file|
|
131
|
+
project_name = File.basename(file)
|
132
|
+
call_punchcard(
|
133
|
+
selected_action: action,
|
134
|
+
project_name: project_name,
|
135
|
+
arguments: arguments
|
136
|
+
)
|
137
|
+
end
|
138
|
+
break if found.any?
|
139
|
+
end
|
140
|
+
found
|
141
|
+
end
|
142
|
+
|
143
|
+
def validate_project_name_and_stop_if_invalid(project_name)
|
144
|
+
if project_name.strip.strip.start_with?('.')
|
145
|
+
STDERR.puts "Error: project name's are not allowed to start with '.'"
|
146
|
+
exit 1
|
101
147
|
end
|
102
148
|
end
|
103
149
|
|
@@ -114,18 +160,26 @@ if selected_action
|
|
114
160
|
if selected_action == 'all'
|
115
161
|
all(ARGV[1] || 'plain')
|
116
162
|
elsif selected_action == 'totalsum'
|
117
|
-
|
163
|
+
pattern_argument = ARGV.slice(1)
|
164
|
+
pattern = !pattern_argument || pattern_argument.empty? || pattern_argument.start_with?('--') ? '*' : pattern_argument
|
118
165
|
puts PunchCard.humanize_duration(
|
119
166
|
call_punchcards_by_pattern(pattern, 'total').reduce(&:+)
|
120
167
|
)
|
121
168
|
else
|
122
|
-
|
169
|
+
validate_project_name_and_stop_if_invalid(project_name)
|
170
|
+
result = call_punchcard(
|
171
|
+
selected_action: selected_action,
|
172
|
+
project_name: project_name,
|
173
|
+
arguments: ARGV.drop(2)
|
174
|
+
)
|
123
175
|
if result.is_a?(Hash)
|
124
176
|
puts result.to_json
|
125
177
|
else
|
126
178
|
puts result
|
127
179
|
end
|
128
180
|
end
|
181
|
+
rescue InvalidAllArgument => e
|
182
|
+
exit_with_error! e.message
|
129
183
|
rescue PunchCardError => e
|
130
184
|
exit_with_error! "Error: #{e.message}"
|
131
185
|
rescue UnknownActionError => e
|
data/lib/punchcard.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# (c) 2017-2019 by Philipp Staender
|
2
4
|
|
3
5
|
require 'date'
|
@@ -11,7 +13,7 @@ class PunchCard
|
|
11
13
|
HOURLY_RATE_PATTERN = /^\s*(\d+)([^\d]+)*\s*/i.freeze
|
12
14
|
TIME_POINT_PATTERN = /^((\d+|.+?\s[\+\-]\d{4}?\s*)(\-)*(\d+|\s.+\d?)*)$/.freeze
|
13
15
|
META_KEY_PATTERN = /^([a-zA-Z0-9]+)\:\s*(.*)$/.freeze
|
14
|
-
VERSION = '1.
|
16
|
+
VERSION = '1.3.1'
|
15
17
|
|
16
18
|
attr_accessor :title
|
17
19
|
|
@@ -101,7 +103,7 @@ class PunchCard
|
|
101
103
|
output.join("\n")
|
102
104
|
end
|
103
105
|
|
104
|
-
def csv
|
106
|
+
def csv(start_at: nil, end_at: nil)
|
105
107
|
project_exists_or_stop!
|
106
108
|
find_or_make_file
|
107
109
|
durations = []
|
@@ -110,16 +112,27 @@ class PunchCard
|
|
110
112
|
points = line_to_time_points(line)
|
111
113
|
next unless points
|
112
114
|
|
113
|
-
|
114
|
-
|
115
|
+
start_time = points[0]
|
116
|
+
end_time = points[1] || timestamp
|
117
|
+
|
118
|
+
next if time_range_is_excluded_by_filter?(
|
119
|
+
start_at: start_at,
|
120
|
+
end_at: end_at,
|
121
|
+
start_time: start_time,
|
122
|
+
end_time: end_time
|
123
|
+
)
|
124
|
+
|
115
125
|
last_activity = points[1] || points[0]
|
116
|
-
durations.push
|
126
|
+
durations.push end_time - start_time
|
117
127
|
end
|
128
|
+
total_duration = self.class.humanize_duration(
|
129
|
+
durations.reduce(&:+) || 0
|
130
|
+
)
|
118
131
|
'"' + [
|
119
132
|
title_and_project,
|
120
133
|
running_status,
|
121
134
|
last_activity ? self.class.format_time(Time.at(last_activity).to_datetime) : '',
|
122
|
-
|
135
|
+
total_duration,
|
123
136
|
hourly_rate ? hourly_rate[:hourlyRate].to_s + " #{hourly_rate[:currency]}" : '',
|
124
137
|
hourly_rate ? (hourly_rate[:hourlyRate] * total / 3600.0).round(2).to_s + " #{hourly_rate[:currency]}" : ''
|
125
138
|
].join('","') + '"'
|
@@ -155,22 +168,32 @@ class PunchCard
|
|
155
168
|
end
|
156
169
|
|
157
170
|
def set(key, value)
|
158
|
-
|
171
|
+
unless key =~ /^[a-zA-Z0-9]+$/
|
172
|
+
raise PunchCardError, "Key '#{key}' can only be alphanumeric"
|
173
|
+
end
|
159
174
|
|
160
175
|
@meta_data[key.to_sym] = value
|
161
176
|
write_to_project_file!
|
162
177
|
@meta_data
|
163
178
|
end
|
164
179
|
|
165
|
-
def total
|
180
|
+
def total(start_at: nil, end_at: nil)
|
166
181
|
total = 0
|
167
182
|
project_data.map do |line|
|
168
183
|
points = line_to_time_points(line)
|
169
184
|
next unless points
|
170
185
|
|
171
|
-
|
172
|
-
|
173
|
-
|
186
|
+
start_time = points[0]
|
187
|
+
end_time = points[1] || timestamp
|
188
|
+
|
189
|
+
next if time_range_is_excluded_by_filter?(
|
190
|
+
start_at: start_at,
|
191
|
+
end_at: end_at,
|
192
|
+
start_time: start_time,
|
193
|
+
end_time: end_time
|
194
|
+
)
|
195
|
+
|
196
|
+
total += end_time - start_time
|
174
197
|
end
|
175
198
|
total
|
176
199
|
end
|
@@ -180,6 +203,8 @@ class PunchCard
|
|
180
203
|
end
|
181
204
|
|
182
205
|
def self.humanize_duration(duration)
|
206
|
+
return nil unless duration
|
207
|
+
|
183
208
|
hours = duration / (60 * 60)
|
184
209
|
minutes = (duration / 60) % 60
|
185
210
|
seconds = duration % 60
|
@@ -197,7 +222,7 @@ class PunchCard
|
|
197
222
|
private
|
198
223
|
|
199
224
|
def hourly_rate
|
200
|
-
hourly_rate_found = @meta_data[:hourlyRate]
|
225
|
+
hourly_rate_found = @meta_data[:hourlyRate]&.match(HOURLY_RATE_PATTERN)
|
201
226
|
return unless hourly_rate_found
|
202
227
|
|
203
228
|
{
|
@@ -222,9 +247,9 @@ class PunchCard
|
|
222
247
|
self.class.humanize_duration total
|
223
248
|
end
|
224
249
|
|
225
|
-
def duration(
|
226
|
-
if
|
227
|
-
self.class.humanize_duration
|
250
|
+
def duration(start_time, end_time)
|
251
|
+
if start_time
|
252
|
+
self.class.humanize_duration end_time - start_time
|
228
253
|
else
|
229
254
|
self.class.humanize_duration 0
|
230
255
|
end
|
@@ -254,7 +279,7 @@ class PunchCard
|
|
254
279
|
matches = line.match(TIME_POINT_PATTERN)
|
255
280
|
|
256
281
|
time_points = matches ? [string_to_timestamp(matches[2]), string_to_timestamp(matches[4])] : nil
|
257
|
-
if time_points
|
282
|
+
if time_points&.reject(&:nil?)&.empty?
|
258
283
|
nil
|
259
284
|
else
|
260
285
|
time_points
|
@@ -351,4 +376,8 @@ class PunchCard
|
|
351
376
|
def sanitize_filename(name)
|
352
377
|
name.downcase.gsub(%r{(\\|/)}, '').gsub(/[^0-9a-z.\-]/, '_')
|
353
378
|
end
|
379
|
+
|
380
|
+
def time_range_is_excluded_by_filter?(start_time:, end_time:, start_at: nil, end_at: nil)
|
381
|
+
start_at && start_at.to_time.to_i >= start_time || end_at && end_at.to_time.to_i <= end_time
|
382
|
+
end
|
354
383
|
end
|
data/punched.gemspec
CHANGED
@@ -11,9 +11,8 @@ Gem::Specification.new do |s|
|
|
11
11
|
s.description = 'Minimal time tracking tool for cli'
|
12
12
|
s.license = 'GPL-3.0'
|
13
13
|
s.executables = ['punched']
|
14
|
-
s.rubyforge_project = 'punched'
|
15
14
|
s.require_paths = ['lib']
|
16
|
-
s.required_ruby_version = '>= 2.
|
15
|
+
s.required_ruby_version = '>= 2.6'
|
17
16
|
s.files = `git ls-files`.split("\n")
|
18
17
|
|
19
18
|
s.add_dependency 'markdown-tables', '~> 1.0.2'
|
data/spec/punchcard_spec.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
$LOAD_PATH.push File.expand_path('lib', __dir__)
|
2
3
|
|
3
4
|
require 'punchcard'
|
@@ -13,6 +14,10 @@ def setup_example_settings_dir
|
|
13
14
|
PunchCard.const_set(:SETTINGS_DIR, example_settings_dir)
|
14
15
|
end
|
15
16
|
|
17
|
+
def punched_bin
|
18
|
+
"PUNCHCARD_DIR=#{example_settings_dir} #{Dir.pwd}/bin/punched"
|
19
|
+
end
|
20
|
+
|
16
21
|
describe PunchCard do
|
17
22
|
before do
|
18
23
|
setup_example_settings_dir
|
@@ -86,6 +91,13 @@ describe PunchCard do
|
|
86
91
|
expect(project.project).to eq('playing_mot_rhead')
|
87
92
|
end
|
88
93
|
|
94
|
+
xit 'should read and write utf8 names' do
|
95
|
+
PunchCard.new 'Playing Motörhead'
|
96
|
+
expect(my_project_file('playing_mot_rhead').strip).to eq('Playing Motörhead')
|
97
|
+
project = PunchCard.new 'Playing*'
|
98
|
+
expect(project.project).to eq('Playing Motörhead')
|
99
|
+
end
|
100
|
+
|
89
101
|
it 'should set hourlyRate' do
|
90
102
|
project = start_and_stop
|
91
103
|
project.set 'hourlyRate', '1000 €'
|
@@ -150,4 +162,10 @@ describe PunchCard do
|
|
150
162
|
project.remove
|
151
163
|
expect(File.exist?("#{example_settings_dir}/my_project")).to be_falsey
|
152
164
|
end
|
165
|
+
|
166
|
+
it 'should call punched all' do
|
167
|
+
two_seconds_tracking
|
168
|
+
result = `#{punched_bin} all`
|
169
|
+
expect(result).to match('My Project')
|
170
|
+
end
|
153
171
|
end
|
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: 1.
|
4
|
+
version: 1.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Philipp Staender
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-08-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: markdown-tables
|
@@ -45,7 +45,7 @@ homepage: https://github.com/pstaender/punchcard
|
|
45
45
|
licenses:
|
46
46
|
- GPL-3.0
|
47
47
|
metadata: {}
|
48
|
-
post_install_message:
|
48
|
+
post_install_message:
|
49
49
|
rdoc_options: []
|
50
50
|
require_paths:
|
51
51
|
- lib
|
@@ -53,15 +53,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
53
53
|
requirements:
|
54
54
|
- - ">="
|
55
55
|
- !ruby/object:Gem::Version
|
56
|
-
version: '2.
|
56
|
+
version: '2.6'
|
57
57
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '0'
|
62
62
|
requirements: []
|
63
|
-
rubygems_version: 3.0.
|
64
|
-
signing_key:
|
63
|
+
rubygems_version: 3.0.6
|
64
|
+
signing_key:
|
65
65
|
specification_version: 4
|
66
66
|
summary: Punchcard Timetracker
|
67
67
|
test_files: []
|