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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/checkoff.gemspec +7 -7
  3. data/lib/checkoff/cli.rb +71 -1
  4. data/lib/checkoff/clients.rb +1 -1
  5. data/lib/checkoff/custom_fields.rb +3 -3
  6. data/lib/checkoff/events.rb +3 -3
  7. data/lib/checkoff/internal/asana_event_enrichment.rb +13 -14
  8. data/lib/checkoff/internal/config_loader.rb +4 -2
  9. data/lib/checkoff/internal/logging.rb +3 -0
  10. data/lib/checkoff/internal/project_selector_evaluator.rb +5 -2
  11. data/lib/checkoff/internal/project_timing.rb +0 -2
  12. data/lib/checkoff/internal/search_url/custom_field_param_converter.rb +12 -12
  13. data/lib/checkoff/internal/search_url/custom_field_variant.rb +19 -18
  14. data/lib/checkoff/internal/search_url/date_param_converter.rb +9 -9
  15. data/lib/checkoff/internal/search_url/parser.rb +20 -30
  16. data/lib/checkoff/internal/search_url/results_merger.rb +4 -6
  17. data/lib/checkoff/internal/search_url/simple_param_converter.rb +19 -11
  18. data/lib/checkoff/internal/section_selector_evaluator.rb +7 -3
  19. data/lib/checkoff/internal/selector_classes/common/function_evaluator.rb +3 -2
  20. data/lib/checkoff/internal/selector_classes/common.rb +5 -6
  21. data/lib/checkoff/internal/selector_classes/function_evaluator.rb +2 -3
  22. data/lib/checkoff/internal/selector_classes/project/function_evaluator.rb +3 -2
  23. data/lib/checkoff/internal/selector_classes/section/function_evaluator.rb +2 -2
  24. data/lib/checkoff/internal/selector_classes/section.rb +2 -2
  25. data/lib/checkoff/internal/selector_classes/task/function_evaluator.rb +3 -2
  26. data/lib/checkoff/internal/selector_classes/task.rb +1 -2
  27. data/lib/checkoff/internal/selector_evaluator.rb +2 -2
  28. data/lib/checkoff/internal/task_hashes.rb +3 -3
  29. data/lib/checkoff/internal/task_selector_evaluator.rb +3 -0
  30. data/lib/checkoff/internal/task_timing.rb +0 -2
  31. data/lib/checkoff/internal/thread_local.rb +5 -4
  32. data/lib/checkoff/my_tasks.rb +4 -4
  33. data/lib/checkoff/portfolios.rb +1 -1
  34. data/lib/checkoff/project_selectors.rb +4 -4
  35. data/lib/checkoff/projects.rb +6 -6
  36. data/lib/checkoff/resources.rb +5 -3
  37. data/lib/checkoff/section_selectors.rb +4 -4
  38. data/lib/checkoff/sections.rb +18 -15
  39. data/lib/checkoff/subtasks.rb +2 -2
  40. data/lib/checkoff/tags.rb +7 -3
  41. data/lib/checkoff/task_searches.rb +9 -9
  42. data/lib/checkoff/task_selectors.rb +10 -6
  43. data/lib/checkoff/tasks.rb +5 -5
  44. data/lib/checkoff/timelines.rb +0 -1
  45. data/lib/checkoff/timing.rb +5 -4
  46. data/lib/checkoff/version.rb +1 -1
  47. data/lib/checkoff/workspaces.rb +1 -1
  48. data/rbi/checkoff.rbi +342 -305
  49. data/sig/checkoff.rbs +327 -279
  50. metadata +7 -7
@@ -1,4 +1,4 @@
1
- # typed: false
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
- # @sg-ignore
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[0]
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<(Hash, 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<(Hash, 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<(Hash, 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<(Hash, 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<(Hash, 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<(Hash, 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<(Hash, 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<(Hash, 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<(Hash, 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<(Hash, 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<String, Array<String>>] the simple params
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<String, String>, Array<[Symbol, Array]>)]
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<String, String>, Array<[Symbol, Array]>)]
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<String, String>, Array<[Symbol, Array]>)] See https://developers.asana.com/docs/search-tasks-in-a-workspace
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<String, String>, Array<[Symbol, Array]>)] See https://developers.asana.com/docs/search-tasks-in-a-workspace
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<String, String>, Array<[Symbol, Array]>)] See https://developers.asana.com/docs/search-tasks-in-a-workspace
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<String, String>, Array<[Symbol, Array]>)] See https://developers.asana.com/docs/search-tasks-in-a-workspace
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<String, Array<String>>]
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: false
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<String, String>, Hash<String, String>)]
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<String, Array<String>>]
50
- # @return [Array(Hash<String, String>, Array<[Symbol, Array]>)]
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<String, Array<String>>]
56
- # @return [Hash<String, String>]
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<String, Array<String>>]
62
- # @return [Array(Hash<String, String>, Array<[Symbol, Array]>)]
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<String, String>]
68
- # @return [Array(Hash<String, String>, Hash<String, String>, 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
- if key.start_with? 'custom_field_'
72
- :custom_field
73
- elsif key.include? '_date'
74
- :date
75
- else
76
- :simple
77
- end
78
- end.transform_values(&:to_h)
79
- # @sg-ignore
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<[Hash<String, String>]>]
10
- # @return [Hash<String, String>
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<Array<[Symbol, Array]>>]
22
- # @return [Array<[Symbol, 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: false
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<[String, Boolean]>]
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<String, Array<String>>] the simple params
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<String, String>] the converted params
195
+ # @return [Hash{String => String}] the converted params
194
196
  def convert
195
- out = simple_url_params.to_a.flat_map do |key, values|
196
- convert_arg(key, values).each_slice(2).to_a
197
- end.to_h
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<String, Class<SimpleParam::SimpleParam>>] the mapping from param name to class
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<String, String>] the converted params
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<String, Array<String>>]
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::Project]
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
- FUNCTION_EVALUTORS = (COMMON_FUNCTION_EVALUATORS + SECTION_FUNCTION_EVALUATORS).freeze
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
- FUNCTION_EVALUTORS
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<(Symbol, Array)>,String]
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<(Symbol, Array)>]
22
+ # @return [Array(Symbol, Array), String]
22
23
  attr_reader :selector
23
24
  end
24
25
  end
@@ -1,4 +1,4 @@
1
- # typed: false
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 [Boolean]
230
- # @sg-ignore
229
+ # @return [boolish]
231
230
  def evaluate(resource, prefix)
232
- resource.name.start_with?(prefix)
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: strict
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<(Symbol, Array)>,String]
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<(Symbol, 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<(Symbol, Array)>,String]
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<(Symbol, Array)>]
27
+ # @return [Array(Symbol, Array)]
28
28
  attr_reader :selector
29
29
 
30
30
  # @return [Asana::Client]
@@ -1,4 +1,4 @@
1
- # typed: false
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<(Symbol, Array)>,String]
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<(Symbol, 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
- # only projects in this portfolio will be evaluated.
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<String, Hash, Array>] task_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' => {