plansheet 0.2.0 → 0.5.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: 7ccfb13735d8626143db08903deac727870c66e6bd6fec21648fd70bf4050727
4
- data.tar.gz: 847f0a0f78cdb0035ee03829f2761e3780fb6296738ac89bcca55635079b9e3a
3
+ metadata.gz: 3546f42fdd342ea128be90bff2e19b7bcb5c0910990e2132b89b87cbf6a1f776
4
+ data.tar.gz: 2ea5d505262832e19e77a63e7aa7c59c9fff0b98ddc3ee8218c68b010f4768eb
5
5
  SHA512:
6
- metadata.gz: 34835dc03602c977afb76a4b5202f3ccf7322445086550d11d6506a4cce329f437d1f1a650b8500f46f6f81d72879f8a0ed506ed087411c68c1362b50523aeb8
7
- data.tar.gz: ff0832cc110fa2f8ab2350867aa9c3642cc4eeb6ad9bea9cb620e69dceb4afe5f8e139d9c23f4d9bfd5270000ebc4f5885d1a6cce5ea5db2270edd3caf277428
6
+ metadata.gz: 335cb1a3e74ab82a1441ec034099427dc0caabaad8a87c1f2620c7143d1fd4772023fe089a7305063fb12a96d169e44dd0b01f8f20437f45bdfa945b03aa2422
7
+ data.tar.gz: 5d618d61c6a07d8e32e46cfb4dba5df0264370f01d8b4ecef4c68f9fdcf6fcf600ca33bda0a8918e63992434e2a009e4d836f1f838851e0ee94de53128fe1ab2
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 CHANGED
@@ -6,7 +6,7 @@ source "https://rubygems.org"
6
6
  gemspec
7
7
 
8
8
  group :development, optional: true do
9
- gem "rake", "~> 13.0"
10
9
  gem "minitest", "~> 5.0"
10
+ gem "rake", "~> 13.0"
11
11
  gem "rubocop", "~> 1.21"
12
12
  end
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- plansheet (0.2.0)
4
+ plansheet (0.5.1)
5
5
  dc-kwalify (~> 1.0)
6
6
 
7
7
  GEM
@@ -0,0 +1,10 @@
1
+ - project: Add snazzy patches to backpack
2
+ status: planning
3
+ tasks:
4
+ - gather patches around the house in one spot
5
+ - determine which patches to put on
6
+ - find thread that matches patch colors
7
+ - plug in sewing machine
8
+ - put thread onto bobbin
9
+ - sew patches onto backpack
10
+
data/exe/plansheet CHANGED
@@ -1,77 +1,39 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- require "yaml"
5
-
6
- begin
7
- config = YAML.load_file "#{Dir.home}/.plansheet.yml"
8
- rescue StandardError
9
- abort "unable to load plansheet config file"
10
- end
11
-
12
- status_priority = {
13
- "wip" => 1,
14
- "ready" => 2,
15
- "blocked" => 3,
16
- "planning" => 4,
17
- "idea" => 5,
18
- "dropped" => 6,
19
- "done" => 7
20
- }
21
-
22
- project_hash = {}
23
- projects = Dir.glob("*yml", base: config["projects_dir"])
24
- projects.each do |l|
25
- contents = YAML.load_file(File.join(config["projects_dir"], l))
26
- key = l.gsub(".yml", "")
27
- contents.each do |project|
28
- key = project["project"]
29
- project_hash[key] = {
30
- name: project["project"]
31
- }
32
- %w[tasks desc done].each do |k|
33
- project_hash[key][k.to_sym] = project[k] if project[k]
34
- end
35
- project_hash[key][:status] = if project["status"]
36
- project["status"]
37
- elsif project_hash[key][:tasks]
38
- "planning"
39
- else
40
- "idea"
41
- end
4
+ require "plansheet"
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.each do |proj|
36
+ puts proj
37
+ puts "\n"
42
38
  end
43
39
  end
44
-
45
- sorted_hash = project_hash.sort_by { |_, v| status_priority[v[:status]] }
46
-
47
- def project_minipage(proj)
48
- p proj
49
- str = String.new
50
- str << "\\begin{minipage}{5cm}\n"
51
- str << "#{proj[:name]} - #{proj[:status]} \\\\\n"
52
- proj[:tasks]&.each do |t|
53
- str << "$\\square$ #{t} \\\\\n"
54
- end
55
- str << "\\end{minipage}\n"
56
- str
57
- end
58
-
59
- require "date"
60
- projects_str = String.new
61
- projects_str << <<~FRONTMATTER
62
- ---
63
- geometry: margin=3cm
64
- ---
65
- \\thispagestyle{empty}
66
-
67
- # Date: #{Date.today}
68
- FRONTMATTER
69
-
70
- sorted_hash.first(30).each do |_, p|
71
- projects_str << project_minipage(p)
72
- end
73
-
74
- Dir.mkdir config["output_dir"] unless Dir.exist? config["output_dir"]
75
- f = File.open("#{config["output_dir"]}/projects.md", "w")
76
- f.write(projects_str)
77
- f.close
@@ -0,0 +1,152 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "yaml"
4
+
5
+ module Plansheet
6
+ PROJECT_STATUS_PRIORITY = {
7
+ "wip" => 1,
8
+ "ready" => 2,
9
+ "blocked" => 3,
10
+ "planning" => 4,
11
+ "idea" => 5,
12
+ "dropped" => 6,
13
+ "done" => 7
14
+ }.freeze
15
+
16
+ # Once there's some stability in plansheet and dc-kwalify, will pre-load this
17
+ # to save the later YAML.load
18
+ PROJECT_YAML_SCHEMA = <<~YAML
19
+ desc: dc-tasks project schema
20
+ type: seq
21
+ sequence:
22
+ - type: map
23
+ mapping:
24
+ "project":
25
+ desc: Project name
26
+ type: str
27
+ required: yes
28
+ "status":
29
+ desc: The current status of the project
30
+ type: str
31
+ enum:
32
+ - wip # project is a work-in-progress
33
+ - ready # project is fully scoped, ready to go
34
+ - blocked # project is blocked, but otherwise ready/wip
35
+ - planning # project in planning phase
36
+ - idea # project is little more than an idea
37
+ - dropped # project has been explicitly dropped, but
38
+ # want to keep around for reference, etc
39
+ - done # project is finished, but want to keep around
40
+ # for reference, etc.
41
+ "priority":
42
+ desc: Project priority (not currently implemented)
43
+ type: str
44
+ enum:
45
+ - high
46
+ - low
47
+ "location":
48
+ desc: Location (not currently implemented)
49
+ type: str
50
+ "tasks":
51
+ desc: List of tasks to do
52
+ type: seq
53
+ sequence:
54
+ - type: str
55
+ "done":
56
+ desc: List of tasks which have been completed
57
+ type: seq
58
+ sequence:
59
+ - type: str
60
+ "notes":
61
+ desc: Free-form notes string
62
+ type: str
63
+ YAML
64
+ PROJECT_SCHEMA = YAML.safe_load(PROJECT_YAML_SCHEMA)
65
+ class Project
66
+ attr_reader :name, :tasks, :done, :notes, :location
67
+
68
+ def initialize(options)
69
+ @name = options["project"]
70
+
71
+ @tasks = options["tasks"] || []
72
+ @done = options["done"] || []
73
+
74
+ @notes = options["notes"] if options["notes"]
75
+ @location = options["location"] if options["location"]
76
+ @status = options["status"] if options["status"]
77
+ end
78
+
79
+ def status
80
+ return @status if @status
81
+
82
+ if @tasks.count.positive?
83
+ if @done.count.positive?
84
+ "wip"
85
+ else
86
+ "planning"
87
+ end
88
+ else
89
+ "idea"
90
+ end
91
+ end
92
+
93
+ def to_s
94
+ str = String.new
95
+ str << "# #{@name}\n"
96
+ str << "status: #{status}\n"
97
+ str << "notes: #{notes}\n" unless @notes.nil?
98
+ str << "location: #{location}\n" unless @location.nil?
99
+ str << "tasks:\n" unless @tasks.empty?
100
+ @tasks.each do |t|
101
+ str << "- #{t}\n"
102
+ end
103
+ str << "done:\n" unless @done.empty?
104
+ @done.each do |d|
105
+ str << "- #{d}\n"
106
+ end
107
+ str
108
+ end
109
+ def to_h
110
+ h = { "project" => @name }
111
+ h["status"] = status unless status == "idea"
112
+ h["notes"] = @notes unless @notes.nil?
113
+ h["location"] = @location unless @location.nil?
114
+ h["tasks"] = @tasks unless @tasks.empty?
115
+ h["done"] = @done unless @done.empty?
116
+ h
117
+ end
118
+ end
119
+
120
+ class ProjectYAMLFile
121
+ attr_reader :projects
122
+
123
+ def initialize(path)
124
+ @path = path
125
+ # TODO: this won't GC, inline validation instead?
126
+ @raw = YAML.load_file(path)
127
+ validate_schema
128
+ @projects = @raw.map { |proj| Project.new proj }
129
+ end
130
+
131
+ def validate_schema
132
+ validator = Kwalify::Validator.new(Plansheet::PROJECT_SCHEMA)
133
+ errors = validator.validate(@raw)
134
+ # Check YAML validity
135
+ if errors && !errors.empty?
136
+ $stderr.write "Schema errors in #{l}\n"
137
+ errors.each { |err| puts "- [#{err.path}] #{err.message}" }
138
+ abort
139
+ end
140
+ end
141
+
142
+ def sort!
143
+ @projects.sort_by! do |project|
144
+ Plansheet::PROJECT_STATUS_PRIORITY[project.status]
145
+ end
146
+ end
147
+
148
+ def yaml_dump
149
+ YAML.dump(@projects.map(&:to_h))
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,52 @@
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_by do |p|
9
+ Plansheet::PROJECT_STATUS_PRIORITY[p.status]
10
+ end
11
+
12
+ projects_str = String.new
13
+ projects_str << sheet_header
14
+
15
+ sorted_arr.first(60).each do |p|
16
+ projects_str << project_minipage(p)
17
+ end
18
+ puts "Writing to #{output_file}"
19
+ File.write(output_file, projects_str)
20
+ end
21
+
22
+ def sheet_header
23
+ <<~FRONTMATTER
24
+ ---
25
+ geometry: margin=1.5cm
26
+ ---
27
+ \\thispagestyle{empty}
28
+
29
+ # Date: #{Date.today}
30
+ FRONTMATTER
31
+ end
32
+
33
+ def project_minipage(proj)
34
+ str = String.new
35
+ str << "\\begin{minipage}{4.5cm}\n"
36
+ str << project_header(proj)
37
+ proj.tasks.each do |t|
38
+ str << "$\\square$ #{t} \\\\\n"
39
+ end
40
+ str << "\\end{minipage}\n"
41
+ str
42
+ end
43
+
44
+ def project_header(proj)
45
+ str = String.new
46
+ str << "#{proj.name} - #{proj.status}"
47
+ str << " - #{proj.location}" if proj.location
48
+ str << " \\\\\n"
49
+ str
50
+ end
51
+ end
52
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Plansheet
4
- VERSION = "0.2.0"
4
+ VERSION = "0.5.1"
5
5
  end
data/lib/plansheet.rb CHANGED
@@ -1,8 +1,36 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "plansheet/version"
4
+ require_relative "plansheet/project"
5
+ require_relative "plansheet/sheet"
6
+ require "yaml"
7
+ require "kwalify"
4
8
 
5
9
  module Plansheet
6
10
  class Error < StandardError; end
7
- # 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
8
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.2.0
4
+ version: 0.5.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-19 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:
@@ -40,16 +39,18 @@ files:
40
39
  - LICENSE.txt
41
40
  - README.md
42
41
  - Rakefile
42
+ - examples/backpack.yml
43
43
  - exe/plansheet
44
- - exe/plansheet-sorter
45
44
  - lib/plansheet.rb
45
+ - lib/plansheet/project.rb
46
+ - lib/plansheet/sheet.rb
46
47
  - lib/plansheet/version.rb
47
- - project.schema.yaml
48
48
  homepage: https://dafyddcrosby.com
49
49
  licenses:
50
50
  - MIT
51
51
  metadata:
52
52
  homepage_uri: https://dafyddcrosby.com
53
+ rubygems_mfa_required: 'true'
53
54
  post_install_message:
54
55
  rdoc_options: []
55
56
  require_paths:
data/exe/plansheet-sorter DELETED
@@ -1,32 +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
-
8
- status_priority = {
9
- "wip" => 1,
10
- "ready" => 2,
11
- "blocked" => 3,
12
- "planning" => 4,
13
- "idea" => 5,
14
- "dropped" => 6,
15
- "done" => 7
16
- }
17
-
18
- def project_priority(project)
19
- if project["status"]
20
- project["status"]
21
- elsif project["tasks"]
22
- "planning"
23
- else
24
- "idea"
25
- end
26
- end
27
-
28
- filename = ARGV.first
29
- contents = YAML.load_file(filename)
30
- sorted_hash = contents.sort_by { |project| status_priority[project_priority project] }
31
-
32
- File.write(filename, YAML.dump(sorted_hash))
data/project.schema.yaml DELETED
@@ -1,41 +0,0 @@
1
- desc: dc-tasks project schema
2
- type: seq
3
- sequence:
4
- - type: map
5
- mapping:
6
- "project":
7
- desc: Project name
8
- type: str
9
- required: yes
10
- "status":
11
- desc: The current status of the project
12
- type: str
13
- enum:
14
- - wip # project is a work-in-progress
15
- - ready # project is fully scoped, ready to go
16
- - blocked # project is blocked, but otherwise ready/wip
17
- - planning # project in planning phase
18
- - idea # project is little more than an idea
19
- - dropped # project has been explicitly dropped, but
20
- # want to keep around for reference, etc
21
- - done # project is finished, but want to keep around
22
- # for reference, etc.
23
- "priority":
24
- desc: Project priority (not currently implemented)
25
- type: str
26
- enum:
27
- - high
28
- - low
29
- "tasks":
30
- desc: List of tasks to do
31
- type: seq
32
- sequence:
33
- - type: str
34
- "done":
35
- desc: List of tasks which have been completed
36
- type: seq
37
- sequence:
38
- - type: str
39
- "notes":
40
- desc: Free-form notes string
41
- type: str