checkoff 0.93.0 → 0.95.0
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.lock +1 -1
- data/config/definitions.rb +2 -0
- data/lib/checkoff/internal/task_hashes.rb +57 -0
- data/lib/checkoff/internal/task_timing.rb +31 -0
- data/lib/checkoff/tasks.rb +41 -31
- data/lib/checkoff/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 31607f856925472f48fd4ae56a34d190bef6ea7105086b399e1f2755a0f1dfa5
|
4
|
+
data.tar.gz: 8af77b66a6a15caa5e5f3c5b46746f042d30d6ff56742845a6c537b3afe01d11
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5da70b5bbbd6538afa7b7953dfff42ec6377afe959f224c548d8886e64b36f1c101425c1ee51e6fced39ed8b06baa5f3c0f1aa96e92078cfebf1e1949ae4c3c9
|
7
|
+
data.tar.gz: 93f0ae0f4b00cf74cad672b3492b927ea72dc9f2dabd9b052e98da20098953848a69c55e79bcceda6ce6ce8c21fa77b0c08aff8f3378d0cb15a516f17e04a23e
|
data/Gemfile.lock
CHANGED
data/config/definitions.rb
CHANGED
@@ -50,6 +50,8 @@
|
|
50
50
|
# def assignee; end
|
51
51
|
# # @return [String, nil]
|
52
52
|
# def html_notes; end
|
53
|
+
# # @return [Array<Hash{String => Hash{String => String}}>]
|
54
|
+
# def memberships; end
|
53
55
|
# class << self
|
54
56
|
# # @return [Asana::Resources::Task]
|
55
57
|
# def create(client, assignee:, workspace:, name:); end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Checkoff
|
4
|
+
module Internal
|
5
|
+
# Builds on the standard API representation of an Asana task with some
|
6
|
+
# convenience keys.
|
7
|
+
class TaskHashes
|
8
|
+
# @param task [Asana::Resources::Task]
|
9
|
+
# @return [Hash]
|
10
|
+
def task_to_h(task)
|
11
|
+
# @type [Hash]
|
12
|
+
task_hash = task.to_h
|
13
|
+
task_hash['unwrapped'] = {}
|
14
|
+
unwrap_custom_fields(task_hash)
|
15
|
+
unwrap_memberships(task_hash)
|
16
|
+
task_hash['task'] = task.name
|
17
|
+
task_hash
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
# @param task_hash [Hash]
|
23
|
+
# @return [void]
|
24
|
+
def unwrap_custom_fields(task_hash)
|
25
|
+
unwrapped_custom_fields = task_hash.fetch('custom_fields', []).group_by do |cf|
|
26
|
+
cf['name']
|
27
|
+
end.transform_values(&:first)
|
28
|
+
task_hash['unwrapped']['custom_fields'] = unwrapped_custom_fields
|
29
|
+
end
|
30
|
+
|
31
|
+
# @param task_hash [Hash]
|
32
|
+
# @param resource [String]
|
33
|
+
# @param key [String]
|
34
|
+
#
|
35
|
+
# @return [void]
|
36
|
+
def unwrap_membership(task_hash, resource, key)
|
37
|
+
# @sg-ignore
|
38
|
+
# @type [Array<Hash>]
|
39
|
+
memberships = task_hash.fetch('memberships', [])
|
40
|
+
# @sg-ignore
|
41
|
+
# @type [Hash]
|
42
|
+
unwrapped = task_hash.fetch('unwrapped')
|
43
|
+
unwrapped["membership_by_#{resource}_#{key}"] = memberships.group_by do |membership|
|
44
|
+
membership[resource][key]
|
45
|
+
end.transform_values(&:first)
|
46
|
+
end
|
47
|
+
|
48
|
+
# @param task_hash [Hash]
|
49
|
+
# @return [void]
|
50
|
+
def unwrap_memberships(task_hash)
|
51
|
+
unwrap_membership(task_hash, 'section', 'gid')
|
52
|
+
unwrap_membership(task_hash, 'project', 'gid')
|
53
|
+
unwrap_membership(task_hash, 'project', 'name')
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Checkoff
|
4
|
+
module Internal
|
5
|
+
# Utility methods for working with task dates and times
|
6
|
+
class TaskTiming
|
7
|
+
# @param time_class [Class<Time>]
|
8
|
+
def initialize(time_class: Time)
|
9
|
+
@time_class = time_class
|
10
|
+
end
|
11
|
+
|
12
|
+
# @param task [Asana::Resources::Task]
|
13
|
+
# @return [Time, nil]
|
14
|
+
def start_time(task)
|
15
|
+
return @time_class.parse(task.start_at) if task.start_at
|
16
|
+
return @time_class.parse(task.start_on) if task.start_on
|
17
|
+
|
18
|
+
nil
|
19
|
+
end
|
20
|
+
|
21
|
+
# @param task [Asana::Resources::Task]
|
22
|
+
# @return [Time, nil]
|
23
|
+
def due_time(task)
|
24
|
+
return @time_class.parse(task.due_at) if task.due_at
|
25
|
+
return @time_class.parse(task.due_on) if task.due_on
|
26
|
+
|
27
|
+
nil
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/checkoff/tasks.rb
CHANGED
@@ -5,6 +5,8 @@
|
|
5
5
|
require_relative 'sections'
|
6
6
|
require_relative 'workspaces'
|
7
7
|
require_relative 'internal/config_loader'
|
8
|
+
require_relative 'internal/task_timing'
|
9
|
+
require_relative 'internal/task_hashes'
|
8
10
|
require 'asana'
|
9
11
|
|
10
12
|
module Checkoff
|
@@ -57,8 +59,8 @@ module Checkoff
|
|
57
59
|
def task_ready?(task, ignore_dependencies: false)
|
58
60
|
return false if !ignore_dependencies && incomplete_dependencies?(task)
|
59
61
|
|
60
|
-
start = start_time(task)
|
61
|
-
due = due_time(task)
|
62
|
+
start = task_timing.start_time(task)
|
63
|
+
due = task_timing.due_time(task)
|
62
64
|
|
63
65
|
return true if start.nil? && due.nil?
|
64
66
|
|
@@ -79,12 +81,12 @@ module Checkoff
|
|
79
81
|
only_uncompleted: true,
|
80
82
|
extra_fields: [])
|
81
83
|
# @sg-ignore
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
84
|
+
t = tasks(workspace_name,
|
85
|
+
project_name,
|
86
|
+
section_name: section_name,
|
87
|
+
only_uncompleted: only_uncompleted,
|
88
|
+
extra_fields: extra_fields)
|
89
|
+
t.find { |task| task.name == task_name }
|
88
90
|
end
|
89
91
|
cache_method :task, SHORT_CACHE_TIME
|
90
92
|
|
@@ -144,18 +146,44 @@ module Checkoff
|
|
144
146
|
end
|
145
147
|
end
|
146
148
|
|
149
|
+
# Builds on the standard API representation of an Asana task with some
|
150
|
+
# convenience keys:
|
151
|
+
#
|
152
|
+
# <regular keys from API response>
|
153
|
+
# +
|
154
|
+
# unwrapped:
|
155
|
+
# membership_by_section_gid: Hash<String, Hash (membership)>
|
156
|
+
# membership_by_project_gid: Hash<String, Hash (membership)>
|
157
|
+
# membership_by_project_name: Hash<String, Hash (membership)>
|
158
|
+
# task: String (name)
|
159
|
+
#
|
160
|
+
# @param task [Asana::Resources::Task]
|
161
|
+
# @return [Hash]
|
162
|
+
def task_to_h(task)
|
163
|
+
task_hashes.task_to_h(task)
|
164
|
+
end
|
165
|
+
|
147
166
|
private
|
148
167
|
|
168
|
+
# @return [Checkoff::Internal::TaskTiming]
|
169
|
+
def task_timing
|
170
|
+
@task_timing ||= Checkoff::Internal::TaskTiming.new(time_class: @time_class)
|
171
|
+
end
|
172
|
+
|
173
|
+
# @return [Checkoff::Internal::TaskHashes]
|
174
|
+
def task_hashes
|
175
|
+
@task_hashes ||= Checkoff::Internal::TaskHashes.new
|
176
|
+
end
|
177
|
+
|
149
178
|
# @param workspace_name [String]
|
150
179
|
# @param project_name [String, Symbol]
|
151
|
-
# @param section_name [String, nil,
|
180
|
+
# @param section_name [String, nil, Symbol<:unspecified>]
|
152
181
|
# @param only_uncompleted [Boolean]
|
153
182
|
# @param extra_fields [Array<String>]
|
183
|
+
#
|
154
184
|
# @return [Enumerable<Asana::Resources::Task>]
|
155
|
-
def
|
156
|
-
|
157
|
-
only_uncompleted:,
|
158
|
-
extra_fields:)
|
185
|
+
def tasks(workspace_name, project_name,
|
186
|
+
only_uncompleted:, extra_fields:, section_name: :unspecified)
|
159
187
|
if section_name == :unspecified
|
160
188
|
project = projects.project_or_raise(workspace_name, project_name)
|
161
189
|
projects.tasks_from_project(project,
|
@@ -182,23 +210,5 @@ module Checkoff
|
|
182
210
|
def default_assignee_gid
|
183
211
|
@config.fetch(:default_assignee_gid)
|
184
212
|
end
|
185
|
-
|
186
|
-
# @param task [Asana::Resources::Task]
|
187
|
-
# @return [Time, nil]
|
188
|
-
def start_time(task)
|
189
|
-
return @time_class.parse(task.start_at) if task.start_at
|
190
|
-
return @time_class.parse(task.start_on) if task.start_on
|
191
|
-
|
192
|
-
nil
|
193
|
-
end
|
194
|
-
|
195
|
-
# @param task [Asana::Resources::Task]
|
196
|
-
# @return [Time, nil]
|
197
|
-
def due_time(task)
|
198
|
-
return @time_class.parse(task.due_at) if task.due_at
|
199
|
-
return @time_class.parse(task.due_on) if task.due_on
|
200
|
-
|
201
|
-
nil
|
202
|
-
end
|
203
213
|
end
|
204
214
|
end
|
data/lib/checkoff/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: checkoff
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.95.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Vince Broz
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-10-
|
11
|
+
date: 2023-10-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -152,7 +152,9 @@ files:
|
|
152
152
|
- lib/checkoff/internal/selector_classes/task.rb
|
153
153
|
- lib/checkoff/internal/selector_classes/task/function_evaluator.rb
|
154
154
|
- lib/checkoff/internal/selector_evaluator.rb
|
155
|
+
- lib/checkoff/internal/task_hashes.rb
|
155
156
|
- lib/checkoff/internal/task_selector_evaluator.rb
|
157
|
+
- lib/checkoff/internal/task_timing.rb
|
156
158
|
- lib/checkoff/my_tasks.rb
|
157
159
|
- lib/checkoff/portfolios.rb
|
158
160
|
- lib/checkoff/project_selectors.rb
|