checkoff 0.44.0 → 0.44.2
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 +3 -2
- data/README.md +5 -1
- data/docs/.gitignore +3 -0
- data/lib/checkoff/internal/task_selector_evaluator.rb +331 -311
- data/lib/checkoff/sections.rb +22 -5
- data/lib/checkoff/tasks.rb +4 -5
- data/lib/checkoff/version.rb +1 -1
- data/lib/checkoff/workspaces.rb +8 -3
- data/rakelib/doc.rake +6 -0
- 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: d924c906eed129ad1c57bdbfdd8cdcc61b572e296a09721195b7c1a10d78dbe5
|
4
|
+
data.tar.gz: 79e71aac6289b18a448288a601c62a02cee6583bcbbc966e64a71003c8e73e89
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8bc265211c02ebf11e7c7f35ce79aae7517c6b86cf023c8d0b41713a24df2365954f9757bfe9b44a85573187af7fb355f84e7d6b1bad9e8b32fc9b8b9ed6891d
|
7
|
+
data.tar.gz: 5de92894cb1f12d633667b87f426f4460d63a54d84cb1a9f2e8e38c529c45d41efdd9097cb9a2dd6f73691669a4a070ba87aedc55a5d8ec7780fa9cec5e2d13a
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -12,7 +12,7 @@ GIT
|
|
12
12
|
PATH
|
13
13
|
remote: .
|
14
14
|
specs:
|
15
|
-
checkoff (0.44.
|
15
|
+
checkoff (0.44.2)
|
16
16
|
activesupport
|
17
17
|
asana (> 0.10.0)
|
18
18
|
cache_method
|
@@ -22,7 +22,7 @@ PATH
|
|
22
22
|
GEM
|
23
23
|
remote: https://rubygems.org/
|
24
24
|
specs:
|
25
|
-
activesupport (7.0.
|
25
|
+
activesupport (7.0.6)
|
26
26
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
27
27
|
i18n (>= 1.6, < 2)
|
28
28
|
minitest (>= 5.1)
|
@@ -235,6 +235,7 @@ DEPENDENCIES
|
|
235
235
|
solargraph (>= 0.49.0)
|
236
236
|
undercover
|
237
237
|
webmock
|
238
|
+
yard
|
238
239
|
|
239
240
|
BUNDLED WITH
|
240
241
|
2.3.26
|
data/README.md
CHANGED
data/docs/.gitignore
ADDED
@@ -1,379 +1,399 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Checkoff
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
4
|
+
module TaskSelectorClasses
|
5
|
+
# Base class to evaluate a task selector function given fully evaluated arguments
|
6
|
+
class FunctionEvaluator
|
7
|
+
# @param task_selector [Array<(Symbol, Array)>,String]
|
8
|
+
# @param tasks [Checkoff::Tasks]
|
9
|
+
def initialize(task_selector:,
|
10
|
+
tasks:)
|
11
|
+
@task_selector = task_selector
|
12
|
+
@tasks = tasks
|
13
|
+
end
|
13
14
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
15
|
+
# @sg-ignore
|
16
|
+
# @param _index [Integer]
|
17
|
+
def evaluate_arg?(_index)
|
18
|
+
true
|
19
|
+
end
|
19
20
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
21
|
+
# @sg-ignore
|
22
|
+
# @return [Boolean]
|
23
|
+
def matches?
|
24
|
+
raise 'Override me!'
|
25
|
+
end
|
25
26
|
|
26
|
-
|
27
|
+
private
|
27
28
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
29
|
+
# @param object [Object]
|
30
|
+
# @param fn_name [Symbol]
|
31
|
+
def fn?(object, fn_name)
|
32
|
+
object.is_a?(Array) && !object.empty? && [fn_name, fn_name.to_s].include?(object[0])
|
33
|
+
end
|
33
34
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
35
|
+
# @sg-ignore
|
36
|
+
# @param task [Asana::Resources::Task]
|
37
|
+
# @param custom_field_gid [String]
|
38
|
+
# @return [Hash]
|
39
|
+
def pull_custom_field_or_raise(task, custom_field_gid)
|
40
|
+
# @type [Array<Hash>]
|
41
|
+
custom_fields = task.custom_fields
|
42
|
+
if custom_fields.nil?
|
43
|
+
raise "Could not find custom_fields under task (was 'custom_fields' included in 'extra_fields'?)"
|
44
|
+
end
|
45
|
+
|
46
|
+
# @sg-ignore
|
47
|
+
# @type [Hash, nil]
|
48
|
+
matched_custom_field = custom_fields.find { |data| data.fetch('gid') == custom_field_gid }
|
49
|
+
if matched_custom_field.nil?
|
50
|
+
raise "Could not find custom field with gid #{custom_field_gid} " \
|
51
|
+
"in task #{task.gid} with custom fields #{custom_fields}"
|
52
|
+
end
|
53
|
+
|
54
|
+
matched_custom_field
|
43
55
|
end
|
44
56
|
|
57
|
+
# @return [Array<(Symbol, Array)>]
|
58
|
+
attr_reader :task_selector
|
59
|
+
|
45
60
|
# @sg-ignore
|
46
|
-
# @
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
61
|
+
# @param custom_field [Hash]
|
62
|
+
# @return [Array<String>]
|
63
|
+
def pull_enum_values(custom_field)
|
64
|
+
resource_subtype = custom_field.fetch('resource_subtype')
|
65
|
+
case resource_subtype
|
66
|
+
when 'enum'
|
67
|
+
[custom_field.fetch('enum_value')]
|
68
|
+
when 'multi_enum'
|
69
|
+
custom_field.fetch('multi_enum_values')
|
70
|
+
else
|
71
|
+
raise "Teach me how to handle resource_subtype #{resource_subtype}"
|
72
|
+
end
|
51
73
|
end
|
52
74
|
|
53
|
-
|
54
|
-
|
75
|
+
# @param custom_field [Hash]
|
76
|
+
# @param enum_value [Object, nil]
|
77
|
+
# @return [Array<String>]
|
78
|
+
def find_gids(custom_field, enum_value)
|
79
|
+
if enum_value.nil?
|
80
|
+
[]
|
81
|
+
else
|
82
|
+
raise "Unexpected enabled value on custom field: #{custom_field}" if enum_value.fetch('enabled') == false
|
83
|
+
|
84
|
+
[enum_value.fetch('gid')]
|
85
|
+
end
|
86
|
+
end
|
55
87
|
|
56
|
-
|
57
|
-
|
88
|
+
# @param task [Asana::Resources::Task]
|
89
|
+
# @param custom_field_gid [String]
|
90
|
+
# @return [Array<String>]
|
91
|
+
def pull_custom_field_values_gids(task, custom_field_gid)
|
92
|
+
custom_field = pull_custom_field_or_raise(task, custom_field_gid)
|
93
|
+
pull_enum_values(custom_field).flat_map do |enum_value|
|
94
|
+
find_gids(custom_field, enum_value)
|
95
|
+
end
|
96
|
+
end
|
58
97
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
98
|
+
# @sg-ignore
|
99
|
+
# @param task [Asana::Resources::Task]
|
100
|
+
# @param custom_field_name [String]
|
101
|
+
# @return [Hash, nil]
|
102
|
+
def pull_custom_field_by_name(task, custom_field_name)
|
103
|
+
custom_fields = task.custom_fields
|
104
|
+
if custom_fields.nil?
|
105
|
+
raise "custom fields not found on task - did you add 'custom_fields' in your extra_fields argument?"
|
106
|
+
end
|
107
|
+
|
108
|
+
# @sg-ignore
|
109
|
+
# @type [Hash, nil]
|
110
|
+
custom_fields.find { |field| field.fetch('name') == custom_field_name }
|
111
|
+
end
|
112
|
+
|
113
|
+
# @param task [Asana::Resources::Task]
|
114
|
+
# @param custom_field_name [String]
|
115
|
+
# @return [Hash]
|
116
|
+
def pull_custom_field_by_name_or_raise(task, custom_field_name)
|
117
|
+
custom_field = pull_custom_field_by_name(task, custom_field_name)
|
118
|
+
if custom_field.nil?
|
119
|
+
raise "Could not find custom field with name #{custom_field_name} " \
|
120
|
+
"in task #{task.gid} with custom fields #{task.custom_fields}"
|
121
|
+
end
|
122
|
+
custom_field
|
71
123
|
end
|
72
124
|
end
|
73
125
|
|
74
|
-
#
|
75
|
-
|
76
|
-
|
77
|
-
def find_gids(custom_field, enum_value)
|
78
|
-
if enum_value.nil?
|
79
|
-
[]
|
80
|
-
else
|
81
|
-
raise "Unexpected enabled value on custom field: #{custom_field}" if enum_value.fetch('enabled') == false
|
126
|
+
# :and function
|
127
|
+
class AndFunctionEvaluator < FunctionEvaluator
|
128
|
+
FUNCTION_NAME = :and
|
82
129
|
|
83
|
-
|
130
|
+
def matches?
|
131
|
+
fn?(task_selector, FUNCTION_NAME)
|
84
132
|
end
|
85
|
-
end
|
86
133
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
find_gids(custom_field, enum_value)
|
134
|
+
# @param _task [Asana::Resources::Task]
|
135
|
+
# @param lhs [Object]
|
136
|
+
# @param rhs [Object]
|
137
|
+
# @return [Object]
|
138
|
+
def evaluate(_task, lhs, rhs)
|
139
|
+
lhs && rhs
|
94
140
|
end
|
95
141
|
end
|
96
142
|
|
97
|
-
#
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
if custom_fields.nil?
|
104
|
-
raise "custom fields not found on task - did you add 'custom_fields' in your extra_fields argument?"
|
143
|
+
# :not function
|
144
|
+
class NotFunctionEvaluator < FunctionEvaluator
|
145
|
+
FUNCTION_NAME = :not
|
146
|
+
|
147
|
+
def matches?
|
148
|
+
fn?(task_selector, FUNCTION_NAME)
|
105
149
|
end
|
106
150
|
|
107
|
-
# @
|
108
|
-
# @
|
109
|
-
|
151
|
+
# @param _task [Asana::Resources::Task]
|
152
|
+
# @param subvalue [Object]
|
153
|
+
# @return [Boolean]
|
154
|
+
def evaluate(_task, subvalue)
|
155
|
+
!subvalue
|
156
|
+
end
|
110
157
|
end
|
111
158
|
|
112
|
-
#
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
if custom_field.nil?
|
118
|
-
raise "Could not find custom field with name #{custom_field_name} " \
|
119
|
-
"in task #{task.gid} with custom fields #{task.custom_fields}"
|
120
|
-
end
|
121
|
-
custom_field
|
122
|
-
end
|
123
|
-
end
|
159
|
+
# :nil? function
|
160
|
+
class NilPFunctionEvaluator < FunctionEvaluator
|
161
|
+
def matches?
|
162
|
+
fn?(task_selector, :nil?)
|
163
|
+
end
|
124
164
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
165
|
+
# @param _task [Asana::Resources::Task]
|
166
|
+
# @param subvalue [Object]
|
167
|
+
# @return [Boolean]
|
168
|
+
def evaluate(_task, subvalue)
|
169
|
+
subvalue.nil?
|
170
|
+
end
|
129
171
|
end
|
130
172
|
|
131
|
-
#
|
132
|
-
|
133
|
-
|
134
|
-
# @return [Object]
|
135
|
-
def evaluate(_task, lhs, rhs)
|
136
|
-
lhs && rhs
|
137
|
-
end
|
138
|
-
end
|
173
|
+
# :equals? function
|
174
|
+
class EqualsPFunctionEvaluator < FunctionEvaluator
|
175
|
+
FUNCTION_NAME = :equals?
|
139
176
|
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
fn?(task_selector, :not)
|
144
|
-
end
|
177
|
+
def matches?
|
178
|
+
fn?(task_selector, FUNCTION_NAME)
|
179
|
+
end
|
145
180
|
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
181
|
+
# @param _task [Asana::Resources::Task]
|
182
|
+
# @param lhs [Object]
|
183
|
+
# @param rhs [Object]
|
184
|
+
# @return [Boolean]
|
185
|
+
def evaluate(_task, lhs, rhs)
|
186
|
+
lhs == rhs
|
187
|
+
end
|
151
188
|
end
|
152
|
-
end
|
153
189
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
190
|
+
# :tag function
|
191
|
+
class TagPFunctionEvaluator < FunctionEvaluator
|
192
|
+
def matches?
|
193
|
+
fn?(task_selector, :tag)
|
194
|
+
end
|
159
195
|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
subvalue.nil?
|
165
|
-
end
|
166
|
-
end
|
196
|
+
# @param _index [Integer]
|
197
|
+
def evaluate_arg?(_index)
|
198
|
+
false
|
199
|
+
end
|
167
200
|
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
201
|
+
# @sg-ignore
|
202
|
+
# @param task [Asana::Resources::Task]
|
203
|
+
# @param tag_name [String]
|
204
|
+
# @return [Boolean]
|
205
|
+
def evaluate(task, tag_name)
|
206
|
+
task.tags.map(&:name).include? tag_name
|
207
|
+
end
|
172
208
|
end
|
173
209
|
|
174
|
-
#
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
lhs == rhs
|
180
|
-
end
|
181
|
-
end
|
210
|
+
# :due function
|
211
|
+
class DuePFunctionEvaluator < FunctionEvaluator
|
212
|
+
def matches?
|
213
|
+
fn?(task_selector, :due)
|
214
|
+
end
|
182
215
|
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
216
|
+
# @param task [Asana::Resources::Task]
|
217
|
+
# @return [Boolean]
|
218
|
+
def evaluate(task)
|
219
|
+
@tasks.task_ready?(task)
|
220
|
+
end
|
187
221
|
end
|
188
222
|
|
189
|
-
#
|
190
|
-
|
191
|
-
|
192
|
-
end
|
223
|
+
# :due_date_set function
|
224
|
+
class DueDateSetPFunctionEvaluator < FunctionEvaluator
|
225
|
+
FUNCTION_NAME = :due_date_set
|
193
226
|
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
# @return [Boolean]
|
198
|
-
def evaluate(task, tag_name)
|
199
|
-
task.tags.map(&:name).include? tag_name
|
200
|
-
end
|
201
|
-
end
|
227
|
+
def matches?
|
228
|
+
fn?(task_selector, FUNCTION_NAME)
|
229
|
+
end
|
202
230
|
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
231
|
+
# @sg-ignore
|
232
|
+
# @param task [Asana::Resources::Task]
|
233
|
+
# @return [Boolean]
|
234
|
+
def evaluate(task)
|
235
|
+
!task.due_at.nil? || !task.due_on.nil?
|
236
|
+
end
|
207
237
|
end
|
208
238
|
|
209
|
-
#
|
210
|
-
|
211
|
-
|
212
|
-
@tasks.task_ready?(task)
|
213
|
-
end
|
214
|
-
end
|
239
|
+
# :custom_field_value function
|
240
|
+
class CustomFieldValueFunctionEvaluator < FunctionEvaluator
|
241
|
+
FUNCTION_NAME = :custom_field_value
|
215
242
|
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
fn?(task_selector, :due_date_set)
|
220
|
-
end
|
243
|
+
def matches?
|
244
|
+
fn?(task_selector, FUNCTION_NAME)
|
245
|
+
end
|
221
246
|
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
!task.due_at.nil? || !task.due_on.nil?
|
227
|
-
end
|
228
|
-
end
|
247
|
+
# @param _index [Integer]
|
248
|
+
def evaluate_arg?(_index)
|
249
|
+
false
|
250
|
+
end
|
229
251
|
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
252
|
+
# @param task [Asana::Resources::Task]
|
253
|
+
# @param custom_field_name [String]
|
254
|
+
# @return [String, nil]
|
255
|
+
def evaluate(task, custom_field_name)
|
256
|
+
custom_field = pull_custom_field_by_name(task, custom_field_name)
|
257
|
+
return nil if custom_field.nil?
|
235
258
|
|
236
|
-
|
237
|
-
|
238
|
-
false
|
259
|
+
custom_field['display_value']
|
260
|
+
end
|
239
261
|
end
|
240
262
|
|
241
|
-
#
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
return nil if custom_field.nil?
|
263
|
+
# :custom_field_gid_value function
|
264
|
+
class CustomFieldGidValueFunctionEvaluator < FunctionEvaluator
|
265
|
+
def matches?
|
266
|
+
fn?(task_selector, :custom_field_gid_value)
|
267
|
+
end
|
247
268
|
|
248
|
-
|
249
|
-
|
250
|
-
|
269
|
+
def evaluate_arg?(_index)
|
270
|
+
false
|
271
|
+
end
|
251
272
|
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
273
|
+
# @sg-ignore
|
274
|
+
# @param task [Asana::Resources::Task]
|
275
|
+
# @param custom_field_gid [String]
|
276
|
+
# @return [String, nil]
|
277
|
+
def evaluate(task, custom_field_gid)
|
278
|
+
custom_field = pull_custom_field_or_raise(task, custom_field_gid)
|
279
|
+
custom_field['display_value']
|
280
|
+
end
|
256
281
|
end
|
257
282
|
|
258
|
-
|
259
|
-
|
260
|
-
|
283
|
+
# :custom_field_gid_value_contains_any_gid function
|
284
|
+
class CustomFieldGidValueContainsAnyGidFunctionEvaluator < FunctionEvaluator
|
285
|
+
FUNCTION_NAME = :custom_field_gid_value_contains_any_gid
|
261
286
|
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
# @return [String, nil]
|
266
|
-
def evaluate(task, custom_field_gid)
|
267
|
-
custom_field = pull_custom_field_or_raise(task, custom_field_gid)
|
268
|
-
custom_field['display_value']
|
269
|
-
end
|
270
|
-
end
|
287
|
+
def matches?
|
288
|
+
fn?(task_selector, FUNCTION_NAME)
|
289
|
+
end
|
271
290
|
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
291
|
+
def evaluate_arg?(_index)
|
292
|
+
false
|
293
|
+
end
|
294
|
+
|
295
|
+
# @param task [Asana::Resources::Task]
|
296
|
+
# @param custom_field_gid [String]
|
297
|
+
# @param custom_field_values_gids [Array<String>]
|
298
|
+
# @return [Boolean]
|
299
|
+
def evaluate(task, custom_field_gid, custom_field_values_gids)
|
300
|
+
actual_custom_field_values_gids = pull_custom_field_values_gids(task, custom_field_gid)
|
277
301
|
|
278
|
-
|
279
|
-
|
302
|
+
actual_custom_field_values_gids.any? do |custom_field_value|
|
303
|
+
custom_field_values_gids.include?(custom_field_value)
|
304
|
+
end
|
305
|
+
end
|
280
306
|
end
|
281
307
|
|
282
|
-
#
|
283
|
-
|
284
|
-
|
285
|
-
# @return [Boolean]
|
286
|
-
def evaluate(task, custom_field_gid, custom_field_values_gids)
|
287
|
-
actual_custom_field_values_gids = pull_custom_field_values_gids(task, custom_field_gid)
|
308
|
+
# :custom_field_gid_value_contains_all_gids function
|
309
|
+
class CustomFieldGidValueContainsAllGidsFunctionEvaluator < FunctionEvaluator
|
310
|
+
FUNCTION_NAME = :custom_field_gid_value_contains_all_gids
|
288
311
|
|
289
|
-
|
290
|
-
|
312
|
+
def matches?
|
313
|
+
fn?(task_selector, FUNCTION_NAME)
|
291
314
|
end
|
292
|
-
end
|
293
|
-
end
|
294
315
|
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
fn?(task_selector, :custom_field_gid_value_contains_all_gids)
|
299
|
-
end
|
316
|
+
def evaluate_arg?(_index)
|
317
|
+
false
|
318
|
+
end
|
300
319
|
|
301
|
-
|
302
|
-
|
320
|
+
# @param task [Asana::Resources::Task]
|
321
|
+
# @param custom_field_gid [String]
|
322
|
+
# @param custom_field_values_gids [Array<String>]
|
323
|
+
# @return [Boolean]
|
324
|
+
def evaluate(task, custom_field_gid, custom_field_values_gids)
|
325
|
+
actual_custom_field_values_gids = pull_custom_field_values_gids(task, custom_field_gid)
|
326
|
+
|
327
|
+
custom_field_values_gids.all? do |custom_field_value|
|
328
|
+
actual_custom_field_values_gids.include?(custom_field_value)
|
329
|
+
end
|
330
|
+
end
|
303
331
|
end
|
304
332
|
|
305
|
-
#
|
306
|
-
|
307
|
-
|
308
|
-
# @return [Boolean]
|
309
|
-
def evaluate(task, custom_field_gid, custom_field_values_gids)
|
310
|
-
actual_custom_field_values_gids = pull_custom_field_values_gids(task, custom_field_gid)
|
333
|
+
# :custom_field_less_than_n_days_from_now function
|
334
|
+
class CustomFieldLessThanNDaysFromNowFunctionEvaluator < FunctionEvaluator
|
335
|
+
FUNCTION_NAME = :custom_field_less_than_n_days_from_now
|
311
336
|
|
312
|
-
|
313
|
-
|
337
|
+
def matches?
|
338
|
+
fn?(task_selector, FUNCTION_NAME)
|
314
339
|
end
|
315
|
-
end
|
316
|
-
end
|
317
340
|
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
fn?(task_selector, :custom_field_less_than_n_days_from_now)
|
322
|
-
end
|
341
|
+
def evaluate_arg?(_index)
|
342
|
+
false
|
343
|
+
end
|
323
344
|
|
324
|
-
|
325
|
-
|
345
|
+
# @param task [Asana::Resources::Task]
|
346
|
+
# @param custom_field_name [String]
|
347
|
+
# @param num_days [Integer]
|
348
|
+
# @return [Boolean]
|
349
|
+
def evaluate(task, custom_field_name, num_days)
|
350
|
+
custom_field = pull_custom_field_by_name_or_raise(task, custom_field_name)
|
351
|
+
|
352
|
+
time_str = custom_field.fetch('display_value')
|
353
|
+
time = Time.parse(time_str)
|
354
|
+
n_days_from_now = (Time.now + (num_days * 24 * 60 * 60))
|
355
|
+
time < n_days_from_now
|
356
|
+
end
|
326
357
|
end
|
327
358
|
|
328
|
-
#
|
329
|
-
|
330
|
-
|
331
|
-
# @return [Boolean]
|
332
|
-
def evaluate(task, custom_field_name, num_days)
|
333
|
-
custom_field = pull_custom_field_by_name_or_raise(task, custom_field_name)
|
334
|
-
|
335
|
-
time_str = custom_field.fetch('display_value')
|
336
|
-
time = Time.parse(time_str)
|
337
|
-
n_days_from_now = (Time.now + (num_days * 24 * 60 * 60))
|
338
|
-
time < n_days_from_now
|
339
|
-
end
|
340
|
-
end
|
359
|
+
# :custom_field_greater_than_or_equal_to_n_days_from_now function
|
360
|
+
class CustomFieldGreaterThanOrEqualToNDaysFromNowFunctionEvaluator < FunctionEvaluator
|
361
|
+
FUNCTION_NAME = :custom_field_greater_than_or_equal_to_n_days_from_now
|
341
362
|
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
fn?(task_selector, :custom_field_greater_than_or_equal_to_n_days_from_now)
|
346
|
-
end
|
363
|
+
def matches?
|
364
|
+
fn?(task_selector, FUNCTION_NAME)
|
365
|
+
end
|
347
366
|
|
348
|
-
|
349
|
-
|
350
|
-
|
367
|
+
def evaluate_arg?(_index)
|
368
|
+
false
|
369
|
+
end
|
351
370
|
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
371
|
+
# @param task [Asana::Resources::Task]
|
372
|
+
# @param custom_field_name [String]
|
373
|
+
# @param num_days [Integer]
|
374
|
+
# @return [Boolean]
|
375
|
+
def evaluate(task, custom_field_name, num_days)
|
376
|
+
custom_field = pull_custom_field_by_name_or_raise(task, custom_field_name)
|
377
|
+
|
378
|
+
time_str = custom_field.fetch('display_value')
|
379
|
+
time = Time.parse(time_str)
|
380
|
+
n_days_from_now = (Time.now + (num_days * 24 * 60 * 60))
|
381
|
+
time >= n_days_from_now
|
382
|
+
end
|
363
383
|
end
|
364
|
-
end
|
365
384
|
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
385
|
+
# String literals
|
386
|
+
class StringLiteralEvaluator < FunctionEvaluator
|
387
|
+
def matches?
|
388
|
+
task_selector.is_a?(String)
|
389
|
+
end
|
371
390
|
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
391
|
+
# @sg-ignore
|
392
|
+
# @param _task [Asana::Resources::Task]
|
393
|
+
# @return [String]
|
394
|
+
def evaluate(_task)
|
395
|
+
task_selector
|
396
|
+
end
|
377
397
|
end
|
378
398
|
end
|
379
399
|
|
@@ -388,20 +408,20 @@ module Checkoff
|
|
388
408
|
end
|
389
409
|
|
390
410
|
FUNCTION_EVALUTORS = [
|
391
|
-
NotFunctionEvaluator,
|
392
|
-
NilPFunctionEvaluator,
|
393
|
-
EqualsPFunctionEvaluator,
|
394
|
-
TagPFunctionEvaluator,
|
395
|
-
CustomFieldValueFunctionEvaluator,
|
396
|
-
CustomFieldGidValueFunctionEvaluator,
|
397
|
-
CustomFieldGidValueContainsAnyGidFunctionEvaluator,
|
398
|
-
CustomFieldGidValueContainsAllGidsFunctionEvaluator,
|
399
|
-
AndFunctionEvaluator,
|
400
|
-
DuePFunctionEvaluator,
|
401
|
-
DueDateSetPFunctionEvaluator,
|
402
|
-
CustomFieldLessThanNDaysFromNowFunctionEvaluator,
|
403
|
-
CustomFieldGreaterThanOrEqualToNDaysFromNowFunctionEvaluator,
|
404
|
-
StringLiteralEvaluator,
|
411
|
+
Checkoff::TaskSelectorClasses::NotFunctionEvaluator,
|
412
|
+
Checkoff::TaskSelectorClasses::NilPFunctionEvaluator,
|
413
|
+
Checkoff::TaskSelectorClasses::EqualsPFunctionEvaluator,
|
414
|
+
Checkoff::TaskSelectorClasses::TagPFunctionEvaluator,
|
415
|
+
Checkoff::TaskSelectorClasses::CustomFieldValueFunctionEvaluator,
|
416
|
+
Checkoff::TaskSelectorClasses::CustomFieldGidValueFunctionEvaluator,
|
417
|
+
Checkoff::TaskSelectorClasses::CustomFieldGidValueContainsAnyGidFunctionEvaluator,
|
418
|
+
Checkoff::TaskSelectorClasses::CustomFieldGidValueContainsAllGidsFunctionEvaluator,
|
419
|
+
Checkoff::TaskSelectorClasses::AndFunctionEvaluator,
|
420
|
+
Checkoff::TaskSelectorClasses::DuePFunctionEvaluator,
|
421
|
+
Checkoff::TaskSelectorClasses::DueDateSetPFunctionEvaluator,
|
422
|
+
Checkoff::TaskSelectorClasses::CustomFieldLessThanNDaysFromNowFunctionEvaluator,
|
423
|
+
Checkoff::TaskSelectorClasses::CustomFieldGreaterThanOrEqualToNDaysFromNowFunctionEvaluator,
|
424
|
+
Checkoff::TaskSelectorClasses::StringLiteralEvaluator,
|
405
425
|
].freeze
|
406
426
|
|
407
427
|
# @param task_selector [Array]
|
data/lib/checkoff/sections.rb
CHANGED
@@ -13,15 +13,24 @@ module Checkoff
|
|
13
13
|
# extend CacheMethod::ClassMethods
|
14
14
|
|
15
15
|
MINUTE = 60
|
16
|
-
# @sg-ignore
|
17
16
|
LONG_CACHE_TIME = MINUTE * 15
|
18
|
-
# @sg-ignore
|
19
17
|
SHORT_CACHE_TIME = MINUTE * 5
|
20
18
|
|
21
19
|
extend Forwardable
|
22
20
|
|
23
|
-
|
21
|
+
# @return [Checkoff::Projects]
|
22
|
+
attr_reader :projects
|
23
|
+
|
24
|
+
# @return [Checkoff::Workspaces]
|
25
|
+
attr_reader :workspaces
|
24
26
|
|
27
|
+
# @return [Class<Time>]
|
28
|
+
attr_reader :time
|
29
|
+
|
30
|
+
# @return [Checkoff::MyTasks]
|
31
|
+
attr_reader :my_tasks
|
32
|
+
|
33
|
+
# @param config [Hash<Symbol, Object>]
|
25
34
|
# @param client [Asana::Client]
|
26
35
|
# @param projects [Checkoff::Projects]
|
27
36
|
# @param workspaces [Checkoff::Workspaces]
|
@@ -108,6 +117,7 @@ module Checkoff
|
|
108
117
|
# @param project_name [String, Symbol]
|
109
118
|
# @param section_name [String, nil]
|
110
119
|
#
|
120
|
+
# @sg-ignore
|
111
121
|
# @return [Asana::Resources::Section]
|
112
122
|
def section_or_raise(workspace_name, project_name, section_name)
|
113
123
|
s = section(workspace_name, project_name, section_name)
|
@@ -123,13 +133,13 @@ module Checkoff
|
|
123
133
|
|
124
134
|
private
|
125
135
|
|
126
|
-
#
|
127
|
-
# @return [Asana::Client]
|
136
|
+
# @return [Asana::Client]
|
128
137
|
attr_reader :client
|
129
138
|
|
130
139
|
# Given a project object, pull all tasks, then provide a Hash of
|
131
140
|
# tasks with section name -> task list of the uncompleted tasks
|
132
141
|
# @param project [Asana::Resources::Project]
|
142
|
+
# @param extra_fields [Array<String>]
|
133
143
|
# @return [Hash<[String,nil], Array<Asana::Resources::Task>>]
|
134
144
|
def tasks_by_section_for_project(project, extra_fields: [])
|
135
145
|
raw_tasks = projects.tasks_from_project(project, extra_fields: extra_fields)
|
@@ -137,6 +147,8 @@ module Checkoff
|
|
137
147
|
by_section(active_tasks, project.gid)
|
138
148
|
end
|
139
149
|
|
150
|
+
# @param name [String]
|
151
|
+
# @return [String, nil]
|
140
152
|
def section_key(name)
|
141
153
|
inbox_section_names = ['(no section)', 'Untitled section', 'Inbox']
|
142
154
|
return nil if inbox_section_names.include?(name)
|
@@ -188,6 +200,11 @@ module Checkoff
|
|
188
200
|
project
|
189
201
|
end
|
190
202
|
|
203
|
+
# @sg-ignore
|
204
|
+
# @param workspace_name [String]
|
205
|
+
# @param project_name [String, Symbol]
|
206
|
+
# @param section_name [String, nil]
|
207
|
+
# @return [Asana::Resources::Section, nil]
|
191
208
|
def section(workspace_name, project_name, section_name)
|
192
209
|
sections = sections_or_raise(workspace_name, project_name)
|
193
210
|
sections.find { |section| section_key(section.name)&.chomp(':') == section_name&.chomp(':') }
|
data/lib/checkoff/tasks.rb
CHANGED
@@ -161,12 +161,11 @@ module Checkoff
|
|
161
161
|
|
162
162
|
# @sg-ignore
|
163
163
|
# @type [Array<Asana::Resources::Task>, nil]
|
164
|
-
|
165
|
-
|
166
|
-
return false unless already_fetched_dependencies.nil? || already_fetched_dependencies.size.positive?
|
164
|
+
dependencies = task.instance_variable_get(:@dependencies)
|
165
|
+
dependencies = task.dependencies.map { |task| { 'gid' => task.gid } } if dependencies.nil?
|
167
166
|
|
168
|
-
|
169
|
-
parent_task_gid = parent_task_info.gid
|
167
|
+
dependencies.any? do |parent_task_info|
|
168
|
+
parent_task_gid = parent_task_info.fetch('gid')
|
170
169
|
parent_task = @asana_task.find_by_id(client, parent_task_gid,
|
171
170
|
options: { fields: ['completed'] })
|
172
171
|
!parent_task.completed
|
data/lib/checkoff/version.rb
CHANGED
data/lib/checkoff/workspaces.rb
CHANGED
@@ -12,16 +12,18 @@ module Checkoff
|
|
12
12
|
# Query different workspaces of Asana projects
|
13
13
|
class Workspaces
|
14
14
|
MINUTE = 60
|
15
|
-
# @sg-ignore
|
16
15
|
HOUR = MINUTE * 60
|
17
16
|
DAY = 24 * HOUR
|
18
|
-
# @sg-ignore
|
19
17
|
REALLY_LONG_CACHE_TIME = HOUR * 1
|
20
|
-
# @sg-ignore
|
21
18
|
LONG_CACHE_TIME = MINUTE * 15
|
22
19
|
SHORT_CACHE_TIME = MINUTE
|
23
20
|
|
21
|
+
# @!parse
|
22
|
+
# extend CacheMethod::ClassMethods
|
23
|
+
|
24
|
+
# @param config [Hash<Symbol, Object>]
|
24
25
|
# @param client [Asana::Client]
|
26
|
+
# @param asana_workspace [Class<Asana::Resources::Workspace>]
|
25
27
|
def initialize(config: Checkoff::Internal::ConfigLoader.load(:asana),
|
26
28
|
client: Checkoff::Clients.new(config: config).client,
|
27
29
|
asana_workspace: Asana::Resources::Workspace)
|
@@ -32,6 +34,7 @@ module Checkoff
|
|
32
34
|
|
33
35
|
# Pulls an Asana workspace object
|
34
36
|
# @param [String] workspace_name
|
37
|
+
# @sg-ignore
|
35
38
|
# @return [Asana::Resources::Workspace, nil]
|
36
39
|
def workspace(workspace_name)
|
37
40
|
client.workspaces.find_all.find do |workspace|
|
@@ -43,6 +46,7 @@ module Checkoff
|
|
43
46
|
def default_workspace
|
44
47
|
@asana_workspace.find_by_id(client, default_workspace_gid)
|
45
48
|
end
|
49
|
+
cache_method :default_workspace, REALLY_LONG_CACHE_TIME
|
46
50
|
|
47
51
|
# @param [String] workspace_name
|
48
52
|
# @return [Asana::Resources::Workspace]
|
@@ -61,6 +65,7 @@ module Checkoff
|
|
61
65
|
|
62
66
|
private
|
63
67
|
|
68
|
+
# @return [Asana::Client]
|
64
69
|
attr_reader :client
|
65
70
|
end
|
66
71
|
end
|
data/rakelib/doc.rake
ADDED
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.44.
|
4
|
+
version: 0.44.2
|
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-
|
11
|
+
date: 2023-07-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -120,6 +120,7 @@ files:
|
|
120
120
|
- bin/yard
|
121
121
|
- checkoff.gemspec
|
122
122
|
- config/definitions.rb
|
123
|
+
- docs/.gitignore
|
123
124
|
- docs/cookiecutter_input.json
|
124
125
|
- docs/example_project.png
|
125
126
|
- exe/checkoff
|
@@ -169,6 +170,7 @@ files:
|
|
169
170
|
- rakelib/clear_metrics.rake
|
170
171
|
- rakelib/console.rake
|
171
172
|
- rakelib/default.rake
|
173
|
+
- rakelib/doc.rake
|
172
174
|
- rakelib/gem_tasks.rake
|
173
175
|
- rakelib/localtest.rake
|
174
176
|
- rakelib/overcommit.rake
|