plansheet 0.24.1 → 0.27.0
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/.rubocop.yml +3 -0
- data/Gemfile.lock +1 -1
- data/lib/plansheet/pool.rb +29 -6
- data/lib/plansheet/project/yaml.rb +16 -3
- data/lib/plansheet/project.rb +24 -7
- data/lib/plansheet/sheet/latex.rb +55 -0
- data/lib/plansheet/sheet.rb +1 -53
- data/lib/plansheet/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e590a914b9d074b7ce833d04aac6e5320684c15a398c1c88d5774ae884cad297
|
4
|
+
data.tar.gz: 7e7d5004b022e6286e0e7792b9392b95c1536c398c7915a2534ead4dbf364080
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4f03c2eaa802dd20a82180ab4a3ad2b23b2a3b69d6e7536f81a42305a3aab486175e18c767a9cb5b919a7c8d5d7e5a22032253e19b95d47d19c64a4583fd150f
|
7
|
+
data.tar.gz: 6a1923c54d08ba01d33dbfb8d0c76b813fb57b65edba8d79fd002db43b9c63299a301c763acb5084ab5d1e9a773af24be12b15d5f5c2d4fad3b009f820939cfa
|
data/.rubocop.yml
CHANGED
data/Gemfile.lock
CHANGED
data/lib/plansheet/pool.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "pathname"
|
3
4
|
require "rgl/adjacency"
|
4
5
|
require "rgl/topsort"
|
5
6
|
|
@@ -23,7 +24,6 @@ module Plansheet
|
|
23
24
|
def initialize(config, debug: false)
|
24
25
|
@projects_dir = config[:projects_dir]
|
25
26
|
@sort_order = config[:sort_order]
|
26
|
-
# @completed_projects_dir = config(:completed_projects_dir)
|
27
27
|
|
28
28
|
# This bit of trickiness is because we don't know what the sort order is
|
29
29
|
# until runtime. I'm sure this design decision definitely won't bite me
|
@@ -77,6 +77,25 @@ module Plansheet
|
|
77
77
|
@projects.sort!
|
78
78
|
end
|
79
79
|
|
80
|
+
def archive_projects
|
81
|
+
archive_dir = "#{@projects_dir}/archive/"
|
82
|
+
Dir.mkdir archive_dir unless Dir.exist? archive_dir
|
83
|
+
|
84
|
+
# NOTE: It would save writes if we sorted and did all month/namespaces
|
85
|
+
# writes only once, but as the normal case only sees a few projects
|
86
|
+
# archived at a time, I'll leave that for someone else to implement ;-)
|
87
|
+
projects_to_archive = @projects.select(&:archivable?)
|
88
|
+
projects_to_archive.each do |project|
|
89
|
+
path = Pathname.new "#{archive_dir}/#{project.completed_on_month}/#{project.namespace}.yml"
|
90
|
+
Dir.mkdir path.dirname unless path.dirname.exist?
|
91
|
+
pyf = ProjectYAMLFile.new path
|
92
|
+
pyf.append_project project
|
93
|
+
end
|
94
|
+
|
95
|
+
# Now that the projects have been archived, remove them from the pool
|
96
|
+
@projects.reject!(&:archivable?)
|
97
|
+
end
|
98
|
+
|
80
99
|
def project_namespaces
|
81
100
|
@projects.collect(&:namespace).uniq.sort
|
82
101
|
end
|
@@ -86,12 +105,16 @@ module Plansheet
|
|
86
105
|
end
|
87
106
|
|
88
107
|
def write_projects
|
89
|
-
#
|
90
|
-
#
|
91
|
-
|
92
|
-
|
108
|
+
# Collect the namespaces *before* archiving is done, for the case where
|
109
|
+
# all active projects in a namespace have been completed and archived
|
110
|
+
namespaces_before_archiving = project_namespaces
|
111
|
+
|
112
|
+
archive_projects
|
113
|
+
|
114
|
+
namespaces_before_archiving.each do |ns|
|
115
|
+
projects = projects_in_namespace(ns)
|
93
116
|
pyf = ProjectYAMLFile.new "#{@projects_dir}/#{ns}.yml"
|
94
|
-
pyf.compare_and_write
|
117
|
+
pyf.compare_and_write projects
|
95
118
|
end
|
96
119
|
end
|
97
120
|
|
@@ -4,6 +4,7 @@ require "yaml"
|
|
4
4
|
require "date"
|
5
5
|
require "pathname"
|
6
6
|
|
7
|
+
require "diffy"
|
7
8
|
require "kwalify"
|
8
9
|
|
9
10
|
module Plansheet
|
@@ -152,7 +153,13 @@ module Plansheet
|
|
152
153
|
# TODO: this won't GC, inline validation instead?
|
153
154
|
end
|
154
155
|
|
156
|
+
def stub_file
|
157
|
+
File.write @path, YAML.dump([])
|
158
|
+
end
|
159
|
+
|
155
160
|
def load_file
|
161
|
+
stub_file unless File.exist? @path
|
162
|
+
|
156
163
|
# Handle pre-Ruby 3.1 psych versions (this is brittle)
|
157
164
|
@raw = if Psych::VERSION.split(".")[0].to_i >= 4
|
158
165
|
YAML.load_file(@path, permitted_classes: [Date])
|
@@ -189,16 +196,22 @@ module Plansheet
|
|
189
196
|
@projects.sort!
|
190
197
|
end
|
191
198
|
|
199
|
+
def append_project(project)
|
200
|
+
load_file
|
201
|
+
compare_and_write(@projects.append(project))
|
202
|
+
end
|
203
|
+
|
192
204
|
def compare_and_write(projects)
|
205
|
+
load_file
|
206
|
+
orig_string = yaml_dump(@projects)
|
193
207
|
updated_projects_string = yaml_dump(projects)
|
194
208
|
|
195
209
|
# Compare the existing file to the newly generated one - we only want a
|
196
210
|
# write if something has changed
|
197
|
-
return if updated_projects_string ==
|
211
|
+
return if updated_projects_string == orig_string
|
198
212
|
|
199
213
|
puts "#{@path} has changed, writing"
|
200
|
-
|
201
|
-
puts Diffy::Diff.new(updated_projects_string, yaml_dump(load_file)).to_s(:color)
|
214
|
+
puts Diffy::Diff.new(orig_string, updated_projects_string).to_s(:color)
|
202
215
|
File.write @path, updated_projects_string
|
203
216
|
end
|
204
217
|
|
data/lib/plansheet/project.rb
CHANGED
@@ -138,13 +138,25 @@ module Plansheet
|
|
138
138
|
# Convert the field to minutes
|
139
139
|
@time_estimate_minutes = Plansheet.parse_time_duration(@time_estimate)
|
140
140
|
end
|
141
|
-
if @time_estimate_minutes
|
141
|
+
if @time_estimate_minutes
|
142
142
|
# Rewrite time_estimate field
|
143
143
|
@time_estimate = Plansheet.build_time_duration(@time_estimate_minutes)
|
144
144
|
|
145
145
|
yms = yearly_minutes_saved
|
146
146
|
@time_roi_payoff = yms.to_f / @time_estimate_minutes if yms
|
147
147
|
end
|
148
|
+
|
149
|
+
if done?
|
150
|
+
@completed_on ||= Date.today unless recurring?
|
151
|
+
remove_instance_variable("@status") if @status
|
152
|
+
remove_instance_variable("@time_estimate") if @time_estimate
|
153
|
+
remove_instance_variable("@time_estimate_minutes") if @time_estimate
|
154
|
+
remove_instance_variable("@time_roi_payoff") if @time_roi_payoff
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def completed_on_month
|
159
|
+
@completed_on&.strftime("%Y-%m")
|
148
160
|
end
|
149
161
|
|
150
162
|
def yearly_minutes_saved
|
@@ -287,11 +299,6 @@ module Plansheet
|
|
287
299
|
task_based_status
|
288
300
|
end
|
289
301
|
|
290
|
-
def process_recurring
|
291
|
-
# TODO: Tasks will be moved from done->tasks if recurring project is
|
292
|
-
# starting again
|
293
|
-
end
|
294
|
-
|
295
302
|
# Due date either explicit or recurring
|
296
303
|
def due
|
297
304
|
return @due if @due
|
@@ -326,6 +333,8 @@ module Plansheet
|
|
326
333
|
|
327
334
|
def last_for_deferral
|
328
335
|
return @last_done + Plansheet.parse_date_duration(@last_for) if @last_done
|
336
|
+
|
337
|
+
Date.today
|
329
338
|
end
|
330
339
|
|
331
340
|
def lead_time_deferral
|
@@ -338,13 +347,21 @@ module Plansheet
|
|
338
347
|
end
|
339
348
|
|
340
349
|
def recurring?
|
341
|
-
!@frequency.nil? || !@day_of_week.nil? || !@last_done.nil?
|
350
|
+
!@frequency.nil? || !@day_of_week.nil? || !@last_done.nil? || !@last_for.nil?
|
342
351
|
end
|
343
352
|
|
344
353
|
def dropped_or_done?
|
345
354
|
status == "dropped" || status == "done"
|
346
355
|
end
|
347
356
|
|
357
|
+
def done?
|
358
|
+
status == "done"
|
359
|
+
end
|
360
|
+
|
361
|
+
def archivable?
|
362
|
+
!recurring? && @completed_on
|
363
|
+
end
|
364
|
+
|
348
365
|
def self.task_time_estimate(str)
|
349
366
|
Plansheet.parse_time_duration(Regexp.last_match(1)) if str.match(TIME_EST_REGEX)
|
350
367
|
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "date"
|
4
|
+
module Plansheet
|
5
|
+
# The Sheet class constructs a Markdown/LaTeX file for use with pandoc
|
6
|
+
class Sheet
|
7
|
+
def initialize(output_file, project_arr)
|
8
|
+
projects_str = String.new
|
9
|
+
projects_str << sheet_header
|
10
|
+
|
11
|
+
project_arr.each do |p|
|
12
|
+
projects_str << project_minipage(p)
|
13
|
+
end
|
14
|
+
puts "Writing to #{output_file}"
|
15
|
+
File.write(output_file, projects_str)
|
16
|
+
end
|
17
|
+
|
18
|
+
def sheet_header
|
19
|
+
<<~FRONTMATTER
|
20
|
+
---
|
21
|
+
geometry: margin=1.5cm
|
22
|
+
---
|
23
|
+
\\thispagestyle{empty}
|
24
|
+
|
25
|
+
# Date: #{Date.today}
|
26
|
+
FRONTMATTER
|
27
|
+
end
|
28
|
+
|
29
|
+
def project_minipage(proj)
|
30
|
+
str = String.new
|
31
|
+
str << "\\begin{minipage}{6cm}\n"
|
32
|
+
str << project_header(proj)
|
33
|
+
proj&.tasks&.each do |t|
|
34
|
+
str << "$\\square$ #{sanitize_string(t)} \\\\\n"
|
35
|
+
end
|
36
|
+
str << "\\end{minipage}\n"
|
37
|
+
str
|
38
|
+
end
|
39
|
+
|
40
|
+
def sanitize_string(str)
|
41
|
+
str.gsub("_", '\_')
|
42
|
+
end
|
43
|
+
|
44
|
+
def project_header(proj)
|
45
|
+
str = String.new
|
46
|
+
str << "#{sanitize_string(proj.namespace)}: #{sanitize_string(proj.name)}\\\\\n"
|
47
|
+
str << proj.status.to_s
|
48
|
+
str << " - #{sanitize_string(proj.location)}" if proj.location
|
49
|
+
str << " due: #{proj.due}" if proj.due
|
50
|
+
str << " time: #{proj.time_estimate}" if proj.time_estimate
|
51
|
+
str << " \\\\\n"
|
52
|
+
str
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/lib/plansheet/sheet.rb
CHANGED
@@ -1,55 +1,3 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
module Plansheet
|
5
|
-
# The Sheet class constructs a Markdown/LaTeX file for use with pandoc
|
6
|
-
class Sheet
|
7
|
-
def initialize(output_file, project_arr)
|
8
|
-
projects_str = String.new
|
9
|
-
projects_str << sheet_header
|
10
|
-
|
11
|
-
project_arr.each do |p|
|
12
|
-
projects_str << project_minipage(p)
|
13
|
-
end
|
14
|
-
puts "Writing to #{output_file}"
|
15
|
-
File.write(output_file, projects_str)
|
16
|
-
end
|
17
|
-
|
18
|
-
def sheet_header
|
19
|
-
<<~FRONTMATTER
|
20
|
-
---
|
21
|
-
geometry: margin=1.5cm
|
22
|
-
---
|
23
|
-
\\thispagestyle{empty}
|
24
|
-
|
25
|
-
# Date: #{Date.today}
|
26
|
-
FRONTMATTER
|
27
|
-
end
|
28
|
-
|
29
|
-
def project_minipage(proj)
|
30
|
-
str = String.new
|
31
|
-
str << "\\begin{minipage}{6cm}\n"
|
32
|
-
str << project_header(proj)
|
33
|
-
proj&.tasks&.each do |t|
|
34
|
-
str << "$\\square$ #{sanitize_string(t)} \\\\\n"
|
35
|
-
end
|
36
|
-
str << "\\end{minipage}\n"
|
37
|
-
str
|
38
|
-
end
|
39
|
-
|
40
|
-
def sanitize_string(str)
|
41
|
-
str.gsub("_", '\_')
|
42
|
-
end
|
43
|
-
|
44
|
-
def project_header(proj)
|
45
|
-
str = String.new
|
46
|
-
str << "#{sanitize_string(proj.namespace)}: #{sanitize_string(proj.name)}\\\\\n"
|
47
|
-
str << proj.status.to_s
|
48
|
-
str << " - #{sanitize_string(proj.location)}" if proj.location
|
49
|
-
str << " due: #{proj.due}" if proj.due
|
50
|
-
str << " time: #{proj.time_estimate}" if proj.time_estimate
|
51
|
-
str << " \\\\\n"
|
52
|
-
str
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
3
|
+
require_relative "sheet/latex"
|
data/lib/plansheet/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: plansheet
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.27.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Crosby
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-07-
|
11
|
+
date: 2022-07-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dc-kwalify
|
@@ -76,6 +76,7 @@ files:
|
|
76
76
|
- lib/plansheet/project/stringify.rb
|
77
77
|
- lib/plansheet/project/yaml.rb
|
78
78
|
- lib/plansheet/sheet.rb
|
79
|
+
- lib/plansheet/sheet/latex.rb
|
79
80
|
- lib/plansheet/version.rb
|
80
81
|
homepage: https://dafyddcrosby.com
|
81
82
|
licenses:
|