checkoff 0.40.0 → 0.42.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 42f156ed0a4b85a8fa1b0887a74c3df016d8245293c547ea6b2ed49be7254b18
4
- data.tar.gz: 55e6d2c6c560e4c74c18c8db95f079a36637912973e849154f1f2e2bcb724f97
3
+ metadata.gz: 83cd30ff493ada586596020db325eed63c9e4c24919e34c7e9926c0f9bedf51f
4
+ data.tar.gz: fee54feaa76dafc06dba69267f4ea6a7b2877e68df6af43738468e65cca552b6
5
5
  SHA512:
6
- metadata.gz: 8e200395f12114df856c15c030dcbf4d2a8a7a77333cd431881352975655fa7d6a559626dafb15d9f93c9fbcec47e6c1d1be5afc6f7ee6e5d816d315b4566d20
7
- data.tar.gz: 6ce670c2ce1e0b783ca3d044b1e957004dc460cc0b207cda9f7ce12898021c32c94efa44bd4e1a652f76f2986c3a4d9873afbe1fe9e3eeec32df8ab4b9e40072
6
+ metadata.gz: 7d4cb677d35d91830b2aa6145d40a74ebb1e34ddd9a1e17203ef62ac66afb30a3a864924462de263ff663d33cc561272143fd1b0ab45e9499c4f42e2dad97840
7
+ data.tar.gz: b074ac5d6a2675e801b52e96d8453847607bf0e523a5988a50456258f1a668319846c8c1f965eadb09409f83b82d23b1262935c2606bab175de0664c7af2077a
data/Gemfile.lock CHANGED
@@ -12,7 +12,7 @@ GIT
12
12
  PATH
13
13
  remote: .
14
14
  specs:
15
- checkoff (0.40.0)
15
+ checkoff (0.42.0)
16
16
  activesupport
17
17
  asana (> 0.10.0)
18
18
  cache_method
@@ -39,6 +39,7 @@ module Checkoff
39
39
  # Load configuration file
40
40
  class ConfigLoader
41
41
  class << self
42
+ # @return EnvFallbackConfigLoader
42
43
  def load(sym)
43
44
  yaml_result = load_yaml_file(sym)
44
45
  EnvFallbackConfigLoader.new(yaml_result, sym, yaml_filename(sym))
@@ -3,28 +3,47 @@
3
3
  module Checkoff
4
4
  # Base class to evaluate a task selector function given fully evaluated arguments
5
5
  class FunctionEvaluator
6
+ # @param task_selector [Array<(Symbol, Array)>,String]
7
+ # @param tasks [Checkoff::Tasks]
6
8
  def initialize(task_selector:,
7
9
  tasks:)
8
10
  @task_selector = task_selector
9
11
  @tasks = tasks
10
12
  end
11
13
 
14
+ # @sg-ignore
15
+ # @param _index [Integer]
12
16
  def evaluate_arg?(_index)
13
17
  true
14
18
  end
15
19
 
20
+ # @sg-ignore
21
+ # @return [Boolean]
22
+ def matches?
23
+ raise 'Override me!'
24
+ end
25
+
16
26
  private
17
27
 
28
+ # @param object [Object]
29
+ # @param fn_name [Symbol]
18
30
  def fn?(object, fn_name)
19
31
  object.is_a?(Array) && !object.empty? && [fn_name, fn_name.to_s].include?(object[0])
20
32
  end
21
33
 
34
+ # @sg-ignore
35
+ # @param task [Asana::Resources::Task]
36
+ # @param custom_field_gid [String]
37
+ # @return [Hash]
22
38
  def pull_custom_field_or_raise(task, custom_field_gid)
39
+ # @type [Array<Hash>]
23
40
  custom_fields = task.custom_fields
24
41
  if custom_fields.nil?
25
42
  raise "Could not find custom_fields under task (was 'custom_fields' included in 'extra_fields'?)"
26
43
  end
27
44
 
45
+ # @sg-ignore
46
+ # @type [Hash, nil]
28
47
  matched_custom_field = custom_fields.find { |data| data.fetch('gid') == custom_field_gid }
29
48
  if matched_custom_field.nil?
30
49
  raise "Could not find custom field with gid #{custom_field_gid} " \
@@ -34,8 +53,12 @@ module Checkoff
34
53
  matched_custom_field
35
54
  end
36
55
 
56
+ # @return [Array<(Symbol, Array)>]
37
57
  attr_reader :task_selector
38
58
 
59
+ # @sg-ignore
60
+ # @param custom_field [Hash]
61
+ # @return [Array<String>]
39
62
  def pull_enum_values(custom_field)
40
63
  resource_subtype = custom_field.fetch('resource_subtype')
41
64
  case resource_subtype
@@ -48,6 +71,9 @@ module Checkoff
48
71
  end
49
72
  end
50
73
 
74
+ # @param custom_field [Hash]
75
+ # @param enum_value [Object, nil]
76
+ # @return [Array<String>]
51
77
  def find_gids(custom_field, enum_value)
52
78
  if enum_value.nil?
53
79
  []
@@ -58,12 +84,42 @@ module Checkoff
58
84
  end
59
85
  end
60
86
 
87
+ # @param task [Asana::Resources::Task]
88
+ # @param custom_field_gid [String]
89
+ # @return [Array<String>]
61
90
  def pull_custom_field_values_gids(task, custom_field_gid)
62
91
  custom_field = pull_custom_field_or_raise(task, custom_field_gid)
63
92
  pull_enum_values(custom_field).flat_map do |enum_value|
64
93
  find_gids(custom_field, enum_value)
65
94
  end
66
95
  end
96
+
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_field' in your extra_fields argument?"
105
+ end
106
+
107
+ # @sg-ignore
108
+ # @type [Hash, nil]
109
+ custom_fields.find { |field| field.fetch('name') == custom_field_name }
110
+ end
111
+
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
67
123
  end
68
124
 
69
125
  # :and function
@@ -72,6 +128,10 @@ module Checkoff
72
128
  fn?(task_selector, :and)
73
129
  end
74
130
 
131
+ # @param _task [Asana::Resources::Task]
132
+ # @param lhs [Object]
133
+ # @param rhs [Object]
134
+ # @return [Object]
75
135
  def evaluate(_task, lhs, rhs)
76
136
  lhs && rhs
77
137
  end
@@ -83,6 +143,9 @@ module Checkoff
83
143
  fn?(task_selector, :not)
84
144
  end
85
145
 
146
+ # @param _task [Asana::Resources::Task]
147
+ # @param subvalue [Object]
148
+ # @return [Boolean]
86
149
  def evaluate(_task, subvalue)
87
150
  !subvalue
88
151
  end
@@ -94,21 +157,44 @@ module Checkoff
94
157
  fn?(task_selector, :nil?)
95
158
  end
96
159
 
160
+ # @param _task [Asana::Resources::Task]
161
+ # @param subvalue [Object]
162
+ # @return [Boolean]
97
163
  def evaluate(_task, subvalue)
98
164
  subvalue.nil?
99
165
  end
100
166
  end
101
167
 
168
+ # :equals? function
169
+ class EqualsPFunctionEvaluator < FunctionEvaluator
170
+ def matches?
171
+ fn?(task_selector, :equals?)
172
+ end
173
+
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
182
+
102
183
  # :tag function
103
184
  class TagPFunctionEvaluator < FunctionEvaluator
104
185
  def matches?
105
186
  fn?(task_selector, :tag)
106
187
  end
107
188
 
189
+ # @param _index [Integer]
108
190
  def evaluate_arg?(_index)
109
191
  false
110
192
  end
111
193
 
194
+ # @sg-ignore
195
+ # @param task [Asana::Resources::Task]
196
+ # @param tag_name [String]
197
+ # @return [Boolean]
112
198
  def evaluate(task, tag_name)
113
199
  task.tags.map(&:name).include? tag_name
114
200
  end
@@ -120,6 +206,8 @@ module Checkoff
120
206
  fn?(task_selector, :due)
121
207
  end
122
208
 
209
+ # @param task [Asana::Resources::Task]
210
+ # @return [Boolean]
123
211
  def evaluate(task)
124
212
  @tasks.task_ready?(task)
125
213
  end
@@ -131,6 +219,9 @@ module Checkoff
131
219
  fn?(task_selector, :due_date_set)
132
220
  end
133
221
 
222
+ # @sg-ignore
223
+ # @param task [Asana::Resources::Task]
224
+ # @return [Boolean]
134
225
  def evaluate(task)
135
226
  !task.due_at.nil? || !task.due_on.nil?
136
227
  end
@@ -142,17 +233,16 @@ module Checkoff
142
233
  fn?(task_selector, :custom_field_value)
143
234
  end
144
235
 
236
+ # @param _index [Integer]
145
237
  def evaluate_arg?(_index)
146
238
  false
147
239
  end
148
240
 
241
+ # @param task [Asana::Resources::Task]
242
+ # @param custom_field_name [String]
243
+ # @return [String, nil]
149
244
  def evaluate(task, custom_field_name)
150
- custom_fields = task.custom_fields
151
- if custom_fields.nil?
152
- raise "custom fields not found on task - did you add 'custom_field' in your extra_fields argument?"
153
- end
154
-
155
- custom_field = custom_fields.find { |field| field.fetch('name') == custom_field_name }
245
+ custom_field = pull_custom_field_by_name(task, custom_field_name)
156
246
  return nil if custom_field.nil?
157
247
 
158
248
  custom_field['display_value']
@@ -169,6 +259,10 @@ module Checkoff
169
259
  false
170
260
  end
171
261
 
262
+ # @sg-ignore
263
+ # @param task [Asana::Resources::Task]
264
+ # @param custom_field_gid [String]
265
+ # @return [String, nil]
172
266
  def evaluate(task, custom_field_gid)
173
267
  custom_field = pull_custom_field_or_raise(task, custom_field_gid)
174
268
  custom_field['display_value']
@@ -185,6 +279,10 @@ module Checkoff
185
279
  false
186
280
  end
187
281
 
282
+ # @param task [Asana::Resources::Task]
283
+ # @param custom_field_gid [String]
284
+ # @param custom_field_values_gids [Array<String>]
285
+ # @return [Boolean]
188
286
  def evaluate(task, custom_field_gid, custom_field_values_gids)
189
287
  actual_custom_field_values_gids = pull_custom_field_values_gids(task, custom_field_gid)
190
288
 
@@ -204,6 +302,10 @@ module Checkoff
204
302
  false
205
303
  end
206
304
 
305
+ # @param task [Asana::Resources::Task]
306
+ # @param custom_field_gid [String]
307
+ # @param custom_field_values_gids [Array<String>]
308
+ # @return [Boolean]
207
309
  def evaluate(task, custom_field_gid, custom_field_values_gids)
208
310
  actual_custom_field_values_gids = pull_custom_field_values_gids(task, custom_field_gid)
209
311
 
@@ -213,8 +315,48 @@ module Checkoff
213
315
  end
214
316
  end
215
317
 
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
323
+
324
+ def evaluate_arg?(_index)
325
+ false
326
+ end
327
+
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
341
+
342
+ # String literals
343
+ class StringLiteralEvaluator < FunctionEvaluator
344
+ def matches?
345
+ task_selector.is_a?(String)
346
+ end
347
+
348
+ # @sg-ignore
349
+ # @param _task [Asana::Resources::Task]
350
+ # @return [String]
351
+ def evaluate(_task)
352
+ task_selector
353
+ end
354
+ end
355
+
216
356
  # Evaluator task selectors against a task
217
357
  class TaskSelectorEvaluator
358
+ # @param task [Asana::Resources::Task]
359
+ # @param tasks [Checkoff::Tasks]
218
360
  def initialize(task:,
219
361
  tasks: Checkoff::Tasks.new)
220
362
  @task = task
@@ -224,6 +366,7 @@ module Checkoff
224
366
  FUNCTION_EVALUTORS = [
225
367
  NotFunctionEvaluator,
226
368
  NilPFunctionEvaluator,
369
+ EqualsPFunctionEvaluator,
227
370
  TagPFunctionEvaluator,
228
371
  CustomFieldValueFunctionEvaluator,
229
372
  CustomFieldGidValueFunctionEvaluator,
@@ -232,12 +375,19 @@ module Checkoff
232
375
  AndFunctionEvaluator,
233
376
  DuePFunctionEvaluator,
234
377
  DueDateSetPFunctionEvaluator,
378
+ CustomFieldLessThanNDaysFromNowFunctionEvaluator,
379
+ StringLiteralEvaluator,
235
380
  ].freeze
236
381
 
382
+ # @param task_selector [Array]
383
+ # @return [Boolean, Object, nil]
237
384
  def evaluate(task_selector)
238
- return true if task_selector == []
385
+ return true if task_selector.empty?
239
386
 
387
+ # @param evaluator_class [Class<FunctionEvaluator>]
240
388
  FUNCTION_EVALUTORS.each do |evaluator_class|
389
+ # @sg-ignore
390
+ # @type [FunctionEvaluator]
241
391
  evaluator = evaluator_class.new(task_selector: task_selector,
242
392
  tasks: tasks)
243
393
 
@@ -246,23 +396,37 @@ module Checkoff
246
396
  return try_this_evaluator(task_selector, evaluator)
247
397
  end
248
398
 
249
- raise "Syntax issue trying to handle #{task_selector}"
399
+ raise "Syntax issue trying to handle #{task_selector.inspect}"
250
400
  end
251
401
 
252
402
  private
253
403
 
404
+ # @sg-ignore
405
+ # @param task_selector [Array]
406
+ # @param evaluator [FunctionEvaluator]
407
+ # @return [Boolean, Object, nil]
254
408
  def try_this_evaluator(task_selector, evaluator)
255
- evaluated_args = task_selector[1..].map.with_index do |item, index|
256
- if evaluator.evaluate_arg?(index)
257
- evaluate(item)
258
- else
259
- item
260
- end
261
- end
409
+ # if task_selector is an array
410
+ evaluated_args = if task_selector.is_a?(Array)
411
+ task_selector[1..].map.with_index do |item, index|
412
+ if evaluator.evaluate_arg?(index)
413
+ evaluate(item)
414
+ else
415
+ item
416
+ end
417
+ end
418
+ else
419
+ []
420
+ end
262
421
 
263
422
  evaluator.evaluate(task, *evaluated_args)
264
423
  end
265
424
 
266
- attr_reader :task, :tasks, :task_selector
425
+ # @return [Asana::Resources::Task]
426
+ attr_reader :task
427
+ # @return [Checkoff::Tasks]
428
+ attr_reader :tasks
429
+ # @return [Array<(Symbol, Array)>]
430
+ attr_reader :task_selector
267
431
  end
268
432
  end
@@ -19,12 +19,9 @@ module Checkoff
19
19
  # Run task searches against the Asana API
20
20
  class TaskSearches
21
21
  MINUTE = 60
22
- # @sg-ignore
23
22
  HOUR = MINUTE * 60
24
23
  DAY = 24 * HOUR
25
- # @sg-ignore
26
24
  REALLY_LONG_CACHE_TIME = HOUR * 1
27
- # @sg-ignore
28
25
  LONG_CACHE_TIME = MINUTE * 15
29
26
  SHORT_CACHE_TIME = MINUTE
30
27
 
@@ -62,7 +59,6 @@ module Checkoff
62
59
  client: client)
63
60
  tasks.select { |task| task_selectors.filter_via_task_selector(task, task_selector) }
64
61
  end
65
- # @sg-ignore
66
62
  cache_method :task_search, LONG_CACHE_TIME
67
63
 
68
64
  private
@@ -81,11 +77,7 @@ module Checkoff
81
77
  # :nocov:
82
78
  class << self
83
79
  def run
84
- # @sg-ignore
85
- # @type [String]
86
80
  workspace_name = ARGV[0] || raise('Please pass workspace name as first argument')
87
- # @sg-ignore
88
- # @type [String]
89
81
  url = ARGV[1] || raise('Please pass task search URL as second argument')
90
82
  task_searches = Checkoff::TaskSearches.new
91
83
  task_search = task_searches.task_search(workspace_name, url)
@@ -21,6 +21,10 @@ module Checkoff
21
21
  LONG_CACHE_TIME = MINUTE * 15
22
22
  SHORT_CACHE_TIME = MINUTE
23
23
 
24
+ # @sg-ignore
25
+ # @param [Hash] config
26
+ # @param [Asana::Client] client
27
+ # @param [Checkoff::Tasks] tasks
24
28
  def initialize(config: Checkoff::Internal::ConfigLoader.load(:asana),
25
29
  client: Checkoff::Clients.new(config: config).client,
26
30
  tasks: Checkoff::Tasks.new(config: config,
@@ -30,8 +34,8 @@ module Checkoff
30
34
  end
31
35
 
32
36
  # @param [Asana::Resources::Task] task
33
- # @param [Hash<Symbol, Object>] task_selector Filter based on
34
- # description. Examples: {tag: 'foo'} {:not {tag: 'foo'} (:tag 'foo')
37
+ # @param [Array<(Symbol, Array)>] task_selector Filter based on
38
+ # task details. Examples: [:tag, 'foo'] [:not, [:tag, 'foo']] [:tag, 'foo']
35
39
  # @return [Boolean]
36
40
  def filter_via_task_selector(task, task_selector)
37
41
  evaluator = TaskSelectorEvaluator.new(task: task, tasks: tasks)
@@ -40,16 +44,19 @@ module Checkoff
40
44
 
41
45
  private
42
46
 
47
+ # @return [Checkoff::Tasks]
43
48
  attr_reader :tasks
44
49
 
45
50
  # bundle exec ./task_selectors.rb
46
51
  # :nocov:
47
52
  class << self
53
+ # @sg-ignore
48
54
  # @return [String]
49
55
  def project_name
50
56
  ARGV[1] || raise('Please pass project name to pull tasks from as first argument')
51
57
  end
52
58
 
59
+ # @sg-ignore
53
60
  # @return [String]
54
61
  def workspace_name
55
62
  ARGV[0] || raise('Please pass workspace name as first argument')
@@ -61,6 +68,7 @@ module Checkoff
61
68
  JSON.parse(task_selector_json)
62
69
  end
63
70
 
71
+ # @return [void]
64
72
  def run
65
73
  require 'checkoff/projects'
66
74
 
@@ -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.40.0'
6
+ VERSION = '0.42.0'
7
7
  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.40.0
4
+ version: 0.42.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vince Broz
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-06-18 00:00:00.000000000 Z
11
+ date: 2023-06-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport