plansheet 0.3.3 → 0.6.1

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: e78fa7422ef53cce690b2d8500c406ac6bb2136d195725b3d839d67cc234c780
4
- data.tar.gz: 65093bd8b89bf39b2a144de85867bcb4635e41f5a8c379b8486c0a8a0135cebb
3
+ metadata.gz: 36b1a62d85f75f6fe04c0ad37b6d344dc9d9192a02d093283979986f09532935
4
+ data.tar.gz: 13a281430dfc803f940d05efa83c68758db7a4452912cfcfd6b5fe9a7247d69c
5
5
  SHA512:
6
- metadata.gz: a70d01f6617f79041d95e4a1b596f68c36de68a9be8abd7be684f3d394dd15a5d49bc0a7560435670fab7d5fc59dd505c1f4adee0aba68d7feaed46cc2f61bcb
7
- data.tar.gz: f63764aaaca3a1a7efa75c07f2776d279171dc297cee0d34306416690fb2b08f5c85697f7d1ebc1a40a03671727f3162f0293d552231405c0084438a61dfb9b6
6
+ metadata.gz: fc3b217bf90a0333dc9f09b011c1f09caba8977a0f19bdd0a3695b76c519da54a5f2144897af49ee6e4f726a8abddc35532c51895c1c37a30422ddd39118676b
7
+ data.tar.gz: a553efe99e604078e55ae0ea9cfdfa625a026a242ac92025e6600ebc5e04935c528a4d1807ecbe3a2a469ec6c37d3923cf22bad9c6f292d3ab79d1eca868c58b
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- plansheet (0.3.3)
4
+ plansheet (0.6.1)
5
5
  dc-kwalify (~> 1.0)
6
6
 
7
7
  GEM
data/exe/plansheet CHANGED
@@ -1,81 +1,39 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- require "kwalify"
5
- require "yaml"
6
4
  require "plansheet"
7
-
8
- begin
9
- config = YAML.load_file "#{Dir.home}/.plansheet.yml"
10
- rescue StandardError
11
- abort "unable to load plansheet config file"
12
- end
13
-
14
- project_hash = {}
15
- projects = Dir.glob("*yml", base: config["projects_dir"])
16
- projects.each do |l|
17
- contents = YAML.load_file(File.join(config["projects_dir"], l))
18
- validator = Kwalify::Validator.new(Plansheet::PROJECT_SCHEMA)
19
- errors = validator.validate(contents)
20
- # Check YAML validity
21
- if errors && !errors.empty?
22
- $stderr.write "Schema errors in #{l}\n"
23
- errors.each { |err| puts "- [#{err.path}] #{err.message}" }
24
- abort
25
- end
26
-
27
- key = l.gsub(".yml", "")
28
- contents.each do |project|
29
- key = project["project"]
30
- project_hash[key] = {
31
- name: project["project"]
32
- }
33
- %w[tasks desc done].each do |k|
34
- project_hash[key][k.to_sym] = project[k] if project[k]
35
- end
36
- project_hash[key][:status] = if project["status"]
37
- project["status"]
38
- elsif project_hash[key][:tasks]
39
- "planning"
40
- else
41
- "idea"
42
- 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"
43
38
  end
44
39
  end
45
-
46
- sorted_hash = project_hash.sort_by do |_, v|
47
- Plansheet::PROJECT_STATUS_PRIORITY[v[:status]]
48
- end
49
-
50
- def project_minipage(proj)
51
- str = String.new
52
- str << "\\begin{minipage}{5cm}\n"
53
- str << "#{proj[:name]} - #{proj[:status]} \\\\\n"
54
- proj[:tasks]&.each do |t|
55
- str << "$\\square$ #{t} \\\\\n"
56
- end
57
- str << "\\end{minipage}\n"
58
- str
59
- end
60
-
61
- require "date"
62
- projects_str = String.new
63
- projects_str << <<~FRONTMATTER
64
- ---
65
- geometry: margin=3cm
66
- ---
67
- \\thispagestyle{empty}
68
-
69
- # Date: #{Date.today}
70
- FRONTMATTER
71
-
72
- sorted_hash.first(60).each do |_, p|
73
- projects_str << project_minipage(p)
74
- end
75
-
76
- output_file = "#{config["output_dir"]}/projects.md"
77
- puts "Writing to #{output_file}"
78
- Dir.mkdir config["output_dir"] unless Dir.exist? config["output_dir"]
79
- f = File.open(output_file, "w")
80
- f.write(projects_str)
81
- 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 #{@path}:\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.3"
4
+ VERSION = "0.6.1"
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.3
4
+ version: 0.6.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-05-24 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,7 +29,6 @@ email:
29
29
  - dave@dafyddcrosby.com
30
30
  executables:
31
31
  - plansheet
32
- - plansheet-sorter
33
32
  extensions: []
34
33
  extra_rdoc_files: []
35
34
  files:
@@ -42,9 +41,9 @@ files:
42
41
  - Rakefile
43
42
  - examples/backpack.yml
44
43
  - exe/plansheet
45
- - exe/plansheet-sorter
46
44
  - lib/plansheet.rb
47
45
  - lib/plansheet/project.rb
46
+ - lib/plansheet/sheet.rb
48
47
  - lib/plansheet/version.rb
49
48
  homepage: https://dafyddcrosby.com
50
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))