checkoff 0.39.4 → 0.41.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4157afdaf7db7bbf6334a968a5d06f1a5ce0f248d62aa854192b85c0514232ff
4
- data.tar.gz: be6032a66aa14f3ddad56293d5728508f1540304f28c6acd59d1677097d26a0c
3
+ metadata.gz: ca8318553efc488d88a70b394e290ec8030f532ac9b3d4fa4fc67eb60849270a
4
+ data.tar.gz: cd86cc76ca2f74bed8e35212da234f5cbcad358db6a08d181f702fda149e785a
5
5
  SHA512:
6
- metadata.gz: 6d6b3bcae0366a5da00d6735d7f2cb5a96d29cdf08b85ac8a9571dd2c13bce8553e2083d3760895ae02a1a3b1f354c07ab50b589d4bf9e55799faefa899150ca
7
- data.tar.gz: a58eb7f567d9d70af6b0a60eac27fc918ce0fddccf6773bcc7e969c260269d114618d6042042331015f9c6e095ddc40cd3c9fa77ebd2cf99f3a17b8f1e30edd7
6
+ metadata.gz: ecde71759c34fe1cee589084e7c06577726af223cc207f3cb4236f02d3d4fba75662bf622d69de7cabc7f22acb6f041cd8ddfeb142f60aba07051b35a3ac9e00
7
+ data.tar.gz: bb87fb6a83333fc0efffcd4ce5a37da55689bd617642a15dbbb4b4a1c94cb8511aa9a2e9d11e4fc16fc6ec6631d8191976e125156a1241b8f27367fb0afd4d27
@@ -8,6 +8,7 @@ module Overcommit
8
8
  module PreCommit
9
9
  # CircleCI plugin for Overcommit to validate config file (.circleci/config.yml)
10
10
  class CircleCi < Base
11
+ # @return [Symbol, Array<[Symbol, String]>]
11
12
  def run
12
13
  result = execute(command)
13
14
  return :pass if result.success?
@@ -10,7 +10,7 @@ module Overcommit
10
10
  # Runs `punchlist` against any modified Ruby files.
11
11
  class Punchlist < Base
12
12
  # @param stdout [String]
13
- # @return [Array<Overcommit::Hook::Message]
13
+ # @return [Array<Overcommit::Hook::Message>]
14
14
  def parse_output(stdout)
15
15
  stdout.split("\n").map do |line|
16
16
  # @sg-ignore
@@ -19,12 +19,14 @@ module Overcommit
19
19
  end
20
20
  end
21
21
 
22
+ # @return [String]
22
23
  def files_glob
23
24
  "{" \
24
25
  "#{applicable_files.join(',')}" \
25
26
  "}"
26
27
  end
27
28
 
29
+ # @return [Symbol, Array<Overcommit::Hook::Message>]
28
30
  def run
29
31
  # @sg-ignore
30
32
  # @type [Overcommit::Subprocess::Result]
@@ -11,6 +11,7 @@ module Overcommit
11
11
  module PreCommit
12
12
  # Runs `solargraph typecheck` against any modified Ruby files.
13
13
  class SolargraphTypecheck < Base
14
+ # @return [Array<String>]
14
15
  def run
15
16
  errors = []
16
17
 
@@ -24,8 +25,11 @@ module Overcommit
24
25
 
25
26
  private
26
27
 
28
+ # @param file [String]
29
+ # @param errors [Array<String>]
30
+ # @return [void]
27
31
  def generate_errors_for_file(file, errors)
28
- result = execute(['bundle', 'exec', 'solargraph', 'typecheck', '--level', 'strict', file])
32
+ result = execute(['bundle', 'exec', 'solargraph', 'typecheck', '--level', 'strong', file])
29
33
  return if result.success?
30
34
 
31
35
  # @type [String]
@@ -37,6 +41,9 @@ module Overcommit
37
41
  end
38
42
  end
39
43
 
44
+ # @param file [String]
45
+ # @param error [String]
46
+ # @return [Overcommit::Hook::Message, nil]
40
47
  def parse_error(file, error)
41
48
  # Parse the result for the line number # @type [MatchData]
42
49
  match = error.match(/^(.+?):(\d+)/)
data/.solargraph.yml CHANGED
@@ -4,6 +4,7 @@ include:
4
4
  - ".git-hooks/**/*.rb"
5
5
  exclude:
6
6
  - spec/**/*
7
+ - feature/**/*
7
8
  - test/**/*
8
9
  - vendor/**/*
9
10
  - ".bundle/**/*"
@@ -12,7 +13,7 @@ domains: []
12
13
  reporters:
13
14
  - rubocop
14
15
  - require_not_found
15
- - typecheck:strict
16
+ - typecheck:strong
16
17
  - update_errors
17
18
  formatter:
18
19
  rubocop:
data/Gemfile CHANGED
@@ -19,15 +19,14 @@ gem 'overcommit', ['>=0.60.0', '<0.61.0']
19
19
  gem 'pry'
20
20
  gem 'punchlist'
21
21
  gem 'rake', '~> 13.0'
22
- # ensure recent definitions
23
- gem 'rbs', ['>3.0.3']
22
+ gem 'rbs'
24
23
  gem 'rubocop', ['~> 1.52']
25
24
  gem 'rubocop-minitest'
26
25
  gem 'rubocop-rake'
27
26
  # ensure version with branch coverage
28
27
  gem 'simplecov', ['>=0.18.0']
29
28
  gem 'simplecov-lcov'
30
- gem 'solargraph'
29
+ gem 'solargraph', ['>=0.49.0']
31
30
  gem 'undercover'
32
31
  gem 'webmock'
33
32
 
data/Gemfile.lock CHANGED
@@ -12,7 +12,7 @@ GIT
12
12
  PATH
13
13
  remote: .
14
14
  specs:
15
- checkoff (0.39.4)
15
+ checkoff (0.41.0)
16
16
  activesupport
17
17
  asana (> 0.10.0)
18
18
  cache_method
@@ -79,7 +79,7 @@ GEM
79
79
  imagen (0.1.8)
80
80
  parser (>= 2.5, != 2.5.1.1)
81
81
  iniparse (1.5.0)
82
- jaro_winkler (1.5.4)
82
+ jaro_winkler (1.5.6)
83
83
  json (2.6.3)
84
84
  jwt (2.2.3)
85
85
  kramdown (2.4.0)
@@ -110,12 +110,12 @@ GEM
110
110
  multi_json (1.15.0)
111
111
  multi_xml (0.6.0)
112
112
  multipart-post (2.1.1)
113
- nokogiri (1.14.3)
114
- mini_portile2 (~> 2.8.0)
113
+ nokogiri (1.15.2)
114
+ mini_portile2 (~> 2.8.2)
115
115
  racc (~> 1.4)
116
- nokogiri (1.14.3-x86_64-darwin)
116
+ nokogiri (1.15.2-x86_64-darwin)
117
117
  racc (~> 1.4)
118
- nokogiri (1.14.3-x86_64-linux)
118
+ nokogiri (1.15.2-x86_64-linux)
119
119
  racc (~> 1.4)
120
120
  oauth2 (1.4.11)
121
121
  faraday (>= 0.17.3, < 3.0)
@@ -136,11 +136,11 @@ GEM
136
136
  public_suffix (5.0.0)
137
137
  punchlist (1.3.0)
138
138
  source_finder (>= 2)
139
- racc (1.6.2)
139
+ racc (1.7.1)
140
140
  rack (3.0.6.1)
141
141
  rainbow (3.1.1)
142
142
  rake (13.0.3)
143
- rbs (3.1.0)
143
+ rbs (2.8.4)
144
144
  regexp_parser (2.8.0)
145
145
  reverse_markdown (2.1.1)
146
146
  nokogiri
@@ -171,24 +171,25 @@ GEM
171
171
  simplecov-html (0.12.3)
172
172
  simplecov-lcov (0.8.0)
173
173
  simplecov_json_formatter (0.1.3)
174
- solargraph (0.48.0)
174
+ solargraph (0.49.0)
175
175
  backport (~> 1.2)
176
176
  benchmark
177
- bundler (>= 1.17.2)
177
+ bundler (~> 2.0)
178
178
  diff-lcs (~> 1.4)
179
179
  e2mmap
180
180
  jaro_winkler (~> 1.5)
181
181
  kramdown (~> 2.3)
182
182
  kramdown-parser-gfm (~> 1.1)
183
183
  parser (~> 3.0)
184
- reverse_markdown (>= 1.0.5, < 3)
185
- rubocop (>= 0.52)
184
+ rbs (~> 2.0)
185
+ reverse_markdown (~> 2.0)
186
+ rubocop (~> 1.38)
186
187
  thor (~> 1.0)
187
188
  tilt (~> 2.0)
188
189
  yard (~> 0.9, >= 0.9.24)
189
190
  source_finder (3.2.1)
190
- thor (1.2.1)
191
- tilt (2.1.0)
191
+ thor (1.2.2)
192
+ tilt (2.2.0)
192
193
  tomlrb (2.0.3)
193
194
  tzinfo (2.0.6)
194
195
  concurrent-ruby (~> 1.0)
@@ -225,13 +226,13 @@ DEPENDENCIES
225
226
  pry
226
227
  punchlist
227
228
  rake (~> 13.0)
228
- rbs (> 3.0.3)
229
+ rbs
229
230
  rubocop (~> 1.52)
230
231
  rubocop-minitest
231
232
  rubocop-rake
232
233
  simplecov (>= 0.18.0)
233
234
  simplecov-lcov
234
- solargraph
235
+ solargraph (>= 0.49.0)
235
236
  undercover
236
237
  webmock
237
238
 
@@ -39,6 +39,7 @@ module Checkoff
39
39
  # Load configuration file
40
40
  class ConfigLoader
41
41
  class << self
42
+ # @return EnvFallbackConfigLoader
42
43
  def load(sym)
43
44
  yaml_result = load_yaml_file(sym)
44
45
  EnvFallbackConfigLoader.new(yaml_result, sym, yaml_filename(sym))
@@ -31,12 +31,20 @@ module Checkoff
31
31
  end
32
32
  end
33
33
 
34
- attr_reader :key, :values
34
+ # @return [String]
35
+ attr_reader :key
36
+
37
+ # @return [Array<String>]
38
+ attr_reader :values
35
39
 
36
40
  # Inputs:
37
41
  # 123_column_456 means "abc" project, "def" section
38
42
  # 123 means "abc" project
39
43
  # 123~456 means "abc" and "def" projects
44
+ #
45
+ # @param projects [Array<String>]
46
+ # @param sections [Array<String>]
47
+ # @return [void]
40
48
  def parse_projects_and_sections(projects, sections)
41
49
  single_value.split('~').each do |project_section_pair|
42
50
  # @sg-ignore
@@ -49,6 +57,8 @@ module Checkoff
49
57
  end
50
58
  end
51
59
 
60
+ # @param verb [String]
61
+ # @return [Array<String>]
52
62
  def convert_from_projects_and_sections(verb)
53
63
  projects = []
54
64
  sections = []
@@ -62,6 +72,7 @@ module Checkoff
62
72
 
63
73
  # Handle 'any_projects.ids' search url param
64
74
  class AnyProjectsIds < SimpleParam
75
+ # @return [Array<String>]
65
76
  def convert
66
77
  convert_from_projects_and_sections('any')
67
78
  end
@@ -69,6 +80,7 @@ module Checkoff
69
80
 
70
81
  # Handle 'not_projects.ids' search url param
71
82
  class NotProjectsIds < SimpleParam
83
+ # @return [Array<String>]
72
84
  def convert
73
85
  convert_from_projects_and_sections('not')
74
86
  end
@@ -76,6 +88,7 @@ module Checkoff
76
88
 
77
89
  # Handle 'completion' search url param
78
90
  class Completion < SimpleParam
91
+ # @return [Array<String>]
79
92
  def convert
80
93
  case single_value
81
94
  when 'incomplete'
@@ -90,6 +103,7 @@ module Checkoff
90
103
 
91
104
  # Handle 'not_tags.ids' search url param
92
105
  class NotTagsIds < SimpleParam
106
+ # @return [Array<String>]
93
107
  def convert
94
108
  tag_ids = single_value.split('~')
95
109
  ['tags.not', tag_ids.join(',')]
@@ -98,6 +112,7 @@ module Checkoff
98
112
 
99
113
  # handle 'subtask' search url param
100
114
  class Subtask < SimpleParam
115
+ # @return [Array<[String, Boolean]>]
101
116
  def convert
102
117
  case single_value
103
118
  when 'is_not_subtask'
@@ -112,6 +127,7 @@ module Checkoff
112
127
 
113
128
  # Handle 'any_tags.ids' search url param
114
129
  class AnyTagsIds < SimpleParam
130
+ # @return [Array<String>]
115
131
  def convert
116
132
  tag_ids = single_value.split('~')
117
133
  ['tags.any', tag_ids.join(',')]
@@ -120,6 +136,7 @@ module Checkoff
120
136
 
121
137
  # Handle 'sort' search url param
122
138
  class Sort < SimpleParam
139
+ # @return [Array<String>]
123
140
  def convert
124
141
  # https://developers.asana.com/reference/searchtasksforworkspace
125
142
  conversion = {
@@ -132,6 +149,16 @@ module Checkoff
132
149
  ['sort_by', conversion.fetch(single_value)]
133
150
  end
134
151
  end
152
+
153
+ # Handle 'milestone' search url param
154
+ class Milestone < SimpleParam
155
+ # @return [Array<String>]
156
+ def convert
157
+ return %w[resource_subtype milestone] if single_value == 'is_milestone'
158
+
159
+ raise "Teach me how to handle #{key} = #{values}"
160
+ end
161
+ end
135
162
  end
136
163
 
137
164
  # Convert simple parameters - ones where the param name itself
@@ -160,6 +187,7 @@ module Checkoff
160
187
  'any_tags.ids' => SimpleParam::AnyTagsIds,
161
188
  'subtask' => SimpleParam::Subtask,
162
189
  'sort' => SimpleParam::Sort,
190
+ 'milestone' => SimpleParam::Milestone,
163
191
  }.freeze
164
192
 
165
193
  # https://developers.asana.com/docs/search-tasks-in-a-workspace
@@ -170,12 +198,14 @@ module Checkoff
170
198
  def convert_arg(key, values)
171
199
  # @type [Class<SimpleParam::SimpleParam>]
172
200
  clazz = ARGS.fetch(key)
201
+ # @sg-ignore
173
202
  # @type [SimpleParam::SimpleParam]
174
203
  obj = clazz.new(key: key, values: values)
175
204
  # @sg-ignore
176
205
  obj.convert
177
206
  end
178
207
 
208
+ # @return [Hash<String, Array<String>>]
179
209
  attr_reader :simple_url_params
180
210
  end
181
211
  end
@@ -3,28 +3,47 @@
3
3
  module Checkoff
4
4
  # Base class to evaluate a task selector function given fully evaluated arguments
5
5
  class FunctionEvaluator
6
+ # @param task_selector [Array<(Symbol, Array)>]
7
+ # @param tasks [Checkoff::Tasks]
6
8
  def initialize(task_selector:,
7
9
  tasks:)
8
10
  @task_selector = task_selector
9
11
  @tasks = tasks
10
12
  end
11
13
 
14
+ # @sg-ignore
15
+ # @param _index [Integer]
12
16
  def evaluate_arg?(_index)
13
17
  true
14
18
  end
15
19
 
20
+ # @sg-ignore
21
+ # @return [Boolean]
22
+ def matches?
23
+ raise 'Override me!'
24
+ end
25
+
16
26
  private
17
27
 
28
+ # @param object [Object]
29
+ # @param fn_name [Symbol]
18
30
  def fn?(object, fn_name)
19
31
  object.is_a?(Array) && !object.empty? && [fn_name, fn_name.to_s].include?(object[0])
20
32
  end
21
33
 
34
+ # @sg-ignore
35
+ # @param task [Asana::Resources::Task]
36
+ # @param custom_field_gid [String]
37
+ # @return [Hash]
22
38
  def pull_custom_field_or_raise(task, custom_field_gid)
39
+ # @type [Array<Hash>]
23
40
  custom_fields = task.custom_fields
24
41
  if custom_fields.nil?
25
42
  raise "Could not find custom_fields under task (was 'custom_fields' included in 'extra_fields'?)"
26
43
  end
27
44
 
45
+ # @sg-ignore
46
+ # @type [Hash, nil]
28
47
  matched_custom_field = custom_fields.find { |data| data.fetch('gid') == custom_field_gid }
29
48
  if matched_custom_field.nil?
30
49
  raise "Could not find custom field with gid #{custom_field_gid} " \
@@ -34,8 +53,12 @@ module Checkoff
34
53
  matched_custom_field
35
54
  end
36
55
 
56
+ # @return [Array<(Symbol, Array)>]
37
57
  attr_reader :task_selector
38
58
 
59
+ # @sg-ignore
60
+ # @param custom_field [Hash]
61
+ # @return [Array<String>]
39
62
  def pull_enum_values(custom_field)
40
63
  resource_subtype = custom_field.fetch('resource_subtype')
41
64
  case resource_subtype
@@ -48,6 +71,9 @@ module Checkoff
48
71
  end
49
72
  end
50
73
 
74
+ # @param custom_field [Hash]
75
+ # @param enum_value [Object, nil]
76
+ # @return [Array<String>]
51
77
  def find_gids(custom_field, enum_value)
52
78
  if enum_value.nil?
53
79
  []
@@ -58,12 +84,42 @@ module Checkoff
58
84
  end
59
85
  end
60
86
 
87
+ # @param task [Asana::Resources::Task]
88
+ # @param custom_field_gid [String]
89
+ # @return [Array<String>]
61
90
  def pull_custom_field_values_gids(task, custom_field_gid)
62
91
  custom_field = pull_custom_field_or_raise(task, custom_field_gid)
63
92
  pull_enum_values(custom_field).flat_map do |enum_value|
64
93
  find_gids(custom_field, enum_value)
65
94
  end
66
95
  end
96
+
97
+ # @sg-ignore
98
+ # @param task [Asana::Resources::Task]
99
+ # @param custom_field_name [String]
100
+ # @return [Hash, nil]
101
+ def pull_custom_field_by_name(task, custom_field_name)
102
+ custom_fields = task.custom_fields
103
+ if custom_fields.nil?
104
+ raise "custom fields not found on task - did you add 'custom_field' in your extra_fields argument?"
105
+ end
106
+
107
+ # @sg-ignore
108
+ # @type [Hash, nil]
109
+ custom_fields.find { |field| field.fetch('name') == custom_field_name }
110
+ end
111
+
112
+ # @param task [Asana::Resources::Task]
113
+ # @param custom_field_name [String]
114
+ # @return [Hash]
115
+ def pull_custom_field_by_name_or_raise(task, custom_field_name)
116
+ custom_field = pull_custom_field_by_name(task, custom_field_name)
117
+ if custom_field.nil?
118
+ raise "Could not find custom field with name #{custom_field_name} " \
119
+ "in task #{task.gid} with custom fields #{task.custom_fields}"
120
+ end
121
+ custom_field
122
+ end
67
123
  end
68
124
 
69
125
  # :and function
@@ -72,6 +128,10 @@ module Checkoff
72
128
  fn?(task_selector, :and)
73
129
  end
74
130
 
131
+ # @param _task [Asana::Resources::Task]
132
+ # @param lhs [Object]
133
+ # @param rhs [Object]
134
+ # @return [Object]
75
135
  def evaluate(_task, lhs, rhs)
76
136
  lhs && rhs
77
137
  end
@@ -83,6 +143,9 @@ module Checkoff
83
143
  fn?(task_selector, :not)
84
144
  end
85
145
 
146
+ # @param _task [Asana::Resources::Task]
147
+ # @param subvalue [Object]
148
+ # @return [Boolean]
86
149
  def evaluate(_task, subvalue)
87
150
  !subvalue
88
151
  end
@@ -94,6 +157,9 @@ module Checkoff
94
157
  fn?(task_selector, :nil?)
95
158
  end
96
159
 
160
+ # @param _task [Asana::Resources::Task]
161
+ # @param subvalue [Object]
162
+ # @return [Boolean]
97
163
  def evaluate(_task, subvalue)
98
164
  subvalue.nil?
99
165
  end
@@ -105,10 +171,15 @@ module Checkoff
105
171
  fn?(task_selector, :tag)
106
172
  end
107
173
 
174
+ # @param _index [Integer]
108
175
  def evaluate_arg?(_index)
109
176
  false
110
177
  end
111
178
 
179
+ # @sg-ignore
180
+ # @param task [Asana::Resources::Task]
181
+ # @param tag_name [String]
182
+ # @return [Boolean]
112
183
  def evaluate(task, tag_name)
113
184
  task.tags.map(&:name).include? tag_name
114
185
  end
@@ -120,6 +191,8 @@ module Checkoff
120
191
  fn?(task_selector, :due)
121
192
  end
122
193
 
194
+ # @param task [Asana::Resources::Task]
195
+ # @return [Boolean]
123
196
  def evaluate(task)
124
197
  @tasks.task_ready?(task)
125
198
  end
@@ -131,6 +204,9 @@ module Checkoff
131
204
  fn?(task_selector, :due_date_set)
132
205
  end
133
206
 
207
+ # @sg-ignore
208
+ # @param task [Asana::Resources::Task]
209
+ # @return [Boolean]
134
210
  def evaluate(task)
135
211
  !task.due_at.nil? || !task.due_on.nil?
136
212
  end
@@ -142,17 +218,16 @@ module Checkoff
142
218
  fn?(task_selector, :custom_field_value)
143
219
  end
144
220
 
221
+ # @param _index [Integer]
145
222
  def evaluate_arg?(_index)
146
223
  false
147
224
  end
148
225
 
226
+ # @param task [Asana::Resources::Task]
227
+ # @param custom_field_name [String]
228
+ # @return [String, nil]
149
229
  def evaluate(task, custom_field_name)
150
- custom_fields = task.custom_fields
151
- if custom_fields.nil?
152
- raise "custom fields not found on task - did you add 'custom_field' in your extra_fields argument?"
153
- end
154
-
155
- custom_field = custom_fields.find { |field| field.fetch('name') == custom_field_name }
230
+ custom_field = pull_custom_field_by_name(task, custom_field_name)
156
231
  return nil if custom_field.nil?
157
232
 
158
233
  custom_field['display_value']
@@ -169,6 +244,10 @@ module Checkoff
169
244
  false
170
245
  end
171
246
 
247
+ # @sg-ignore
248
+ # @param task [Asana::Resources::Task]
249
+ # @param custom_field_gid [String]
250
+ # @return [String, nil]
172
251
  def evaluate(task, custom_field_gid)
173
252
  custom_field = pull_custom_field_or_raise(task, custom_field_gid)
174
253
  custom_field['display_value']
@@ -185,6 +264,10 @@ module Checkoff
185
264
  false
186
265
  end
187
266
 
267
+ # @param task [Asana::Resources::Task]
268
+ # @param custom_field_gid [String]
269
+ # @param custom_field_values_gids [Array<String>]
270
+ # @return [Boolean]
188
271
  def evaluate(task, custom_field_gid, custom_field_values_gids)
189
272
  actual_custom_field_values_gids = pull_custom_field_values_gids(task, custom_field_gid)
190
273
 
@@ -204,6 +287,10 @@ module Checkoff
204
287
  false
205
288
  end
206
289
 
290
+ # @param task [Asana::Resources::Task]
291
+ # @param custom_field_gid [String]
292
+ # @param custom_field_values_gids [Array<String>]
293
+ # @return [Boolean]
207
294
  def evaluate(task, custom_field_gid, custom_field_values_gids)
208
295
  actual_custom_field_values_gids = pull_custom_field_values_gids(task, custom_field_gid)
209
296
 
@@ -213,8 +300,34 @@ module Checkoff
213
300
  end
214
301
  end
215
302
 
303
+ # :custom_field_less_than_n_days_from_now function
304
+ class CustomFieldLessThanNDaysFromNowFunctionEvaluator < FunctionEvaluator
305
+ def matches?
306
+ fn?(task_selector, :custom_field_less_than_n_days_from_now)
307
+ end
308
+
309
+ def evaluate_arg?(_index)
310
+ false
311
+ end
312
+
313
+ # @param task [Asana::Resources::Task]
314
+ # @param custom_field_name [String]
315
+ # @param num_days [Integer]
316
+ # @return [Boolean]
317
+ def evaluate(task, custom_field_name, num_days)
318
+ custom_field = pull_custom_field_by_name_or_raise(task, custom_field_name)
319
+
320
+ time_str = custom_field.fetch('display_value')
321
+ time = Time.parse(time_str)
322
+ n_days_from_now = (Time.now + (num_days * 24 * 60 * 60))
323
+ time < n_days_from_now
324
+ end
325
+ end
326
+
216
327
  # Evaluator task selectors against a task
217
328
  class TaskSelectorEvaluator
329
+ # @param task [Asana::Resources::Task]
330
+ # @param tasks [Checkoff::Tasks]
218
331
  def initialize(task:,
219
332
  tasks: Checkoff::Tasks.new)
220
333
  @task = task
@@ -232,12 +345,18 @@ module Checkoff
232
345
  AndFunctionEvaluator,
233
346
  DuePFunctionEvaluator,
234
347
  DueDateSetPFunctionEvaluator,
348
+ CustomFieldLessThanNDaysFromNowFunctionEvaluator,
235
349
  ].freeze
236
350
 
351
+ # @param task_selector [Array]
352
+ # @return [Boolean, Object, nil]
237
353
  def evaluate(task_selector)
238
- return true if task_selector == []
354
+ return true if task_selector.empty?
239
355
 
356
+ # @param evaluator_class [Class<FunctionEvaluator>]
240
357
  FUNCTION_EVALUTORS.each do |evaluator_class|
358
+ # @sg-ignore
359
+ # @type [FunctionEvaluator]
241
360
  evaluator = evaluator_class.new(task_selector: task_selector,
242
361
  tasks: tasks)
243
362
 
@@ -246,11 +365,15 @@ module Checkoff
246
365
  return try_this_evaluator(task_selector, evaluator)
247
366
  end
248
367
 
249
- raise "Syntax issue trying to handle #{task_selector}"
368
+ raise "Syntax issue trying to handle #{task_selector.inspect}"
250
369
  end
251
370
 
252
371
  private
253
372
 
373
+ # @sg-ignore
374
+ # @param task_selector [Array]
375
+ # @param evaluator [FunctionEvaluator]
376
+ # @return [Boolean, Object, nil]
254
377
  def try_this_evaluator(task_selector, evaluator)
255
378
  evaluated_args = task_selector[1..].map.with_index do |item, index|
256
379
  if evaluator.evaluate_arg?(index)
@@ -263,6 +386,11 @@ module Checkoff
263
386
  evaluator.evaluate(task, *evaluated_args)
264
387
  end
265
388
 
266
- attr_reader :task, :tasks, :task_selector
389
+ # @return [Asana::Resources::Task]
390
+ attr_reader :task
391
+ # @return [Checkoff::Tasks]
392
+ attr_reader :tasks
393
+ # @return [Array<(Symbol, Array)>]
394
+ attr_reader :task_selector
267
395
  end
268
396
  end
@@ -19,12 +19,9 @@ module Checkoff
19
19
  # Run task searches against the Asana API
20
20
  class TaskSearches
21
21
  MINUTE = 60
22
- # @sg-ignore
23
22
  HOUR = MINUTE * 60
24
23
  DAY = 24 * HOUR
25
- # @sg-ignore
26
24
  REALLY_LONG_CACHE_TIME = HOUR * 1
27
- # @sg-ignore
28
25
  LONG_CACHE_TIME = MINUTE * 15
29
26
  SHORT_CACHE_TIME = MINUTE
30
27
 
@@ -62,7 +59,6 @@ module Checkoff
62
59
  client: client)
63
60
  tasks.select { |task| task_selectors.filter_via_task_selector(task, task_selector) }
64
61
  end
65
- # @sg-ignore
66
62
  cache_method :task_search, LONG_CACHE_TIME
67
63
 
68
64
  private
@@ -81,11 +77,7 @@ module Checkoff
81
77
  # :nocov:
82
78
  class << self
83
79
  def run
84
- # @sg-ignore
85
- # @type [String]
86
80
  workspace_name = ARGV[0] || raise('Please pass workspace name as first argument')
87
- # @sg-ignore
88
- # @type [String]
89
81
  url = ARGV[1] || raise('Please pass task search URL as second argument')
90
82
  task_searches = Checkoff::TaskSearches.new
91
83
  task_search = task_searches.task_search(workspace_name, url)
@@ -21,6 +21,10 @@ module Checkoff
21
21
  LONG_CACHE_TIME = MINUTE * 15
22
22
  SHORT_CACHE_TIME = MINUTE
23
23
 
24
+ # @sg-ignore
25
+ # @param [Hash] config
26
+ # @param [Asana::Client] client
27
+ # @param [Checkoff::Tasks] tasks
24
28
  def initialize(config: Checkoff::Internal::ConfigLoader.load(:asana),
25
29
  client: Checkoff::Clients.new(config: config).client,
26
30
  tasks: Checkoff::Tasks.new(config: config,
@@ -30,8 +34,8 @@ module Checkoff
30
34
  end
31
35
 
32
36
  # @param [Asana::Resources::Task] task
33
- # @param [Hash<Symbol, Object>] task_selector Filter based on
34
- # description. Examples: {tag: 'foo'} {:not {tag: 'foo'} (:tag 'foo')
37
+ # @param [Array<(Symbol, Array)>] task_selector Filter based on
38
+ # task details. Examples: [:tag, 'foo'] [:not, [:tag, 'foo']] [:tag, 'foo']
35
39
  # @return [Boolean]
36
40
  def filter_via_task_selector(task, task_selector)
37
41
  evaluator = TaskSelectorEvaluator.new(task: task, tasks: tasks)
@@ -40,16 +44,19 @@ module Checkoff
40
44
 
41
45
  private
42
46
 
47
+ # @return [Checkoff::Tasks]
43
48
  attr_reader :tasks
44
49
 
45
50
  # bundle exec ./task_selectors.rb
46
51
  # :nocov:
47
52
  class << self
53
+ # @sg-ignore
48
54
  # @return [String]
49
55
  def project_name
50
56
  ARGV[1] || raise('Please pass project name to pull tasks from as first argument')
51
57
  end
52
58
 
59
+ # @sg-ignore
53
60
  # @return [String]
54
61
  def workspace_name
55
62
  ARGV[0] || raise('Please pass workspace name as first argument')
@@ -61,6 +68,7 @@ module Checkoff
61
68
  JSON.parse(task_selector_json)
62
69
  end
63
70
 
71
+ # @return [void]
64
72
  def run
65
73
  require 'checkoff/projects'
66
74
 
@@ -3,5 +3,5 @@
3
3
  # Command-line and gem client for Asana (unofficial)
4
4
  module Checkoff
5
5
  # Version of library
6
- VERSION = '0.39.4'
6
+ VERSION = '0.41.0'
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: checkoff
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.39.4
4
+ version: 0.41.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vince Broz
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-06-16 00:00:00.000000000 Z
11
+ date: 2023-06-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport