plansheet 0.30.1 → 0.34.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 19345ed604fc0cbbde2039faf1ffb9b11906c15d7810ad32706beb8ce3ff3fce
4
- data.tar.gz: 4c155173ebb564eeed831258435ee2fae898f859027c453ca2bc66076713e5c1
3
+ metadata.gz: 0127f89bb4b286c6bda0d5ff1d1c8e02d4ceb26f0898f78f2031ad7d69913bf1
4
+ data.tar.gz: 0ce4e76d7693d51bfdd96cd6390124955858c15b5fe109f03d11d4aa707bdf98
5
5
  SHA512:
6
- metadata.gz: 6c48221ba589561d204608a4bab90a1f8c05f19ee5e264835f2a663782b1a51f9ed9ac9e43562228ac055c563c443645f4a4488a381063d184031fff1b42348b
7
- data.tar.gz: c1aa45f17d310b9a9b7dbf06ff1d2bc5e488b44ab87fcbb990c54edd14ca1f0e7e5538c4e4c86eabb7887aba02f88e55d8c1b5112b2c87069ac283c30c155206
6
+ metadata.gz: 7d694e749bff3c2a4b7f6983f75ecc6861eb8a793752658439bc0e2a3381c0037aa09edad3ab4f33fc8365992ee21ab12bdc450eb6283a4e1fa8b2f7250078a3
7
+ data.tar.gz: 81e8c85c1914e225b2bca1fe8655e367b1d36a830ea0905d0bf449fa4c3ced79b023c92ecd9d655cf09a5843ec9be78de67a63e5efdaa341e843999dec736eb6
data/.rubocop.yml CHANGED
@@ -1,5 +1,2 @@
1
1
  inherit_gem:
2
- dc-rubocop: default.yml
3
-
4
- AllCops:
5
- TargetRubyVersion: 2.6
2
+ dc-rubocop: ruby26.yml
data/Gemfile CHANGED
@@ -2,10 +2,9 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- # Specify your gem's dependencies in plansheet.gemspec
6
5
  gemspec
7
6
 
8
7
  group :development, optional: true do
9
- gem "dc-devtools"
8
+ gem "dc-devtools", "~> 0.5"
10
9
  gem "rdoc"
11
10
  end
data/Rakefile CHANGED
@@ -9,8 +9,6 @@ Rake::TestTask.new(:test) do |t|
9
9
  t.test_files = FileList["test/**/test_*.rb"]
10
10
  end
11
11
 
12
- require "rubocop/rake_task"
13
-
14
- RuboCop::RakeTask.new
12
+ require "dc_rake"
15
13
 
16
14
  task default: %i[test rubocop]
data/exe/plansheet CHANGED
@@ -4,11 +4,14 @@
4
4
  require "plansheet"
5
5
  require "optparse"
6
6
 
7
+ options = {}
7
8
  parser = OptionParser.new
8
9
  parser.on(
9
- "--sheet",
10
+ "--sheet [TYPE]",
10
11
  "Generates MD/LaTeX project PDF"
11
- )
12
+ ) do |sheet_type|
13
+ options[:sheet] = sheet_type || "projects"
14
+ end
12
15
  parser.on(
13
16
  "--sort",
14
17
  "Sort project files"
@@ -29,6 +32,10 @@ parser.on(
29
32
  "--time-roi",
30
33
  "Show projects with a time return-on-investment"
31
34
  )
35
+ parser.on(
36
+ "--needs-thinking",
37
+ "Show projects that need tasks, time estimates, etc (WIP)"
38
+ )
32
39
  parser.on(
33
40
  "--calendar",
34
41
  "List of projects ordered by due date"
@@ -37,7 +44,6 @@ parser.on(
37
44
  "--location_filter LOCATION",
38
45
  "location filter for CLI dump (WIP)"
39
46
  )
40
- options = {}
41
47
  parser.parse!(into: options)
42
48
 
43
49
  config = Plansheet.load_config
@@ -45,9 +51,21 @@ pool = Plansheet::Pool.new({ projects_dir: config["projects_dir"],
45
51
  sort_order: config["sort_order"] })
46
52
 
47
53
  if options[:sheet] || options.empty?
54
+ # TODO: Add pdflatex command (customizable path)
48
55
  require "plansheet/sheet"
49
56
  FileUtils.mkdir_p config["output_dir"]
50
- Plansheet::LaTeXSheet.new("#{config["output_dir"]}/projects.tex", pool.projects)
57
+ case options[:sheet]
58
+ when "daily"
59
+ Plansheet::DailyLaTeXSheet.new("#{config["output_dir"]}/daily.tex", config["daily"])
60
+ when "weekly"
61
+ Plansheet::WeeklyLaTeXSheet.new("#{config["output_dir"]}/weekly.tex", pool.projects, config["weekly"])
62
+ when "monthly"
63
+ Plansheet::MonthlyLaTeXSheet.new("#{config["output_dir"]}/monthly.tex", config["monthly"])
64
+ else
65
+ project_arr = pool.projects
66
+ project_arr.delete_if { |x| %w[dropped done paused].include? x.status }
67
+ Plansheet::LaTeXSheet.new("#{config["output_dir"]}/projects.tex", project_arr)
68
+ end
51
69
  elsif options[:irb]
52
70
  binding.irb # rubocop:disable Lint/Debugger
53
71
  elsif options[:stats]
@@ -68,6 +86,15 @@ elsif options[:"time-roi"]
68
86
  puts "time ROI payoff: #{proj.time_roi_payoff}"
69
87
  puts "\n"
70
88
  end
89
+ elsif options[:"needs-thinking"]
90
+ puts "Projects with no tasks"
91
+ project_arr = pool.projects.sort
92
+ project_arr.delete_if(&:dropped_or_done?)
93
+ project_arr.delete_if(&:tasks)
94
+ project_arr.each do |proj|
95
+ puts proj
96
+ puts "\n"
97
+ end
71
98
  elsif options[:calendar]
72
99
  # TODO: add a project filter method
73
100
  project_arr = pool.projects
@@ -140,6 +140,16 @@ module Plansheet
140
140
  type: seq
141
141
  sequence:
142
142
  - type: str
143
+ "setup_tasks":
144
+ desc: List of tasks needed before main project work begins
145
+ type: seq
146
+ sequence:
147
+ - type: str
148
+ "cleanup_tasks":
149
+ desc: List of tasks needed before main project work begins
150
+ type: seq
151
+ sequence:
152
+ - type: str
143
153
  "done":
144
154
  desc: List of tasks which have been completed
145
155
  type: seq
@@ -6,14 +6,17 @@ require_relative "project/yaml"
6
6
  require_relative "project/stringify"
7
7
  require_relative "./time"
8
8
 
9
- # Needed for Project#time_estimate, would be much happier *not* patching Array
10
- class Array
11
- def nil_if_empty
12
- count.zero? ? nil : self
9
+ module Plansheet
10
+ module PlansheetArray
11
+ # Needed for Project#time_estimate
12
+ refine Array do
13
+ def nil_if_empty
14
+ count.zero? ? nil : self
15
+ end
16
+ end
13
17
  end
14
- end
18
+ using PlansheetArray
15
19
 
16
- module Plansheet
17
20
  PROJECT_STATUS_PRIORITY = {
18
21
  "wip" => 1,
19
22
  "ready" => 2,
@@ -58,7 +61,7 @@ module Plansheet
58
61
  day_of_week frequency last_for lead_time].freeze
59
62
  DATE_PROPERTIES = %w[due defer paused_on dropped_on completed_on created_on starts_on last_done
60
63
  last_reviewed].freeze
61
- ARRAY_PROPERTIES = %w[dependencies externals urls tasks done tags].freeze
64
+ ARRAY_PROPERTIES = %w[dependencies externals urls tasks setup_tasks cleanup_tasks done tags].freeze
62
65
 
63
66
  ALL_PROPERTIES = STRING_PROPERTIES + DATE_PROPERTIES + ARRAY_PROPERTIES
64
67
 
@@ -121,11 +124,13 @@ module Plansheet
121
124
  end
122
125
 
123
126
  if done?
124
- @completed_on ||= Date.today unless recurring?
125
127
  remove_instance_variable("@status") if @status
126
- remove_instance_variable("@time_estimate") if @time_estimate
127
- remove_instance_variable("@time_estimate_minutes") if @time_estimate
128
- remove_instance_variable("@time_roi_payoff") if @time_roi_payoff
128
+ unless recurring?
129
+ @completed_on ||= Date.today
130
+ remove_instance_variable("@time_estimate") if @time_estimate
131
+ remove_instance_variable("@time_estimate_minutes") if @time_estimate
132
+ remove_instance_variable("@time_roi_payoff") if @time_roi_payoff
133
+ end
129
134
  elsif paused?
130
135
  @paused_on ||= Date.today
131
136
  remove_instance_variable("@status") if @status
@@ -332,16 +337,10 @@ module Plansheet
332
337
  !@frequency.nil? || !@day_of_week.nil? || !@last_done.nil? || !@last_for.nil?
333
338
  end
334
339
 
335
- def paused?
336
- status == "paused"
337
- end
338
-
339
- def dropped?
340
- status == "dropped"
341
- end
342
-
343
- def done?
344
- status == "done"
340
+ PROJECT_STATUS_PRIORITY.each_key do |stat|
341
+ define_method("#{stat}?".to_sym) do
342
+ status == stat
343
+ end
345
344
  end
346
345
 
347
346
  def dropped_or_done?
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: false
2
+
3
+ require "date"
4
+ module Plansheet
5
+ class DailyLaTeXSheet
6
+ include Plansheet::LaTeXMixins
7
+ def initialize(output_file, config)
8
+ @config = config
9
+ projects_str = sheet_header
10
+ projects_str << document do
11
+ sheet_body
12
+ end
13
+
14
+ puts "Writing to #{output_file}"
15
+ File.write(output_file, projects_str)
16
+ end
17
+
18
+ def dateline
19
+ <<~DATELINE
20
+ \\thispagestyle{empty}
21
+
22
+ Date \\(\\underline{\\hspace{4cm}}\\)
23
+
24
+ DATELINE
25
+ end
26
+
27
+ INCOLUMN_SPACING = "7mm".freeze
28
+ def sheet_body
29
+ [
30
+ dateline,
31
+ vspace("1cm"),
32
+ vbox do
33
+ @config["top"].map do |section|
34
+ minipage("8cm") do
35
+ section_output(section)
36
+ end
37
+ end.join
38
+ end,
39
+
40
+ %w[left_bar right_bar].map do |col|
41
+ minipage("8cm") do
42
+ @config[col].map do |section|
43
+ minipage("\\textwidth") do
44
+ section_output(section)
45
+ end
46
+ end.join(vspace(INCOLUMN_SPACING))
47
+ end
48
+ end
49
+ ].flatten.join
50
+ end
51
+
52
+ def section_output(section)
53
+ case section["type"]
54
+ when "checkboxes"
55
+ checkboxes(section["items"])
56
+ when "checkbox_and_lines"
57
+ checkbox_and_lines(section["items"])
58
+ when "multiline_checkbox_and_lines"
59
+ multiline_checkbox_and_lines(section["items"])
60
+ end
61
+ end
62
+
63
+ def checkboxes(items)
64
+ items.map do |l|
65
+ l.map do |i|
66
+ checkbox_item i
67
+ end.join(" ")
68
+ end.join(HARD_NL)
69
+ end
70
+
71
+ def checkbox_and_lines(items)
72
+ items.map do |i|
73
+ checkbox_item(i, line: "4cm")
74
+ end.join(HARD_NL)
75
+ end
76
+
77
+ def multiline_checkbox_and_lines(items)
78
+ items.map do |q|
79
+ "#{checkbox_item q} #{HARD_NL}#{writein_line("\\textwidth")}"
80
+ end.join(HARD_NL)
81
+ end
82
+ end
83
+ end
@@ -2,97 +2,39 @@
2
2
 
3
3
  require "date"
4
4
  module Plansheet
5
- # The Sheet class constructs a Markdown/LaTeX file for use with pandoc
5
+ # The Sheet class constructs a Markdown/LaTeX file for use with pdflatex
6
6
  class LaTeXSheet
7
+ include LaTeXMixins
7
8
  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)
9
+ projects_str = sheet_header
10
+ projects_str << document do
11
+ "\\thispagestyle{empty}\n\n\\section{Date: #{Date.today}}\n".concat(
12
+ project_arr.map do |p|
13
+ project_minipage(p)
14
+ end.join
15
+ )
13
16
  end
14
17
  puts "Writing to #{output_file}"
15
- projects_str << sheet_footer
16
18
  File.write(output_file, projects_str)
17
19
  end
18
20
 
19
- def sheet_header
20
- # LaTeX used to be generated by pandoc
21
- <<~FRONTMATTER
22
- \\PassOptionsToPackage{unicode}{hyperref}
23
- \\PassOptionsToPackage{hyphens}{url}
24
- \\documentclass[]{article}
25
- \\author{}
26
- \\date{#{Date.today}}
27
- \\usepackage{amsmath,amssymb}
28
- \\usepackage{lmodern}
29
- \\usepackage{iftex}
30
- \\usepackage[T1]{fontenc}
31
- \\usepackage[utf8]{inputenc}
32
- \\usepackage{textcomp}
33
- \\IfFileExists{upquote.sty}{\\usepackage{upquote}}{}
34
- \\IfFileExists{microtype.sty}{
35
- \\usepackage[]{microtype}
36
- \\UseMicrotypeSet[protrusion]{basicmath}
37
- }{}
38
- \\makeatletter
39
- \\@ifundefined{KOMAClassName}{
40
- \\IfFileExists{parskip.sty}{
41
- \\usepackage{parskip}
42
- }{
43
- \\setlength{\\parindent}{0pt}
44
- \\setlength{\\parskip}{6pt plus 2pt minus 1pt}}
45
- }{
46
- \\KOMAoptions{parskip=half}}
47
- \\makeatother
48
- \\usepackage{xcolor}
49
- \\IfFileExists{xurl.sty}{\\usepackage{xurl}}{}
50
- \\IfFileExists{bookmark.sty}{\\usepackage{bookmark}}{\\usepackage{hyperref}}
51
- \\hypersetup{
52
- hidelinks,
53
- pdfcreator={LaTeX via plansheet}}
54
- \\urlstyle{same}
55
- \\usepackage[margin=1.5cm]{geometry}
56
- \\setlength{\\emergencystretch}{3em}
57
- \\providecommand{\\tightlist}{
58
- \\setlength{\\itemsep}{0pt}\\setlength{\\parskip}{0pt}}
59
- \\setcounter{secnumdepth}{-\\maxdimen}
60
-
61
- \\begin{document}
62
-
63
- \\thispagestyle{empty}
64
-
65
- \\section{Date: #{Date.today}}
66
- FRONTMATTER
67
- end
68
-
69
- def sheet_footer
70
- '\end{document}'
71
- end
72
-
73
21
  def project_minipage(proj)
74
- str = String.new
75
- str << "\\begin{minipage}{6cm}\n"
76
- str << project_header(proj)
77
- proj&.tasks&.each do |t|
78
- str << "$\\square$ #{sanitize_string(t)} \\\\\n"
22
+ minipage("6cm") do
23
+ project_header(proj)&.concat(
24
+ proj&.tasks&.map do |t|
25
+ "#{checkbox_item sanitize_string(t)}#{HARD_NL}"
26
+ end&.join("") || "" # empty string to catch nil
27
+ )
79
28
  end
80
- str << "\\end{minipage}\n"
81
- str
82
- end
83
-
84
- def sanitize_string(str)
85
- str.gsub("_", '\_')
86
29
  end
87
30
 
88
31
  def project_header(proj)
89
- str = String.new
90
- str << "#{sanitize_string(proj.namespace)}: #{sanitize_string(proj.name)}\\\\\n"
32
+ str = "#{sanitize_string(proj.namespace)}: #{sanitize_string(proj.name)}#{HARD_NL}"
91
33
  str << proj.status.to_s
92
34
  str << " - #{sanitize_string(proj.location)}" if proj.location
93
35
  str << " due: #{proj.due}" if proj.due
94
36
  str << " time: #{proj.time_estimate}" if proj.time_estimate
95
- str << " \\\\\n"
37
+ str << HARD_NL
96
38
  str
97
39
  end
98
40
  end
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "date"
4
+ module Plansheet
5
+ module LaTeXMixins
6
+ HARD_NL = " \\\\\n"
7
+ SQUARE = "$\\square$"
8
+
9
+ def vspace(space)
10
+ "\\vspace{#{space}}\n"
11
+ end
12
+
13
+ def writein_line(space)
14
+ "$\\underline{\\hspace{#{space}}}$"
15
+ end
16
+
17
+ def checkbox_item(str, line: nil)
18
+ "#{SQUARE} #{str}#{" #{writein_line(line)}" if line}"
19
+ end
20
+
21
+ def vbox
22
+ "\\vbox{\n#{yield}\n}\n"
23
+ end
24
+
25
+ %w[center document enumerate tabbing].each do |env|
26
+ define_method(env.to_sym) do |&e|
27
+ <<~ENV
28
+ \\begin{#{env}}
29
+ #{e.call}
30
+ \\end{#{env}}
31
+ ENV
32
+ end
33
+ end
34
+
35
+ def itemize_tightlist
36
+ <<~DOCUMENT
37
+ \\begin{itemize}
38
+ \\tightlist
39
+ #{yield}
40
+ \\end{itemize}
41
+ DOCUMENT
42
+ end
43
+
44
+ def itemline(item, opt: nil)
45
+ "\\item#{opt ? "[#{opt}]" : ""} #{item}\n"
46
+ end
47
+
48
+ def minipage(size)
49
+ <<~MINIPAGE
50
+ \\begin{minipage}{#{size}}
51
+ #{yield}
52
+ \\end{minipage}
53
+ MINIPAGE
54
+ end
55
+
56
+ def sanitize_string(str)
57
+ str.gsub("_", '\_')
58
+ end
59
+
60
+ def sheet_header
61
+ # LaTeX used to be generated by pandoc
62
+ <<~FRONTMATTER
63
+ \\PassOptionsToPackage{unicode}{hyperref}
64
+ \\PassOptionsToPackage{hyphens}{url}
65
+ \\documentclass[]{article}
66
+ \\author{}
67
+ \\date{#{Date.today}}
68
+ \\usepackage{amsmath,amssymb}
69
+ \\usepackage{lmodern}
70
+ \\usepackage{iftex}
71
+ \\usepackage[T1]{fontenc}
72
+ \\usepackage[utf8]{inputenc}
73
+ \\usepackage{textcomp}
74
+ \\IfFileExists{upquote.sty}{\\usepackage{upquote}}{}
75
+ \\IfFileExists{microtype.sty}{
76
+ \\usepackage[]{microtype}
77
+ \\UseMicrotypeSet[protrusion]{basicmath}
78
+ }{}
79
+ \\makeatletter
80
+ \\@ifundefined{KOMAClassName}{
81
+ \\IfFileExists{parskip.sty}{
82
+ \\usepackage{parskip}
83
+ }{
84
+ \\setlength{\\parindent}{0pt}
85
+ \\setlength{\\parskip}{6pt plus 2pt minus 1pt}}
86
+ }{
87
+ \\KOMAoptions{parskip=half}}
88
+ \\makeatother
89
+ \\usepackage{xcolor}
90
+ \\IfFileExists{xurl.sty}{\\usepackage{xurl}}{}
91
+ \\IfFileExists{bookmark.sty}{\\usepackage{bookmark}}{\\usepackage{hyperref}}
92
+ \\hypersetup{
93
+ hidelinks,
94
+ pdfcreator={LaTeX via plansheet}}
95
+ \\urlstyle{same}
96
+ \\usepackage[margin=1.5cm]{geometry}
97
+ \\setlength{\\emergencystretch}{3em}
98
+ \\providecommand{\\tightlist}{
99
+ \\setlength{\\itemsep}{0pt}\\setlength{\\parskip}{0pt}}
100
+ \\setcounter{secnumdepth}{-\\maxdimen}
101
+ FRONTMATTER
102
+ end
103
+
104
+ def config_file_sanity_check(options = {})
105
+ options.each do |opt, type|
106
+ unless @config[opt].is_a?(type) && !@config[opt]&.empty?
107
+ abort "Need to specify #{opt} #{type.to_s.downcase} in your ~/.plansheet.yml config"
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,110 @@
1
+ # frozen_string_literal: false
2
+
3
+ require "date"
4
+ module Plansheet
5
+ class MonthlyLaTeXSheet
6
+ include LaTeXMixins
7
+ def initialize(output_file, config)
8
+ @config = config || {}
9
+ config_file_sanity_check({
10
+ "highlevel_items" => Array,
11
+ "tags" => Hash
12
+ })
13
+
14
+ str = sheet_header
15
+ str << document do
16
+ [
17
+ month_line,
18
+ highlevel_items,
19
+ center do
20
+ [
21
+ events_minipage,
22
+ tags_minipages
23
+ ].join
24
+ end,
25
+ monthly_calendar_grid
26
+ ].join
27
+ end
28
+ puts "Writing to #{output_file}"
29
+ File.write(output_file, str)
30
+ end
31
+
32
+ def highlevel_items
33
+ itemize_tightlist do
34
+ @config["highlevel_items"].map do |i|
35
+ itemline("#{i} #{writein_line("5cm")}", opt: SQUARE)
36
+ end.join.concat("\n")
37
+ end
38
+ end
39
+
40
+ def tags_minipages
41
+ minipage("6.5cm") do
42
+ @config["tags"].map { |k, v| tag_minipage k, v }.join
43
+ end.concat("\n")
44
+ end
45
+
46
+ def events_minipage
47
+ minipage("8cm") do
48
+ "Events:\n#{
49
+ itemize_tightlist do
50
+ 30.times.map do |n|
51
+ itemline(
52
+ writein_line("6cm"),
53
+ opt: (Date.today + n).strftime("%a %m-%d")
54
+ )
55
+ end.join.concat("\n")
56
+ end
57
+ }"
58
+ end
59
+ end
60
+
61
+ def pretty_tag_name(tag)
62
+ tag.capitalize.gsub("_", " ")
63
+ end
64
+
65
+ def tag_minipage(tag, items = 10)
66
+ "#{pretty_tag_name tag}:\n".concat(
67
+ itemize_tightlist do
68
+ items.times.map do
69
+ itemline(writein_line("6cm"), opt: SQUARE)
70
+ end.join
71
+ end
72
+ )
73
+ end
74
+
75
+ def month_line
76
+ "For the next month: #{Date.today} - #{Date.today + 30}\n\n"
77
+ end
78
+
79
+ def monthly_calendar_grid
80
+ <<~GRID
81
+ \\begin{tabular}{|#{7.times.map { "p{2cm}" }.join("|")}|}
82
+ \\hline
83
+ GRID
84
+ .concat(
85
+ %w[Sunday Monday Tuesday Wednesday Thursday Friday Saturday].join(" & ").concat(HARD_NL)
86
+ ).concat(
87
+ 5.times.map do |n|
88
+ calendar_grid_line n
89
+ end.join(HARD_NL).concat(HARD_NL)
90
+ ).concat(
91
+ <<~GRID
92
+ \\hline
93
+ \\end{tabular}
94
+ GRID
95
+ )
96
+ end
97
+
98
+ private
99
+
100
+ def calendar_grid_line(week_multiplier = 0)
101
+ "\\hline\n#{
102
+ 7.times.map do |n|
103
+ (Date.today - Date.today.wday + (n + (week_multiplier * 7))).strftime("%d")
104
+ end.join(" & ")
105
+ } #{
106
+ vspace("5mm")
107
+ }"
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,132 @@
1
+ # frozen_string_literal: false
2
+
3
+ require "date"
4
+ module Plansheet
5
+ class WeeklyLaTeXSheet
6
+ include LaTeXMixins
7
+ include TimeUtils
8
+ MINIPAGE_SIZE = "6cm".freeze
9
+ def initialize(output_file, projects, config)
10
+ @config = config || {}
11
+ config_file_sanity_check({
12
+ "namespaces" => Hash,
13
+ "tags" => Hash
14
+ })
15
+
16
+ @external_commits = projects.select(&:externals) || []
17
+ @projects = projects # TODO: remove finished?
18
+ str = sheet_header
19
+ str << document do
20
+ [
21
+ week_line,
22
+ [
23
+ event_writeins,
24
+ past_due,
25
+ upcoming_due
26
+ ].compact.join,
27
+ # Since the following are a lot more volatile in minipage length,
28
+ # sort by newline so more fits on the page
29
+ [
30
+ external_commits,
31
+ works_in_progress,
32
+ tag_minipages,
33
+ namespace_minipages,
34
+ recurring_defer
35
+ ].flatten.compact.sort_by { |x| x.count("\n") }.join
36
+ ].flatten.join
37
+ end
38
+ puts "Writing to #{output_file}"
39
+ File.write(output_file, str)
40
+ end
41
+
42
+ def namespace_minipages
43
+ @config["namespaces"].map do |namespace, limit|
44
+ projects = @projects.select { |x| x.namespace == namespace }
45
+ project_minipage namespace, projects_in_time(projects, limit)
46
+ end&.join
47
+ end
48
+
49
+ def tag_minipages
50
+ @config["tags"].map do |tag, limit|
51
+ projects = @projects.select { |x| x&.tags&.any?(tag) }
52
+ project_minipage pretty_tag_name(tag), projects_in_time(projects, limit)
53
+ end&.join
54
+ end
55
+
56
+ def works_in_progress
57
+ projects = @projects.select(&:wip?)
58
+ project_minipage "Works in progress", projects if projects
59
+ end
60
+
61
+ def past_due
62
+ projects = @projects.select { |x| x.due ? x.due < Date.today : false }
63
+ project_minipage "Past due", projects if projects
64
+ end
65
+
66
+ def recurring_defer
67
+ projects = @projects.select { |x| x.last_for ? x.last_for_deferral < Date.today + 8 : false }
68
+ project_minipage "Recurring defer", projects if projects
69
+ end
70
+
71
+ def upcoming_due
72
+ projects = @projects.select { |x| x.due ? (x.due >= Date.today && x.due < Date.today + 8) : false }
73
+ project_minipage "Upcoming due", projects if projects
74
+ end
75
+
76
+ def external_commits
77
+ project_minipage("Externals", @external_commits) unless @external_commits&.empty?
78
+ end
79
+
80
+ def event_writeins
81
+ minipage(MINIPAGE_SIZE) do
82
+ "Events:\n#{
83
+ itemize_tightlist do
84
+ 7.times.map do |n|
85
+ itemline(
86
+ writein_line("4cm"),
87
+ opt: (Date.today + n).strftime("%a %m-%d")
88
+ )
89
+ end.join.concat("\n")
90
+ end
91
+ }"
92
+ end
93
+ end
94
+
95
+ def pretty_tag_name(tag)
96
+ tag.capitalize.gsub("_", " ")
97
+ end
98
+
99
+ def project_minipage(thing, projects = [])
100
+ unless projects&.empty?
101
+ minipage(MINIPAGE_SIZE) do
102
+ "#{thing}:
103
+ #{itemize_tightlist do
104
+ projects&.map do |x|
105
+ itemline("#{x.name} #{x&.time_estimate}", opt: SQUARE)
106
+ end&.join("\n")
107
+ end
108
+ }"
109
+ end
110
+ end
111
+ end
112
+
113
+ DEFAULT_PROJECT_TIME_ESTIMATE_MIN = 120
114
+ def projects_in_time(projects, time)
115
+ projects ||= []
116
+ t = parse_time_duration(time)
117
+ p = []
118
+ projects.each do |proj|
119
+ e = proj&.time_estimate ? parse_time_duration(proj.time_estimate) : DEFAULT_PROJECT_TIME_ESTIMATE_MIN
120
+ if e <= t
121
+ p.append proj
122
+ t -= e
123
+ end
124
+ end
125
+ p
126
+ end
127
+
128
+ def week_line
129
+ "For the next week: #{Date.today} - #{Date.today + 7}\n\n"
130
+ end
131
+ end
132
+ end
@@ -1,3 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "sheet/latex_utils"
3
4
  require_relative "sheet/latex"
5
+ require_relative "sheet/daily"
6
+ require_relative "sheet/weekly"
7
+ require_relative "sheet/monthly"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Plansheet
4
- VERSION = "0.30.1"
4
+ VERSION = "0.34.1"
5
5
  end
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.30.1
4
+ version: 0.34.1
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-28 00:00:00.000000000 Z
11
+ date: 2022-09-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dc-kwalify
@@ -63,7 +63,6 @@ files:
63
63
  - ".rubocop.yml"
64
64
  - CODE_OF_CONDUCT.md
65
65
  - Gemfile
66
- - Gemfile.lock
67
66
  - Guardfile
68
67
  - LICENSE.txt
69
68
  - README.md
@@ -76,7 +75,11 @@ files:
76
75
  - lib/plansheet/project/stringify.rb
77
76
  - lib/plansheet/project/yaml.rb
78
77
  - lib/plansheet/sheet.rb
78
+ - lib/plansheet/sheet/daily.rb
79
79
  - lib/plansheet/sheet/latex.rb
80
+ - lib/plansheet/sheet/latex_utils.rb
81
+ - lib/plansheet/sheet/monthly.rb
82
+ - lib/plansheet/sheet/weekly.rb
80
83
  - lib/plansheet/time.rb
81
84
  - lib/plansheet/version.rb
82
85
  homepage: https://dafyddcrosby.com
data/Gemfile.lock DELETED
@@ -1,108 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- plansheet (0.30.1)
5
- dc-kwalify (~> 1.0)
6
- diffy (= 3.4.2)
7
- rgl (= 0.5.8)
8
-
9
- GEM
10
- remote: https://rubygems.org/
11
- specs:
12
- ast (2.4.2)
13
- coderay (1.1.3)
14
- dc-devtools (0.0.202207232239)
15
- dc-rubocop (>= 0.0.3)
16
- guard (~> 2.18)
17
- guard-rake (~> 1.0)
18
- minitest
19
- rake (~> 13.0)
20
- rubocop (~> 1.30)
21
- rubocop-minitest
22
- rubocop-rake (~> 0.6)
23
- dc-kwalify (1.0.0)
24
- dc-rubocop (0.0.3)
25
- rubocop
26
- diffy (3.4.2)
27
- ffi (1.15.5)
28
- formatador (1.1.0)
29
- generator (0.0.1)
30
- guard (2.18.0)
31
- formatador (>= 0.2.4)
32
- listen (>= 2.7, < 4.0)
33
- lumberjack (>= 1.0.12, < 2.0)
34
- nenv (~> 0.1)
35
- notiffany (~> 0.0)
36
- pry (>= 0.13.0)
37
- shellany (~> 0.0)
38
- thor (>= 0.18.1)
39
- guard-rake (1.0.0)
40
- guard
41
- rake
42
- json (2.6.2)
43
- lazy_priority_queue (0.1.1)
44
- listen (3.7.1)
45
- rb-fsevent (~> 0.10, >= 0.10.3)
46
- rb-inotify (~> 0.9, >= 0.9.10)
47
- lumberjack (1.2.8)
48
- method_source (1.0.0)
49
- minitest (5.16.2)
50
- nenv (0.3.0)
51
- notiffany (0.1.3)
52
- nenv (~> 0.1)
53
- shellany (~> 0.0)
54
- parallel (1.22.1)
55
- parser (3.1.2.0)
56
- ast (~> 2.4.1)
57
- pry (0.14.1)
58
- coderay (~> 1.1)
59
- method_source (~> 1.0)
60
- psych (4.0.4)
61
- stringio
62
- rainbow (3.1.1)
63
- rake (13.0.6)
64
- rb-fsevent (0.11.1)
65
- rb-inotify (0.10.1)
66
- ffi (~> 1.0)
67
- rdoc (6.4.0)
68
- psych (>= 4.0.0)
69
- regexp_parser (2.5.0)
70
- rexml (3.2.5)
71
- rgl (0.5.8)
72
- lazy_priority_queue (~> 0.1.0)
73
- rexml (~> 3.2, >= 3.2.4)
74
- stream (~> 0.5.3)
75
- rubocop (1.32.0)
76
- json (~> 2.3)
77
- parallel (~> 1.10)
78
- parser (>= 3.1.0.0)
79
- rainbow (>= 2.2.2, < 4.0)
80
- regexp_parser (>= 1.8, < 3.0)
81
- rexml (>= 3.2.5, < 4.0)
82
- rubocop-ast (>= 1.19.1, < 2.0)
83
- ruby-progressbar (~> 1.7)
84
- unicode-display_width (>= 1.4.0, < 3.0)
85
- rubocop-ast (1.19.1)
86
- parser (>= 3.1.1.0)
87
- rubocop-minitest (0.20.1)
88
- rubocop (>= 0.90, < 2.0)
89
- rubocop-rake (0.6.0)
90
- rubocop (~> 1.0)
91
- ruby-progressbar (1.11.0)
92
- shellany (0.0.1)
93
- stream (0.5.4)
94
- generator
95
- stringio (3.0.2)
96
- thor (1.2.1)
97
- unicode-display_width (2.2.0)
98
-
99
- PLATFORMS
100
- x86_64-linux
101
-
102
- DEPENDENCIES
103
- dc-devtools
104
- plansheet!
105
- rdoc
106
-
107
- BUNDLED WITH
108
- 2.3.6