checkoff 0.36.1 → 0.37.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: 1695c4a845c22ee1bbdb6ffb62eb1c78b119867b06c1a004e713eab663f315f6
4
- data.tar.gz: f55d3aeaf99ff74dba23349ff6b8bd388c92236236fcbc51f34416812b1c5a83
3
+ metadata.gz: 78eb26c757cafb9c92eb8e1127e454a3d05a0ed16548483cf0dceeca53c22114
4
+ data.tar.gz: 39a81ddbcb197370af6e7328664ada5a26268cc434363f7291c518e3a7ce1621
5
5
  SHA512:
6
- metadata.gz: 6b24d4ebc9fb9d6f82eaf53ea5fa7cbc949dcf9d0df84e93e547c09d364bfe291c90e86222cd092eea0b68a3acae3943cde8225980ce9c4ae5eafd4719685605
7
- data.tar.gz: b49d2c7e82b74159b0eec2105d27f91be60e58ecabc4c5074ca14d09f52381baec100d96a88f02eacaefb26447fab43e5df108c848d28c4598aab5f9b23320d3
6
+ metadata.gz: 1455835c137f7ed819cd6d5b774d360ee8d72b841a193955ad0b9df665a3f53568c515910b07d8221d6981a9e6f416a089add42025179c0f260cf8cc612740b5
7
+ data.tar.gz: 31619893659ffe14a38183190f4d299c4354f5161ee41be0647eea5f4c45bc4f297d5051311d1e16fc1b300fdbf2ef6eefd88c21256e1ac0541e3b86312b446e
data/Gemfile.lock CHANGED
@@ -12,7 +12,7 @@ GIT
12
12
  PATH
13
13
  remote: .
14
14
  specs:
15
- checkoff (0.36.1)
15
+ checkoff (0.37.0)
16
16
  activesupport
17
17
  asana (> 0.10.0)
18
18
  cache_method
@@ -22,7 +22,7 @@ PATH
22
22
  GEM
23
23
  remote: https://rubygems.org/
24
24
  specs:
25
- activesupport (7.0.4.3)
25
+ activesupport (7.0.5)
26
26
  concurrent-ruby (~> 1.0, >= 1.0.2)
27
27
  i18n (>= 1.6, < 2)
28
28
  minitest (>= 5.1)
@@ -145,19 +145,6 @@ GEM
145
145
  reverse_markdown (2.1.1)
146
146
  nokogiri
147
147
  rexml (3.2.5)
148
- rspec (3.11.0)
149
- rspec-core (~> 3.11.0)
150
- rspec-expectations (~> 3.11.0)
151
- rspec-mocks (~> 3.11.0)
152
- rspec-core (3.11.0)
153
- rspec-support (~> 3.11.0)
154
- rspec-expectations (3.11.1)
155
- diff-lcs (>= 1.2.0, < 2.0)
156
- rspec-support (~> 3.11.0)
157
- rspec-mocks (3.11.1)
158
- diff-lcs (>= 1.2.0, < 2.0)
159
- rspec-support (~> 3.11.0)
160
- rspec-support (3.11.1)
161
148
  rubocop (1.36.0)
162
149
  json (~> 2.3)
163
150
  parallel (~> 1.10)
@@ -239,7 +226,6 @@ DEPENDENCIES
239
226
  punchlist
240
227
  rake (~> 13.0)
241
228
  rbs (> 3.0.3)
242
- rspec (>= 3.4)
243
229
  rubocop (~> 1.36, < 1.44)
244
230
  rubocop-minitest
245
231
  rubocop-rake
data/checkoff.gemspec CHANGED
@@ -46,7 +46,6 @@ Gem::Specification.new do |spec|
46
46
  spec.add_development_dependency 'rake', '~> 13.0'
47
47
  # ensure recent definitions
48
48
  spec.add_development_dependency 'rbs', ['>3.0.3']
49
- spec.add_development_dependency 'rspec', '>=3.4'
50
49
  # I haven't adapted things to Gemspec/DevelopmentDependencies yet,
51
50
  # which arrives in 1.44
52
51
  spec.add_development_dependency 'rubocop', ['~> 1.36', '<1.44']
@@ -2,6 +2,8 @@
2
2
 
3
3
  # frozen_string_literal: true
4
4
 
5
+ require 'cgi'
6
+ require 'uri'
5
7
  require_relative 'simple_param_converter'
6
8
  require_relative 'custom_field_param_converter'
7
9
 
@@ -17,7 +19,9 @@ module Checkoff
17
19
 
18
20
  def convert_params(url)
19
21
  url_params = CGI.parse(URI.parse(url).query)
22
+ # @sg-ignore
20
23
  custom_field_params, simple_url_params = partition_url_params(url_params)
24
+ # @sg-ignore
21
25
  custom_field_args, task_selector = convert_custom_field_params(custom_field_params)
22
26
  simple_url_args = convert_simple_params(simple_url_params)
23
27
  [custom_field_args.merge(simple_url_args), task_selector]
@@ -33,6 +37,8 @@ module Checkoff
33
37
  CustomFieldParamConverter.new(custom_field_params: custom_field_params).convert
34
38
  end
35
39
 
40
+ # @param url_params [Hash<String, String>]
41
+ # @return [Array(Hash<String, String>, Hash<String, String>)]
36
42
  def partition_url_params(url_params)
37
43
  url_params.to_a.partition do |key, _values|
38
44
  key.start_with? 'custom_field_'
@@ -11,6 +11,8 @@ module Checkoff
11
11
  module SimpleParam
12
12
  # base class for handling different types of search url params
13
13
  class SimpleParam
14
+ # @param key [String] the name of the search url param
15
+ # @param values [Array<String>] the values of the search url param
14
16
  def initialize(key:, values:)
15
17
  @key = key
16
18
  @values = values
@@ -18,10 +20,13 @@ module Checkoff
18
20
 
19
21
  private
20
22
 
23
+ # @sg-ignore
24
+ # @return [String] the single value of the search url param
21
25
  def single_value
22
26
  @single_value ||= begin
23
27
  raise "Teach me how to handle #{key} = #{values}" if values.length != 1
24
28
 
29
+ # @type [String]
25
30
  values.fetch(0)
26
31
  end
27
32
  end
@@ -34,6 +39,7 @@ module Checkoff
34
39
  # 123~456 means "abc" and "def" projects
35
40
  def parse_projects_and_sections(projects, sections)
36
41
  single_value.split('~').each do |project_section_pair|
42
+ # @sg-ignore
37
43
  project, section = project_section_pair.split('_column_')
38
44
  if section.nil?
39
45
  projects << project
@@ -106,15 +112,32 @@ module Checkoff
106
112
  ['tags.any', tag_ids.join(',')]
107
113
  end
108
114
  end
115
+
116
+ # Handle 'sort' search url param
117
+ class Sort < SimpleParam
118
+ def convert
119
+ # https://developers.asana.com/reference/searchtasksforworkspace
120
+ conversion = {
121
+ 'last_modified' => 'modified_at',
122
+ 'due_date' => 'due_date',
123
+ 'creation_time' => 'created_at',
124
+ 'completion_time' => 'completed_at',
125
+ 'likes' => 'likes',
126
+ }
127
+ ['sort_by', conversion.fetch(single_value)]
128
+ end
129
+ end
109
130
  end
110
131
 
111
132
  # Convert simple parameters - ones where the param name itself
112
133
  # doesn't encode any parameters'
113
134
  class SimpleParamConverter
135
+ # @param simple_url_params [Hash<String, Array<String>>] the simple params
114
136
  def initialize(simple_url_params:)
115
137
  @simple_url_params = simple_url_params
116
138
  end
117
139
 
140
+ # @return [Hash<String, String>] the converted params
118
141
  def convert
119
142
  simple_url_params.to_a.flat_map do |key, values|
120
143
  convert_arg(key, values).each_slice(2).to_a
@@ -123,6 +146,7 @@ module Checkoff
123
146
 
124
147
  private
125
148
 
149
+ # @type [Hash<String, Class<SimpleParam::SimpleParam>>] the mapping from param name to class
126
150
  ARGS = {
127
151
  'any_projects.ids' => SimpleParam::AnyProjectsIds,
128
152
  'not_projects.ids' => SimpleParam::NotProjectsIds,
@@ -130,12 +154,21 @@ module Checkoff
130
154
  'not_tags.ids' => SimpleParam::NotTagsIds,
131
155
  'any_tags.ids' => SimpleParam::AnyTagsIds,
132
156
  'subtask' => SimpleParam::Subtask,
157
+ 'sort' => SimpleParam::Sort,
133
158
  }.freeze
134
159
 
135
160
  # https://developers.asana.com/docs/search-tasks-in-a-workspace
161
+ # @sg-ignore
162
+ # @param key [String] the name of the search url param
163
+ # @param values [Array<String>] the values of the search url param
164
+ # @return [Hash<String, String>] the converted params
136
165
  def convert_arg(key, values)
166
+ # @type [Class<SimpleParam::SimpleParam>]
137
167
  clazz = ARGS.fetch(key)
138
- clazz.new(key: key, values: values).convert
168
+ # @type [SimpleParam::SimpleParam]
169
+ obj = clazz.new(key: key, values: values)
170
+ # @sg-ignore
171
+ obj.convert
139
172
  end
140
173
 
141
174
  attr_reader :simple_url_params
@@ -17,12 +17,19 @@ module Checkoff
17
17
  # Work with projects in Asana
18
18
  class Projects
19
19
  MINUTE = 60
20
+ # @sg-ignore
20
21
  HOUR = MINUTE * 60
21
22
  DAY = 24 * HOUR
23
+ # @sg-ignore
22
24
  REALLY_LONG_CACHE_TIME = HOUR * 1
25
+ # @sg-ignore
23
26
  LONG_CACHE_TIME = MINUTE * 15
24
27
  SHORT_CACHE_TIME = MINUTE
25
28
 
29
+ # @!parse
30
+ # extend CacheMethod::ClassMethods
31
+
32
+ # @param client [Asana::Client]
26
33
  def initialize(config: Checkoff::Internal::ConfigLoader.load(:asana),
27
34
  client: Checkoff::Clients.new(config: config).client,
28
35
  workspaces: Checkoff::Workspaces.new(config: config,
@@ -33,7 +40,7 @@ module Checkoff
33
40
  end
34
41
 
35
42
  # Default options used in Asana API to pull taskso
36
- # @return [Hash]
43
+ # @return [Hash<Symbol, Object>]
37
44
  def task_options
38
45
  {
39
46
  per_page: 100,
@@ -45,6 +52,9 @@ module Checkoff
45
52
  end
46
53
 
47
54
  # pulls an Asana API project class given a name
55
+ # @param [String] workspace_name
56
+ # @param [String] project_name
57
+ # @return [Asana::Resources::Project, nil]
48
58
  def project(workspace_name, project_name)
49
59
  if project_name.is_a?(Symbol) && project_name.to_s.start_with?('my_tasks')
50
60
  my_tasks(workspace_name)
@@ -57,21 +67,30 @@ module Checkoff
57
67
  end
58
68
  cache_method :project, LONG_CACHE_TIME
59
69
 
60
- # @return [Asana::Project]
70
+ # @param workspace_name [String]
71
+ # @param project_name [String]
72
+ # @return [Asana::Resources::Project]
61
73
  def project_or_raise(workspace_name, project_name)
62
- project = project(workspace_name, project_name)
63
- raise "Could not find project #{project_name} under workspace #{workspace_name}." if project.nil?
74
+ p = project(workspace_name, project_name)
75
+ raise "Could not find project #{project_name} under workspace #{workspace_name}." if p.nil?
64
76
 
65
- project
77
+ p
66
78
  end
67
79
  cache_method :project_or_raise, LONG_CACHE_TIME
68
80
 
69
81
  # find uncompleted tasks in a list
82
+ # @param [Array<Asana::Resources::Task>] tasks
83
+ # @return [Array<Asana::Resources::Task>]
70
84
  def active_tasks(tasks)
71
85
  tasks.select { |task| task.completed_at.nil? }
72
86
  end
73
87
 
74
88
  # pull task objects from a named project
89
+ # @sg-ignore
90
+ # @param [Asana::Resources::Project] project
91
+ # @param [Boolean] only_uncompleted
92
+ # @param [Array<String>] extra_fields
93
+ # @return [Array<Asana::Resources::Task>]
75
94
  def tasks_from_project(project, only_uncompleted: true, extra_fields: [])
76
95
  options = task_options
77
96
  options[:completed_since] = '9999-12-01' if only_uncompleted
@@ -85,11 +104,15 @@ module Checkoff
85
104
 
86
105
  attr_reader :client
87
106
 
107
+ # @sg-ignore
88
108
  def projects
89
109
  client.projects
90
110
  end
91
111
  cache_method :projects, LONG_CACHE_TIME
92
112
 
113
+ # @sg-ignore
114
+ # @param [String] workspace_name
115
+ # @return [Array<Asana::Resources::Project>]
93
116
  def projects_by_workspace_name(workspace_name)
94
117
  workspace = @workspaces.workspace_or_raise(workspace_name)
95
118
  raise "Could not find workspace named #{workspace_name}" unless workspace
@@ -97,8 +120,13 @@ module Checkoff
97
120
  projects.find_by_workspace(workspace: workspace.gid)
98
121
  end
99
122
 
123
+ # @sg-ignore
124
+ # @param [String] workspace_name
125
+ # @return [Asana::Resources::Project]
100
126
  def my_tasks(workspace_name)
101
127
  workspace = @workspaces.workspace_or_raise(workspace_name)
128
+ # @sg-ignore
129
+ # @type [Asana::Resources::UserTaskList]
102
130
  result = client.user_task_lists.get_user_task_list_for_user(user_gid: 'me',
103
131
  workspace: workspace.gid)
104
132
  gid = result.gid
@@ -19,9 +19,12 @@ module Checkoff
19
19
  # Run task searches against the Asana API
20
20
  class TaskSearches
21
21
  MINUTE = 60
22
+ # @sg-ignore
22
23
  HOUR = MINUTE * 60
23
24
  DAY = 24 * HOUR
25
+ # @sg-ignore
24
26
  REALLY_LONG_CACHE_TIME = HOUR * 1
27
+ # @sg-ignore
25
28
  LONG_CACHE_TIME = MINUTE * 15
26
29
  SHORT_CACHE_TIME = MINUTE
27
30
 
@@ -59,11 +62,15 @@ module Checkoff
59
62
  client: client)
60
63
  tasks.select { |task| task_selectors.filter_via_task_selector(task, task_selector) }
61
64
  end
65
+ # @sg-ignore
62
66
  cache_method :task_search, LONG_CACHE_TIME
63
67
 
64
68
  private
65
69
 
70
+ # @param [Array<String>] extra_fields
71
+ # @return [Hash<Symbol, Object>]
66
72
  def calculate_api_options(extra_fields)
73
+ # @type [Hash<Symbol, Object>]
67
74
  options = projects.task_options[:options]
68
75
  options[:fields] += ['custom_fields']
69
76
  options[:fields] += extra_fields
@@ -74,7 +81,11 @@ module Checkoff
74
81
  # :nocov:
75
82
  class << self
76
83
  def run
84
+ # @sg-ignore
85
+ # @type [String]
77
86
  workspace_name = ARGV[0] || raise('Please pass workspace name as first argument')
87
+ # @sg-ignore
88
+ # @type [String]
78
89
  url = ARGV[1] || raise('Please pass task search URL as second argument')
79
90
  task_searches = Checkoff::TaskSearches.new
80
91
  task_search = task_searches.task_search(workspace_name, url)
@@ -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.36.1'
6
+ VERSION = '0.37.0'
7
7
  end
@@ -36,6 +36,8 @@ module Checkoff
36
36
  @asana_workspace.find_by_id(client, default_workspace_gid)
37
37
  end
38
38
 
39
+ # @param [String] workspace_name
40
+ # @return [Asana::Resources::Workspace]
39
41
  def workspace_or_raise(workspace_name)
40
42
  workspace = workspace(workspace_name)
41
43
  raise "Could not find workspace #{workspace_name}" if workspace.nil?
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.36.1
4
+ version: 0.37.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-05-20 00:00:00.000000000 Z
11
+ date: 2023-05-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -254,20 +254,6 @@ dependencies:
254
254
  - - ">"
255
255
  - !ruby/object:Gem::Version
256
256
  version: 3.0.3
257
- - !ruby/object:Gem::Dependency
258
- name: rspec
259
- requirement: !ruby/object:Gem::Requirement
260
- requirements:
261
- - - ">="
262
- - !ruby/object:Gem::Version
263
- version: '3.4'
264
- type: :development
265
- prerelease: false
266
- version_requirements: !ruby/object:Gem::Requirement
267
- requirements:
268
- - - ">="
269
- - !ruby/object:Gem::Version
270
- version: '3.4'
271
257
  - !ruby/object:Gem::Dependency
272
258
  name: rubocop
273
259
  requirement: !ruby/object:Gem::Requirement