plansheet 0.7.1 → 0.12.3

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: d9c1a116df170c31d73c29dce213b757743c0e49bbee8c86a47ce7ce09009730
4
- data.tar.gz: 2baeb58d82c15823d9beb3e6504bb452e14cabded159f9931bf2300fdaed5d8f
3
+ metadata.gz: 72d3799f5166153c1775c768f0734cf0e390adfd80893ef1ae1aa710b7888b0b
4
+ data.tar.gz: a18fd6eeb6a787438ddcdff1e6b0f25a17688f05a7bccff82495520517754b19
5
5
  SHA512:
6
- metadata.gz: a87a4f7386a651ca82d385600f7b32ee78ff436406d596b6c2966ed721bdcee16f9bd4ad73b158be03305541dceda0d525e68ea2dc520a028fb603a6b5f0c1c0
7
- data.tar.gz: d679906ef154e9b84e9282e1811ac0dff8da8b4dfb17c6e0e24d7f08226933346c4229468ddf51526e7532af7bdfd9a502557b64efc6439c128716a380e86d86
6
+ metadata.gz: c97c83093f8e70948a96392b5d02329128c5f1031a0645b35b9c42bebeabb82192207c3ff71671081792ef3d61e9277c219984f0f558a7b54c1fac632fa68445
7
+ data.tar.gz: 6723401a02c2086976e1002e4f8d08855f25726d1610fd9f4e593ae3ceac707c47bb6a1114ec1b40f707295c1c627fd5b72cce5ebe45f84b78b24d8304107bcf
data/.rubocop.yml CHANGED
@@ -1,5 +1,3 @@
1
- inherit_from: .rubocop_todo.yml
2
-
3
1
  AllCops:
4
2
  TargetRubyVersion: 2.6
5
3
  NewCops: enable
@@ -15,3 +13,9 @@ Style/StringLiteralsInInterpolation:
15
13
 
16
14
  Layout/LineLength:
17
15
  Max: 120
16
+
17
+ Metrics:
18
+ Enabled: false
19
+
20
+ Style/Documentation:
21
+ Enabled: false
data/Gemfile CHANGED
@@ -6,7 +6,12 @@ source "https://rubygems.org"
6
6
  gemspec
7
7
 
8
8
  group :development, optional: true do
9
+ gem "guard", "~> 2.18"
10
+ gem "guard-minitest", "~> 2.4"
9
11
  gem "minitest", "~> 5.0"
10
12
  gem "rake", "~> 13.0"
13
+
11
14
  gem "rubocop", "~> 1.21"
15
+ gem "rubocop-minitest"
16
+ gem "rubocop-rake"
12
17
  end
data/Gemfile.lock CHANGED
@@ -1,20 +1,51 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- plansheet (0.7.1)
4
+ plansheet (0.12.3)
5
5
  dc-kwalify (~> 1.0)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
10
  ast (2.4.2)
11
+ coderay (1.1.3)
11
12
  dc-kwalify (1.0.0)
13
+ ffi (1.15.5)
14
+ formatador (1.1.0)
15
+ guard (2.18.0)
16
+ formatador (>= 0.2.4)
17
+ listen (>= 2.7, < 4.0)
18
+ lumberjack (>= 1.0.12, < 2.0)
19
+ nenv (~> 0.1)
20
+ notiffany (~> 0.0)
21
+ pry (>= 0.13.0)
22
+ shellany (~> 0.0)
23
+ thor (>= 0.18.1)
24
+ guard-compat (1.2.1)
25
+ guard-minitest (2.4.6)
26
+ guard-compat (~> 1.2)
27
+ minitest (>= 3.0)
28
+ listen (3.7.1)
29
+ rb-fsevent (~> 0.10, >= 0.10.3)
30
+ rb-inotify (~> 0.9, >= 0.9.10)
31
+ lumberjack (1.2.8)
32
+ method_source (1.0.0)
12
33
  minitest (5.15.0)
34
+ nenv (0.3.0)
35
+ notiffany (0.1.3)
36
+ nenv (~> 0.1)
37
+ shellany (~> 0.0)
13
38
  parallel (1.22.1)
14
39
  parser (3.1.2.0)
15
40
  ast (~> 2.4.1)
41
+ pry (0.14.1)
42
+ coderay (~> 1.1)
43
+ method_source (~> 1.0)
16
44
  rainbow (3.1.1)
17
45
  rake (13.0.6)
46
+ rb-fsevent (0.11.1)
47
+ rb-inotify (0.10.1)
48
+ ffi (~> 1.0)
18
49
  regexp_parser (2.4.0)
19
50
  rexml (3.2.5)
20
51
  rubocop (1.29.1)
@@ -28,17 +59,27 @@ GEM
28
59
  unicode-display_width (>= 1.4.0, < 3.0)
29
60
  rubocop-ast (1.18.0)
30
61
  parser (>= 3.1.1.0)
62
+ rubocop-minitest (0.20.0)
63
+ rubocop (>= 0.90, < 2.0)
64
+ rubocop-rake (0.6.0)
65
+ rubocop (~> 1.0)
31
66
  ruby-progressbar (1.11.0)
67
+ shellany (0.0.1)
68
+ thor (1.2.1)
32
69
  unicode-display_width (2.1.0)
33
70
 
34
71
  PLATFORMS
35
72
  x86_64-linux
36
73
 
37
74
  DEPENDENCIES
75
+ guard (~> 2.18)
76
+ guard-minitest (~> 2.4)
38
77
  minitest (~> 5.0)
39
78
  plansheet!
40
79
  rake (~> 13.0)
41
80
  rubocop (~> 1.21)
81
+ rubocop-minitest
82
+ rubocop-rake
42
83
 
43
84
  BUNDLED WITH
44
85
  2.3.6
data/Guardfile ADDED
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ directories(%w[lib test].select { |d| Dir.exist?(d) ? d : UI.warning("Directory #{d} does not exist") })
4
+
5
+ guard :minitest do
6
+ watch(%r{^test/test_(.*)\.rb$}) { "test" }
7
+ watch(%r{^lib/plansheet/(.*)\.rb$}) { "test" }
8
+ watch(%r{^lib/plansheet\.rb$}) { "test" }
9
+ end
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
+ "--location_filter LOCATION",
22
+ "location filter for CLI dump (WIP)"
23
+ )
20
24
  options = {}
21
25
  parser.parse!(into: options)
22
26
 
@@ -32,7 +36,10 @@ elsif options[:sort]
32
36
  Plansheet.resort_projects_in_dir config["projects_dir"]
33
37
  elsif options[:cli]
34
38
  project_arr = Plansheet.load_projects_dir config["projects_dir"]
35
- project_arr.sort.each do |proj|
39
+ project_arr.sort!
40
+ project_arr.delete_if { |x| x.status == "dropped" || x.status == "done" }
41
+ project_arr.select! { |x| x.location == options[:location_filter] } if options[:location_filter]
42
+ project_arr.each do |proj|
36
43
  puts proj
37
44
  puts "\n"
38
45
  end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Plansheet
4
+ class Project
5
+ def to_s
6
+ str = String.new
7
+ str << "# #{@name}\n"
8
+ STRING_PROPERTIES.each do |o|
9
+ str << stringify_string_property(o)
10
+ end
11
+ DATE_PROPERTIES.each do |o|
12
+ str << stringify_string_property(o)
13
+ end
14
+ ARRAY_PROPERTIES.each do |o|
15
+ str << stringify_array_property(o)
16
+ end
17
+ str
18
+ end
19
+
20
+ def stringify_string_property(prop)
21
+ if instance_variable_defined? "@#{prop}"
22
+ "#{prop}: #{instance_variable_get("@#{prop}")}\n"
23
+ else
24
+ ""
25
+ end
26
+ end
27
+
28
+ def stringify_date_property(prop)
29
+ if instance_variable_defined? "@#{prop}"
30
+ "#{prop}: #{instance_variable_get("@#{prop}")}\n"
31
+ else
32
+ ""
33
+ end
34
+ end
35
+
36
+ def stringify_array_property(prop)
37
+ str = String.new
38
+ if instance_variable_defined? "@#{prop}"
39
+ str << "#{prop}:\n"
40
+ instance_variable_get("@#{prop}").each do |t|
41
+ str << "- #{t}\n"
42
+ end
43
+ end
44
+ str
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,148 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "yaml"
4
+ require "date"
5
+
6
+ module Plansheet
7
+ # Once there's some stability in plansheet and dc-kwalify, will pre-load this
8
+ # to save the later YAML.load
9
+ PROJECT_YAML_SCHEMA = <<~YAML
10
+ desc: dc-tasks project schema
11
+ type: seq
12
+ sequence:
13
+ - type: map
14
+ mapping:
15
+ "project":
16
+ desc: Project name
17
+ type: str
18
+ required: yes
19
+ "priority":
20
+ desc: Project priority
21
+ type: str
22
+ enum:
23
+ - high
24
+ - medium
25
+ - low
26
+ "status":
27
+ desc: The current status of the project
28
+ type: str
29
+ enum:
30
+ - wip # project is a work-in-progress
31
+ - ready # project has tasks, ready to go
32
+ - waiting # project in waiting on some external person/event
33
+ - blocked # project is blocked by another project, but otherwise ready/wip
34
+ - planning # project in planning phase (set manually)
35
+ - idea # project is little more than an idea
36
+ - dropped # project has been explicitly dropped, but
37
+ # want to keep around for reference, etc
38
+ - done # project is finished, but want to keep around
39
+ # for reference, etc.
40
+ "location":
41
+ desc: Location
42
+ type: str
43
+ "notes":
44
+ desc: Free-form notes string
45
+ type: str
46
+ "time_estimate":
47
+ desc: The estimated amount of time before a project is completed
48
+ type: str
49
+ "frequency":
50
+ desc: The amount of time before a recurring project moves to ready status again from when it was last done (WIP)
51
+ type: str
52
+ pattern: /\\d+[dwDW]/
53
+ "lead_time":
54
+ desc: The amount of time before a recurring project is "due" moved to ready where the project (sort of a deferral mechanism) (WIP)
55
+ type: str
56
+ pattern: /\\d+[dwDW]/
57
+ "due":
58
+ desc: Due date of the task
59
+ type: date
60
+ "defer":
61
+ desc: Defer task until this day
62
+ type: date
63
+ "completed_on":
64
+ desc: When the (non-recurring) project was completed
65
+ type: date
66
+ "created_on":
67
+ desc: When the project was created
68
+ type: date
69
+ "starts_on":
70
+ desc: For ICS (WIP)
71
+ type: date
72
+ "last_reviewed":
73
+ desc: When the project was last reviewed (WIP)
74
+ type: date
75
+ "last_done":
76
+ desc: When the recurring project was last completed (WIP)
77
+ type: date
78
+ "dependencies":
79
+ desc: The names of projects that need to be completed before this project can be started/completed
80
+ type: seq
81
+ sequence:
82
+ - type: str
83
+ "externals":
84
+ desc: List of external commitments, ie who else cares about project completion?
85
+ type: seq
86
+ sequence:
87
+ - type: str
88
+ "urls":
89
+ desc: List of URLs that may be pertinent
90
+ type: seq
91
+ sequence:
92
+ - type: str
93
+ "tasks":
94
+ desc: List of tasks to do
95
+ type: seq
96
+ sequence:
97
+ - type: str
98
+ "done":
99
+ desc: List of tasks which have been completed
100
+ type: seq
101
+ sequence:
102
+ - type: str
103
+ "tags":
104
+ desc: List of tags (WIP)
105
+ type: seq
106
+ sequence:
107
+ - type: str
108
+ YAML
109
+ PROJECT_SCHEMA = YAML.safe_load(PROJECT_YAML_SCHEMA)
110
+
111
+ class ProjectYAMLFile
112
+ attr_reader :projects
113
+
114
+ def initialize(path)
115
+ @path = path
116
+ # TODO: this won't GC, inline validation instead?
117
+
118
+ # Handle pre-Ruby 3.1 psych versions (this is brittle)
119
+ @raw = if Psych::VERSION.split(".")[0].to_i >= 4
120
+ YAML.load_file(path, permitted_classes: [Date])
121
+ else
122
+ YAML.load_file(path)
123
+ end
124
+
125
+ validate_schema
126
+ @projects = @raw.map { |proj| Project.new proj }
127
+ end
128
+
129
+ def validate_schema
130
+ validator = Kwalify::Validator.new(Plansheet::PROJECT_SCHEMA)
131
+ errors = validator.validate(@raw)
132
+ # Check YAML validity
133
+ return unless errors && !errors.empty?
134
+
135
+ $stderr.write "Schema errors in #{@path}:\n"
136
+ errors.each { |err| puts "- [#{err.path}] #{err.message}" }
137
+ abort
138
+ end
139
+
140
+ def sort!
141
+ @projects.sort!
142
+ end
143
+
144
+ def yaml_dump
145
+ YAML.dump(@projects.map(&:to_h))
146
+ end
147
+ end
148
+ end
@@ -2,16 +2,19 @@
2
2
 
3
3
  require "yaml"
4
4
  require "date"
5
+ require_relative "project/yaml"
6
+ require_relative "project/stringify"
5
7
 
6
8
  module Plansheet
7
9
  PROJECT_STATUS_PRIORITY = {
8
10
  "wip" => 1,
9
11
  "ready" => 2,
10
12
  "blocked" => 3,
11
- "planning" => 4,
12
- "idea" => 5,
13
- "dropped" => 6,
14
- "done" => 7
13
+ "waiting" => 4,
14
+ "planning" => 5,
15
+ "idea" => 6,
16
+ "dropped" => 7,
17
+ "done" => 8
15
18
  }.freeze
16
19
 
17
20
  PROJECT_PRIORITY = {
@@ -20,72 +23,12 @@ module Plansheet
20
23
  "low" => 3
21
24
  }.freeze
22
25
 
23
- # Once there's some stability in plansheet and dc-kwalify, will pre-load this
24
- # to save the later YAML.load
25
- PROJECT_YAML_SCHEMA = <<~YAML
26
- desc: dc-tasks project schema
27
- type: seq
28
- sequence:
29
- - type: map
30
- mapping:
31
- "project":
32
- desc: Project name
33
- type: str
34
- required: yes
35
- "priority":
36
- desc: Project priority
37
- type: str
38
- enum:
39
- - high
40
- - medium
41
- - low
42
- "status":
43
- desc: The current status of the project
44
- type: str
45
- enum:
46
- - wip # project is a work-in-progress
47
- - ready # project is fully scoped, ready to go
48
- - blocked # project is blocked, but otherwise ready/wip
49
- - planning # project in planning phase
50
- - idea # project is little more than an idea
51
- - dropped # project has been explicitly dropped, but
52
- # want to keep around for reference, etc
53
- - done # project is finished, but want to keep around
54
- # for reference, etc.
55
- "location":
56
- desc: Location
57
- type: str
58
- "notes":
59
- desc: Free-form notes string
60
- type: str
61
- "due":
62
- desc: Due date of the task (WIP)
63
- type: date
64
- "defer":
65
- desc: Defer task until this day (WIP)
66
- type: date
67
- "externals":
68
- desc: List of external commitments, ie who else cares about project completion?
69
- type: seq
70
- sequence:
71
- - type: str
72
- "urls":
73
- desc: List of URLs that may be pertinent
74
- type: seq
75
- sequence:
76
- - type: str
77
- "tasks":
78
- desc: List of tasks to do
79
- type: seq
80
- sequence:
81
- - type: str
82
- "done":
83
- desc: List of tasks which have been completed
84
- type: seq
85
- sequence:
86
- - type: str
87
- YAML
88
- PROJECT_SCHEMA = YAML.safe_load(PROJECT_YAML_SCHEMA)
26
+ def self.parse_date_duration(str)
27
+ return Regexp.last_match(1).to_i if str.strip.match(/(\d+)[dD]/)
28
+ return (Regexp.last_match(1).to_i * 7) if str.strip.match(/(\d+)[wW]/)
29
+
30
+ raise "Can't parse time duration string #{str}"
31
+ end
89
32
 
90
33
  # The use of instance_variable_set/get probably seems a bit weird, but the
91
34
  # intent is to avoid object allocation on non-existent project properties, as
@@ -96,10 +39,18 @@ module Plansheet
96
39
  class Project
97
40
  include Comparable
98
41
 
42
+ DEFAULT_COMPARISON_ORDER = %w[
43
+ completeness
44
+ dependency
45
+ priority
46
+ defer
47
+ due
48
+ status
49
+ ].map { |x| "compare_#{x}".to_sym }.freeze
99
50
  # NOTE: The order of these affects presentation!
100
- STRING_PROPERTIES = %w[priority status location notes].freeze
101
- DATE_PROPERTIES = %w[due defer].freeze
102
- ARRAY_PROPERTIES = %w[externals urls tasks done].freeze
51
+ STRING_PROPERTIES = %w[priority status location notes time_estimate frequency lead_time].freeze
52
+ DATE_PROPERTIES = %w[due defer completed_on created_on starts_on last_done last_reviewed].freeze
53
+ ARRAY_PROPERTIES = %w[dependencies externals urls tasks done tags].freeze
103
54
 
104
55
  ALL_PROPERTIES = STRING_PROPERTIES + DATE_PROPERTIES + ARRAY_PROPERTIES
105
56
 
@@ -126,109 +77,155 @@ module Plansheet
126
77
  end
127
78
 
128
79
  def <=>(other)
129
- if @priority == other.priority
130
- # TODO: if planning status, then sort based on tasks? category? alphabetically?
131
- PROJECT_STATUS_PRIORITY[status] <=> PROJECT_STATUS_PRIORITY[other.status]
132
- else
133
- PROJECT_PRIORITY[@priority] <=> PROJECT_PRIORITY[other.priority]
80
+ ret_val = 0
81
+ DEFAULT_COMPARISON_ORDER.each do |method|
82
+ ret_val = send(method, other)
83
+ break if ret_val != 0
134
84
  end
85
+ ret_val
135
86
  end
136
87
 
137
- def status
138
- return @status if @status
88
+ def compare_priority(other)
89
+ PROJECT_PRIORITY[@priority] <=> PROJECT_PRIORITY[other.priority]
90
+ end
139
91
 
140
- if @tasks&.count&.positive?
141
- if @done&.count&.positive?
142
- "wip"
143
- else
144
- "planning"
145
- end
146
- else
147
- "idea"
148
- end
92
+ def compare_status(other)
93
+ PROJECT_STATUS_PRIORITY[status] <=> PROJECT_STATUS_PRIORITY[other.status]
149
94
  end
150
95
 
151
- def to_s
152
- str = String.new
153
- str << "# #{@name}\n"
154
- STRING_PROPERTIES.each do |o|
155
- str << stringify_string_property(o)
156
- end
157
- DATE_PROPERTIES.each do |o|
158
- str << stringify_string_property(o)
96
+ def compare_due(other)
97
+ # -1 is receiving object being older
98
+
99
+ # Handle nil
100
+ if @due.nil?
101
+ return 0 if other.due.nil?
102
+
103
+ return 1
104
+ elsif other.due.nil?
105
+ return -1
159
106
  end
160
- ARRAY_PROPERTIES.each do |o|
161
- str << stringify_array_property(o)
107
+
108
+ @due <=> other.due
109
+ end
110
+
111
+ def compare_defer(other)
112
+ receiver = @defer.nil? || @defer < Date.today ? Date.today : @defer
113
+ comparison = other.defer.nil? || other.defer < Date.today ? Date.today : other.defer
114
+ receiver <=> comparison
115
+ end
116
+
117
+ def compare_dependency(other)
118
+ return 0 if @dependencies.nil? && other.dependencies.nil?
119
+
120
+ if @dependencies.nil?
121
+ return -1 if other.dependencies.any? do |dep|
122
+ @name.downcase == dep.downcase
123
+ end
124
+ elsif @dependencies.any? do |dep|
125
+ other.name.downcase == dep.downcase
126
+ end
127
+ return 1
162
128
  end
163
- str
129
+ 0
130
+ end
131
+
132
+ # Projects that are dropped or done are considered "complete", insofar as
133
+ # they are only kept around for later reference.
134
+ def compare_completeness(other)
135
+ return 0 if dropped_or_done? && other.dropped_or_done?
136
+ return 0 if !dropped_or_done? && !other.dropped_or_done?
137
+
138
+ dropped_or_done? ? 1 : -1
139
+ end
140
+
141
+ def status
142
+ return @status if @status
143
+ return recurring_status if recurring?
144
+ return task_based_status if @tasks || @done
145
+ return "done" if @completed_on && @tasks.nil?
146
+
147
+ "idea"
164
148
  end
165
149
 
166
- def stringify_string_property(prop)
167
- if instance_variable_defined? "@#{prop}"
168
- "#{prop}: #{instance_variable_get("@#{prop}")}\n"
150
+ def task_based_status
151
+ if @tasks&.count&.positive? && @done&.count&.positive?
152
+ "wip"
153
+ elsif @tasks&.count&.positive?
154
+ "ready"
155
+ elsif @done&.count&.positive?
156
+ "done"
169
157
  else
170
- ""
158
+ "idea"
171
159
  end
172
160
  end
173
161
 
174
- def stringify_date_property(prop)
175
- if instance_variable_defined? "@#{prop}"
176
- "#{prop}: #{instance_variable_get("@#{prop}")}\n"
162
+ def recurring_status
163
+ # add frequency to last_done
164
+ if @last_done
165
+ # This project has been done once before
166
+ subsequent_recurring_status
177
167
  else
178
- ""
168
+ # This recurring project is being done for the first time
169
+ task_based_status
179
170
  end
180
171
  end
181
172
 
182
- def stringify_array_property(prop)
183
- str = String.new
184
- if instance_variable_defined? "@#{prop}"
185
- str << "#{prop}:\n"
186
- instance_variable_get("@#{prop}").each do |t|
187
- str << "- #{t}\n"
188
- end
189
- end
190
- str
173
+ def subsequent_recurring_status
174
+ return "done" if @lead_time && defer > Date.today
175
+ return "done" if due > Date.today
176
+
177
+ task_based_status
191
178
  end
192
179
 
193
- def to_h
194
- h = { "project" => @name }
195
- ALL_PROPERTIES.each do |prop|
196
- h[prop] = instance_variable_get("@#{prop}") if instance_variable_defined?("@#{prop}")
180
+ def process_recurring
181
+ # TODO: Tasks will be moved from done->tasks if recurring project is
182
+ # starting again
183
+ end
184
+
185
+ # Due date either explicit or recurring
186
+ def due
187
+ return @due if @due
188
+ return recurring_due_date if recurring?
189
+
190
+ nil
191
+ end
192
+
193
+ def recurring_due_date
194
+ if @last_done
195
+ @last_done + Plansheet.parse_date_duration(@frequency)
196
+ else
197
+ Date.today
197
198
  end
198
- h.delete "priority" if h.key?("priority") && h["priority"] == "low"
199
- h.delete "status" if h.key?("status") && h["status"] == "idea"
200
- h
201
199
  end
202
- end
203
200
 
204
- class ProjectYAMLFile
205
- attr_reader :projects
201
+ def defer
202
+ return @defer if @defer
203
+ return lead_time_deferral if @lead_time && due
206
204
 
207
- def initialize(path)
208
- @path = path
209
- # TODO: this won't GC, inline validation instead?
210
- @raw = YAML.load_file(path, permitted_classes: [Date])
211
- validate_schema
212
- @projects = @raw.map { |proj| Project.new proj }
205
+ nil
213
206
  end
214
207
 
215
- def validate_schema
216
- validator = Kwalify::Validator.new(Plansheet::PROJECT_SCHEMA)
217
- errors = validator.validate(@raw)
218
- # Check YAML validity
219
- return unless errors && !errors.empty?
208
+ def lead_time_deferral
209
+ [(due - Plansheet.parse_date_duration(@lead_time)),
210
+ Date.today].max
211
+ end
220
212
 
221
- $stderr.write "Schema errors in #{@path}:\n"
222
- errors.each { |err| puts "- [#{err.path}] #{err.message}" }
223
- abort
213
+ def recurring?
214
+ !@frequency.nil?
224
215
  end
225
216
 
226
- def sort!
227
- @projects.sort!
217
+ def dropped_or_done?
218
+ status == "dropped" || status == "done"
228
219
  end
229
220
 
230
- def yaml_dump
231
- YAML.dump(@projects.map(&:to_h))
221
+ def to_h
222
+ h = { "project" => @name }
223
+ ALL_PROPERTIES.each do |prop|
224
+ h[prop] = instance_variable_get("@#{prop}") if instance_variable_defined?("@#{prop}")
225
+ end
226
+ h.delete "priority" if h.key?("priority") && h["priority"] == "low"
227
+ h.delete "status" if h.key?("status") && h["status"] == "idea"
228
+ h
232
229
  end
233
230
  end
234
231
  end
@@ -10,7 +10,7 @@ module Plansheet
10
10
  projects_str = String.new
11
11
  projects_str << sheet_header
12
12
 
13
- sorted_arr.first(60).each do |p|
13
+ sorted_arr.each do |p|
14
14
  projects_str << project_minipage(p)
15
15
  end
16
16
  puts "Writing to #{output_file}"
@@ -32,7 +32,7 @@ module Plansheet
32
32
  str = String.new
33
33
  str << "\\begin{minipage}{4.5cm}\n"
34
34
  str << project_header(proj)
35
- proj.tasks.each do |t|
35
+ proj&.tasks&.each do |t|
36
36
  str << "$\\square$ #{t} \\\\\n"
37
37
  end
38
38
  str << "\\end{minipage}\n"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Plansheet
4
- VERSION = "0.7.1"
4
+ VERSION = "0.12.3"
5
5
  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.7.1
4
+ version: 0.12.3
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-02 00:00:00.000000000 Z
11
+ date: 2022-06-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dc-kwalify
@@ -33,10 +33,10 @@ extensions: []
33
33
  extra_rdoc_files: []
34
34
  files:
35
35
  - ".rubocop.yml"
36
- - ".rubocop_todo.yml"
37
36
  - CODE_OF_CONDUCT.md
38
37
  - Gemfile
39
38
  - Gemfile.lock
39
+ - Guardfile
40
40
  - LICENSE.txt
41
41
  - README.md
42
42
  - Rakefile
@@ -44,6 +44,8 @@ files:
44
44
  - exe/plansheet
45
45
  - lib/plansheet.rb
46
46
  - lib/plansheet/project.rb
47
+ - lib/plansheet/project/stringify.rb
48
+ - lib/plansheet/project/yaml.rb
47
49
  - lib/plansheet/sheet.rb
48
50
  - lib/plansheet/version.rb
49
51
  homepage: https://dafyddcrosby.com
data/.rubocop_todo.yml DELETED
@@ -1,31 +0,0 @@
1
- # This configuration was generated by
2
- # `rubocop --auto-gen-config`
3
- # on 2022-06-02 13:59:36 UTC using RuboCop version 1.29.1.
4
- # The point is for the user to remove these configuration records
5
- # one by one as the offenses are removed from the code base.
6
- # Note that changes in the inspected code, or installation of new
7
- # versions of RuboCop, may require this file to be generated again.
8
-
9
- # Offense count: 1
10
- # Configuration parameters: IgnoredMethods.
11
- Metrics/CyclomaticComplexity:
12
- Max: 8
13
-
14
- # Offense count: 1
15
- # Configuration parameters: CountComments, CountAsOne, ExcludedMethods, IgnoredMethods.
16
- Metrics/MethodLength:
17
- Max: 12
18
-
19
- # Offense count: 1
20
- # Configuration parameters: IgnoredMethods.
21
- Metrics/PerceivedComplexity:
22
- Max: 10
23
-
24
- # Offense count: 2
25
- # Configuration parameters: AllowedConstants.
26
- Style/Documentation:
27
- Exclude:
28
- - 'spec/**/*'
29
- - 'test/**/*'
30
- - 'lib/plansheet.rb'
31
- - 'lib/plansheet/project.rb'