time-sheet 0.9.0 → 0.11.2
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/lib/time_sheet.rb +15 -0
- data/lib/time_sheet/time/cmd.rb +9 -1
- data/lib/time_sheet/time/entry.rb +20 -2
- data/lib/time_sheet/time/parser.rb +14 -6
- data/lib/time_sheet/version.rb +1 -1
- data/time_sheet.gemspec +2 -2
- metadata +12 -13
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 34d0ef63890eeae177443276610e4537d5dc2cfd138497132e6eb351ef5aa869
|
|
4
|
+
data.tar.gz: e40b4fc84073bfc67a358e54c72107bd5a2a988969a75a3a5b04261b2574255c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1bc92043a7bd4085427ade8981d7e7e014bc6704cec744174b53ec3ce9f6bd5e274d58d740371f08356fc1968207bc8b2c487d01b82fef1c2bbdd294b603cc75
|
|
7
|
+
data.tar.gz: 4ebf6508e2c23bb2ca6ba88f00c9ab945777f39ec76236a66362908787004c1d339bd6df7405f29f5fcde48f235853b611606e0c7b9d67d61dca8a7398265456
|
data/lib/time_sheet.rb
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
require 'time_sheet/version'
|
|
2
2
|
|
|
3
|
+
# silence HTTPClient
|
|
4
|
+
module Warning
|
|
5
|
+
def warn(mgs)
|
|
6
|
+
# drop
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
|
|
3
10
|
if defined?(Bundler)
|
|
4
11
|
begin
|
|
5
12
|
require 'pry'
|
|
@@ -15,4 +22,12 @@ module TimeSheet
|
|
|
15
22
|
def self.root
|
|
16
23
|
@root ||= File.expand_path(File.dirname(__FILE__) + '/..')
|
|
17
24
|
end
|
|
25
|
+
|
|
26
|
+
def self.options=(options)
|
|
27
|
+
@options = options
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.options
|
|
31
|
+
@options
|
|
32
|
+
end
|
|
18
33
|
end
|
data/lib/time_sheet/time/cmd.rb
CHANGED
|
@@ -3,6 +3,8 @@ require 'time'
|
|
|
3
3
|
|
|
4
4
|
class TimeSheet::Time::Cmd
|
|
5
5
|
def run
|
|
6
|
+
TimeSheet.options = options
|
|
7
|
+
|
|
6
8
|
if d = options[:from]
|
|
7
9
|
if d.match(/^\d\d?-\d\d?$/)
|
|
8
10
|
d = "#{TimeSheet::Time::Util.now.year}-#{d}"
|
|
@@ -64,6 +66,10 @@ class TimeSheet::Time::Cmd
|
|
|
64
66
|
options[:to] = TimeSheet::Time::Util.month_end(-1)
|
|
65
67
|
options[:summary] = true
|
|
66
68
|
report
|
|
69
|
+
when 'year-to-day', 'year'
|
|
70
|
+
options[:from] = TimeSheet::Time::Util.year_start(-1)
|
|
71
|
+
options[:summary] = true
|
|
72
|
+
report
|
|
67
73
|
when 'overview'
|
|
68
74
|
overview
|
|
69
75
|
else
|
|
@@ -111,12 +117,14 @@ class TimeSheet::Time::Cmd
|
|
|
111
117
|
o.string '-t', '--to', 'ignore entries more recent than the date given'
|
|
112
118
|
o.string '-p', '--project', 'take only entries of this project into account'
|
|
113
119
|
o.string '-a', '--activity', 'take only entries of this activity into account'
|
|
120
|
+
o.string '--tags', 'take only entries with these tags into account (comma separated, not case sensitive)'
|
|
114
121
|
o.string '-d', '--description', 'consider only entries matching this description'
|
|
115
122
|
o.string '-e', '--employee', 'consider only entries for this employee'
|
|
116
123
|
o.float '-r', '--rate', 'use an alternative hourly rate (default: 80.0)', default: 80.00
|
|
117
124
|
o.boolean '-s', '--summary', 'when reporting, add summary section'
|
|
118
125
|
o.boolean '--trim', 'compact the output for processing as CSV', default: false
|
|
119
126
|
o.boolean '-v', '--verbose', 'be more verbose'
|
|
127
|
+
o.boolean '--debug', 'drop into a REPL on errors'
|
|
120
128
|
o.separator "\n invoice options:"
|
|
121
129
|
o.integer '--package', 'for invoice output: build packages of this duration in hours', default: 0
|
|
122
130
|
o.integer '--petty', 'fold records under a certain threshold into a "misc" activity', default: 0
|
|
@@ -148,7 +156,7 @@ class TimeSheet::Time::Cmd
|
|
|
148
156
|
end
|
|
149
157
|
|
|
150
158
|
if options[:package]
|
|
151
|
-
package = data.last.map{|entry| entry[1]}.sum
|
|
159
|
+
package = (data.last.nil? ? 0 : data.last.map{|entry| entry[1]}.sum)
|
|
152
160
|
total = options[:package] * 60
|
|
153
161
|
percent = (package / total.to_f * 100)
|
|
154
162
|
|
|
@@ -78,7 +78,7 @@ class TimeSheet::Time::Entry
|
|
|
78
78
|
end
|
|
79
79
|
|
|
80
80
|
def tags
|
|
81
|
-
(@data['tags']
|
|
81
|
+
self.class.parse_tags(@data['tags'])
|
|
82
82
|
end
|
|
83
83
|
|
|
84
84
|
def working_day?
|
|
@@ -90,7 +90,9 @@ class TimeSheet::Time::Entry
|
|
|
90
90
|
from = from.to_time if from.is_a?(Date)
|
|
91
91
|
to = (filters[:to] ? filters[:to] : nil)
|
|
92
92
|
to = (to + 1).to_time if to.is_a?(Date)
|
|
93
|
+
tags = self.class.parse_tags(filters[:tags])
|
|
93
94
|
|
|
95
|
+
has_tags?(tags) &&
|
|
94
96
|
self.class.attrib_matches_any?(employee, filters[:employee]) &&
|
|
95
97
|
self.class.attrib_matches_any?(description, filters[:description]) &&
|
|
96
98
|
self.class.attrib_matches_any?(project, filters[:project]) &&
|
|
@@ -99,12 +101,23 @@ class TimeSheet::Time::Entry
|
|
|
99
101
|
(!to || to >= self.end)
|
|
100
102
|
end
|
|
101
103
|
|
|
104
|
+
def has_tags?(tags)
|
|
105
|
+
return true if tags.empty?
|
|
106
|
+
|
|
107
|
+
tags.all? do |tag|
|
|
108
|
+
self.tags.include?(tag)
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
102
112
|
def valid?
|
|
103
113
|
valid!
|
|
104
114
|
true
|
|
105
115
|
rescue TimeSheet::Time::Exception => e
|
|
106
116
|
self.exception = e
|
|
107
117
|
false
|
|
118
|
+
rescue StandardError => e
|
|
119
|
+
binding.pry if Timesheet.options[:debug]
|
|
120
|
+
false
|
|
108
121
|
end
|
|
109
122
|
|
|
110
123
|
def valid!
|
|
@@ -154,7 +167,8 @@ class TimeSheet::Time::Entry
|
|
|
154
167
|
'duration' => duration,
|
|
155
168
|
'project' => project,
|
|
156
169
|
'activity' => activity,
|
|
157
|
-
'description' => description
|
|
170
|
+
'description' => description,
|
|
171
|
+
'tags' => tags
|
|
158
172
|
}
|
|
159
173
|
end
|
|
160
174
|
|
|
@@ -170,4 +184,8 @@ class TimeSheet::Time::Entry
|
|
|
170
184
|
end
|
|
171
185
|
end
|
|
172
186
|
|
|
187
|
+
def self.parse_tags(string)
|
|
188
|
+
(string || '').to_s.downcase.split(/\s*,\s*/).map{|t| t.strip}
|
|
189
|
+
end
|
|
190
|
+
|
|
173
191
|
end
|
|
@@ -68,10 +68,11 @@ class TimeSheet::Time::Parser
|
|
|
68
68
|
|
|
69
69
|
Spreadsheet.open(filename).worksheets.each do |sheet|
|
|
70
70
|
headers = sheet.rows.first.to_a
|
|
71
|
-
sheet.rows[1..-1].each do |row|
|
|
71
|
+
sheet.rows[1..-1].each.with_index do |row, i|
|
|
72
72
|
# TODO find a way to guard against xls sheets with 65535 (empty)
|
|
73
73
|
# lines, perhaps:
|
|
74
74
|
# break if row[1].nil?
|
|
75
|
+
next if row.all?{|cell| [nil, ''].include?(cell)}
|
|
75
76
|
|
|
76
77
|
record = {}
|
|
77
78
|
row.each_with_index do |value, i|
|
|
@@ -84,16 +85,16 @@ class TimeSheet::Time::Parser
|
|
|
84
85
|
results
|
|
85
86
|
end
|
|
86
87
|
|
|
87
|
-
def parse_google_doc(
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
def parse_google_doc(url)
|
|
89
|
+
# Chart Tools datasource protocol, see
|
|
90
|
+
# https://developers.google.com/chart/interactive/docs/querylanguage
|
|
90
91
|
response = HTTPClient.get(url)
|
|
91
92
|
|
|
92
93
|
if response.status == 200
|
|
93
|
-
data = CSV.parse(response.body,
|
|
94
|
+
data = CSV.parse(response.body, liberal_parsing: true)
|
|
94
95
|
headers = data.shift
|
|
95
96
|
data.map do |row|
|
|
96
|
-
record = headers.zip(row).to_h
|
|
97
|
+
record = nullify_empties(headers.zip(row).to_h)
|
|
97
98
|
parse_date_and_time(record)
|
|
98
99
|
end
|
|
99
100
|
else
|
|
@@ -108,9 +109,16 @@ class TimeSheet::Time::Parser
|
|
|
108
109
|
'end' => (record['end'] ? DateTime.parse(record['end']) : nil)
|
|
109
110
|
)
|
|
110
111
|
rescue ArgumentError => e
|
|
112
|
+
binding.pry if TimeSheet.options[:debug]
|
|
111
113
|
puts "current record: #{record.inspect}"
|
|
112
114
|
return {}
|
|
113
115
|
# raise e
|
|
114
116
|
end
|
|
115
117
|
|
|
118
|
+
def nullify_empties(record)
|
|
119
|
+
record.transform_values do |v|
|
|
120
|
+
v == '' ? nil : v
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
116
124
|
end
|
data/lib/time_sheet/version.rb
CHANGED
data/time_sheet.gemspec
CHANGED
|
@@ -28,8 +28,8 @@ Gem::Specification.new do |spec|
|
|
|
28
28
|
spec.add_dependency 'slop'
|
|
29
29
|
spec.add_dependency 'httpclient'
|
|
30
30
|
|
|
31
|
-
spec.add_development_dependency "bundler", "~>
|
|
32
|
-
spec.add_development_dependency "rake", "~>
|
|
31
|
+
spec.add_development_dependency "bundler", "~> 2.2.16"
|
|
32
|
+
spec.add_development_dependency "rake", "~> 13.0"
|
|
33
33
|
spec.add_development_dependency "rspec", "~> 3.0"
|
|
34
34
|
spec.add_development_dependency 'pry'
|
|
35
35
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: time-sheet
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.11.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Moritz Schepp
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2021-06-25 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: spreadsheet
|
|
@@ -58,28 +58,28 @@ dependencies:
|
|
|
58
58
|
requirements:
|
|
59
59
|
- - "~>"
|
|
60
60
|
- !ruby/object:Gem::Version
|
|
61
|
-
version:
|
|
61
|
+
version: 2.2.16
|
|
62
62
|
type: :development
|
|
63
63
|
prerelease: false
|
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
65
|
requirements:
|
|
66
66
|
- - "~>"
|
|
67
67
|
- !ruby/object:Gem::Version
|
|
68
|
-
version:
|
|
68
|
+
version: 2.2.16
|
|
69
69
|
- !ruby/object:Gem::Dependency
|
|
70
70
|
name: rake
|
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
|
72
72
|
requirements:
|
|
73
73
|
- - "~>"
|
|
74
74
|
- !ruby/object:Gem::Version
|
|
75
|
-
version: '
|
|
75
|
+
version: '13.0'
|
|
76
76
|
type: :development
|
|
77
77
|
prerelease: false
|
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
|
79
79
|
requirements:
|
|
80
80
|
- - "~>"
|
|
81
81
|
- !ruby/object:Gem::Version
|
|
82
|
-
version: '
|
|
82
|
+
version: '13.0'
|
|
83
83
|
- !ruby/object:Gem::Dependency
|
|
84
84
|
name: rspec
|
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -108,7 +108,7 @@ dependencies:
|
|
|
108
108
|
- - ">="
|
|
109
109
|
- !ruby/object:Gem::Version
|
|
110
110
|
version: '0'
|
|
111
|
-
description:
|
|
111
|
+
description:
|
|
112
112
|
email:
|
|
113
113
|
- moritz.schepp@gmail.com
|
|
114
114
|
executables:
|
|
@@ -134,13 +134,13 @@ files:
|
|
|
134
134
|
- lib/time_sheet/time/util.rb
|
|
135
135
|
- lib/time_sheet/version.rb
|
|
136
136
|
- time_sheet.gemspec
|
|
137
|
-
homepage:
|
|
137
|
+
homepage:
|
|
138
138
|
licenses:
|
|
139
139
|
- GPL-3.0-only
|
|
140
140
|
metadata:
|
|
141
141
|
bug_tracker_uri: https://github.com/moritzschepp/time-sheet/issues
|
|
142
142
|
documentation_uri: https://github.com/moritzschepp/time-sheet
|
|
143
|
-
post_install_message:
|
|
143
|
+
post_install_message:
|
|
144
144
|
rdoc_options: []
|
|
145
145
|
require_paths:
|
|
146
146
|
- lib
|
|
@@ -155,9 +155,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
155
155
|
- !ruby/object:Gem::Version
|
|
156
156
|
version: '0'
|
|
157
157
|
requirements: []
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
signing_key:
|
|
158
|
+
rubygems_version: 3.1.6
|
|
159
|
+
signing_key:
|
|
161
160
|
specification_version: 4
|
|
162
161
|
summary: a time tracking solution based on spreadsheets
|
|
163
162
|
test_files: []
|