checkoff 0.43.0 → 0.44.1

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: af9b4c58d6440cc99eab9508632a3140d3f1519ad32fdf5f21b65833291999ba
4
- data.tar.gz: 8d32790e9071087f948f9c1e3a3f3870f2de3dd0a1ab835e2b3727b7725d69e0
3
+ metadata.gz: c5186c70798590604d6800a0c6da9ee511ea72114e9cfea4f47bb3f4f77b5237
4
+ data.tar.gz: 814265150a1a7af8b8980e7f71e2f085d762ef0b1c690a6b04e31c72ef128e2b
5
5
  SHA512:
6
- metadata.gz: cf699102f03d8d6169e317f94aa88229537626ea74ec3b17446396e35fcf7e9d758d1b881d3c0d4fade4324a52e4ec64ed60d6540cac736e11440a9b4fbb1ca4
7
- data.tar.gz: ea3952f4603dcb3344b856df43f11686589f8341763bb360d467bb99c852922b8480c3a41a86829dd25a79d3874561675e4ac4d98e09dddbc059720d86577583
6
+ metadata.gz: 89b6ec01624867af12f192762ff2179846856d60641efdd6e1f59acd2a3a22dbbe76d9ad439ed21086385004d1c973c229a49ad085036e8696507bbaf275c44a
7
+ data.tar.gz: 0d344a736addad549df2918c8d24d351ece8a13c7962a2af951569073f0c3956e9b9094a0e0ccc691d429019885af9e4fa0dc64b1ce7401ae62b15ba0facfef2
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.43.0)
15
+ checkoff (0.44.1)
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)
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,355 +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
362
+
363
+ def matches?
364
+ fn?(task_selector, FUNCTION_NAME)
365
+ end
341
366
 
342
- # String literals
343
- class StringLiteralEvaluator < FunctionEvaluator
344
- def matches?
345
- task_selector.is_a?(String)
367
+ def evaluate_arg?(_index)
368
+ false
369
+ end
370
+
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
346
383
  end
347
384
 
348
- # @sg-ignore
349
- # @param _task [Asana::Resources::Task]
350
- # @return [String]
351
- def evaluate(_task)
352
- task_selector
385
+ # String literals
386
+ class StringLiteralEvaluator < FunctionEvaluator
387
+ def matches?
388
+ task_selector.is_a?(String)
389
+ end
390
+
391
+ # @sg-ignore
392
+ # @param _task [Asana::Resources::Task]
393
+ # @return [String]
394
+ def evaluate(_task)
395
+ task_selector
396
+ end
353
397
  end
354
398
  end
355
399
 
@@ -364,19 +408,20 @@ module Checkoff
364
408
  end
365
409
 
366
410
  FUNCTION_EVALUTORS = [
367
- NotFunctionEvaluator,
368
- NilPFunctionEvaluator,
369
- EqualsPFunctionEvaluator,
370
- TagPFunctionEvaluator,
371
- CustomFieldValueFunctionEvaluator,
372
- CustomFieldGidValueFunctionEvaluator,
373
- CustomFieldGidValueContainsAnyGidFunctionEvaluator,
374
- CustomFieldGidValueContainsAllGidsFunctionEvaluator,
375
- AndFunctionEvaluator,
376
- DuePFunctionEvaluator,
377
- DueDateSetPFunctionEvaluator,
378
- CustomFieldLessThanNDaysFromNowFunctionEvaluator,
379
- 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,
380
425
  ].freeze
381
426
 
382
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,11 +161,10 @@ 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 if dependencies.nil?
167
166
 
168
- task.dependencies.any? do |parent_task_info|
167
+ dependencies.any? do |parent_task_info|
169
168
  parent_task_gid = parent_task_info.gid
170
169
  parent_task = @asana_task.find_by_id(client, parent_task_gid,
171
170
  options: { fields: ['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.43.0'
6
+ VERSION = '0.44.1'
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.43.0
4
+ version: 0.44.1
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-26 00:00:00.000000000 Z
11
+ date: 2023-07-01 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