plansheet 0.15.0 → 0.17.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 +4 -4
- data/Gemfile +1 -0
- data/Gemfile.lock +16 -1
- data/exe/plansheet +17 -1
- data/lib/plansheet/pool.rb +56 -5
- data/lib/plansheet/project/yaml.rb +3 -1
- data/lib/plansheet/project.rb +33 -30
- data/lib/plansheet/sheet.rb +3 -4
- data/lib/plansheet/version.rb +1 -1
- data/lib/plansheet.rb +0 -3
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4c094d7236b6603dcab810d785eab766754e0cd9f161a2cb2daf280962b41026
|
4
|
+
data.tar.gz: 2686468ff7aa21915ff73ff27c49990cd05c2dc4e75c139837a69c1580a49dd5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 646ede4ae64522cfc33912eaefae96083de293800647700ec04b2569fe305d40bf7855a0780c63262db5fdaa5adf8472dba4790bd5f0b60228acc7a921b84417
|
7
|
+
data.tar.gz: 0c56e57fa79c225d9c3edf055e5c033e9bb9c5b63a49d2d1e7ae1bc17e3c1298e086af4c06d88d270fe9a6e83f3d6f67bba6c4f65f09afbcaf80ed46570f4a3f
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
plansheet (0.
|
4
|
+
plansheet (0.17.1)
|
5
5
|
dc-kwalify (~> 1.0)
|
6
|
+
rgl (= 0.5.8)
|
6
7
|
|
7
8
|
GEM
|
8
9
|
remote: https://rubygems.org/
|
@@ -12,6 +13,7 @@ GEM
|
|
12
13
|
dc-kwalify (1.0.0)
|
13
14
|
ffi (1.15.5)
|
14
15
|
formatador (1.1.0)
|
16
|
+
generator (0.0.1)
|
15
17
|
guard (2.18.0)
|
16
18
|
formatador (>= 0.2.4)
|
17
19
|
listen (>= 2.7, < 4.0)
|
@@ -25,6 +27,7 @@ GEM
|
|
25
27
|
guard-minitest (2.4.6)
|
26
28
|
guard-compat (~> 1.2)
|
27
29
|
minitest (>= 3.0)
|
30
|
+
lazy_priority_queue (0.1.1)
|
28
31
|
listen (3.7.1)
|
29
32
|
rb-fsevent (~> 0.10, >= 0.10.3)
|
30
33
|
rb-inotify (~> 0.9, >= 0.9.10)
|
@@ -41,13 +44,21 @@ GEM
|
|
41
44
|
pry (0.14.1)
|
42
45
|
coderay (~> 1.1)
|
43
46
|
method_source (~> 1.0)
|
47
|
+
psych (4.0.4)
|
48
|
+
stringio
|
44
49
|
rainbow (3.1.1)
|
45
50
|
rake (13.0.6)
|
46
51
|
rb-fsevent (0.11.1)
|
47
52
|
rb-inotify (0.10.1)
|
48
53
|
ffi (~> 1.0)
|
54
|
+
rdoc (6.4.0)
|
55
|
+
psych (>= 4.0.0)
|
49
56
|
regexp_parser (2.4.0)
|
50
57
|
rexml (3.2.5)
|
58
|
+
rgl (0.5.8)
|
59
|
+
lazy_priority_queue (~> 0.1.0)
|
60
|
+
rexml (~> 3.2, >= 3.2.4)
|
61
|
+
stream (~> 0.5.3)
|
51
62
|
rubocop (1.29.1)
|
52
63
|
parallel (~> 1.10)
|
53
64
|
parser (>= 3.1.0.0)
|
@@ -65,6 +76,9 @@ GEM
|
|
65
76
|
rubocop (~> 1.0)
|
66
77
|
ruby-progressbar (1.11.0)
|
67
78
|
shellany (0.0.1)
|
79
|
+
stream (0.5.4)
|
80
|
+
generator
|
81
|
+
stringio (3.0.2)
|
68
82
|
thor (1.2.1)
|
69
83
|
unicode-display_width (2.1.0)
|
70
84
|
|
@@ -77,6 +91,7 @@ DEPENDENCIES
|
|
77
91
|
minitest (~> 5.0)
|
78
92
|
plansheet!
|
79
93
|
rake (~> 13.0)
|
94
|
+
rdoc
|
80
95
|
rubocop (~> 1.21)
|
81
96
|
rubocop-minitest
|
82
97
|
rubocop-rake
|
data/exe/plansheet
CHANGED
@@ -17,6 +17,10 @@ parser.on(
|
|
17
17
|
"--cli",
|
18
18
|
"CLI dump of projects (WIP)"
|
19
19
|
)
|
20
|
+
parser.on(
|
21
|
+
"--calendar",
|
22
|
+
"List of projects ordered by due date"
|
23
|
+
)
|
20
24
|
parser.on(
|
21
25
|
"--location_filter LOCATION",
|
22
26
|
"location filter for CLI dump (WIP)"
|
@@ -25,14 +29,26 @@ options = {}
|
|
25
29
|
parser.parse!(into: options)
|
26
30
|
|
27
31
|
config = Plansheet.load_config
|
28
|
-
pool = Plansheet::Pool.new({ projects_dir: config["projects_dir"]
|
32
|
+
pool = Plansheet::Pool.new({ projects_dir: config["projects_dir"],
|
33
|
+
sort_order: config["sort_order"] })
|
29
34
|
|
30
35
|
if options[:sheet] || options.empty?
|
36
|
+
require "plansheet/sheet"
|
31
37
|
Dir.mkdir config["output_dir"] unless Dir.exist? config["output_dir"]
|
32
38
|
Plansheet::Sheet.new("#{config["output_dir"]}/projects.md", pool.projects)
|
33
39
|
elsif options[:sort]
|
34
40
|
# Pool sorts projects, this now just matches old behaviour
|
35
41
|
pool.write_projects
|
42
|
+
elsif options[:calendar]
|
43
|
+
# TODO: add a project filter method
|
44
|
+
project_arr = pool.projects
|
45
|
+
project_arr.delete_if { |x| x.status == "dropped" || x.status == "done" }
|
46
|
+
project_arr.delete_if { |x| x.due.nil? }
|
47
|
+
project_arr.sort_by!(&:due)
|
48
|
+
project_arr.each do |proj|
|
49
|
+
puts proj
|
50
|
+
puts "\n"
|
51
|
+
end
|
36
52
|
elsif options[:cli]
|
37
53
|
# TODO: add a project filter method
|
38
54
|
project_arr = pool.projects
|
data/lib/plansheet/pool.rb
CHANGED
@@ -1,21 +1,75 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "rgl/adjacency"
|
4
|
+
require "rgl/topsort"
|
5
|
+
|
3
6
|
module Plansheet
|
4
7
|
# The "pool" is the aggregated collection of projects, calendar events, etc.
|
5
8
|
class Pool
|
6
9
|
attr_accessor :projects
|
7
10
|
|
11
|
+
DEFAULT_COMPARISON_ORDER = %w[
|
12
|
+
completeness
|
13
|
+
dependency
|
14
|
+
priority
|
15
|
+
defer
|
16
|
+
due
|
17
|
+
status
|
18
|
+
].freeze
|
19
|
+
|
8
20
|
def initialize(config)
|
9
21
|
@projects_dir = config[:projects_dir]
|
22
|
+
@sort_order = config[:sort_order]
|
10
23
|
# @completed_projects_dir = config(:completed_projects_dir)
|
11
24
|
|
25
|
+
# This bit of trickiness is because we don't know what the sort order is
|
26
|
+
# until runtime. I'm sure this design decision definitely won't bite me
|
27
|
+
# in the future ;-) Fortunately, it's also not a problem that can't be
|
28
|
+
# walked back from.
|
29
|
+
if config[:sort_order]
|
30
|
+
self.class.const_set("POOL_COMPARISON_ORDER", config[:sort_order])
|
31
|
+
else
|
32
|
+
self.class.const_set("POOL_COMPARISON_ORDER", Plansheet::Pool::DEFAULT_COMPARISON_ORDER)
|
33
|
+
end
|
34
|
+
require_relative "project"
|
12
35
|
load_projects_dir(@projects_dir)
|
13
|
-
# TODO: Slurp all files
|
14
36
|
sort_projects
|
15
37
|
end
|
16
38
|
|
17
39
|
def sort_projects
|
18
40
|
@projects.sort!
|
41
|
+
# lookup_hash returns the index of a project
|
42
|
+
lookup_hash = Hash.new nil
|
43
|
+
|
44
|
+
# initialize the lookups
|
45
|
+
@projects.each_index do |i|
|
46
|
+
lookup_hash[@projects[i].name] = i
|
47
|
+
end
|
48
|
+
|
49
|
+
pg = RGL::DirectedAdjacencyGraph.new
|
50
|
+
pg.add_vertices @projects
|
51
|
+
@projects.each_index do |proj_index|
|
52
|
+
next if @projects[proj_index].dropped_or_done?
|
53
|
+
|
54
|
+
@projects[proj_index]&.dependencies&.each do |dep|
|
55
|
+
di = lookup_hash[dep]
|
56
|
+
if di
|
57
|
+
# Don't add edges for dropped/done projects, they'll be sorted out
|
58
|
+
# later
|
59
|
+
next if @projects[di].dropped_or_done?
|
60
|
+
|
61
|
+
pg.add_edge(@projects[di], @projects[proj_index])
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# The topological sort of pg is the correct dependency order of the
|
67
|
+
# projects
|
68
|
+
@projects = pg.topsort_iterator.to_a.flatten.uniq
|
69
|
+
|
70
|
+
# TODO: second sort doesn't deal with problems where deferred task gets
|
71
|
+
# pushed below.
|
72
|
+
@projects.sort!
|
19
73
|
end
|
20
74
|
|
21
75
|
def project_namespaces
|
@@ -31,10 +85,7 @@ module Plansheet
|
|
31
85
|
# are involved once completed project directories are a thing - will need
|
32
86
|
# to keep a list of project files to delete
|
33
87
|
project_namespaces.each do |ns|
|
34
|
-
|
35
|
-
#
|
36
|
-
f = "#{@projects_dir}/#{ns}.yml"
|
37
|
-
pyf = ProjectYAMLFile.new f
|
88
|
+
pyf = ProjectYAMLFile.new "#{@projects_dir}/#{ns}.yml"
|
38
89
|
pyf.projects = projects_in_namespace(ns)
|
39
90
|
pyf.write
|
40
91
|
end
|
@@ -4,6 +4,8 @@ require "yaml"
|
|
4
4
|
require "date"
|
5
5
|
require "pathname"
|
6
6
|
|
7
|
+
require "kwalify"
|
8
|
+
|
7
9
|
module Plansheet
|
8
10
|
# Once there's some stability in plansheet and dc-kwalify, will pre-load this
|
9
11
|
# to save the later YAML.load
|
@@ -161,7 +163,7 @@ module Plansheet
|
|
161
163
|
end
|
162
164
|
|
163
165
|
def yaml_dump
|
164
|
-
YAML.dump(@projects.map { |x| x.to_h.
|
166
|
+
YAML.dump(@projects.map { |x| x.to_h.delete_if { |k, _| k == "namespace" } })
|
165
167
|
end
|
166
168
|
end
|
167
169
|
end
|
data/lib/plansheet/project.rb
CHANGED
@@ -17,12 +17,6 @@ module Plansheet
|
|
17
17
|
"done" => 8
|
18
18
|
}.freeze
|
19
19
|
|
20
|
-
PROJECT_PRIORITY = {
|
21
|
-
"high" => 1,
|
22
|
-
"medium" => 2,
|
23
|
-
"low" => 3
|
24
|
-
}.freeze
|
25
|
-
|
26
20
|
def self.parse_date_duration(str)
|
27
21
|
return Regexp.last_match(1).to_i if str.strip.match(/(\d+)[dD]/)
|
28
22
|
return (Regexp.last_match(1).to_i * 7) if str.strip.match(/(\d+)[wW]/)
|
@@ -39,14 +33,13 @@ module Plansheet
|
|
39
33
|
class Project
|
40
34
|
include Comparable
|
41
35
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
].map { |x| "compare_#{x}".to_sym }.freeze
|
36
|
+
PROJECT_PRIORITY = {
|
37
|
+
"high" => 1,
|
38
|
+
"medium" => 2,
|
39
|
+
"low" => 3
|
40
|
+
}.freeze
|
41
|
+
|
42
|
+
COMPARISON_ORDER_SYMS = Plansheet::Pool::POOL_COMPARISON_ORDER.map { |x| "compare_#{x}".to_sym }.freeze
|
50
43
|
# NOTE: The order of these affects presentation!
|
51
44
|
# namespace is derived from file name
|
52
45
|
STRING_PROPERTIES = %w[priority status location notes time_estimate frequency lead_time].freeze
|
@@ -55,7 +48,7 @@ module Plansheet
|
|
55
48
|
|
56
49
|
ALL_PROPERTIES = STRING_PROPERTIES + DATE_PROPERTIES + ARRAY_PROPERTIES
|
57
50
|
|
58
|
-
attr_reader :name, *ALL_PROPERTIES
|
51
|
+
attr_reader :name, :priority_val, *ALL_PROPERTIES
|
59
52
|
attr_accessor :namespace
|
60
53
|
|
61
54
|
def initialize(options)
|
@@ -76,12 +69,16 @@ module Plansheet
|
|
76
69
|
# date/external commits/penalties for project failure, etc
|
77
70
|
#
|
78
71
|
# Assume all projects are low priority unless stated otherwise.
|
79
|
-
@
|
72
|
+
@priority_val = if @priority
|
73
|
+
PROJECT_PRIORITY[@priority]
|
74
|
+
else
|
75
|
+
PROJECT_PRIORITY["low"]
|
76
|
+
end
|
80
77
|
end
|
81
78
|
|
82
79
|
def <=>(other)
|
83
80
|
ret_val = 0
|
84
|
-
|
81
|
+
COMPARISON_ORDER_SYMS.each do |method|
|
85
82
|
ret_val = send(method, other)
|
86
83
|
break if ret_val != 0
|
87
84
|
end
|
@@ -89,7 +86,7 @@ module Plansheet
|
|
89
86
|
end
|
90
87
|
|
91
88
|
def compare_priority(other)
|
92
|
-
|
89
|
+
priority_val <=> other.priority_val
|
93
90
|
end
|
94
91
|
|
95
92
|
def compare_status(other)
|
@@ -117,19 +114,25 @@ module Plansheet
|
|
117
114
|
receiver <=> comparison
|
118
115
|
end
|
119
116
|
|
120
|
-
def
|
121
|
-
|
122
|
-
|
123
|
-
if @dependencies.nil?
|
124
|
-
return -1 if other.dependencies.any? do |dep|
|
125
|
-
@name.downcase == dep.downcase
|
126
|
-
end
|
127
|
-
elsif @dependencies.any? do |dep|
|
128
|
-
other.name.downcase == dep.downcase
|
129
|
-
end
|
130
|
-
return 1
|
117
|
+
def dependency_of?(other)
|
118
|
+
other&.dependencies&.any? do |dep|
|
119
|
+
@name&.downcase == dep.downcase
|
131
120
|
end
|
132
|
-
|
121
|
+
end
|
122
|
+
|
123
|
+
def dependent_on?(other)
|
124
|
+
@dependencies&.any? do |dep|
|
125
|
+
other&.name&.downcase == dep.downcase
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def compare_dependency(other)
|
130
|
+
# This approach might seem odd,
|
131
|
+
# but it's to handle circular dependencies
|
132
|
+
retval = 0
|
133
|
+
retval -= 1 if dependency_of?(other)
|
134
|
+
retval += 1 if dependent_on?(other)
|
135
|
+
retval
|
133
136
|
end
|
134
137
|
|
135
138
|
# Projects that are dropped or done are considered "complete", insofar as
|
data/lib/plansheet/sheet.rb
CHANGED
@@ -5,12 +5,10 @@ module Plansheet
|
|
5
5
|
# The Sheet class constructs a Markdown/LaTeX file for use with pandoc
|
6
6
|
class Sheet
|
7
7
|
def initialize(output_file, project_arr)
|
8
|
-
sorted_arr = project_arr.sort!
|
9
|
-
|
10
8
|
projects_str = String.new
|
11
9
|
projects_str << sheet_header
|
12
10
|
|
13
|
-
|
11
|
+
project_arr.each do |p|
|
14
12
|
projects_str << project_minipage(p)
|
15
13
|
end
|
16
14
|
puts "Writing to #{output_file}"
|
@@ -41,8 +39,9 @@ module Plansheet
|
|
41
39
|
|
42
40
|
def project_header(proj)
|
43
41
|
str = String.new
|
44
|
-
str << "#{proj.name} - #{proj.status}"
|
42
|
+
str << "#{proj.namespace}: #{proj.name} - #{proj.status}"
|
45
43
|
str << " - #{proj.location}" if proj.location
|
44
|
+
str << " - due #{proj.due}" if proj.due
|
46
45
|
str << " \\\\\n"
|
47
46
|
str
|
48
47
|
end
|
data/lib/plansheet/version.rb
CHANGED
data/lib/plansheet.rb
CHANGED
@@ -1,11 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative "plansheet/version"
|
4
|
-
require_relative "plansheet/project"
|
5
4
|
require_relative "plansheet/pool"
|
6
|
-
require_relative "plansheet/sheet"
|
7
5
|
require "yaml"
|
8
|
-
require "kwalify"
|
9
6
|
|
10
7
|
module Plansheet
|
11
8
|
class Error < StandardError; 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.
|
4
|
+
version: 0.17.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-06-
|
11
|
+
date: 2022-06-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dc-kwalify
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rgl
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.5.8
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.5.8
|
27
41
|
description: Convert YAML project files into a nice PDF
|
28
42
|
email:
|
29
43
|
- dave@dafyddcrosby.com
|