plansheet 0.3.1 → 0.6.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bddf541a519a646283dbd872816140c667290b05fe81a38a79297e283f48f87b
4
- data.tar.gz: 49e9670228ddb622b9cc332f4bd5f8b943bf674b242851212aabfa6384a1162f
3
+ metadata.gz: 0df6d0d15bff6b0d639ea6561ad722308c02e00b1bd313649b952a48c7826ad4
4
+ data.tar.gz: 51faedcd44ccaeec7ee88a3e345bb8d5ae1597a5689324953a188e1725a465e2
5
5
  SHA512:
6
- metadata.gz: 697436e3c7dbc92323a321c75b23ef47a2c4c6f632f93bd4686a95a84b9edd4004691055d2aadfb75f802aaf1b4d88554f3a4f32e8e79942c4e073c65835dd5a
7
- data.tar.gz: 285490462d0ff27a9e3a81ae09baaac60754260e6a64fc15c5ad52887d2d1df815e41c84854b98cdbe07d5d6799ddb39f1fc99e52de4b44c41ea85e6b46f2bd0
6
+ metadata.gz: 0eb27167a0d754f27df229da3e2e12a07734a1e90f8d1a19374a6d408fd822d67286b31efbaa223eae61ec97931727ed4d3ea70e4211035cb8f2ea68f728f207
7
+ data.tar.gz: 646ed78dd6f00b145ad61778fc7462b1ee1a3f9c52df3b3e27347c5d30ac199b2b4ef914239dd1a586d2e575e9fe8d44f664d5e152075a8ca5211150b4034838
data/.rubocop.yml CHANGED
@@ -1,6 +1,7 @@
1
1
  AllCops:
2
2
  TargetRubyVersion: 2.6
3
3
  NewCops: enable
4
+ SuggestExtensions: false
4
5
 
5
6
  Style/StringLiterals:
6
7
  Enabled: true
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- plansheet (0.3.1)
4
+ plansheet (0.6.0)
5
5
  dc-kwalify (~> 1.0)
6
6
 
7
7
  GEM
data/exe/plansheet CHANGED
@@ -1,70 +1,39 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- require "yaml"
5
4
  require "plansheet"
6
-
7
- begin
8
- config = YAML.load_file "#{Dir.home}/.plansheet.yml"
9
- rescue StandardError
10
- abort "unable to load plansheet config file"
11
- end
12
-
13
- project_hash = {}
14
- projects = Dir.glob("*yml", base: config["projects_dir"])
15
- projects.each do |l|
16
- contents = YAML.load_file(File.join(config["projects_dir"], l))
17
- key = l.gsub(".yml", "")
18
- contents.each do |project|
19
- key = project["project"]
20
- project_hash[key] = {
21
- name: project["project"]
22
- }
23
- %w[tasks desc done].each do |k|
24
- project_hash[key][k.to_sym] = project[k] if project[k]
25
- end
26
- project_hash[key][:status] = if project["status"]
27
- project["status"]
28
- elsif project_hash[key][:tasks]
29
- "planning"
30
- else
31
- "idea"
32
- end
5
+ require "optparse"
6
+
7
+ parser = OptionParser.new
8
+ parser.on(
9
+ "--sheet",
10
+ "Generates MD/LaTeX project PDF"
11
+ )
12
+ parser.on(
13
+ "--sort",
14
+ "Sort project files"
15
+ )
16
+ parser.on(
17
+ "--cli",
18
+ "CLI dump of projects (WIP)"
19
+ )
20
+ options = {}
21
+ parser.parse!(into: options)
22
+
23
+ config = Plansheet.load_config
24
+
25
+ if options[:sheet] || options.empty?
26
+ project_arr = Plansheet.load_projects_dir config["projects_dir"]
27
+
28
+ Dir.mkdir config["output_dir"] unless Dir.exist? config["output_dir"]
29
+
30
+ Plansheet::Sheet.new("#{config["output_dir"]}/projects.md", project_arr)
31
+ elsif options[:sort]
32
+ Plansheet.resort_projects_in_dir config["projects_dir"]
33
+ elsif options[:cli]
34
+ project_arr = Plansheet.load_projects_dir config["projects_dir"]
35
+ project_arr.sort.each do |proj|
36
+ puts proj
37
+ puts "\n"
33
38
  end
34
39
  end
35
-
36
- sorted_hash = project_hash.sort_by do |_, v|
37
- Plansheet::PROJECT_STATUS_PRIORITY[v[:status]]
38
- end
39
-
40
- def project_minipage(proj)
41
- p proj
42
- str = String.new
43
- str << "\\begin{minipage}{5cm}\n"
44
- str << "#{proj[:name]} - #{proj[:status]} \\\\\n"
45
- proj[:tasks]&.each do |t|
46
- str << "$\\square$ #{t} \\\\\n"
47
- end
48
- str << "\\end{minipage}\n"
49
- str
50
- end
51
-
52
- require "date"
53
- projects_str = String.new
54
- projects_str << <<~FRONTMATTER
55
- ---
56
- geometry: margin=3cm
57
- ---
58
- \\thispagestyle{empty}
59
-
60
- # Date: #{Date.today}
61
- FRONTMATTER
62
-
63
- sorted_hash.first(60).each do |_, p|
64
- projects_str << project_minipage(p)
65
- end
66
-
67
- Dir.mkdir config["output_dir"] unless Dir.exist? config["output_dir"]
68
- f = File.open("#{config["output_dir"]}/projects.md", "w")
69
- f.write(projects_str)
70
- f.close
@@ -13,6 +13,17 @@ module Plansheet
13
13
  "done" => 7
14
14
  }.freeze
15
15
 
16
+ PROJECT_PRIORITY = {
17
+ "high" => 1,
18
+ "medium" => 2,
19
+ "low" => 3
20
+ }.freeze
21
+ PROJECT_PRIORITY_REV = {
22
+ 1 => "high",
23
+ 2 => "medium",
24
+ 3 => "low"
25
+ }.freeze
26
+
16
27
  # Once there's some stability in plansheet and dc-kwalify, will pre-load this
17
28
  # to save the later YAML.load
18
29
  PROJECT_YAML_SCHEMA = <<~YAML
@@ -39,11 +50,14 @@ module Plansheet
39
50
  - done # project is finished, but want to keep around
40
51
  # for reference, etc.
41
52
  "priority":
42
- desc: Project priority (not currently implemented)
53
+ desc: Project priority
43
54
  type: str
44
55
  enum:
45
56
  - high
46
57
  - low
58
+ "location":
59
+ desc: Location
60
+ type: str
47
61
  "tasks":
48
62
  desc: List of tasks to do
49
63
  type: seq
@@ -59,4 +73,108 @@ module Plansheet
59
73
  type: str
60
74
  YAML
61
75
  PROJECT_SCHEMA = YAML.safe_load(PROJECT_YAML_SCHEMA)
76
+ class Project
77
+ include Comparable
78
+ attr_reader :name, :tasks, :done, :notes, :location, :priority
79
+
80
+ def initialize(options)
81
+ @name = options["project"]
82
+
83
+ @tasks = options["tasks"] || []
84
+ @done = options["done"] || []
85
+
86
+ @notes = options["notes"] if options["notes"]
87
+ @priority = PROJECT_PRIORITY[options["priority"] || "medium"]
88
+ @location = options["location"] if options["location"]
89
+ @status = options["status"] if options["status"]
90
+ end
91
+
92
+ def <=>(other)
93
+ if @priority == other.priority
94
+ # TODO: if planning status, then sort based on tasks? category? alphabetically?
95
+ PROJECT_STATUS_PRIORITY[status] <=> PROJECT_STATUS_PRIORITY[other.status]
96
+ else
97
+ @priority <=> other.priority
98
+ end
99
+ end
100
+
101
+ # TODO: clean up priority handling
102
+ def priority_string
103
+ PROJECT_PRIORITY_REV[@priority]
104
+ end
105
+
106
+ def status
107
+ return @status if @status
108
+
109
+ if @tasks.count.positive?
110
+ if @done.count.positive?
111
+ "wip"
112
+ else
113
+ "planning"
114
+ end
115
+ else
116
+ "idea"
117
+ end
118
+ end
119
+
120
+ def to_s
121
+ str = String.new
122
+ str << "# #{@name}\n"
123
+ str << "priority: #{priority_string}\n"
124
+ str << "status: #{status}\n"
125
+ str << "notes: #{notes}\n" unless @notes.nil?
126
+ str << "location: #{location}\n" unless @location.nil?
127
+ str << "tasks:\n" unless @tasks.empty?
128
+ @tasks.each do |t|
129
+ str << "- #{t}\n"
130
+ end
131
+ str << "done:\n" unless @done.empty?
132
+ @done.each do |d|
133
+ str << "- #{d}\n"
134
+ end
135
+ str
136
+ end
137
+
138
+ def to_h
139
+ h = { "project" => @name }
140
+ h["priority"] = priority_string unless priority_string == "medium"
141
+ h["status"] = status unless status == "idea"
142
+ h["notes"] = @notes unless @notes.nil?
143
+ h["location"] = @location unless @location.nil?
144
+ h["tasks"] = @tasks unless @tasks.empty?
145
+ h["done"] = @done unless @done.empty?
146
+ h
147
+ end
148
+ end
149
+
150
+ class ProjectYAMLFile
151
+ attr_reader :projects
152
+
153
+ def initialize(path)
154
+ @path = path
155
+ # TODO: this won't GC, inline validation instead?
156
+ @raw = YAML.load_file(path)
157
+ validate_schema
158
+ @projects = @raw.map { |proj| Project.new proj }
159
+ end
160
+
161
+ def validate_schema
162
+ validator = Kwalify::Validator.new(Plansheet::PROJECT_SCHEMA)
163
+ errors = validator.validate(@raw)
164
+ # Check YAML validity
165
+ return unless errors && !errors.empty?
166
+
167
+ $stderr.write "Schema errors in #{l}\n"
168
+ errors.each { |err| puts "- [#{err.path}] #{err.message}" }
169
+ abort
170
+ end
171
+
172
+ def sort!
173
+ @projects.sort!
174
+ end
175
+
176
+ def yaml_dump
177
+ YAML.dump(@projects.map(&:to_h))
178
+ end
179
+ end
62
180
  end
@@ -0,0 +1,50 @@
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
+ sorted_arr = project_arr.sort!
9
+
10
+ projects_str = String.new
11
+ projects_str << sheet_header
12
+
13
+ sorted_arr.first(60).each do |p|
14
+ projects_str << project_minipage(p)
15
+ end
16
+ puts "Writing to #{output_file}"
17
+ File.write(output_file, projects_str)
18
+ end
19
+
20
+ def sheet_header
21
+ <<~FRONTMATTER
22
+ ---
23
+ geometry: margin=1.5cm
24
+ ---
25
+ \\thispagestyle{empty}
26
+
27
+ # Date: #{Date.today}
28
+ FRONTMATTER
29
+ end
30
+
31
+ def project_minipage(proj)
32
+ str = String.new
33
+ str << "\\begin{minipage}{4.5cm}\n"
34
+ str << project_header(proj)
35
+ proj.tasks.each do |t|
36
+ str << "$\\square$ #{t} \\\\\n"
37
+ end
38
+ str << "\\end{minipage}\n"
39
+ str
40
+ end
41
+
42
+ def project_header(proj)
43
+ str = String.new
44
+ str << "#{proj.name} - #{proj.status}"
45
+ str << " - #{proj.location}" if proj.location
46
+ str << " \\\\\n"
47
+ str
48
+ end
49
+ end
50
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Plansheet
4
- VERSION = "0.3.1"
4
+ VERSION = "0.6.0"
5
5
  end
data/lib/plansheet.rb CHANGED
@@ -2,8 +2,35 @@
2
2
 
3
3
  require_relative "plansheet/version"
4
4
  require_relative "plansheet/project"
5
+ require_relative "plansheet/sheet"
6
+ require "yaml"
7
+ require "kwalify"
5
8
 
6
9
  module Plansheet
7
10
  class Error < StandardError; end
8
- # Your code goes here...
11
+
12
+ def self.load_config
13
+ YAML.load_file "#{Dir.home}/.plansheet.yml"
14
+ rescue StandardError
15
+ abort "unable to load plansheet config file"
16
+ end
17
+
18
+ def self.resort_projects_in_dir(dir)
19
+ project_files = Dir.glob("#{dir}/*yml")
20
+ project_files.each do |f|
21
+ pyf = ProjectYAMLFile.new(f)
22
+ pyf.sort!
23
+ File.write(f, pyf.yaml_dump)
24
+ end
25
+ end
26
+
27
+ def self.load_projects_dir(dir)
28
+ project_arr = []
29
+ projects = Dir.glob("*yml", base: dir)
30
+ projects.each do |l|
31
+ project_arr << ProjectYAMLFile.new(File.join(dir, l)).projects
32
+ end
33
+
34
+ project_arr.flatten!
35
+ end
9
36
  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.3.1
4
+ version: 0.6.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-05-22 00:00:00.000000000 Z
11
+ date: 2022-05-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dc-kwalify
@@ -29,8 +29,6 @@ email:
29
29
  - dave@dafyddcrosby.com
30
30
  executables:
31
31
  - plansheet
32
- - plansheet-sorter
33
- - plansheet-validator
34
32
  extensions: []
35
33
  extra_rdoc_files: []
36
34
  files:
@@ -43,10 +41,9 @@ files:
43
41
  - Rakefile
44
42
  - examples/backpack.yml
45
43
  - exe/plansheet
46
- - exe/plansheet-sorter
47
- - exe/plansheet-validator
48
44
  - lib/plansheet.rb
49
45
  - lib/plansheet/project.rb
46
+ - lib/plansheet/sheet.rb
50
47
  - lib/plansheet/version.rb
51
48
  homepage: https://dafyddcrosby.com
52
49
  licenses:
data/exe/plansheet-sorter DELETED
@@ -1,25 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- # An ugly script to sort projects by status (and eventually priority)
5
-
6
- require "yaml"
7
- require "plansheet"
8
-
9
- def project_priority(project)
10
- if project["status"]
11
- project["status"]
12
- elsif project["tasks"]
13
- "planning"
14
- else
15
- "idea"
16
- end
17
- end
18
-
19
- filename = ARGV.first
20
- contents = YAML.load_file(filename)
21
- sorted_hash = contents.sort_by do |project|
22
- Plansheet::PROJECT_STATUS_PRIORITY[project_priority project]
23
- end
24
-
25
- File.write(filename, YAML.dump(sorted_hash))
@@ -1,19 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- require "plansheet"
5
- require "kwalify"
6
- require "yaml"
7
- require "pp"
8
-
9
- # TODO: yuck!
10
- filename = ARGV.first
11
- validator = Kwalify::Validator.new(Plansheet::PROJECT_SCHEMA)
12
- errors = validator.validate(YAML.load_file(filename))
13
- # Check YAML validity
14
- if errors && !errors.empty?
15
- errors.each do |err|
16
- puts "- [#{err.path}] #{err.message}"
17
- end
18
- abort "Schema errors in #{filename}"
19
- end