checkoff 0.227.0 → 0.229.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 +4 -4
- data/checkoff.gemspec +7 -7
- data/lib/checkoff/cli.rb +71 -1
- data/lib/checkoff/clients.rb +1 -1
- data/lib/checkoff/custom_fields.rb +3 -3
- data/lib/checkoff/events.rb +3 -3
- data/lib/checkoff/internal/asana_event_enrichment.rb +13 -14
- data/lib/checkoff/internal/config_loader.rb +4 -2
- data/lib/checkoff/internal/logging.rb +3 -0
- data/lib/checkoff/internal/project_selector_evaluator.rb +5 -2
- data/lib/checkoff/internal/project_timing.rb +0 -2
- data/lib/checkoff/internal/search_url/custom_field_param_converter.rb +12 -12
- data/lib/checkoff/internal/search_url/custom_field_variant.rb +19 -18
- data/lib/checkoff/internal/search_url/date_param_converter.rb +9 -9
- data/lib/checkoff/internal/search_url/parser.rb +20 -30
- data/lib/checkoff/internal/search_url/results_merger.rb +4 -6
- data/lib/checkoff/internal/search_url/simple_param_converter.rb +19 -11
- data/lib/checkoff/internal/section_selector_evaluator.rb +7 -3
- data/lib/checkoff/internal/selector_classes/common/function_evaluator.rb +3 -2
- data/lib/checkoff/internal/selector_classes/common.rb +5 -6
- data/lib/checkoff/internal/selector_classes/function_evaluator.rb +2 -3
- data/lib/checkoff/internal/selector_classes/project/function_evaluator.rb +3 -2
- data/lib/checkoff/internal/selector_classes/section/function_evaluator.rb +2 -2
- data/lib/checkoff/internal/selector_classes/section.rb +2 -2
- data/lib/checkoff/internal/selector_classes/task/function_evaluator.rb +3 -2
- data/lib/checkoff/internal/selector_classes/task.rb +1 -2
- data/lib/checkoff/internal/selector_evaluator.rb +2 -2
- data/lib/checkoff/internal/task_hashes.rb +3 -3
- data/lib/checkoff/internal/task_selector_evaluator.rb +3 -0
- data/lib/checkoff/internal/task_timing.rb +0 -2
- data/lib/checkoff/internal/thread_local.rb +5 -4
- data/lib/checkoff/my_tasks.rb +4 -4
- data/lib/checkoff/portfolios.rb +1 -1
- data/lib/checkoff/project_selectors.rb +4 -4
- data/lib/checkoff/projects.rb +6 -6
- data/lib/checkoff/resources.rb +5 -3
- data/lib/checkoff/section_selectors.rb +4 -4
- data/lib/checkoff/sections.rb +18 -15
- data/lib/checkoff/subtasks.rb +2 -2
- data/lib/checkoff/tags.rb +7 -3
- data/lib/checkoff/task_searches.rb +9 -9
- data/lib/checkoff/task_selectors.rb +10 -6
- data/lib/checkoff/tasks.rb +5 -5
- data/lib/checkoff/timelines.rb +0 -1
- data/lib/checkoff/timing.rb +5 -4
- data/lib/checkoff/version.rb +1 -1
- data/lib/checkoff/workspaces.rb +1 -1
- data/rbi/checkoff.rbi +342 -305
- data/sig/checkoff.rbs +327 -279
- metadata +7 -7
@@ -1,4 +1,4 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: true
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
module Checkoff
|
@@ -9,10 +9,10 @@ module Checkoff
|
|
9
9
|
# base class for handling different custom_field_#{gid}.variant params
|
10
10
|
class CustomFieldVariant
|
11
11
|
# @param [String] gid
|
12
|
-
# @param [Hash] remaining_params
|
12
|
+
# @param [Hash{String => Array<String>}] remaining_params
|
13
13
|
def initialize(gid, remaining_params)
|
14
|
-
@gid = gid
|
15
|
-
@remaining_params = remaining_params
|
14
|
+
@gid = T.let(gid, String)
|
15
|
+
@remaining_params = T.let(remaining_params, T::Hash[String, T::Array[String]])
|
16
16
|
end
|
17
17
|
|
18
18
|
private
|
@@ -20,7 +20,7 @@ module Checkoff
|
|
20
20
|
# @return [String]
|
21
21
|
attr_reader :gid
|
22
22
|
|
23
|
-
# @return [Hash]
|
23
|
+
# @return [Hash{String => Array<String>}]
|
24
24
|
attr_reader :remaining_params
|
25
25
|
|
26
26
|
# @return [void]
|
@@ -32,18 +32,18 @@ module Checkoff
|
|
32
32
|
|
33
33
|
# @param [String] param_name
|
34
34
|
#
|
35
|
+
# @sg-ignore
|
35
36
|
# @return [String]
|
36
37
|
def fetch_solo_param(param_name)
|
37
38
|
case remaining_params.keys
|
38
39
|
when [param_name]
|
39
|
-
# @
|
40
|
-
# @type [Array<String>]
|
40
|
+
# @type param_values [Array<String>]
|
41
41
|
param_values = remaining_params.fetch(param_name)
|
42
42
|
unless param_values.length == 1
|
43
43
|
raise "Teach me how to handle these remaining keys for #{param_name}: #{remaining_params}"
|
44
44
|
end
|
45
45
|
|
46
|
-
param_values
|
46
|
+
param_values.fetch(0)
|
47
47
|
else
|
48
48
|
raise "Teach me how to handle #{remaining_params}"
|
49
49
|
end
|
@@ -52,7 +52,7 @@ module Checkoff
|
|
52
52
|
|
53
53
|
# custom_field_#{gid}.variant = 'less_than'
|
54
54
|
class LessThan < CustomFieldVariant
|
55
|
-
# @return [Array
|
55
|
+
# @return [Array(Hash{String => String}, Array<Array<String>,String>)]
|
56
56
|
def convert
|
57
57
|
max_value = fetch_solo_param("custom_field_#{gid}.max")
|
58
58
|
empty_task_selector = []
|
@@ -62,7 +62,7 @@ module Checkoff
|
|
62
62
|
|
63
63
|
# custom_field_#{gid}.variant = 'greater_than'
|
64
64
|
class GreaterThan < CustomFieldVariant
|
65
|
-
# @return [Array
|
65
|
+
# @return [Array(Hash{String => String}, Array<Array<String>,String>)]
|
66
66
|
def convert
|
67
67
|
max_value = fetch_solo_param("custom_field_#{gid}.min")
|
68
68
|
empty_task_selector = []
|
@@ -72,7 +72,7 @@ module Checkoff
|
|
72
72
|
|
73
73
|
# custom_field_#{gid}.variant = 'equals'
|
74
74
|
class Equals < CustomFieldVariant
|
75
|
-
# @return [Array
|
75
|
+
# @return [Array(Hash{String => String}, Array<Array<String>,String>)]
|
76
76
|
def convert
|
77
77
|
value = fetch_solo_param("custom_field_#{gid}.value")
|
78
78
|
empty_task_selector = []
|
@@ -84,7 +84,7 @@ module Checkoff
|
|
84
84
|
#
|
85
85
|
# custom_field_#{gid}.variant = 'is_not'
|
86
86
|
class IsNot < CustomFieldVariant
|
87
|
-
# @return [Array
|
87
|
+
# @return [Array(Hash{String => String}, Array<Array<String>, String, Array>)]
|
88
88
|
def convert
|
89
89
|
selected_options = fetch_solo_param("custom_field_#{gid}.selected_options").split('~')
|
90
90
|
|
@@ -101,7 +101,7 @@ module Checkoff
|
|
101
101
|
#
|
102
102
|
# custom_field_#{gid}.variant = 'doesnt_contain_any'
|
103
103
|
class DoesntContainAny < CustomFieldVariant
|
104
|
-
# @return [Array
|
104
|
+
# @return [Array(Hash{String => String}, Array<Array<String>, String, Array>)]
|
105
105
|
def convert
|
106
106
|
selected_options = fetch_solo_param("custom_field_#{gid}.selected_options").split('~')
|
107
107
|
|
@@ -117,7 +117,7 @@ module Checkoff
|
|
117
117
|
#
|
118
118
|
# custom_field_#{gid}.variant = 'contains_any'
|
119
119
|
class ContainsAny < CustomFieldVariant
|
120
|
-
# @return [Array
|
120
|
+
# @return [Array(Hash{String => String}, Array<Array<String>, String, Array>)]
|
121
121
|
def convert
|
122
122
|
selected_options = fetch_solo_param("custom_field_#{gid}.selected_options").split('~')
|
123
123
|
|
@@ -132,7 +132,7 @@ module Checkoff
|
|
132
132
|
#
|
133
133
|
# custom_field_#{gid}.variant = 'contains_all'
|
134
134
|
class ContainsAll < CustomFieldVariant
|
135
|
-
# @return [Array
|
135
|
+
# @return [Array(Hash{String => String}, Array<Array<String>, String, Array>)]
|
136
136
|
def convert
|
137
137
|
selected_options = fetch_solo_param("custom_field_#{gid}.selected_options").split('~')
|
138
138
|
|
@@ -145,10 +145,11 @@ module Checkoff
|
|
145
145
|
|
146
146
|
# custom_field_#{gid}.variant = 'no_value'
|
147
147
|
class NoValue < CustomFieldVariant
|
148
|
-
# @return [Array
|
148
|
+
# @return [Array(Hash{String => String}, Array<Array<String>, String, Array, Symbol>)]
|
149
149
|
def convert
|
150
150
|
ensure_no_remaining_params!
|
151
151
|
|
152
|
+
# @type [Hash{String => String}]
|
152
153
|
api_params = { "custom_fields.#{gid}.is_set" => 'false' }
|
153
154
|
# As of 2023-02, the 'is_set' => 'false' seems to not do
|
154
155
|
# the intuitive thing on multi-select fields; it either
|
@@ -165,7 +166,7 @@ module Checkoff
|
|
165
166
|
#
|
166
167
|
# Not used for multi-select fields
|
167
168
|
class AnyValue < CustomFieldVariant
|
168
|
-
# @return [Array
|
169
|
+
# @return [Array(Hash{String => String}, Array<Array<String>, String, Array>)]
|
169
170
|
def convert
|
170
171
|
ensure_no_remaining_params!
|
171
172
|
|
@@ -177,7 +178,7 @@ module Checkoff
|
|
177
178
|
|
178
179
|
# custom_field_#{gid}.variant = 'is'
|
179
180
|
class Is < CustomFieldVariant
|
180
|
-
# @return [Array
|
181
|
+
# @return [Array(Hash{String => String}, Array<Array<String>, String, Array>)]
|
181
182
|
def convert
|
182
183
|
selected_options = fetch_solo_param("custom_field_#{gid}.selected_options").split('~')
|
183
184
|
|
@@ -9,13 +9,13 @@ module Checkoff
|
|
9
9
|
# Convert date parameters - ones where the param name itself
|
10
10
|
# doesn't encode any parameters'
|
11
11
|
class DateParamConverter
|
12
|
-
# @param date_url_params [Hash
|
12
|
+
# @param date_url_params [Hash{String => Array<String>}] the simple params
|
13
13
|
def initialize(date_url_params:)
|
14
14
|
@date_url_params = date_url_params
|
15
15
|
end
|
16
16
|
|
17
17
|
# @sg-ignore
|
18
|
-
# @return [Array(Hash
|
18
|
+
# @return [Array(Hash{String => String}, Array<Symbol, Array>)]
|
19
19
|
def convert
|
20
20
|
return [{}, []] if date_url_params.empty?
|
21
21
|
|
@@ -35,9 +35,8 @@ module Checkoff
|
|
35
35
|
|
36
36
|
private
|
37
37
|
|
38
|
-
# @sg-ignore
|
39
38
|
# @param prefix [String]
|
40
|
-
# @return [Array(Hash
|
39
|
+
# @return [Array(Hash{String => String}, Array<Symbol, Array>)]
|
41
40
|
def convert_for_prefix(prefix)
|
42
41
|
# example params:
|
43
42
|
# due_date.operator=through_next
|
@@ -70,9 +69,10 @@ module Checkoff
|
|
70
69
|
'start_date' => 'start_on',
|
71
70
|
'completion_date' => 'completed_on',
|
72
71
|
}.freeze
|
72
|
+
private_constant :API_PREFIX
|
73
73
|
|
74
74
|
# @param prefix [String]
|
75
|
-
# @return [Array(Hash
|
75
|
+
# @return [Array(Hash{String => String}, Array<Symbol, Array>)] See https://developers.asana.com/docs/search-tasks-in-a-workspace
|
76
76
|
def handle_through_next(prefix)
|
77
77
|
value = get_single_param("#{prefix}.value").to_i
|
78
78
|
|
@@ -89,7 +89,7 @@ module Checkoff
|
|
89
89
|
end
|
90
90
|
|
91
91
|
# @param prefix [String]
|
92
|
-
# @return [Array(Hash
|
92
|
+
# @return [Array(Hash{String => String}, Array<Symbol, Array>)] See https://developers.asana.com/docs/search-tasks-in-a-workspace
|
93
93
|
def handle_between(prefix)
|
94
94
|
after = get_single_param("#{prefix}.after")
|
95
95
|
raise "Teach me how to handle #{prefix}.before" if date_url_params.key? "#{prefix}.before"
|
@@ -105,7 +105,7 @@ module Checkoff
|
|
105
105
|
end
|
106
106
|
|
107
107
|
# @param prefix [String]
|
108
|
-
# @return [Array(Hash
|
108
|
+
# @return [Array(Hash{String => String}, Array<Symbol, Array>)] See https://developers.asana.com/docs/search-tasks-in-a-workspace
|
109
109
|
def handle_within_last(prefix)
|
110
110
|
value = get_single_param("#{prefix}.value").to_i
|
111
111
|
|
@@ -119,7 +119,7 @@ module Checkoff
|
|
119
119
|
end
|
120
120
|
|
121
121
|
# @param prefix [String]
|
122
|
-
# @return [Array(Hash
|
122
|
+
# @return [Array(Hash{String => String}, Array<Symbol, Array>)] See https://developers.asana.com/docs/search-tasks-in-a-workspace
|
123
123
|
def handle_within_next(prefix)
|
124
124
|
value = get_single_param("#{prefix}.value").to_i
|
125
125
|
|
@@ -160,7 +160,7 @@ module Checkoff
|
|
160
160
|
raise "Teach me how to handle other time units: #{unit}" unless unit == 'day'
|
161
161
|
end
|
162
162
|
|
163
|
-
# @return [Hash
|
163
|
+
# @return [Hash{String => Array<String>}]
|
164
164
|
attr_reader :date_url_params
|
165
165
|
end
|
166
166
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
# typed:
|
2
|
+
# typed: true
|
3
3
|
|
4
4
|
# frozen_string_literal: true
|
5
5
|
|
@@ -22,21 +22,11 @@ module Checkoff
|
|
22
22
|
end
|
23
23
|
|
24
24
|
# @param url [String]
|
25
|
-
# @return [Array(Hash
|
25
|
+
# @return [Array(Hash{String => String}, Array)]
|
26
26
|
def convert_params(url)
|
27
27
|
url_params = CGI.parse(URI.parse(url).query)
|
28
|
-
# @type custom_field_params [Hash<String, Array<String>>]
|
29
|
-
# @type date_url_params [Hash<String, Array<String>>]
|
30
|
-
# @type simple_url_params [Hash<String, Array<String>>]
|
31
|
-
# @sg-ignore
|
32
28
|
custom_field_params, date_url_params, simple_url_params = partition_url_params(url_params)
|
33
|
-
# @type custom_field_args [Hash<String, String>]
|
34
|
-
# @type custom_field_task_selector [Hash<String, String>]
|
35
|
-
# @sg-ignore
|
36
29
|
custom_field_args, custom_field_task_selector = convert_custom_field_params(custom_field_params)
|
37
|
-
# @type date_args [Hash<String, String>]
|
38
|
-
# @type date_task_selector [Hash<String, String>]
|
39
|
-
# @sg-ignore
|
40
30
|
date_url_args, date_task_selector = convert_date_params(date_url_params)
|
41
31
|
simple_url_args = convert_simple_params(simple_url_params)
|
42
32
|
# raise 'merge these things'
|
@@ -46,37 +36,37 @@ module Checkoff
|
|
46
36
|
|
47
37
|
private
|
48
38
|
|
49
|
-
# @param date_url_params [Hash
|
50
|
-
# @return [Array(Hash
|
39
|
+
# @param date_url_params [Hash{String => Array<String>}]
|
40
|
+
# @return [Array(Hash{String => String}, Array<Symbol, Array>)]
|
51
41
|
def convert_date_params(date_url_params)
|
52
42
|
DateParamConverter.new(date_url_params:).convert
|
53
43
|
end
|
54
44
|
|
55
|
-
# @param simple_url_params [Hash
|
56
|
-
# @return [Hash
|
45
|
+
# @param simple_url_params [Hash{String => Array<String>}]
|
46
|
+
# @return [Hash{String => String}]
|
57
47
|
def convert_simple_params(simple_url_params)
|
58
48
|
SimpleParamConverter.new(simple_url_params:).convert
|
59
49
|
end
|
60
50
|
|
61
|
-
# @param custom_field_params [Hash
|
62
|
-
# @return [Array(Hash
|
51
|
+
# @param custom_field_params [Hash{String => Array<String>}]
|
52
|
+
# @return [Array(Hash{String => String}, Array<Symbol, Array>)]
|
63
53
|
def convert_custom_field_params(custom_field_params)
|
64
54
|
CustomFieldParamConverter.new(custom_field_params:).convert
|
65
55
|
end
|
66
56
|
|
67
|
-
# @param url_params [Hash
|
68
|
-
# @return [Array(Hash<String, String
|
57
|
+
# @param url_params [Hash{String => String}]
|
58
|
+
# @return [Array(Hash{String => Array<String>}, Hash{String => Array<String>}, Hash{String => Array<String>})]
|
69
59
|
def partition_url_params(url_params)
|
70
|
-
groups = url_params.to_a.group_by do |key, _values|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
60
|
+
groups = T.let(url_params.to_a.group_by do |key, _values|
|
61
|
+
if key.start_with? 'custom_field_'
|
62
|
+
:custom_field
|
63
|
+
elsif key.include? '_date'
|
64
|
+
:date
|
65
|
+
else
|
66
|
+
:simple
|
67
|
+
end
|
68
|
+
end.transform_values(&:to_h),
|
69
|
+
T::Hash[Symbol, T::Hash[String, T::Array[String]]])
|
80
70
|
[groups.fetch(:custom_field, {}), groups.fetch(:date, {}), groups.fetch(:simple, {})]
|
81
71
|
end
|
82
72
|
end
|
@@ -6,20 +6,18 @@ module Checkoff
|
|
6
6
|
module SearchUrl
|
7
7
|
# Merge task selectors and search API arguments
|
8
8
|
class ResultsMerger
|
9
|
-
# @param args [Array<
|
10
|
-
# @return [Hash
|
9
|
+
# @param args [Array<Hash{String => String}>]
|
10
|
+
# @return [Hash{String => String}]
|
11
11
|
def self.merge_args(*args)
|
12
12
|
# first element of args
|
13
|
-
# @sg-ignore
|
14
|
-
# @type [Hash<String, String>]
|
15
13
|
f = args.fetch(0)
|
16
14
|
# rest of args
|
17
15
|
r = args.drop(0)
|
18
16
|
f.merge(*r)
|
19
17
|
end
|
20
18
|
|
21
|
-
# @param task_selectors [Array<
|
22
|
-
# @return [Array
|
19
|
+
# @param task_selectors [Array<Symbol, Array>]
|
20
|
+
# @return [Array(Symbol, Array, Array)]
|
23
21
|
def self.merge_task_selectors(*task_selectors)
|
24
22
|
return [] if task_selectors.empty?
|
25
23
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: true
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require_relative 'custom_field_param_converter'
|
@@ -50,6 +50,8 @@ module Checkoff
|
|
50
50
|
single_value.split('~').each do |project_section_pair|
|
51
51
|
# @sg-ignore
|
52
52
|
project, section = project_section_pair.split('_column_')
|
53
|
+
raise "Invalid query string: #{project_section_pair}" if project.nil?
|
54
|
+
|
53
55
|
if section.nil?
|
54
56
|
projects << project
|
55
57
|
else
|
@@ -97,7 +99,7 @@ module Checkoff
|
|
97
99
|
|
98
100
|
# Handle 'completion' search url param
|
99
101
|
class Completion < SimpleParam
|
100
|
-
# @return [Array<String>]
|
102
|
+
# @return [Array<String,Boolean>]
|
101
103
|
def convert
|
102
104
|
case single_value
|
103
105
|
when 'incomplete'
|
@@ -121,7 +123,7 @@ module Checkoff
|
|
121
123
|
|
122
124
|
# handle 'subtask' search url param
|
123
125
|
class Subtask < SimpleParam
|
124
|
-
# @return [Array<
|
126
|
+
# @return [Array<String, Boolean>]
|
125
127
|
def convert
|
126
128
|
case single_value
|
127
129
|
when 'is_not_subtask'
|
@@ -185,16 +187,21 @@ module Checkoff
|
|
185
187
|
# Convert simple parameters - ones where the param name itself
|
186
188
|
# doesn't encode any parameters'
|
187
189
|
class SimpleParamConverter
|
188
|
-
# @param simple_url_params [Hash
|
190
|
+
# @param simple_url_params [Hash{String => Array<String>}] the simple params
|
189
191
|
def initialize(simple_url_params:)
|
190
192
|
@simple_url_params = simple_url_params
|
191
193
|
end
|
192
194
|
|
193
|
-
# @return [Hash
|
195
|
+
# @return [Hash{String => String}] the converted params
|
194
196
|
def convert
|
195
|
-
|
196
|
-
|
197
|
-
|
197
|
+
# @type [Array<Array(String, String)>]
|
198
|
+
arr_of_tuples = simple_url_params.to_a.flat_map do |key, values|
|
199
|
+
# @type
|
200
|
+
entry = convert_arg(key, values).each_slice(2).to_a
|
201
|
+
entry
|
202
|
+
end
|
203
|
+
# @type [Hash{String => String}]
|
204
|
+
out = T.cast(arr_of_tuples.to_h, T::Hash[String, String])
|
198
205
|
unless out.include? 'sort_by'
|
199
206
|
# keep results consistent between calls; API using default
|
200
207
|
# sort_by does not seem to be.
|
@@ -205,7 +212,7 @@ module Checkoff
|
|
205
212
|
|
206
213
|
private
|
207
214
|
|
208
|
-
# @type [Hash
|
215
|
+
# @type [Hash{String => Class<SimpleParam::SimpleParam>}] the mapping from param name to class
|
209
216
|
ARGS = {
|
210
217
|
'portfolios.ids' => SimpleParam::PortfoliosIds,
|
211
218
|
'any_projects.ids' => SimpleParam::AnyProjectsIds,
|
@@ -218,12 +225,13 @@ module Checkoff
|
|
218
225
|
'milestone' => SimpleParam::Milestone,
|
219
226
|
'searched_type' => SimpleParam::SearchedType,
|
220
227
|
}.freeze
|
228
|
+
private_constant :ARGS
|
221
229
|
|
222
230
|
# https://developers.asana.com/docs/search-tasks-in-a-workspace
|
223
231
|
# @sg-ignore
|
224
232
|
# @param key [String] the name of the search url param
|
225
233
|
# @param values [Array<String>] the values of the search url param
|
226
|
-
# @return [Hash
|
234
|
+
# @return [Hash{String => String}] the converted params
|
227
235
|
def convert_arg(key, values)
|
228
236
|
# @type [Class<SimpleParam::SimpleParam>]
|
229
237
|
clazz = ARGS.fetch(key)
|
@@ -234,7 +242,7 @@ module Checkoff
|
|
234
242
|
obj.convert
|
235
243
|
end
|
236
244
|
|
237
|
-
# @return [Hash
|
245
|
+
# @return [Hash{String => Array<String>}]
|
238
246
|
attr_reader :simple_url_params
|
239
247
|
end
|
240
248
|
end
|
@@ -8,11 +8,12 @@ require_relative 'selector_evaluator'
|
|
8
8
|
module Checkoff
|
9
9
|
# Evaluates section selectors against a section
|
10
10
|
class SectionSelectorEvaluator < SelectorEvaluator
|
11
|
-
# @param section [Asana::Resources::
|
11
|
+
# @param section [Asana::Resources::Section]
|
12
12
|
# @param client [Asana::Client]
|
13
13
|
# @param projects [Checkoff::Projects]
|
14
14
|
# @param sections [Checkoff::Sections]
|
15
15
|
# @param custom_fields [Checkoff::CustomFields]
|
16
|
+
# @param _kwargs [Hash]
|
16
17
|
def initialize(section:,
|
17
18
|
client:,
|
18
19
|
projects: Checkoff::Projects.new(client:),
|
@@ -32,16 +33,19 @@ module Checkoff
|
|
32
33
|
COMMON_FUNCTION_EVALUATORS = (Checkoff::SelectorClasses::Common.constants.map do |const|
|
33
34
|
Checkoff::SelectorClasses::Common.const_get(const)
|
34
35
|
end - [Checkoff::SelectorClasses::Common::FunctionEvaluator]).freeze
|
36
|
+
private_constant :COMMON_FUNCTION_EVALUATORS
|
35
37
|
|
36
38
|
SECTION_FUNCTION_EVALUATORS = (Checkoff::SelectorClasses::Section.constants.map do |const|
|
37
39
|
Checkoff::SelectorClasses::Section.const_get(const)
|
38
40
|
end - [Checkoff::SelectorClasses::Section::FunctionEvaluator]).freeze
|
41
|
+
private_constant :SECTION_FUNCTION_EVALUATORS
|
39
42
|
|
40
|
-
|
43
|
+
FUNCTION_EVALUATORS = (COMMON_FUNCTION_EVALUATORS + SECTION_FUNCTION_EVALUATORS).freeze
|
44
|
+
private_constant :FUNCTION_EVALUATORS
|
41
45
|
|
42
46
|
# @return [Array<Class<Checkoff::SelectorClasses::Project::FunctionEvaluator>>]
|
43
47
|
def function_evaluators
|
44
|
-
|
48
|
+
FUNCTION_EVALUATORS
|
45
49
|
end
|
46
50
|
|
47
51
|
# @return [Hash]
|
@@ -8,8 +8,9 @@ module Checkoff
|
|
8
8
|
module Common
|
9
9
|
# Base class to evaluate a project selector function given fully evaluated arguments
|
10
10
|
class FunctionEvaluator < ::Checkoff::SelectorClasses::FunctionEvaluator
|
11
|
-
# @param selector [Array
|
11
|
+
# @param selector [Array(Symbol, Array), String]
|
12
12
|
# @param custom_fields [Checkoff::CustomFields]
|
13
|
+
# @param _kwargs [Hash]
|
13
14
|
def initialize(selector:, custom_fields:, **_kwargs)
|
14
15
|
@selector = selector
|
15
16
|
@custom_fields = custom_fields
|
@@ -18,7 +19,7 @@ module Checkoff
|
|
18
19
|
|
19
20
|
private
|
20
21
|
|
21
|
-
# @return [Array
|
22
|
+
# @return [Array(Symbol, Array), String]
|
22
23
|
attr_reader :selector
|
23
24
|
end
|
24
25
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: true
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require_relative 'common/function_evaluator'
|
@@ -224,12 +224,11 @@ module Checkoff
|
|
224
224
|
false
|
225
225
|
end
|
226
226
|
|
227
|
-
# @param resource [Asana::Resources::Task,Asana::Resources::Project]
|
227
|
+
# @param resource [Asana::Resources::Task, Asana::Resources::Project]
|
228
228
|
# @param prefix [String]
|
229
|
-
# @return [
|
230
|
-
# @sg-ignore
|
229
|
+
# @return [boolish]
|
231
230
|
def evaluate(resource, prefix)
|
232
|
-
resource.name
|
231
|
+
resource.name&.start_with?(prefix)
|
233
232
|
end
|
234
233
|
end
|
235
234
|
|
@@ -243,7 +242,7 @@ module Checkoff
|
|
243
242
|
# @param _resource [Asana::Resources::Task,Asana::Resources::Project]
|
244
243
|
# @return [String]
|
245
244
|
def evaluate(_resource)
|
246
|
-
selector
|
245
|
+
T.cast(selector, String)
|
247
246
|
end
|
248
247
|
end
|
249
248
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: true
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require 'checkoff/internal/logging'
|
@@ -9,7 +9,6 @@ module Checkoff
|
|
9
9
|
class FunctionEvaluator
|
10
10
|
include Logging
|
11
11
|
|
12
|
-
# @sg-ignore
|
13
12
|
# @param _index [Integer]
|
14
13
|
def evaluate_arg?(_index)
|
15
14
|
true
|
@@ -23,8 +22,8 @@ module Checkoff
|
|
23
22
|
|
24
23
|
# @param _task [Asana::Resources::Task]
|
25
24
|
# @param _args [Array<Object>]
|
26
|
-
# @return [Object]
|
27
25
|
# @sg-ignore
|
26
|
+
# @return [Object]
|
28
27
|
def evaluate(_task, *_args)
|
29
28
|
raise 'Implement me!'
|
30
29
|
end
|
@@ -8,10 +8,11 @@ module Checkoff
|
|
8
8
|
module Project
|
9
9
|
# Base class to evaluate a project selector function given fully evaluated arguments
|
10
10
|
class FunctionEvaluator < ::Checkoff::SelectorClasses::FunctionEvaluator
|
11
|
-
# @param selector [Array
|
11
|
+
# @param selector [Array(Symbol, Array), String]
|
12
12
|
# @param projects [Checkoff::Projects]
|
13
13
|
# @param portfolios [Checkoff::Portfolios]
|
14
14
|
# @param workspaces [Checkoff::Workspaces]
|
15
|
+
# @param _kwargs [Hash]
|
15
16
|
def initialize(selector:,
|
16
17
|
projects:,
|
17
18
|
portfolios:,
|
@@ -26,7 +27,7 @@ module Checkoff
|
|
26
27
|
|
27
28
|
private
|
28
29
|
|
29
|
-
# @return [Array
|
30
|
+
# @return [Array(Symbol, Array)]
|
30
31
|
attr_reader :selector
|
31
32
|
end
|
32
33
|
end
|
@@ -8,7 +8,7 @@ module Checkoff
|
|
8
8
|
module Section
|
9
9
|
# Base class to evaluate a project selector function given fully evaluated arguments
|
10
10
|
class FunctionEvaluator < ::Checkoff::SelectorClasses::FunctionEvaluator
|
11
|
-
# @param selector [Array
|
11
|
+
# @param selector [Array(Symbol, Array), String]
|
12
12
|
# @param client [Asana::Client]
|
13
13
|
# @param sections [Checkoff::Sections]
|
14
14
|
# @param kwargs [Hash]
|
@@ -24,7 +24,7 @@ module Checkoff
|
|
24
24
|
|
25
25
|
private
|
26
26
|
|
27
|
-
# @return [Array
|
27
|
+
# @return [Array(Symbol, Array)]
|
28
28
|
attr_reader :selector
|
29
29
|
|
30
30
|
# @return [Asana::Client]
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: true
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require_relative 'section/function_evaluator'
|
@@ -24,7 +24,7 @@ module Checkoff
|
|
24
24
|
per_page: 100,
|
25
25
|
options: { fields: ['resource_subtype'] })
|
26
26
|
# @sg-ignore
|
27
|
-
tasks.last&.resource_subtype == 'milestone'
|
27
|
+
T.unsafe(tasks).last&.resource_subtype == 'milestone'
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
@@ -8,10 +8,11 @@ module Checkoff
|
|
8
8
|
module Task
|
9
9
|
# Base class to evaluate a task selector function given fully evaluated arguments
|
10
10
|
class FunctionEvaluator < ::Checkoff::SelectorClasses::FunctionEvaluator
|
11
|
-
# @param selector [Array
|
11
|
+
# @param selector [Array(Symbol, Array), String]
|
12
12
|
# @param tasks [Checkoff::Tasks]
|
13
13
|
# @param timelines [Checkoff::Timelines]
|
14
14
|
# @param custom_fields [Checkoff::CustomFields]
|
15
|
+
# @param _kwargs [Hash]
|
15
16
|
def initialize(selector:,
|
16
17
|
tasks:,
|
17
18
|
timelines:,
|
@@ -26,7 +27,7 @@ module Checkoff
|
|
26
27
|
|
27
28
|
private
|
28
29
|
|
29
|
-
# @return [Array
|
30
|
+
# @return [Array(Symbol, Array)]
|
30
31
|
attr_reader :selector
|
31
32
|
end
|
32
33
|
end
|
@@ -298,9 +298,8 @@ module Checkoff
|
|
298
298
|
end
|
299
299
|
|
300
300
|
# @param task [Asana::Resources::Task]
|
301
|
-
# @param project_name [String]
|
302
301
|
# @param limit_to_portfolio_gid [String, nil] If specified,
|
303
|
-
#
|
302
|
+
# only projects in this portfolio will be evaluated.
|
304
303
|
#
|
305
304
|
# @return [Boolean]
|
306
305
|
def evaluate(task, limit_to_portfolio_gid: nil)
|
@@ -4,8 +4,8 @@
|
|
4
4
|
module Checkoff
|
5
5
|
# Base class to evaluate Asana resource selectors against an Asana resource
|
6
6
|
class SelectorEvaluator
|
7
|
-
# @param selector [Array]
|
8
|
-
# @return [Boolean, Object, nil]
|
7
|
+
# @param selector [Symbol, Array<Symbol, Integer, Array>]
|
8
|
+
# @return [Boolean, Object, Array, nil]
|
9
9
|
def evaluate(selector)
|
10
10
|
return true if selector.empty?
|
11
11
|
|
@@ -46,7 +46,7 @@ module Checkoff
|
|
46
46
|
task_hash['unwrapped']['custom_fields'] = unwrapped_custom_fields
|
47
47
|
end
|
48
48
|
|
49
|
-
# @param [Hash
|
49
|
+
# @param [Hash{String => String, Hash, Array}] task_hash
|
50
50
|
# @param [Array<Hash>] memberships
|
51
51
|
#
|
52
52
|
# @return [void]
|
@@ -54,8 +54,8 @@ module Checkoff
|
|
54
54
|
return unless task_hash.key? 'assignee_section'
|
55
55
|
|
56
56
|
assignee_section = task_hash.fetch('assignee_section')
|
57
|
-
# @type [Hash]
|
58
|
-
assignee = task_hash.fetch('assignee')
|
57
|
+
# @type [Hash{String => String}]
|
58
|
+
assignee = T.cast(task_hash.fetch('assignee'), T::Hash[String, String])
|
59
59
|
memberships << {
|
60
60
|
'section' => assignee_section.dup,
|
61
61
|
'project' => {
|