checkoff 0.58.1 → 0.60.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,751 +1,46 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Checkoff
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
14
-
15
- # @sg-ignore
16
- # @param _index [Integer]
17
- def evaluate_arg?(_index)
18
- true
19
- end
20
-
21
- # @sg-ignore
22
- # @return [Boolean]
23
- def matches?
24
- raise 'Override me!'
25
- end
26
-
27
- private
28
-
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
34
-
35
- # @param task [Asana::Resources::Task]
36
- # @param field_name [Symbol]
37
- #
38
- # @sg-ignore
39
- # @return [Date, nil]
40
- def pull_date_field_by_name(task, field_name)
41
- if field_name == :modified
42
- return Time.parse(task.modified_at).to_date unless task.modified_at.nil?
43
-
44
- return nil
45
- end
46
-
47
- if field_name == :due
48
- return Time.parse(task.due_at).to_date unless task.due_at.nil?
49
-
50
- return Date.parse(task.due_on) unless task.due_on.nil?
51
-
52
- return nil
53
- end
54
-
55
- raise "Teach me how to handle field #{field_name}"
56
- end
57
-
58
- # @param task [Asana::Resources::Task]
59
- # @param field_name [Symbol]
60
- #
61
- # @sg-ignore
62
- # @return [Date, Time, nil]
63
- def pull_date_or_time_field_by_name(task, field_name)
64
- if field_name == :due
65
- return Time.parse(task.due_at) unless task.due_at.nil?
66
-
67
- return Date.parse(task.due_on) unless task.due_on.nil?
68
-
69
- return nil
70
- end
71
-
72
- if field_name == :start
73
- return Time.parse(task.start_at) unless task.start_at.nil?
74
-
75
- return Date.parse(task.start_on) unless task.start_on.nil?
76
-
77
- return nil
78
- end
79
-
80
- raise "Teach me how to handle field #{field_name}"
81
- end
82
-
83
- # @sg-ignore
84
- # @param task [Asana::Resources::Task]
85
- # @param custom_field_gid [String]
86
- # @return [Hash]
87
- def pull_custom_field_or_raise(task, custom_field_gid)
88
- # @type [Array<Hash>]
89
- custom_fields = task.custom_fields
90
- if custom_fields.nil?
91
- raise "Could not find custom_fields under task (was 'custom_fields' included in 'extra_fields'?)"
92
- end
93
-
94
- # @sg-ignore
95
- # @type [Hash, nil]
96
- matched_custom_field = custom_fields.find { |data| data.fetch('gid') == custom_field_gid }
97
- if matched_custom_field.nil?
98
- raise "Could not find custom field with gid #{custom_field_gid} " \
99
- "in task #{task.gid} with custom fields #{custom_fields}"
100
- end
101
-
102
- matched_custom_field
103
- end
104
-
105
- # @return [Array<(Symbol, Array)>]
106
- attr_reader :task_selector
107
-
108
- # @sg-ignore
109
- # @param custom_field [Hash]
110
- # @return [Array<String>]
111
- def pull_enum_values(custom_field)
112
- resource_subtype = custom_field.fetch('resource_subtype')
113
- case resource_subtype
114
- when 'enum'
115
- [custom_field.fetch('enum_value')]
116
- when 'multi_enum'
117
- custom_field.fetch('multi_enum_values')
118
- else
119
- raise "Teach me how to handle resource_subtype #{resource_subtype}"
120
- end
121
- end
122
-
123
- # @param custom_field [Hash]
124
- # @param enum_value [Object, nil]
125
- # @return [Array<String>]
126
- def find_gids(custom_field, enum_value)
127
- if enum_value.nil?
128
- []
129
- else
130
- raise "Unexpected enabled value on custom field: #{custom_field}" if enum_value.fetch('enabled') == false
131
-
132
- [enum_value.fetch('gid')]
133
- end
134
- end
135
-
136
- # @param task [Asana::Resources::Task]
137
- # @param custom_field_gid [String]
138
- # @return [Array<String>]
139
- def pull_custom_field_values_gids(task, custom_field_gid)
140
- custom_field = pull_custom_field_or_raise(task, custom_field_gid)
141
- pull_enum_values(custom_field).flat_map do |enum_value|
142
- find_gids(custom_field, enum_value)
143
- end
144
- end
145
-
146
- # @sg-ignore
147
- # @param task [Asana::Resources::Task]
148
- # @param custom_field_name [String]
149
- # @return [Hash, nil]
150
- def pull_custom_field_by_name(task, custom_field_name)
151
- custom_fields = task.custom_fields
152
- if custom_fields.nil?
153
- raise "custom fields not found on task - did you add 'custom_fields' in your extra_fields argument?"
154
- end
155
-
156
- # @sg-ignore
157
- # @type [Hash, nil]
158
- custom_fields.find { |field| field.fetch('name') == custom_field_name }
159
- end
160
-
161
- # @param task [Asana::Resources::Task]
162
- # @param custom_field_name [String]
163
- # @return [Hash]
164
- def pull_custom_field_by_name_or_raise(task, custom_field_name)
165
- custom_field = pull_custom_field_by_name(task, custom_field_name)
166
- if custom_field.nil?
167
- raise "Could not find custom field with name #{custom_field_name} " \
168
- "in task #{task.gid} with custom fields #{task.custom_fields}"
169
- end
170
- custom_field
171
- end
172
- end
173
-
174
- # :and function
175
- class AndFunctionEvaluator < FunctionEvaluator
176
- FUNCTION_NAME = :and
177
-
178
- def matches?
179
- fn?(task_selector, FUNCTION_NAME)
180
- end
181
-
182
- # @param _task [Asana::Resources::Task]
183
- # @param lhs [Object]
184
- # @param rhs [Object]
185
- # @return [Object]
186
- def evaluate(_task, lhs, rhs)
187
- lhs && rhs
188
- end
189
- end
190
-
191
- # :or function
192
- #
193
- # Does not yet shortcut, but may in future - be careful with side
194
- # effects!
195
- class OrFunctionEvaluator < FunctionEvaluator
196
- FUNCTION_NAME = :or
197
-
198
- def matches?
199
- fn?(task_selector, FUNCTION_NAME)
200
- end
201
-
202
- # @param _task [Asana::Resources::Task]
203
- # @param lhs [Object]
204
- # @param rhs [Object]
205
- # @return [Object]
206
- def evaluate(_task, lhs, rhs)
207
- lhs || rhs
208
- end
209
- end
210
-
211
- # :not function
212
- class NotFunctionEvaluator < FunctionEvaluator
213
- FUNCTION_NAME = :not
214
-
215
- def matches?
216
- fn?(task_selector, FUNCTION_NAME)
217
- end
218
-
219
- # @param _task [Asana::Resources::Task]
220
- # @param subvalue [Object]
221
- # @return [Boolean]
222
- def evaluate(_task, subvalue)
223
- !subvalue
224
- end
225
- end
226
-
227
- # :nil? function
228
- class NilPFunctionEvaluator < FunctionEvaluator
229
- def matches?
230
- fn?(task_selector, :nil?)
231
- end
232
-
233
- # @param _task [Asana::Resources::Task]
234
- # @param subvalue [Object]
235
- # @return [Boolean]
236
- def evaluate(_task, subvalue)
237
- subvalue.nil?
238
- end
239
- end
240
-
241
- # :equals? function
242
- class EqualsPFunctionEvaluator < FunctionEvaluator
243
- FUNCTION_NAME = :equals?
244
-
245
- def matches?
246
- fn?(task_selector, FUNCTION_NAME)
247
- end
248
-
249
- # @param _task [Asana::Resources::Task]
250
- # @param lhs [Object]
251
- # @param rhs [Object]
252
- # @return [Boolean]
253
- def evaluate(_task, lhs, rhs)
254
- lhs == rhs
255
- end
256
- end
257
-
258
- # :tag function
259
- class TagPFunctionEvaluator < FunctionEvaluator
260
- def matches?
261
- fn?(task_selector, :tag)
262
- end
263
-
264
- # @param _index [Integer]
265
- def evaluate_arg?(_index)
266
- false
267
- end
268
-
269
- # @sg-ignore
270
- # @param task [Asana::Resources::Task]
271
- # @param tag_name [String]
272
- # @return [Boolean]
273
- def evaluate(task, tag_name)
274
- task.tags.map(&:name).include? tag_name
275
- end
276
- end
277
-
278
- # :due function
279
- class DuePFunctionEvaluator < FunctionEvaluator
280
- def matches?
281
- fn?(task_selector, :due)
282
- end
283
-
284
- # @param task [Asana::Resources::Task]
285
- # @param ignore_dependencies [Boolean]
286
- # @return [Boolean]
287
- def evaluate(task, ignore_dependencies: false)
288
- @tasks.task_ready?(task, ignore_dependencies: ignore_dependencies)
289
- end
290
- end
291
-
292
- # :unassigned function
293
- class UnassignedPFunctionEvaluator < FunctionEvaluator
294
- def matches?
295
- fn?(task_selector, :unassigned)
296
- end
297
-
298
- # @param task [Asana::Resources::Task]
299
- # @return [Boolean]
300
- def evaluate(task)
301
- task.assignee.nil?
302
- end
303
- end
304
-
305
- # :due_date_set function
306
- class DueDateSetPFunctionEvaluator < FunctionEvaluator
307
- FUNCTION_NAME = :due_date_set
308
-
309
- def matches?
310
- fn?(task_selector, FUNCTION_NAME)
311
- end
312
-
313
- # @sg-ignore
314
- # @param task [Asana::Resources::Task]
315
- # @return [Boolean]
316
- def evaluate(task)
317
- !task.due_at.nil? || !task.due_on.nil?
318
- end
319
- end
320
-
321
- # :due_between_n_days function
322
- class DueBetweenRelativePFunctionEvaluator < FunctionEvaluator
323
- FUNCTION_NAME = :due_between_relative
324
-
325
- def matches?
326
- fn?(task_selector, FUNCTION_NAME)
327
- end
328
-
329
- # @param _index [Integer]
330
- def evaluate_arg?(_index)
331
- false
332
- end
333
-
334
- # @param task [Asana::Resources::Task]
335
- # @param beginning_num_days_from_now [Integer]
336
- # @param end_num_days_from_now [Integer]
337
- # @param ignore_dependencies [Boolean]
338
- #
339
- # @return [Boolean]
340
- def evaluate(task, beginning_num_days_from_now, end_num_days_from_now, ignore_dependencies: false)
341
- beginning_n_days_from_now_time = (Time.now + (beginning_num_days_from_now * 24 * 60 * 60))
342
- end_n_days_from_now_time = (Time.now + (end_num_days_from_now * 24 * 60 * 60))
343
-
344
- # @type [Date, Time, nil]
345
- task_date_or_time = pull_date_or_time_field_by_name(task, :start) ||
346
- pull_date_or_time_field_by_name(task, :due)
347
-
348
- return false if task_date_or_time.nil?
349
-
350
- # if time
351
- in_range = if task_date_or_time.is_a?(Time)
352
- task_date_or_time > beginning_n_days_from_now_time &&
353
- task_date_or_time <= end_n_days_from_now_time
354
- else
355
- # if date
356
- task_date_or_time > beginning_n_days_from_now_time.to_date &&
357
- task_date_or_time <= end_n_days_from_now_time.to_date
358
- end
359
-
360
- return false unless in_range
361
-
362
- return false if !ignore_dependencies && @tasks.incomplete_dependencies?(task)
363
-
364
- true
365
- end
366
- end
367
-
368
- # :custom_field_value function
369
- class CustomFieldValueFunctionEvaluator < FunctionEvaluator
370
- FUNCTION_NAME = :custom_field_value
371
-
372
- def matches?
373
- fn?(task_selector, FUNCTION_NAME)
374
- end
3
+ require_relative 'selector_classes/common'
4
+ require_relative 'selector_classes/task'
5
+ require_relative 'selector_evaluator'
375
6
 
376
- # @param _index [Integer]
377
- def evaluate_arg?(_index)
378
- false
379
- end
380
-
381
- # @param task [Asana::Resources::Task]
382
- # @param custom_field_name [String]
383
- # @return [String, nil]
384
- def evaluate(task, custom_field_name)
385
- custom_field = pull_custom_field_by_name(task, custom_field_name)
386
- return nil if custom_field.nil?
387
-
388
- custom_field['display_value']
389
- end
390
- end
391
-
392
- # :custom_field_gid_value function
393
- class CustomFieldGidValueFunctionEvaluator < FunctionEvaluator
394
- def matches?
395
- fn?(task_selector, :custom_field_gid_value)
396
- end
397
-
398
- def evaluate_arg?(_index)
399
- false
400
- end
401
-
402
- # @sg-ignore
403
- # @param task [Asana::Resources::Task]
404
- # @param custom_field_gid [String]
405
- # @return [String, nil]
406
- def evaluate(task, custom_field_gid)
407
- custom_field = pull_custom_field_or_raise(task, custom_field_gid)
408
- custom_field['display_value']
409
- end
410
- end
411
-
412
- # :custom_field_gid_value_contains_any_gid function
413
- class CustomFieldGidValueContainsAnyGidFunctionEvaluator < FunctionEvaluator
414
- FUNCTION_NAME = :custom_field_gid_value_contains_any_gid
415
-
416
- def matches?
417
- fn?(task_selector, FUNCTION_NAME)
418
- end
419
-
420
- def evaluate_arg?(_index)
421
- false
422
- end
423
-
424
- # @param task [Asana::Resources::Task]
425
- # @param custom_field_gid [String]
426
- # @param custom_field_values_gids [Array<String>]
427
- # @return [Boolean]
428
- def evaluate(task, custom_field_gid, custom_field_values_gids)
429
- actual_custom_field_values_gids = pull_custom_field_values_gids(task, custom_field_gid)
430
-
431
- actual_custom_field_values_gids.any? do |custom_field_value|
432
- custom_field_values_gids.include?(custom_field_value)
433
- end
434
- end
435
- end
436
-
437
- # :custom_field_gid_value_contains_all_gids function
438
- class CustomFieldGidValueContainsAllGidsFunctionEvaluator < FunctionEvaluator
439
- FUNCTION_NAME = :custom_field_gid_value_contains_all_gids
440
-
441
- def matches?
442
- fn?(task_selector, FUNCTION_NAME)
443
- end
444
-
445
- def evaluate_arg?(_index)
446
- false
447
- end
448
-
449
- # @param task [Asana::Resources::Task]
450
- # @param custom_field_gid [String]
451
- # @param custom_field_values_gids [Array<String>]
452
- # @return [Boolean]
453
- def evaluate(task, custom_field_gid, custom_field_values_gids)
454
- actual_custom_field_values_gids = pull_custom_field_values_gids(task, custom_field_gid)
455
-
456
- custom_field_values_gids.all? do |custom_field_value|
457
- actual_custom_field_values_gids.include?(custom_field_value)
458
- end
459
- end
460
- end
461
-
462
- # :field_less_than_n_days_ago
463
- class FieldLessThanNDaysAgoPFunctionEvaluator < FunctionEvaluator
464
- FUNCTION_NAME = :field_less_than_n_days_ago
465
-
466
- def matches?
467
- fn?(task_selector, FUNCTION_NAME)
468
- end
469
-
470
- def evaluate_arg?(_index)
471
- false
472
- end
473
-
474
- # @param task [Asana::Resources::Task]
475
- # @param field_name [Symbol]
476
- # @param num_days [Integer]
477
- #
478
- # @return [Boolean]
479
- def evaluate(task, field_name, num_days)
480
- date = pull_date_field_by_name(task, field_name)
481
-
482
- return false if date.nil?
483
-
484
- # @sg-ignore
485
- n_days_ago = Date.today - num_days
486
- # @sg-ignore
487
- date < n_days_ago
488
- end
489
- end
490
-
491
- # :field_greater_than_or_equal_to_n_days_from_today
492
- class FieldGreaterThanOrEqualToNDaysFromTodayPFunctionEvaluator < FunctionEvaluator
493
- FUNCTION_NAME = :field_greater_than_or_equal_to_n_days_from_today
494
-
495
- def matches?
496
- fn?(task_selector, FUNCTION_NAME)
497
- end
498
-
499
- def evaluate_arg?(_index)
500
- false
501
- end
502
-
503
- # @param task [Asana::Resources::Task]
504
- # @param field_name [Symbol]
505
- # @param num_days [Integer]
506
- #
507
- # @return [Boolean]
508
- def evaluate(task, field_name, num_days)
509
- date = pull_date_field_by_name(task, field_name)
510
-
511
- return false if date.nil?
512
-
513
- # @sg-ignore
514
- n_days_from_today = Date.today + num_days
515
- # @sg-ignore
516
- date >= n_days_from_today
517
- end
518
- end
519
-
520
- # :custom_field_less_than_n_days_from_now function
521
- class CustomFieldLessThanNDaysFromNowFunctionEvaluator < FunctionEvaluator
522
- FUNCTION_NAME = :custom_field_less_than_n_days_from_now
523
-
524
- def matches?
525
- fn?(task_selector, FUNCTION_NAME)
526
- end
527
-
528
- def evaluate_arg?(_index)
529
- false
530
- end
531
-
532
- # @param task [Asana::Resources::Task]
533
- # @param custom_field_name [String]
534
- # @param num_days [Integer]
535
- # @return [Boolean]
536
- def evaluate(task, custom_field_name, num_days)
537
- custom_field = pull_custom_field_by_name_or_raise(task, custom_field_name)
538
-
539
- # @sg-ignore
540
- # @type [String, nil]
541
- time_str = custom_field.fetch('display_value')
542
- return false if time_str.nil?
543
-
544
- time = Time.parse(time_str)
545
- n_days_from_now = (Time.now + (num_days * 24 * 60 * 60))
546
- time < n_days_from_now
547
- end
548
- end
549
-
550
- # :custom_field_greater_than_or_equal_to_n_days_from_now function
551
- class CustomFieldGreaterThanOrEqualToNDaysFromNowFunctionEvaluator < FunctionEvaluator
552
- FUNCTION_NAME = :custom_field_greater_than_or_equal_to_n_days_from_now
553
-
554
- def matches?
555
- fn?(task_selector, FUNCTION_NAME)
556
- end
557
-
558
- def evaluate_arg?(_index)
559
- false
560
- end
561
-
562
- # @param task [Asana::Resources::Task]
563
- # @param custom_field_name [String]
564
- # @param num_days [Integer]
565
- # @return [Boolean]
566
- def evaluate(task, custom_field_name, num_days)
567
- custom_field = pull_custom_field_by_name_or_raise(task, custom_field_name)
568
-
569
- # @sg-ignore
570
- # @type [String, nil]
571
- time_str = custom_field.fetch('display_value')
572
- return false if time_str.nil?
573
-
574
- time = Time.parse(time_str)
575
- n_days_from_now = (Time.now + (num_days * 24 * 60 * 60))
576
- time >= n_days_from_now
577
- end
578
- end
579
-
580
- # :last_story_created_less_than_n_days_ago function
581
- class LastStoryCreatedLessThanNDaysAgoFunctionEvaluator < FunctionEvaluator
582
- FUNCTION_NAME = :last_story_created_less_than_n_days_ago
583
-
584
- def matches?
585
- fn?(task_selector, FUNCTION_NAME)
586
- end
587
-
588
- def evaluate_arg?(_index)
589
- false
590
- end
591
-
592
- # @param task [Asana::Resources::Task]
593
- # @param num_days [Integer]
594
- # @param excluding_resource_subtypes [Array<String>]
595
- # @return [Boolean]
596
- def evaluate(task, num_days, excluding_resource_subtypes)
597
- # for whatever reason, .last on the enumerable does not impose ordering; .to_a does!
598
-
599
- # @type [Array<Asana::Resources::Story>]
600
- stories = task.stories(per_page: 100).to_a.reject do |story|
601
- excluding_resource_subtypes.include? story.resource_subtype
602
- end
603
- return true if stories.empty? # no stories == infinitely old!
604
-
605
- last_story = stories.last
606
- last_story_created_at = Time.parse(last_story.created_at)
607
- n_days_ago = Time.now - (num_days * 24 * 60 * 60)
608
- last_story_created_at < n_days_ago
609
- end
610
- end
611
-
612
- # String literals
613
- class StringLiteralEvaluator < FunctionEvaluator
614
- def matches?
615
- task_selector.is_a?(String)
616
- end
617
-
618
- # @sg-ignore
619
- # @param _task [Asana::Resources::Task]
620
- # @return [String]
621
- def evaluate(_task)
622
- task_selector
623
- end
624
- end
625
-
626
- # :estimate_exceeds_duration
627
- class EstimateExceedsDurationFunctionEvaluator < FunctionEvaluator
628
- FUNCTION_NAME = :estimate_exceeds_duration
629
-
630
- def matches?
631
- fn?(task_selector, FUNCTION_NAME)
632
- end
633
-
634
- # @param task [Asana::Resources::Task]
635
- # @return [Float]
636
- def calculate_allocated_hours(task)
637
- due_on = nil
638
- start_on = nil
639
- start_on = Date.parse(task.start_on) unless task.start_on.nil?
640
- due_on = Date.parse(task.due_on) unless task.due_on.nil?
641
- allocated_hours = 8.0
642
- # @sg-ignore
643
- allocated_hours = (due_on - start_on + 1).to_i * 8.0 if start_on && due_on
644
- allocated_hours
645
- end
646
-
647
- # @param task [Asana::Resources::Task]
648
- # @return [Boolean]
649
- def evaluate(task)
650
- custom_field = pull_custom_field_by_name_or_raise(task, 'Estimated time')
651
-
652
- # @sg-ignore
653
- # @type [Integer, nil]
654
- estimate_minutes = custom_field.fetch('number_value')
655
-
656
- # no estimate set
657
- return false if estimate_minutes.nil?
658
-
659
- estimate_hours = estimate_minutes / 60.0
660
-
661
- allocated_hours = calculate_allocated_hours(task)
662
-
663
- estimate_hours > allocated_hours
664
- end
665
- end
666
- end
667
-
668
- # Evaluator task selectors against a task
669
- class TaskSelectorEvaluator
7
+ module Checkoff
8
+ # Evaluates task selectors against a task
9
+ class TaskSelectorEvaluator < SelectorEvaluator
670
10
  # @param task [Asana::Resources::Task]
671
11
  # @param tasks [Checkoff::Tasks]
672
12
  def initialize(task:,
673
13
  tasks: Checkoff::Tasks.new)
674
- @task = task
14
+ @item = task
675
15
  @tasks = tasks
16
+ super()
676
17
  end
677
18
 
678
- FUNCTION_EVALUTORS = [
679
- Checkoff::TaskSelectorClasses::NotFunctionEvaluator,
680
- Checkoff::TaskSelectorClasses::NilPFunctionEvaluator,
681
- Checkoff::TaskSelectorClasses::EqualsPFunctionEvaluator,
682
- Checkoff::TaskSelectorClasses::TagPFunctionEvaluator,
683
- Checkoff::TaskSelectorClasses::CustomFieldValueFunctionEvaluator,
684
- Checkoff::TaskSelectorClasses::CustomFieldGidValueFunctionEvaluator,
685
- Checkoff::TaskSelectorClasses::CustomFieldGidValueContainsAnyGidFunctionEvaluator,
686
- Checkoff::TaskSelectorClasses::CustomFieldGidValueContainsAllGidsFunctionEvaluator,
687
- Checkoff::TaskSelectorClasses::AndFunctionEvaluator,
688
- Checkoff::TaskSelectorClasses::OrFunctionEvaluator,
689
- Checkoff::TaskSelectorClasses::DuePFunctionEvaluator,
690
- Checkoff::TaskSelectorClasses::DueBetweenRelativePFunctionEvaluator,
691
- Checkoff::TaskSelectorClasses::UnassignedPFunctionEvaluator,
692
- Checkoff::TaskSelectorClasses::DueDateSetPFunctionEvaluator,
693
- Checkoff::TaskSelectorClasses::FieldLessThanNDaysAgoPFunctionEvaluator,
694
- Checkoff::TaskSelectorClasses::FieldGreaterThanOrEqualToNDaysFromTodayPFunctionEvaluator,
695
- Checkoff::TaskSelectorClasses::CustomFieldLessThanNDaysFromNowFunctionEvaluator,
696
- Checkoff::TaskSelectorClasses::CustomFieldGreaterThanOrEqualToNDaysFromNowFunctionEvaluator,
697
- Checkoff::TaskSelectorClasses::LastStoryCreatedLessThanNDaysAgoFunctionEvaluator,
698
- Checkoff::TaskSelectorClasses::StringLiteralEvaluator,
699
- Checkoff::TaskSelectorClasses::EstimateExceedsDurationFunctionEvaluator,
700
- ].freeze
701
-
702
- # @param task_selector [Array]
703
- # @return [Boolean, Object, nil]
704
- def evaluate(task_selector)
705
- return true if task_selector.empty?
19
+ private
706
20
 
707
- # @param evaluator_class [Class<TaskSelectorClasses::FunctionEvaluator>]
708
- FUNCTION_EVALUTORS.each do |evaluator_class|
709
- # @sg-ignore
710
- evaluator = evaluator_class.new(task_selector: task_selector,
711
- tasks: tasks)
21
+ COMMON_FUNCTION_EVALUATORS = (Checkoff::SelectorClasses::Common.constants.map do |const|
22
+ Checkoff::SelectorClasses::Common.const_get(const)
23
+ end - [Checkoff::SelectorClasses::Common::FunctionEvaluator]).freeze
712
24
 
713
- next unless evaluator.matches?
25
+ TASK_FUNCTION_EVALUATORS = (Checkoff::SelectorClasses::Task.constants.map do |const|
26
+ Checkoff::SelectorClasses::Task.const_get(const)
27
+ end - [Checkoff::SelectorClasses::Task::FunctionEvaluator]).freeze
714
28
 
715
- return try_this_evaluator(task_selector, evaluator)
716
- end
29
+ FUNCTION_EVALUTORS = (COMMON_FUNCTION_EVALUATORS + TASK_FUNCTION_EVALUATORS).freeze
717
30
 
718
- raise "Syntax issue trying to handle #{task_selector.inspect}"
31
+ # @return [Array<Class<TaskSelectorClasses::FunctionEvaluator>>]
32
+ def function_evaluators
33
+ FUNCTION_EVALUTORS
719
34
  end
720
35
 
721
- private
722
-
723
- # @sg-ignore
724
- # @param task_selector [Array]
725
- # @param evaluator [TaskSelectorClasses::FunctionEvaluator]
726
- # @return [Boolean, Object, nil]
727
- def try_this_evaluator(task_selector, evaluator)
728
- # if task_selector is an array
729
- evaluated_args = if task_selector.is_a?(Array)
730
- task_selector[1..].map.with_index do |item, index|
731
- if evaluator.evaluate_arg?(index)
732
- evaluate(item)
733
- else
734
- item
735
- end
736
- end
737
- else
738
- []
739
- end
740
-
741
- evaluator.evaluate(task, *evaluated_args)
36
+ # @return [Hash]
37
+ def initializer_kwargs
38
+ { tasks: tasks }
742
39
  end
743
40
 
744
41
  # @return [Asana::Resources::Task]
745
- attr_reader :task
42
+ attr_reader :item
746
43
  # @return [Checkoff::Tasks]
747
44
  attr_reader :tasks
748
- # @return [Array<(Symbol, Array)>]
749
- attr_reader :task_selector
750
45
  end
751
46
  end