plansheet 0.9.0 → 0.12.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: a8132e26b8647ea119299716b5f88674af3e4264614f7b881133eb6cbd32d7db
4
- data.tar.gz: c04f8bf586f6866acf03e809ab581b8010b6fb64be486791abb5fdd3274ae6e2
3
+ metadata.gz: d1c4e7e5e45d00a1218ac7346c60ba9182c7b73ac2761958c24ea8c8dcf15d9d
4
+ data.tar.gz: 50cc492240c458e5bc13539f03203007b8922dcd2e00e5108d6f929c81419f2e
5
5
  SHA512:
6
- metadata.gz: 6426deb869f89a6ff87d5f760acbab8687a542dd3942cf829c536ceb49c3a8268b18ab188d0ad0cb91457fa435963eb7193dd9844a283ccdfb4114e4dece54d8
7
- data.tar.gz: 4c03feeae9aed94d4e4df6c931c1317039f1100e67d7475cdbf8b67dae14e753899853291ad46f025e198d93def4b9c67c0c12da24d352d8db0880ae5ebb2f99
6
+ metadata.gz: 2fe3310c09dfe7d4e79172a476f3bcfc0a3ef6261757a4070a6f49d9857673524663ee97622db603acae911201d5f1acc9cdb65d7c30547ea0e3f4610dc5e0bf
7
+ data.tar.gz: 58aee2a5ab4f95c114461a8ef614823b5c4e22e0961c792623d0720b033a40c1abbdf1d23887b7b5a38b4823138994116d3eb6b42f2675263d0825d567fee173
data/.rubocop_todo.yml CHANGED
@@ -9,28 +9,27 @@
9
9
  # Offense count: 1
10
10
  # Configuration parameters: CountComments, CountAsOne.
11
11
  Metrics/ClassLength:
12
- Max: 105
12
+ Enabled: false
13
13
 
14
14
  # Offense count: 1
15
15
  # Configuration parameters: IgnoredMethods.
16
16
  Metrics/CyclomaticComplexity:
17
- Max: 8
17
+ Enabled: false
18
18
 
19
19
  # Offense count: 2
20
20
  # Configuration parameters: CountComments, CountAsOne, ExcludedMethods, IgnoredMethods.
21
21
  Metrics/MethodLength:
22
- Max: 12
22
+ Enabled: false
23
23
 
24
24
  # Offense count: 1
25
25
  # Configuration parameters: IgnoredMethods.
26
26
  Metrics/PerceivedComplexity:
27
- Max: 10
27
+ Enabled: false
28
28
 
29
29
  # Offense count: 2
30
30
  # Configuration parameters: AllowedConstants.
31
31
  Style/Documentation:
32
32
  Exclude:
33
- - 'spec/**/*'
34
33
  - 'test/**/*'
35
34
  - 'lib/plansheet.rb'
36
35
  - 'lib/plansheet/project.rb'
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- plansheet (0.9.0)
4
+ plansheet (0.12.0)
5
5
  dc-kwalify (~> 1.0)
6
6
 
7
7
  GEM
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
@@ -8,10 +8,11 @@ module Plansheet
8
8
  "wip" => 1,
9
9
  "ready" => 2,
10
10
  "blocked" => 3,
11
- "planning" => 4,
12
- "idea" => 5,
13
- "dropped" => 6,
14
- "done" => 7
11
+ "waiting" => 4,
12
+ "planning" => 5,
13
+ "idea" => 6,
14
+ "dropped" => 7,
15
+ "done" => 8
15
16
  }.freeze
16
17
 
17
18
  PROJECT_PRIORITY = {
@@ -44,9 +45,10 @@ module Plansheet
44
45
  type: str
45
46
  enum:
46
47
  - 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
48
+ - ready # project has tasks, ready to go
49
+ - waiting # project in waiting on some external person/event
50
+ - blocked # project is blocked by another project, but otherwise ready/wip
51
+ - planning # project in planning phase (set manually)
50
52
  - idea # project is little more than an idea
51
53
  - dropped # project has been explicitly dropped, but
52
54
  # want to keep around for reference, etc
@@ -58,12 +60,35 @@ module Plansheet
58
60
  "notes":
59
61
  desc: Free-form notes string
60
62
  type: str
63
+ "time_estimate":
64
+ desc: The estimated amount of time before a project is completed
65
+ type: str
66
+ "frequency":
67
+ desc: The amount of time before a recurring project moves to ready status again from when it was last done (WIP)
68
+ type: str
69
+ pattern: /\\d+[dwDW]/
70
+ "lead_time":
71
+ desc: The amount of time before a recurring project is "due" moved to ready where the project (sort of a deferral mechanism) (WIP)
72
+ type: str
73
+ pattern: /\\d+[dwDW]/
61
74
  "due":
62
75
  desc: Due date of the task
63
76
  type: date
64
77
  "defer":
65
78
  desc: Defer task until this day
66
79
  type: date
80
+ "created_on":
81
+ desc: When the project was created
82
+ type: date
83
+ "starts_on":
84
+ desc: For ICS (WIP)
85
+ type: date
86
+ "last_reviewed":
87
+ desc: When the project was last reviewed (WIP)
88
+ type: date
89
+ "last_done":
90
+ desc: When the recurring project was last completed (WIP)
91
+ type: date
67
92
  "dependencies":
68
93
  desc: The names of projects that need to be completed before this project can be started/completed
69
94
  type: seq
@@ -89,9 +114,21 @@ module Plansheet
89
114
  type: seq
90
115
  sequence:
91
116
  - type: str
117
+ "tags":
118
+ desc: List of tags (WIP)
119
+ type: seq
120
+ sequence:
121
+ - type: str
92
122
  YAML
93
123
  PROJECT_SCHEMA = YAML.safe_load(PROJECT_YAML_SCHEMA)
94
124
 
125
+ def self.parse_date_duration(str)
126
+ return Regexp.last_match(1).to_i if str.strip.match(/(\d+)[dD]/)
127
+ return (Regexp.last_match(1).to_i * 7) if str.strip.match(/(\d+)[wW]/)
128
+
129
+ raise "Can't parse time duration string #{str}"
130
+ end
131
+
95
132
  # The use of instance_variable_set/get probably seems a bit weird, but the
96
133
  # intent is to avoid object allocation on non-existent project properties, as
97
134
  # well as avoiding a bunch of copy-paste boilerplate when adding a new
@@ -101,10 +138,18 @@ module Plansheet
101
138
  class Project
102
139
  include Comparable
103
140
 
141
+ DEFAULT_COMPARISON_ORDER = %w[
142
+ completeness
143
+ dependency
144
+ priority
145
+ defer
146
+ due
147
+ status
148
+ ].map { |x| "compare_#{x}".to_sym }.freeze
104
149
  # NOTE: The order of these affects presentation!
105
- STRING_PROPERTIES = %w[priority status location notes].freeze
106
- DATE_PROPERTIES = %w[due defer].freeze
107
- ARRAY_PROPERTIES = %w[dependencies externals urls tasks done].freeze
150
+ STRING_PROPERTIES = %w[priority status location notes time_estimate frequency lead_time].freeze
151
+ DATE_PROPERTIES = %w[due defer created_on starts_on last_done last_reviewed].freeze
152
+ ARRAY_PROPERTIES = %w[dependencies externals urls tasks done tags].freeze
108
153
 
109
154
  ALL_PROPERTIES = STRING_PROPERTIES + DATE_PROPERTIES + ARRAY_PROPERTIES
110
155
 
@@ -132,14 +177,7 @@ module Plansheet
132
177
 
133
178
  def <=>(other)
134
179
  ret_val = 0
135
- %i[
136
- compare_completeness
137
- compare_dependency
138
- compare_priority
139
- compare_due
140
- compare_defer
141
- compare_status
142
- ].each do |method|
180
+ DEFAULT_COMPARISON_ORDER.each do |method|
143
181
  ret_val = send(method, other)
144
182
  break if ret_val != 0
145
183
  end
@@ -177,40 +215,101 @@ module Plansheet
177
215
 
178
216
  def compare_dependency(other)
179
217
  return 0 if @dependencies.nil? && other.dependencies.nil?
218
+
180
219
  if @dependencies.nil?
181
- return -1 if other.dependencies.any? {|dep|
220
+ return -1 if other.dependencies.any? do |dep|
182
221
  @name.downcase == dep.downcase
183
- }
184
- else
185
- return 1 if @dependencies.any? {|dep|
186
- other.name.downcase == dep.downcase
187
- }
222
+ end
223
+ elsif @dependencies.any? do |dep|
224
+ other.name.downcase == dep.downcase
225
+ end
226
+ return 1
188
227
  end
189
- return 0
228
+ 0
190
229
  end
191
230
 
192
231
  # Projects that are dropped or done are considered "complete", insofar as
193
232
  # they are only kept around for later reference.
194
233
  def compare_completeness(other)
195
- return 0 if self.dropped_or_done? && other.dropped_or_done?
196
- return 0 if !self.dropped_or_done? && !other.dropped_or_done?
197
- self.dropped_or_done? ? 1 : -1
234
+ return 0 if dropped_or_done? && other.dropped_or_done?
235
+ return 0 if !dropped_or_done? && !other.dropped_or_done?
236
+
237
+ dropped_or_done? ? 1 : -1
198
238
  end
199
239
 
200
240
  def status
201
241
  return @status if @status
242
+ return recurring_status if recurring?
243
+ return task_based_status if (@tasks || @done)
244
+ # TODO: return done if done count is positive...
202
245
 
203
- if @tasks&.count&.positive?
204
- if @done&.count&.positive?
205
- "wip"
206
- else
207
- "planning"
208
- end
246
+ "idea"
247
+ end
248
+
249
+ def task_based_status
250
+ if @tasks&.count&.positive? && @done&.count&.positive?
251
+ "wip"
252
+ elsif @tasks&.count&.positive?
253
+ "ready"
254
+ elsif @done&.count&.positive?
255
+ "done"
209
256
  else
210
257
  "idea"
211
258
  end
212
259
  end
213
260
 
261
+ def recurring_status
262
+ # add frequency to last_done
263
+ unless @last_done
264
+ # This recurring project is being done for the first time
265
+ task_based_status
266
+ else
267
+ # This project has been done once before
268
+ subsequent_recurring_status
269
+ end
270
+ end
271
+
272
+ def subsequent_recurring_status
273
+ return "done" if @lead_time && defer > Date.today
274
+ return "done" if due > Date.today
275
+ task_based_status
276
+ end
277
+
278
+ def process_recurring
279
+ # TODO: Tasks will be moved from done->tasks if recurring project is
280
+ # starting again
281
+ end
282
+
283
+ # Due date either explicit or recurring
284
+ def due
285
+ return @due if @due
286
+ return recurring_due_date if recurring?
287
+ nil
288
+ end
289
+
290
+ def recurring_due_date
291
+ if @last_done
292
+ @last_done + Plansheet.parse_date_duration(@frequency)
293
+ else
294
+ Date.today
295
+ end
296
+ end
297
+
298
+ def defer
299
+ return @defer if @defer
300
+ return lead_time_deferral if @lead_time && due
301
+ nil
302
+ end
303
+
304
+ def lead_time_deferral
305
+ [(due - Plansheet.parse_date_duration(@lead_time)),
306
+ Date.today].max
307
+ end
308
+
309
+ def recurring?
310
+ !@frequency.nil?
311
+ end
312
+
214
313
  def dropped_or_done?
215
314
  status == "dropped" || status == "done"
216
315
  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}"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Plansheet
4
- VERSION = "0.9.0"
4
+ VERSION = "0.12.0"
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.9.0
4
+ version: 0.12.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-06-04 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