plansheet 0.6.0 → 0.7.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: 0df6d0d15bff6b0d639ea6561ad722308c02e00b1bd313649b952a48c7826ad4
4
- data.tar.gz: 51faedcd44ccaeec7ee88a3e345bb8d5ae1597a5689324953a188e1725a465e2
3
+ metadata.gz: d9c1a116df170c31d73c29dce213b757743c0e49bbee8c86a47ce7ce09009730
4
+ data.tar.gz: 2baeb58d82c15823d9beb3e6504bb452e14cabded159f9931bf2300fdaed5d8f
5
5
  SHA512:
6
- metadata.gz: 0eb27167a0d754f27df229da3e2e12a07734a1e90f8d1a19374a6d408fd822d67286b31efbaa223eae61ec97931727ed4d3ea70e4211035cb8f2ea68f728f207
7
- data.tar.gz: 646ed78dd6f00b145ad61778fc7462b1ee1a3f9c52df3b3e27347c5d30ac199b2b4ef914239dd1a586d2e575e9fe8d44f664d5e152075a8ca5211150b4034838
6
+ metadata.gz: a87a4f7386a651ca82d385600f7b32ee78ff436406d596b6c2966ed721bdcee16f9bd4ad73b158be03305541dceda0d525e68ea2dc520a028fb603a6b5f0c1c0
7
+ data.tar.gz: d679906ef154e9b84e9282e1811ac0dff8da8b4dfb17c6e0e24d7f08226933346c4229468ddf51526e7532af7bdfd9a502557b64efc6439c128716a380e86d86
data/.rubocop.yml CHANGED
@@ -1,3 +1,5 @@
1
+ inherit_from: .rubocop_todo.yml
2
+
1
3
  AllCops:
2
4
  TargetRubyVersion: 2.6
3
5
  NewCops: enable
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,31 @@
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'
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- plansheet (0.6.0)
4
+ plansheet (0.7.1)
5
5
  dc-kwalify (~> 1.0)
6
6
 
7
7
  GEM
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "yaml"
4
+ require "date"
4
5
 
5
6
  module Plansheet
6
7
  PROJECT_STATUS_PRIORITY = {
@@ -18,11 +19,6 @@ module Plansheet
18
19
  "medium" => 2,
19
20
  "low" => 3
20
21
  }.freeze
21
- PROJECT_PRIORITY_REV = {
22
- 1 => "high",
23
- 2 => "medium",
24
- 3 => "low"
25
- }.freeze
26
22
 
27
23
  # Once there's some stability in plansheet and dc-kwalify, will pre-load this
28
24
  # to save the later YAML.load
@@ -36,6 +32,13 @@ module Plansheet
36
32
  desc: Project name
37
33
  type: str
38
34
  required: yes
35
+ "priority":
36
+ desc: Project priority
37
+ type: str
38
+ enum:
39
+ - high
40
+ - medium
41
+ - low
39
42
  "status":
40
43
  desc: The current status of the project
41
44
  type: str
@@ -49,15 +52,28 @@ module Plansheet
49
52
  # want to keep around for reference, etc
50
53
  - done # project is finished, but want to keep around
51
54
  # for reference, etc.
52
- "priority":
53
- desc: Project priority
54
- type: str
55
- enum:
56
- - high
57
- - low
58
55
  "location":
59
56
  desc: Location
60
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
61
77
  "tasks":
62
78
  desc: List of tasks to do
63
79
  type: seq
@@ -68,25 +84,45 @@ module Plansheet
68
84
  type: seq
69
85
  sequence:
70
86
  - type: str
71
- "notes":
72
- desc: Free-form notes string
73
- type: str
74
87
  YAML
75
88
  PROJECT_SCHEMA = YAML.safe_load(PROJECT_YAML_SCHEMA)
89
+
90
+ # The use of instance_variable_set/get probably seems a bit weird, but the
91
+ # intent is to avoid object allocation on non-existent project properties, as
92
+ # well as avoiding a bunch of copy-paste boilerplate when adding a new
93
+ # property. I suspect I'm guilty of premature optimization here, but it's
94
+ # easier to do this at the start than untangle that later (ie easier to
95
+ # unwrap the loops if it's not needed.
76
96
  class Project
77
97
  include Comparable
78
- attr_reader :name, :tasks, :done, :notes, :location, :priority
98
+
99
+ # 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
103
+
104
+ ALL_PROPERTIES = STRING_PROPERTIES + DATE_PROPERTIES + ARRAY_PROPERTIES
105
+
106
+ attr_reader :name, *ALL_PROPERTIES
79
107
 
80
108
  def initialize(options)
81
109
  @name = options["project"]
82
110
 
83
- @tasks = options["tasks"] || []
84
- @done = options["done"] || []
111
+ ALL_PROPERTIES.each do |o|
112
+ instance_variable_set("@#{o}", options[o]) if options[o]
113
+ end
85
114
 
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"]
115
+ # The "priority" concept feels flawed - it requires *me* to figure out
116
+ # the priority, as opposed to the program understanding the project in
117
+ # relation to other tasks. If I truly understood the priority of all the
118
+ # projects, I wouldn't need a todo list program. The point is to remove
119
+ # the need for willpower/executive function/coffee. The long-term value
120
+ # of this field will diminish as I add more project properties that can
121
+ # automatically hone in on the most important items based on due
122
+ # date/external commits/penalties for project failure, etc
123
+ #
124
+ # Assume all projects are low priority unless stated otherwise.
125
+ @priority ||= "low"
90
126
  end
91
127
 
92
128
  def <=>(other)
@@ -94,20 +130,15 @@ module Plansheet
94
130
  # TODO: if planning status, then sort based on tasks? category? alphabetically?
95
131
  PROJECT_STATUS_PRIORITY[status] <=> PROJECT_STATUS_PRIORITY[other.status]
96
132
  else
97
- @priority <=> other.priority
133
+ PROJECT_PRIORITY[@priority] <=> PROJECT_PRIORITY[other.priority]
98
134
  end
99
135
  end
100
136
 
101
- # TODO: clean up priority handling
102
- def priority_string
103
- PROJECT_PRIORITY_REV[@priority]
104
- end
105
-
106
137
  def status
107
138
  return @status if @status
108
139
 
109
- if @tasks.count.positive?
110
- if @done.count.positive?
140
+ if @tasks&.count&.positive?
141
+ if @done&.count&.positive?
111
142
  "wip"
112
143
  else
113
144
  "planning"
@@ -120,29 +151,52 @@ module Plansheet
120
151
  def to_s
121
152
  str = String.new
122
153
  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"
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)
159
+ end
160
+ ARRAY_PROPERTIES.each do |o|
161
+ str << stringify_array_property(o)
162
+ end
163
+ str
164
+ end
165
+
166
+ def stringify_string_property(prop)
167
+ if instance_variable_defined? "@#{prop}"
168
+ "#{prop}: #{instance_variable_get("@#{prop}")}\n"
169
+ else
170
+ ""
171
+ end
172
+ end
173
+
174
+ def stringify_date_property(prop)
175
+ if instance_variable_defined? "@#{prop}"
176
+ "#{prop}: #{instance_variable_get("@#{prop}")}\n"
177
+ else
178
+ ""
130
179
  end
131
- str << "done:\n" unless @done.empty?
132
- @done.each do |d|
133
- str << "- #{d}\n"
180
+ end
181
+
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
134
189
  end
135
190
  str
136
191
  end
137
192
 
138
193
  def to_h
139
194
  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?
195
+ ALL_PROPERTIES.each do |prop|
196
+ h[prop] = instance_variable_get("@#{prop}") if instance_variable_defined?("@#{prop}")
197
+ end
198
+ h.delete "priority" if h.key?("priority") && h["priority"] == "low"
199
+ h.delete "status" if h.key?("status") && h["status"] == "idea"
146
200
  h
147
201
  end
148
202
  end
@@ -153,7 +207,7 @@ module Plansheet
153
207
  def initialize(path)
154
208
  @path = path
155
209
  # TODO: this won't GC, inline validation instead?
156
- @raw = YAML.load_file(path)
210
+ @raw = YAML.load_file(path, permitted_classes: [Date])
157
211
  validate_schema
158
212
  @projects = @raw.map { |proj| Project.new proj }
159
213
  end
@@ -164,7 +218,7 @@ module Plansheet
164
218
  # Check YAML validity
165
219
  return unless errors && !errors.empty?
166
220
 
167
- $stderr.write "Schema errors in #{l}\n"
221
+ $stderr.write "Schema errors in #{@path}:\n"
168
222
  errors.each { |err| puts "- [#{err.path}] #{err.message}" }
169
223
  abort
170
224
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Plansheet
4
- VERSION = "0.6.0"
4
+ VERSION = "0.7.1"
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.6.0
4
+ version: 0.7.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-31 00:00:00.000000000 Z
11
+ date: 2022-06-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dc-kwalify
@@ -33,6 +33,7 @@ extensions: []
33
33
  extra_rdoc_files: []
34
34
  files:
35
35
  - ".rubocop.yml"
36
+ - ".rubocop_todo.yml"
36
37
  - CODE_OF_CONDUCT.md
37
38
  - Gemfile
38
39
  - Gemfile.lock