plansheet 0.3.1 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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