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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 413eeaac4e3e2a4784e5fca4930fed96beedd594b87f1c8d80460aabe4ee1dd3
4
- data.tar.gz: 4127604e8d5c3605d49c2fda86fe0c0e1bed95aaeadfc493d8a2b02c19bed94d
3
+ metadata.gz: d924c906eed129ad1c57bdbfdd8cdcc61b572e296a09721195b7c1a10d78dbe5
4
+ data.tar.gz: 79e71aac6289b18a448288a601c62a02cee6583bcbbc966e64a71003c8e73e89
5
5
  SHA512:
6
- metadata.gz: 001c49dab8df9d273f2c395dd422509afa82c856712b7dfef9b7c65bf7f23c7d3ada832d32e888b188d38751716ee7e54c8d144b4575cd2de384946002ae6fc5
7
- data.tar.gz: a10f6ee8a33870277503458dc19809e642d837899c31c1698ba04942356386fe09c713643db3f3694eca7d5495c43fe13c93d2ae7785e3ad383aeed88651e2f0
6
+ metadata.gz: 8bc265211c02ebf11e7c7f35ce79aae7517c6b86cf023c8d0b41713a24df2365954f9757bfe9b44a85573187af7fb355f84e7d6b1bad9e8b32fc9b8b9ed6891d
7
+ data.tar.gz: 5de92894cb1f12d633667b87f426f4460d63a54d84cb1a9f2e8e38c529c45d41efdd9097cb9a2dd6f73691669a4a070ba87aedc55a5d8ec7780fa9cec5e2d13a
data/Gemfile CHANGED
@@ -29,6 +29,7 @@ gem 'simplecov-lcov'
29
29
  gem 'solargraph', ['>=0.49.0']
30
30
  gem 'undercover'
31
31
  gem 'webmock'
32
+ gem 'yard'
32
33
 
33
34
  # ruby-asana gem is pending key bugfixes for checkoff as of
34
35
  # 2021-07-29:
data/Gemfile.lock CHANGED
@@ -12,7 +12,7 @@ GIT
12
12
  PATH
13
13
  remote: .
14
14
  specs:
15
- checkoff (0.44.0)
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.5.1)
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
@@ -2,7 +2,11 @@
2
2
 
3
3
  Command-line and gem client for Asana (unofficial)
4
4
 
5
- ## Using
5
+ ## Using library
6
+
7
+ See [docs](https://www.rubydoc.info/github/apiology/checkoff)
8
+
9
+ ## Using CLI
6
10
 
7
11
  ```sh
8
12
  $ checkoff --help
data/docs/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ *.html
2
+ /css
3
+ /js
@@ -1,379 +1,399 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Checkoff
4
- # Base class to evaluate a task selector function given fully evaluated arguments
5
- class FunctionEvaluator
6
- # @param task_selector [Array<(Symbol, Array)>,String]
7
- # @param tasks [Checkoff::Tasks]
8
- def initialize(task_selector:,
9
- tasks:)
10
- @task_selector = task_selector
11
- @tasks = tasks
12
- end
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
- # @sg-ignore
15
- # @param _index [Integer]
16
- def evaluate_arg?(_index)
17
- true
18
- end
15
+ # @sg-ignore
16
+ # @param _index [Integer]
17
+ def evaluate_arg?(_index)
18
+ true
19
+ end
19
20
 
20
- # @sg-ignore
21
- # @return [Boolean]
22
- def matches?
23
- raise 'Override me!'
24
- end
21
+ # @sg-ignore
22
+ # @return [Boolean]
23
+ def matches?
24
+ raise 'Override me!'
25
+ end
25
26
 
26
- private
27
+ private
27
28
 
28
- # @param object [Object]
29
- # @param fn_name [Symbol]
30
- def fn?(object, fn_name)
31
- object.is_a?(Array) && !object.empty? && [fn_name, fn_name.to_s].include?(object[0])
32
- end
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
- # @sg-ignore
35
- # @param task [Asana::Resources::Task]
36
- # @param custom_field_gid [String]
37
- # @return [Hash]
38
- def pull_custom_field_or_raise(task, custom_field_gid)
39
- # @type [Array<Hash>]
40
- custom_fields = task.custom_fields
41
- if custom_fields.nil?
42
- raise "Could not find custom_fields under task (was 'custom_fields' included in 'extra_fields'?)"
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
- # @type [Hash, nil]
47
- matched_custom_field = custom_fields.find { |data| data.fetch('gid') == custom_field_gid }
48
- if matched_custom_field.nil?
49
- raise "Could not find custom field with gid #{custom_field_gid} " \
50
- "in task #{task.gid} with custom fields #{custom_fields}"
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
- matched_custom_field
54
- end
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
- # @return [Array<(Symbol, Array)>]
57
- attr_reader :task_selector
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
- # @sg-ignore
60
- # @param custom_field [Hash]
61
- # @return [Array<String>]
62
- def pull_enum_values(custom_field)
63
- resource_subtype = custom_field.fetch('resource_subtype')
64
- case resource_subtype
65
- when 'enum'
66
- [custom_field.fetch('enum_value')]
67
- when 'multi_enum'
68
- custom_field.fetch('multi_enum_values')
69
- else
70
- raise "Teach me how to handle resource_subtype #{resource_subtype}"
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
- # @param custom_field [Hash]
75
- # @param enum_value [Object, nil]
76
- # @return [Array<String>]
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
- [enum_value.fetch('gid')]
130
+ def matches?
131
+ fn?(task_selector, FUNCTION_NAME)
84
132
  end
85
- end
86
133
 
87
- # @param task [Asana::Resources::Task]
88
- # @param custom_field_gid [String]
89
- # @return [Array<String>]
90
- def pull_custom_field_values_gids(task, custom_field_gid)
91
- custom_field = pull_custom_field_or_raise(task, custom_field_gid)
92
- pull_enum_values(custom_field).flat_map do |enum_value|
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
- # @sg-ignore
98
- # @param task [Asana::Resources::Task]
99
- # @param custom_field_name [String]
100
- # @return [Hash, nil]
101
- def pull_custom_field_by_name(task, custom_field_name)
102
- custom_fields = task.custom_fields
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
- # @sg-ignore
108
- # @type [Hash, nil]
109
- custom_fields.find { |field| field.fetch('name') == custom_field_name }
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
- # @param task [Asana::Resources::Task]
113
- # @param custom_field_name [String]
114
- # @return [Hash]
115
- def pull_custom_field_by_name_or_raise(task, custom_field_name)
116
- custom_field = pull_custom_field_by_name(task, custom_field_name)
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
- # :and function
126
- class AndFunctionEvaluator < FunctionEvaluator
127
- def matches?
128
- fn?(task_selector, :and)
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
- # @param _task [Asana::Resources::Task]
132
- # @param lhs [Object]
133
- # @param rhs [Object]
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
- # :not function
141
- class NotFunctionEvaluator < FunctionEvaluator
142
- def matches?
143
- fn?(task_selector, :not)
144
- end
177
+ def matches?
178
+ fn?(task_selector, FUNCTION_NAME)
179
+ end
145
180
 
146
- # @param _task [Asana::Resources::Task]
147
- # @param subvalue [Object]
148
- # @return [Boolean]
149
- def evaluate(_task, subvalue)
150
- !subvalue
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
- # :nil? function
155
- class NilPFunctionEvaluator < FunctionEvaluator
156
- def matches?
157
- fn?(task_selector, :nil?)
158
- end
190
+ # :tag function
191
+ class TagPFunctionEvaluator < FunctionEvaluator
192
+ def matches?
193
+ fn?(task_selector, :tag)
194
+ end
159
195
 
160
- # @param _task [Asana::Resources::Task]
161
- # @param subvalue [Object]
162
- # @return [Boolean]
163
- def evaluate(_task, subvalue)
164
- subvalue.nil?
165
- end
166
- end
196
+ # @param _index [Integer]
197
+ def evaluate_arg?(_index)
198
+ false
199
+ end
167
200
 
168
- # :equals? function
169
- class EqualsPFunctionEvaluator < FunctionEvaluator
170
- def matches?
171
- fn?(task_selector, :equals?)
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
- # @param _task [Asana::Resources::Task]
175
- # @param lhs [Object]
176
- # @param rhs [Object]
177
- # @return [Boolean]
178
- def evaluate(_task, lhs, rhs)
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
- # :tag function
184
- class TagPFunctionEvaluator < FunctionEvaluator
185
- def matches?
186
- fn?(task_selector, :tag)
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
- # @param _index [Integer]
190
- def evaluate_arg?(_index)
191
- false
192
- end
223
+ # :due_date_set function
224
+ class DueDateSetPFunctionEvaluator < FunctionEvaluator
225
+ FUNCTION_NAME = :due_date_set
193
226
 
194
- # @sg-ignore
195
- # @param task [Asana::Resources::Task]
196
- # @param tag_name [String]
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
- # :due function
204
- class DuePFunctionEvaluator < FunctionEvaluator
205
- def matches?
206
- fn?(task_selector, :due)
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
- # @param task [Asana::Resources::Task]
210
- # @return [Boolean]
211
- def evaluate(task)
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
- # :due_date_set function
217
- class DueDateSetPFunctionEvaluator < FunctionEvaluator
218
- def matches?
219
- fn?(task_selector, :due_date_set)
220
- end
243
+ def matches?
244
+ fn?(task_selector, FUNCTION_NAME)
245
+ end
221
246
 
222
- # @sg-ignore
223
- # @param task [Asana::Resources::Task]
224
- # @return [Boolean]
225
- def evaluate(task)
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
- # :custom_field_value function
231
- class CustomFieldValueFunctionEvaluator < FunctionEvaluator
232
- def matches?
233
- fn?(task_selector, :custom_field_value)
234
- end
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
- # @param _index [Integer]
237
- def evaluate_arg?(_index)
238
- false
259
+ custom_field['display_value']
260
+ end
239
261
  end
240
262
 
241
- # @param task [Asana::Resources::Task]
242
- # @param custom_field_name [String]
243
- # @return [String, nil]
244
- def evaluate(task, custom_field_name)
245
- custom_field = pull_custom_field_by_name(task, custom_field_name)
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
- custom_field['display_value']
249
- end
250
- end
269
+ def evaluate_arg?(_index)
270
+ false
271
+ end
251
272
 
252
- # :custom_field_gid_value function
253
- class CustomFieldGidValueFunctionEvaluator < FunctionEvaluator
254
- def matches?
255
- fn?(task_selector, :custom_field_gid_value)
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
- def evaluate_arg?(_index)
259
- false
260
- end
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
- # @sg-ignore
263
- # @param task [Asana::Resources::Task]
264
- # @param custom_field_gid [String]
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
- # :custom_field_gid_value_contains_any_gid function
273
- class CustomFieldGidValueContainsAnyGidFunctionEvaluator < FunctionEvaluator
274
- def matches?
275
- fn?(task_selector, :custom_field_gid_value_contains_any_gid)
276
- end
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
- def evaluate_arg?(_index)
279
- false
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
- # @param task [Asana::Resources::Task]
283
- # @param custom_field_gid [String]
284
- # @param custom_field_values_gids [Array<String>]
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
- actual_custom_field_values_gids.any? do |custom_field_value|
290
- custom_field_values_gids.include?(custom_field_value)
312
+ def matches?
313
+ fn?(task_selector, FUNCTION_NAME)
291
314
  end
292
- end
293
- end
294
315
 
295
- # :custom_field_gid_value_contains_all_gids function
296
- class CustomFieldGidValueContainsAllGidsFunctionEvaluator < FunctionEvaluator
297
- def matches?
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
- def evaluate_arg?(_index)
302
- false
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
- # @param task [Asana::Resources::Task]
306
- # @param custom_field_gid [String]
307
- # @param custom_field_values_gids [Array<String>]
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
- custom_field_values_gids.all? do |custom_field_value|
313
- actual_custom_field_values_gids.include?(custom_field_value)
337
+ def matches?
338
+ fn?(task_selector, FUNCTION_NAME)
314
339
  end
315
- end
316
- end
317
340
 
318
- # :custom_field_less_than_n_days_from_now function
319
- class CustomFieldLessThanNDaysFromNowFunctionEvaluator < FunctionEvaluator
320
- def matches?
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
- def evaluate_arg?(_index)
325
- false
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
- # @param task [Asana::Resources::Task]
329
- # @param custom_field_name [String]
330
- # @param num_days [Integer]
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
- # :custom_field_greater_than_or_equal_to_n_days_from_now function
343
- class CustomFieldGreaterThanOrEqualToNDaysFromNowFunctionEvaluator < FunctionEvaluator
344
- def matches?
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
- def evaluate_arg?(_index)
349
- false
350
- end
367
+ def evaluate_arg?(_index)
368
+ false
369
+ end
351
370
 
352
- # @param task [Asana::Resources::Task]
353
- # @param custom_field_name [String]
354
- # @param num_days [Integer]
355
- # @return [Boolean]
356
- def evaluate(task, custom_field_name, num_days)
357
- custom_field = pull_custom_field_by_name_or_raise(task, custom_field_name)
358
-
359
- time_str = custom_field.fetch('display_value')
360
- time = Time.parse(time_str)
361
- n_days_from_now = (Time.now + (num_days * 24 * 60 * 60))
362
- time >= n_days_from_now
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
- # String literals
367
- class StringLiteralEvaluator < FunctionEvaluator
368
- def matches?
369
- task_selector.is_a?(String)
370
- end
385
+ # String literals
386
+ class StringLiteralEvaluator < FunctionEvaluator
387
+ def matches?
388
+ task_selector.is_a?(String)
389
+ end
371
390
 
372
- # @sg-ignore
373
- # @param _task [Asana::Resources::Task]
374
- # @return [String]
375
- def evaluate(_task)
376
- task_selector
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]
@@ -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
- attr_reader :projects, :workspaces, :time, :my_tasks
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
- # @!attribute [r] client
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(':') }
@@ -161,12 +161,11 @@ module Checkoff
161
161
 
162
162
  # @sg-ignore
163
163
  # @type [Array<Asana::Resources::Task>, nil]
164
- already_fetched_dependencies = task.instance_variable_get(:@dependencies)
165
- # @sg-ignore
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
- task.dependencies.any? do |parent_task_info|
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
@@ -3,5 +3,5 @@
3
3
  # Command-line and gem client for Asana (unofficial)
4
4
  module Checkoff
5
5
  # Version of library
6
- VERSION = '0.44.0'
6
+ VERSION = '0.44.2'
7
7
  end
@@ -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
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ desc 'Push documentation updates to Dropbox'
4
+ task :doc do
5
+ sh 'yard -p yard_templates -o docs/ --no-private'
6
+ end
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.0
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-06-28 00:00:00.000000000 Z
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