checkoff 0.243.0 → 0.244.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 (48) hide show
  1. checksums.yaml +4 -4
  2. data/checkoff.gemspec +39 -22
  3. data/lib/checkoff/attachments.rb +9 -9
  4. data/lib/checkoff/cli.rb +28 -16
  5. data/lib/checkoff/clients.rb +2 -0
  6. data/lib/checkoff/custom_fields.rb +5 -8
  7. data/lib/checkoff/events.rb +0 -2
  8. data/lib/checkoff/internal/asana_event_enrichment.rb +6 -4
  9. data/lib/checkoff/internal/asana_event_filter.rb +0 -3
  10. data/lib/checkoff/internal/config_loader.rb +1 -1
  11. data/lib/checkoff/internal/logging.rb +2 -0
  12. data/lib/checkoff/internal/project_hashes.rb +0 -1
  13. data/lib/checkoff/internal/project_timing.rb +0 -5
  14. data/lib/checkoff/internal/search_url/custom_field_param_converter.rb +6 -5
  15. data/lib/checkoff/internal/search_url/custom_field_variant.rb +0 -1
  16. data/lib/checkoff/internal/search_url/date_param_converter.rb +2 -5
  17. data/lib/checkoff/internal/search_url/parser.rb +4 -0
  18. data/lib/checkoff/internal/search_url/results_merger.rb +1 -0
  19. data/lib/checkoff/internal/search_url/simple_param_converter.rb +2 -4
  20. data/lib/checkoff/internal/selector_classes/common.rb +19 -1
  21. data/lib/checkoff/internal/selector_classes/function_evaluator.rb +1 -1
  22. data/lib/checkoff/internal/selector_classes/project.rb +8 -0
  23. data/lib/checkoff/internal/selector_classes/section.rb +2 -2
  24. data/lib/checkoff/internal/selector_classes/task/function_evaluator.rb +9 -0
  25. data/lib/checkoff/internal/selector_classes/task.rb +28 -27
  26. data/lib/checkoff/internal/selector_evaluator.rb +2 -0
  27. data/lib/checkoff/internal/task_hashes.rb +0 -3
  28. data/lib/checkoff/internal/task_timing.rb +4 -6
  29. data/lib/checkoff/internal/thread_local.rb +1 -1
  30. data/lib/checkoff/monkeypatches/resource_marshalling.rb +0 -2
  31. data/lib/checkoff/my_tasks.rb +2 -1
  32. data/lib/checkoff/portfolios.rb +1 -0
  33. data/lib/checkoff/projects.rb +5 -5
  34. data/lib/checkoff/resources.rb +0 -2
  35. data/lib/checkoff/section_selectors.rb +0 -1
  36. data/lib/checkoff/sections.rb +18 -14
  37. data/lib/checkoff/subtasks.rb +1 -1
  38. data/lib/checkoff/tags.rb +2 -4
  39. data/lib/checkoff/task_searches.rb +2 -8
  40. data/lib/checkoff/task_selectors.rb +2 -3
  41. data/lib/checkoff/tasks.rb +18 -11
  42. data/lib/checkoff/timelines.rb +12 -6
  43. data/lib/checkoff/timing.rb +5 -8
  44. data/lib/checkoff/version.rb +1 -1
  45. data/lib/checkoff/workspaces.rb +5 -4
  46. data/rbi/checkoff.rbi +618 -483
  47. data/sig/checkoff.rbs +574 -481
  48. metadata +1 -1
@@ -14,8 +14,8 @@ module Checkoff
14
14
  @date_url_params = date_url_params
15
15
  end
16
16
 
17
- # @sg-ignore
18
17
  # @return [Array(Hash{String => String}, Array<Symbol, Array>)]
18
+ # @sg-ignore
19
19
  def convert
20
20
  return [{}, []] if date_url_params.empty?
21
21
 
@@ -78,7 +78,6 @@ module Checkoff
78
78
 
79
79
  validate_unit_is_day!(prefix)
80
80
 
81
- # @sg-ignore
82
81
  # @type [Date]
83
82
  before = Date.today + value
84
83
 
@@ -99,7 +98,6 @@ module Checkoff
99
98
  # Example value: 1702857600000
100
99
  # +1 is because API seems to operate on inclusive ranges
101
100
  # @type [Date]
102
- # @sg-ignore
103
101
  after = Time.at(after.to_i / 1000).to_date + 1
104
102
  [{ "#{API_PREFIX.fetch(prefix)}.after" => after.to_s }, []]
105
103
  end
@@ -111,7 +109,6 @@ module Checkoff
111
109
 
112
110
  validate_unit_is_day!(prefix)
113
111
 
114
- # @sg-ignore
115
112
  # @type [Date]
116
113
  after = Date.today - value
117
114
 
@@ -125,7 +122,6 @@ module Checkoff
125
122
 
126
123
  validate_unit_is_day!(prefix)
127
124
 
128
- # @sg-ignore
129
125
  # @type [Date]
130
126
  before = Date.today + value + 1
131
127
 
@@ -133,6 +129,7 @@ module Checkoff
133
129
  end
134
130
 
135
131
  # @param param_key [String]
132
+ # @sg-ignore
136
133
  # @return [String]
137
134
  def get_single_param(param_key)
138
135
  raise "Expected #{param_key} to have at least one value" unless date_url_params.key? param_key
@@ -24,7 +24,9 @@ module Checkoff
24
24
  # @param url [String]
25
25
  # @return [Array(Hash{String => String}, Array)]
26
26
  def convert_params(url)
27
+ # @sg-ignore
27
28
  url_params = CGI.parse(URI.parse(url).query)
29
+ # @sg-ignore
28
30
  custom_field_params, date_url_params, simple_url_params = partition_url_params(url_params)
29
31
  custom_field_args, custom_field_task_selector = convert_custom_field_params(custom_field_params)
30
32
  date_url_args, date_task_selector = convert_date_params(date_url_params)
@@ -58,8 +60,10 @@ module Checkoff
58
60
  # @return [Array(Hash{String => Array<String>}, Hash{String => Array<String>}, Hash{String => Array<String>})]
59
61
  def partition_url_params(url_params)
60
62
  groups = T.let(url_params.to_a.group_by do |key, _values|
63
+ # @sg-ignore
61
64
  if key.start_with? 'custom_field_'
62
65
  :custom_field
66
+ # @sg-ignore
63
67
  elsif key.include? '_date'
64
68
  :date
65
69
  else
@@ -18,6 +18,7 @@ module Checkoff
18
18
 
19
19
  # @param task_selectors [Array<Symbol, Array>]
20
20
  # @return [Array(Symbol, Array, Array)]
21
+ # @sg-ignore
21
22
  def self.merge_task_selectors(*task_selectors)
22
23
  return [] if task_selectors.empty?
23
24
 
@@ -21,7 +21,6 @@ module Checkoff
21
21
 
22
22
  private
23
23
 
24
- # @sg-ignore
25
24
  # @return [String] the single value of the search url param
26
25
  def single_value
27
26
  @single_value ||= begin
@@ -48,7 +47,6 @@ module Checkoff
48
47
  # @return [void]
49
48
  def parse_projects_and_sections(projects, sections)
50
49
  single_value.split('~').each do |project_section_pair|
51
- # @sg-ignore
52
50
  project, section = project_section_pair.split('_column_')
53
51
  raise "Invalid query string: #{project_section_pair}" if project.nil?
54
52
 
@@ -228,6 +226,7 @@ module Checkoff
228
226
  # @return [Hash{String => String}] the converted params
229
227
  def convert
230
228
  # @type [Array<Array(String, String)>]
229
+ # @sg-ignore
231
230
  arr_of_tuples = simple_url_params.to_a.flat_map do |key, values|
232
231
  # @type
233
232
  entry = convert_arg(key, values).each_slice(2).to_a
@@ -264,14 +263,13 @@ module Checkoff
264
263
  private_constant :ARGS
265
264
 
266
265
  # https://developers.asana.com/docs/search-tasks-in-a-workspace
267
- # @sg-ignore
268
266
  # @param key [String] the name of the search url param
269
267
  # @param values [Array<String>] the values of the search url param
268
+ # @sg-ignore
270
269
  # @return [Hash{String => String}] the converted params
271
270
  def convert_arg(key, values)
272
271
  # @type [Class<SimpleParam::SimpleParam>]
273
272
  clazz = ARGS.fetch(key)
274
- # @sg-ignore
275
273
  # @type [SimpleParam::SimpleParam]
276
274
  obj = clazz.new(key:, values:)
277
275
  # @sg-ignore
@@ -105,9 +105,12 @@ module Checkoff
105
105
  # @param custom_field_name [String]
106
106
  # @return [String, nil]
107
107
  def evaluate(resource, custom_field_name)
108
+ # @sg-ignore
108
109
  custom_field = @custom_fields.resource_custom_field_by_name(resource, custom_field_name)
110
+ # @sg-ignore
109
111
  return nil if custom_field.nil?
110
112
 
113
+ # @sg-ignore
111
114
  custom_field['display_value']
112
115
  end
113
116
  end
@@ -124,10 +127,14 @@ module Checkoff
124
127
 
125
128
  # @sg-ignore
126
129
  # @param resource [Asana::Resources::Task,Asana::Resources::Project]
130
+ # @sg-ignore
127
131
  # @param custom_field_gid [String]
128
132
  # @return [String, nil]
133
+ # @sg-ignore
129
134
  def evaluate(resource, custom_field_gid)
135
+ # @sg-ignore
130
136
  custom_field = @custom_fields.resource_custom_field_by_gid_or_raise(resource, custom_field_gid)
137
+ # @sg-ignore
131
138
  custom_field['display_value']
132
139
  end
133
140
  end
@@ -145,13 +152,17 @@ module Checkoff
145
152
  end
146
153
 
147
154
  # @param resource [Asana::Resources::Task,Asana::Resources::Project]
155
+ # @sg-ignore
148
156
  # @param custom_field_gid [String]
149
157
  # @param custom_field_values_gids [Array<String>]
150
158
  # @return [Boolean]
159
+ # @sg-ignore
151
160
  def evaluate(resource, custom_field_gid, custom_field_values_gids)
161
+ # @sg-ignore
152
162
  actual_custom_field_values_gids = @custom_fields.resource_custom_field_values_gids_or_raise(resource,
153
163
  custom_field_gid)
154
164
 
165
+ # @sg-ignore
155
166
  actual_custom_field_values_gids.any? do |custom_field_value|
156
167
  custom_field_values_gids.include?(custom_field_value)
157
168
  end
@@ -172,13 +183,17 @@ module Checkoff
172
183
 
173
184
  # @param resource [Asana::Resources::Task,Asana::Resources::Project]
174
185
  # @param custom_field_name [String]
186
+ # @sg-ignore
175
187
  # @param custom_field_value_names [Array<String>]
188
+ # @sg-ignore
176
189
  # @return [Boolean]
177
190
  def evaluate(resource, custom_field_name, custom_field_value_names)
178
191
  actual_custom_field_values_names =
192
+ # @sg-ignore
179
193
  @custom_fields.resource_custom_field_values_names_by_name(resource,
180
194
  custom_field_name)
181
195
 
196
+ # @sg-ignore
182
197
  actual_custom_field_values_names.any? do |custom_field_value|
183
198
  custom_field_value_names.include?(custom_field_value)
184
199
  end
@@ -203,10 +218,12 @@ module Checkoff
203
218
  # @return [Boolean]
204
219
  def evaluate(resource, custom_field_gid, custom_field_values_gids)
205
220
  actual_custom_field_values_gids =
221
+ # @sg-ignore
206
222
  @custom_fields.resource_custom_field_values_gids_or_raise(resource,
207
223
  custom_field_gid)
208
224
 
209
225
  custom_field_values_gids.all? do |custom_field_value|
226
+ # @sg-ignore
210
227
  actual_custom_field_values_gids.include?(custom_field_value)
211
228
  end
212
229
  end
@@ -225,6 +242,7 @@ module Checkoff
225
242
  end
226
243
 
227
244
  # @param resource [Asana::Resources::Task, Asana::Resources::Project]
245
+ # @sg-ignore
228
246
  # @param prefix [String]
229
247
  # @return [boolish]
230
248
  def evaluate(resource, prefix)
@@ -238,9 +256,9 @@ module Checkoff
238
256
  selector.is_a?(String)
239
257
  end
240
258
 
241
- # @sg-ignore
242
259
  # @param _resource [Asana::Resources::Task,Asana::Resources::Project]
243
260
  # @return [String]
261
+ # @sg-ignore
244
262
  def evaluate(_resource)
245
263
  T.cast(selector, String)
246
264
  end
@@ -14,8 +14,8 @@ module Checkoff
14
14
  true
15
15
  end
16
16
 
17
- # @sg-ignore
18
17
  # @return [Boolean]
18
+ # @sg-ignore
19
19
  def matches?
20
20
  raise 'Override me!'
21
21
  end
@@ -17,6 +17,7 @@ module Checkoff
17
17
 
18
18
  # @param resource [Asana::Resources::Project]
19
19
  # @return [String, nil]
20
+ # @sg-ignore
20
21
  def evaluate(resource)
21
22
  resource.due_date
22
23
  end
@@ -32,8 +33,10 @@ module Checkoff
32
33
 
33
34
  # @param project [Asana::Resources::Project]
34
35
  # @param period [Symbol] - :now_or_before or :this_week
36
+ # @sg-ignore
35
37
  # @return [Boolean]
36
38
  def evaluate(project, period = :now_or_before)
39
+ # @sg-ignore
37
40
  @projects.project_ready?(project, period:)
38
41
  end
39
42
  end
@@ -50,13 +53,18 @@ module Checkoff
50
53
  # @param portfolio_name [String]
51
54
  # @param workspace_name [String, nil]
52
55
  # @param extra_project_fields [Array<String>]
56
+ # @sg-ignore
53
57
  #
58
+ # @sg-ignore
54
59
  # @return [Boolean]
55
60
  def evaluate(project, portfolio_name, workspace_name: nil, extra_project_fields: [])
56
61
  workspace_name ||= project.workspace&.name
62
+ # @sg-ignore
57
63
  workspace_name ||= @workspaces.default_workspace.name
64
+ # @sg-ignore
58
65
  projects = @portfolios.projects_in_portfolio(workspace_name, portfolio_name,
59
66
  extra_project_fields:)
67
+ # @sg-ignore
60
68
  projects.any? { |p| p.name == project.name }
61
69
  end
62
70
  end
@@ -17,13 +17,12 @@ module Checkoff
17
17
 
18
18
  # @param section [Asana::Resources::Section]
19
19
  #
20
- # @sg-ignore
21
20
  # @return [Boolean]
21
+ # @sg-ignore
22
22
  def evaluate(section)
23
23
  tasks = client.tasks.get_tasks(section: section.gid,
24
24
  per_page: 100,
25
25
  options: { fields: ['resource_subtype'] })
26
- # @sg-ignore
27
26
  T.unsafe(tasks).last&.resource_subtype == 'milestone'
28
27
  end
29
28
  end
@@ -41,6 +40,7 @@ module Checkoff
41
40
  # @sg-ignore
42
41
  # @return [Boolean]
43
42
  def evaluate(section)
43
+ # @sg-ignore
44
44
  @sections.tasks_by_section_gid(section.gid).any?
45
45
  end
46
46
  end
@@ -25,6 +25,15 @@ module Checkoff
25
25
  super()
26
26
  end
27
27
 
28
+ # @return [Checkoff::Tasks]
29
+ attr_reader :tasks
30
+
31
+ # @return [Checkoff::Timelines]
32
+ attr_reader :timelines
33
+
34
+ # @return [Checkoff::CustomFields]
35
+ attr_reader :custom_fields
36
+
28
37
  private
29
38
 
30
39
  # @return [Array(Symbol, Array)]
@@ -1,4 +1,4 @@
1
- # typed: false
1
+ # typed: true
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require_relative 'task/function_evaluator'
@@ -18,12 +18,11 @@ module Checkoff
18
18
  false
19
19
  end
20
20
 
21
- # @sg-ignore
22
21
  # @param task [Asana::Resources::Task]
23
22
  # @return [Boolean]
24
23
  def evaluate(task)
25
24
  # @type [Hash{'unwrapped' => Hash}]
26
- task_data = @tasks.task_to_h(task)
25
+ task_data = tasks.task_to_h(task)
27
26
  # @type [Hash{'membership_by_project_name' => Hash}]
28
27
  unwrapped = task_data.fetch('unwrapped')
29
28
  # @type [Array]
@@ -43,14 +42,14 @@ module Checkoff
43
42
  false
44
43
  end
45
44
 
46
- # @sg-ignore
47
45
  # @param task [Asana::Resources::Task]
48
46
  # @param section_name_prefix [String]
49
47
  # @return [Boolean]
48
+ # @sg-ignore
50
49
  def evaluate(task, section_name_prefix)
51
- task_data = @tasks.task_to_h(task)
50
+ task_data = tasks.task_to_h(task)
52
51
  task_data.fetch('unwrapped').fetch('membership_by_section_name').keys.any? do |section_name|
53
- section_name.start_with? section_name_prefix
52
+ String(section_name).start_with?(section_name_prefix)
54
53
  end
55
54
  end
56
55
  end
@@ -71,7 +70,7 @@ module Checkoff
71
70
  # @param section_name [String]
72
71
  # @return [Boolean]
73
72
  def evaluate(task, section_name)
74
- task_data = @tasks.task_to_h(task)
73
+ task_data = tasks.task_to_h(task)
75
74
  task_data.fetch('unwrapped').fetch('membership_by_section_name').keys.any?(section_name)
76
75
  end
77
76
  end
@@ -87,15 +86,16 @@ module Checkoff
87
86
  false
88
87
  end
89
88
 
90
- # @sg-ignore
91
89
  # @param task [Asana::Resources::Task]
92
90
  # @param project_name [String]
93
91
  # @return [Boolean]
92
+ # @sg-ignore
94
93
  def evaluate(task, project_name)
95
94
  project_names = task.memberships.map do |membership|
96
- membership.fetch('project').fetch('name')
95
+ m = T.cast(membership, T::Hash[String, T.untyped])
96
+ T.cast(m.fetch('project'), T::Hash[String, T.untyped]).fetch('name')
97
97
  end
98
- project_names.include? project_name
98
+ T.cast(project_names.include?(project_name), T::Boolean)
99
99
  end
100
100
  end
101
101
 
@@ -110,12 +110,11 @@ module Checkoff
110
110
  false
111
111
  end
112
112
 
113
- # @sg-ignore
114
113
  # @param task [Asana::Resources::Task]
115
114
  # @param portfolio_name [String]
116
115
  # @return [Boolean]
117
116
  def evaluate(task, portfolio_name)
118
- @tasks.in_portfolio_more_than_once?(task, portfolio_name)
117
+ tasks.in_portfolio_more_than_once?(task, portfolio_name)
119
118
  end
120
119
  end
121
120
 
@@ -130,10 +129,10 @@ module Checkoff
130
129
  false
131
130
  end
132
131
 
133
- # @sg-ignore
134
132
  # @param task [Asana::Resources::Task]
135
133
  # @param tag_name [String]
136
134
  # @return [Boolean]
135
+ # @sg-ignore
137
136
  def evaluate(task, tag_name)
138
137
  task.tags.map(&:name).include? tag_name
139
138
  end
@@ -158,7 +157,7 @@ module Checkoff
158
157
  # @return [Boolean]
159
158
  # rubocop:disable Style/OptionalBooleanParameter
160
159
  def evaluate(task, period = :now_or_before, ignore_dependencies = false)
161
- @tasks.task_ready?(task, period:, ignore_dependencies:)
160
+ tasks.task_ready?(task, period:, ignore_dependencies:)
162
161
  end
163
162
  # rubocop:enable Style/OptionalBooleanParameter
164
163
  end
@@ -179,7 +178,7 @@ module Checkoff
179
178
  # @param period [Symbol,Array<Symbol>] See Checkoff::Timing#in_period?
180
179
  # @return [Boolean]
181
180
  def evaluate(task, field_name, period)
182
- @tasks.in_period?(task, field_name, period)
181
+ tasks.in_period?(task, field_name, period)
183
182
  end
184
183
  end
185
184
 
@@ -191,6 +190,7 @@ module Checkoff
191
190
 
192
191
  # @param task [Asana::Resources::Task]
193
192
  # @return [Boolean]
193
+ # @sg-ignore
194
194
  def evaluate(task)
195
195
  task.assignee.nil?
196
196
  end
@@ -204,9 +204,9 @@ module Checkoff
204
204
  fn?(selector, FUNCTION_NAME)
205
205
  end
206
206
 
207
- # @sg-ignore
208
207
  # @param task [Asana::Resources::Task]
209
208
  # @return [Boolean]
209
+ # @sg-ignore
210
210
  def evaluate(task)
211
211
  !task.due_at.nil? || !task.due_on.nil?
212
212
  end
@@ -233,13 +233,15 @@ module Checkoff
233
233
 
234
234
  # @type [Array<Asana::Resources::Story>]
235
235
  stories = task.stories(per_page: 100).to_a.reject do |story|
236
+ # @sg-ignore
236
237
  excluding_resource_subtypes.include? story.resource_subtype
237
238
  end
238
239
  return true if stories.empty? # no stories == infinitely old!
239
240
 
240
241
  last_story = stories.last
242
+ # @sg-ignore
241
243
  last_story_created_at = Time.parse(last_story.created_at)
242
- n_days_ago = Time.now - (num_days * 24 * 60 * 60)
244
+ n_days_ago = Time.at(Time.now.to_i - (num_days * 86_400))
243
245
  last_story_created_at < n_days_ago
244
246
  end
245
247
  end
@@ -260,7 +262,6 @@ module Checkoff
260
262
  start_on = Date.parse(task.start_on) unless task.start_on.nil?
261
263
  due_on = Date.parse(task.due_on) unless task.due_on.nil?
262
264
  allocated_hours = 8.0
263
- # @sg-ignore
264
265
  allocated_hours = (due_on - start_on + 1).to_i * 8.0 if start_on && due_on
265
266
  allocated_hours
266
267
  end
@@ -268,11 +269,10 @@ module Checkoff
268
269
  # @param task [Asana::Resources::Task]
269
270
  # @return [Boolean]
270
271
  def evaluate(task)
271
- custom_field = @custom_fields.resource_custom_field_by_name(task, 'Estimated time')
272
+ custom_field = custom_fields.resource_custom_field_by_name(task, 'Estimated time')
272
273
 
273
274
  return false if custom_field.nil?
274
275
 
275
- # @sg-ignore
276
276
  # @type [Integer, nil]
277
277
  estimate_minutes = custom_field.fetch('number_value')
278
278
 
@@ -301,8 +301,8 @@ module Checkoff
301
301
  #
302
302
  # @return [Boolean]
303
303
  def evaluate(task, limit_to_portfolio_gid: nil)
304
- @timelines.task_dependent_on_previous_section_last_milestone?(task,
305
- limit_to_portfolio_gid:)
304
+ timelines.task_dependent_on_previous_section_last_milestone?(task,
305
+ limit_to_portfolio_gid:)
306
306
  end
307
307
  end
308
308
 
@@ -319,7 +319,7 @@ module Checkoff
319
319
  #
320
320
  # @return [Boolean]
321
321
  def evaluate(task, portfolio_name)
322
- @tasks.in_portfolio_named?(task, portfolio_name)
322
+ tasks.in_portfolio_named?(task, portfolio_name)
323
323
  end
324
324
  end
325
325
 
@@ -340,8 +340,8 @@ module Checkoff
340
340
  #
341
341
  # @return [Boolean]
342
342
  def evaluate(task, limit_to_portfolio_name = nil)
343
- !@timelines.last_task_milestone_depends_on_this_task?(task,
344
- limit_to_portfolio_name:)
343
+ !timelines.last_task_milestone_depends_on_this_task?(task,
344
+ limit_to_portfolio_name:)
345
345
  end
346
346
  end
347
347
 
@@ -360,6 +360,7 @@ module Checkoff
360
360
  # @param task [Asana::Resources::Task]
361
361
  #
362
362
  # @return [Boolean]
363
+ # @sg-ignore
363
364
  def evaluate(task)
364
365
  raise 'Please add resource_subtype to extra_fields' if task.resource_subtype.nil?
365
366
 
@@ -384,8 +385,8 @@ module Checkoff
384
385
  #
385
386
  # @return [Boolean]
386
387
  def evaluate(task, limit_to_portfolio_name = nil)
387
- !@timelines.any_milestone_depends_on_this_task?(task,
388
- limit_to_portfolio_name:)
388
+ !timelines.any_milestone_depends_on_this_task?(task,
389
+ limit_to_portfolio_name:)
389
390
  end
390
391
  end
391
392
  end
@@ -17,6 +17,7 @@ module Checkoff
17
17
 
18
18
  next unless evaluator.matches?
19
19
 
20
+ # @sg-ignore
20
21
  return try_this_evaluator(selector, evaluator)
21
22
  end
22
23
 
@@ -42,6 +43,7 @@ module Checkoff
42
43
  def evaluate_args(selector, evaluator)
43
44
  return [] unless selector.is_a?(Array)
44
45
 
46
+ # @sg-ignore
45
47
  selector[1..].map.with_index do |item, index|
46
48
  if evaluator.evaluate_arg?(index)
47
49
  evaluate(item)
@@ -34,7 +34,6 @@ module Checkoff
34
34
  # @param task_hash [Hash]
35
35
  # @return [void]
36
36
  def unwrap_custom_fields(task_hash)
37
- # @sg-ignore
38
37
  # @type [Array<Hash>,nil]
39
38
  custom_fields = task_hash.fetch('custom_fields', nil)
40
39
 
@@ -72,7 +71,6 @@ module Checkoff
72
71
  #
73
72
  # @return [void]
74
73
  def unwrap_memberships(task_hash, memberships, resource, key)
75
- # @sg-ignore
76
74
  # @type [Hash]
77
75
  unwrapped = task_hash.fetch('unwrapped')
78
76
  unwrapped["membership_by_#{resource}_#{key}"] = memberships.group_by do |membership|
@@ -83,7 +81,6 @@ module Checkoff
83
81
  # @param task_hash [Hash]
84
82
  # @return [void]
85
83
  def unwrap_all_memberships(task_hash)
86
- # @sg-ignore
87
84
  # @type [Array<Hash>]
88
85
  memberships = task_hash.fetch('memberships', []).dup
89
86
  add_user_task_list(task_hash, memberships)
@@ -19,11 +19,13 @@ module Checkoff
19
19
 
20
20
  # @param task [Asana::Resources::Task]
21
21
  # @return [Time, nil]
22
+ # @sg-ignore
22
23
  def start_time(task)
23
24
  date_or_time_field_by_name(task, :start)&.to_time
24
25
  end
25
26
 
26
27
  # @param task [Asana::Resources::Task]
28
+ # @sg-ignore
27
29
  # @return [Time, nil]
28
30
  def due_time(task)
29
31
  date_or_time_field_by_name(task, :due)&.to_time
@@ -31,9 +33,9 @@ module Checkoff
31
33
 
32
34
  # @param task [Asana::Resources::Task]
33
35
  #
34
- # @sg-ignore
35
36
  # @return [Date, Time, nil]
36
37
  def start_date_or_time(task)
38
+ # @sg-ignore
37
39
  return @time_class.parse(task.start_at).localtime unless task.start_at.nil?
38
40
 
39
41
  return @date_class.parse(task.start_on) unless task.start_on.nil?
@@ -43,10 +45,9 @@ module Checkoff
43
45
 
44
46
  # @param task [Asana::Resources::Task]
45
47
  #
46
- # @sg-ignore
47
48
  # @return [Date, Time, nil]
48
49
  def due_date_or_time(task)
49
- return @time_class.parse(task.due_at).localtime unless task.due_at.nil?
50
+ return @time_class.parse(T.must(task.due_at)).localtime unless task.due_at.nil?
50
51
 
51
52
  return @date_class.parse(task.due_on) unless task.due_on.nil?
52
53
 
@@ -66,7 +67,6 @@ module Checkoff
66
67
  # @return [Time, Date, nil]
67
68
  def custom_field(task, custom_field_name)
68
69
  custom_field = @custom_fields.resource_custom_field_by_name_or_raise(task, custom_field_name)
69
- # @sg-ignore
70
70
  # @type [String, nil]
71
71
  time_str = custom_field.fetch('display_value')
72
72
  return nil if time_str.nil?
@@ -77,7 +77,6 @@ module Checkoff
77
77
  # @param task [Asana::Resources::Task]
78
78
  # @param field_name [Symbol,Array]
79
79
  #
80
- # @sg-ignore
81
80
  # @return [Date, Time, nil]
82
81
  def date_or_time_field_by_name(task, field_name)
83
82
  return due_date_or_time(task) if field_name == :due
@@ -89,7 +88,6 @@ module Checkoff
89
88
  return start_date_or_time(task) || due_date_or_time(task) if field_name == :ready
90
89
 
91
90
  if field_name.is_a?(Array)
92
- # @sg-ignore
93
91
  # @type [Symbol]
94
92
  actual_field_name = field_name.first
95
93
  args = field_name[1..]
@@ -9,8 +9,8 @@ module Checkoff
9
9
  # @param name [Symbol]
10
10
  # @param value [Object,Boolean]
11
11
  # @yieldreturn [generic<T>]
12
- # @sg-ignore
13
12
  # @return [generic<T>]
13
+ # @sg-ignore
14
14
  def with_thread_local_variable(name, value, &block)
15
15
  old_value = Thread.current[name]
16
16
  Thread.current[name] = value
@@ -30,10 +30,8 @@ module Asana
30
30
  #
31
31
  # @return [void]
32
32
  def marshal_load(data)
33
- # @sg-ignore
34
33
  # @type [Asana::Client]
35
34
  @_client = data.fetch('client')
36
- # @sg-ignore
37
35
  # @type [Hash]
38
36
  @_data = data.fetch('data')
39
37
  @_data.each do |k, v|
@@ -46,7 +46,7 @@ module Checkoff
46
46
  by_my_tasks_section(active_tasks, project.gid)
47
47
  end
48
48
 
49
- # @param name [String]
49
+ # @param name [String, nil]
50
50
  # @return [String, nil]
51
51
  def section_key(name)
52
52
  return nil if name == 'Recently assigned'
@@ -67,6 +67,7 @@ module Checkoff
67
67
  sections.each_entry { |section| by_section[section_key(section.name)] = [] }
68
68
  tasks.each do |task|
69
69
  assignee_section = task.assignee_section
70
+ # @sg-ignore
70
71
  current_section = section_key(assignee_section.name)
71
72
  by_section[current_section] ||= []
72
73
  by_section[current_section] << task
@@ -47,6 +47,7 @@ module Checkoff
47
47
  # @param portfolio_name [String]
48
48
  #
49
49
  # @return [Asana::Resources::Portfolio]
50
+ # @sg-ignore
50
51
  def portfolio_or_raise(workspace_name, portfolio_name)
51
52
  portfolio_obj = portfolio(workspace_name, portfolio_name)
52
53
  raise "Could not find portfolio #{portfolio_name} under workspace #{workspace_name}." if portfolio_obj.nil?