checkoff 0.45.1 → 0.46.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: 166520f53086eea60a30deae24eacea2bff98b58cc63e1bc14397e016cfce5a3
4
- data.tar.gz: 182f61588c6343c7b16100a56357909b5d1c532a2580040fdb50828dedeb4032
3
+ metadata.gz: a65e8d9c8d8e3012cbe1821983bc48e5151f6c666a454ce627c0084edaac8b46
4
+ data.tar.gz: 35f49e9a77c9409278b3f68a6c84f6afefc68727510b13ac322a1988360163af
5
5
  SHA512:
6
- metadata.gz: 00461660f5b2f2927d5c0bd89b34e12a1393ce105dcddf6782054ef655c3ba55654c0d5a818e35907dd46d457beac3a18b637bb2a5379ae78d30913fdd55944d
7
- data.tar.gz: 8aa6bdc999894732e1e243cac1617b6b40b905b80562c5d8d57bbf2a988b4f1b66fc7848dbe4937dc01228c503a4e26661bc17a28c75c6effed5b10d9afd10db
6
+ metadata.gz: 70162bcc35ac9bb35d3006e7334a0abd36c5b9853b148e3f9ae720761691bb00af8de7f065969f144c01cc5563f78c6a53e90c92f7811ab5bf269eabb30986bc
7
+ data.tar.gz: 3b49077f074571a0b09c7a167601ed7bc99f59707505ef10deb187215dcc059cbd1ea04cff64669ae5e7bbf2007a5d0054aeb62658129ff15e93f3a5baf87534
data/Gemfile.lock CHANGED
@@ -12,7 +12,7 @@ GIT
12
12
  PATH
13
13
  remote: .
14
14
  specs:
15
- checkoff (0.45.1)
15
+ checkoff (0.46.0)
16
16
  activesupport
17
17
  asana (> 0.10.0)
18
18
  cache_method
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'custom_field_variant'
4
+ require_relative 'results_merger'
4
5
 
5
6
  module Checkoff
6
7
  module Internal
@@ -8,44 +9,41 @@ module Checkoff
8
9
  # Convert custom field parameters from an Asana search URL into
9
10
  # API search arguments and Checkoff task selectors
10
11
  class CustomFieldParamConverter
12
+ # @param custom_field_params [Hash<String, Array<String>>]
11
13
  def initialize(custom_field_params:)
12
14
  @custom_field_params = custom_field_params
13
15
  end
14
16
 
17
+ # @return [Array(Hash<String, String>, Array<[Symbol, Array]>)]
15
18
  def convert
19
+ # @type args [Hash<String, String>]
16
20
  args = {}
21
+ # @type task_selector [Array<[Symbol, Array]>]
17
22
  task_selector = []
18
23
  by_custom_field.each do |gid, single_custom_field_params|
24
+ # @sg-ignore
19
25
  new_args, new_task_selector = convert_single_custom_field_params(gid,
20
26
  single_custom_field_params)
21
- args, task_selector = merge_args_and_task_selectors(args, new_args,
22
- task_selector, new_task_selector)
27
+
28
+ args = ResultsMerger.merge_args(args, new_args)
29
+
30
+ # @sg-ignore
31
+ task_selector = ResultsMerger.merge_task_selectors(task_selector, new_task_selector)
23
32
  end
24
33
  [args, task_selector]
25
34
  end
26
35
 
27
36
  private
28
37
 
38
+ # @sg-ignore
39
+ # @return [Hash<String, Hash>]
29
40
  def by_custom_field
30
41
  custom_field_params.group_by do |key, _value|
31
42
  gid_from_custom_field_key(key)
32
43
  end.transform_values(&:to_h)
33
44
  end
34
45
 
35
- def merge_args_and_task_selectors(args, new_args, task_selector, new_task_selector)
36
- final_args = args.merge(new_args)
37
-
38
- final_task_selector = if new_task_selector == []
39
- task_selector
40
- elsif task_selector == []
41
- new_task_selector
42
- else
43
- [:and, task_selector, new_task_selector]
44
- end
45
-
46
- [final_args, final_task_selector]
47
- end
48
-
46
+ # @type [Hash<String, Class<CustomFieldVariant>]
49
47
  VARIANTS = {
50
48
  'is' => CustomFieldVariant::Is,
51
49
  'no_value' => CustomFieldVariant::NoValue,
@@ -58,22 +56,33 @@ module Checkoff
58
56
  'contains_all' => CustomFieldVariant::ContainsAll,
59
57
  }.freeze
60
58
 
59
+ # @param gid [String]
60
+ # @param single_custom_field_params [Hash<String, Array<String>>]
61
+ # @sg-ignore
62
+ # @return [Array(Hash<String, String>, Array<[Symbol, Array]>)]
61
63
  def convert_single_custom_field_params(gid, single_custom_field_params)
62
64
  variant_key = "custom_field_#{gid}.variant"
63
65
  variant = single_custom_field_params.fetch(variant_key)
64
66
  remaining_params = single_custom_field_params.reject { |k, _v| k == variant_key }
65
67
  raise "Teach me how to handle #{variant_key} = #{variant}" unless variant.length == 1
66
68
 
69
+ # @sg-ignore
70
+ # @type variant_class [Class<CustomFieldVariant>]
67
71
  variant_class = VARIANTS[variant[0]]
72
+ # @type [Array(Hash<String, String>, Array<[Symbol, Array]>)]
73
+ # @sg-ignore
68
74
  return variant_class.new(gid, remaining_params).convert unless variant_class.nil?
69
75
 
70
76
  raise "Teach me how to handle #{variant_key} = #{variant}"
71
77
  end
72
78
 
79
+ # @param key [String]
80
+ # @return [String]
73
81
  def gid_from_custom_field_key(key)
74
82
  key.split('_')[2].split('.')[0]
75
83
  end
76
84
 
85
+ # @return [Hash<String, Array<String>>]
77
86
  attr_reader :custom_field_params
78
87
  end
79
88
  end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'custom_field_param_converter'
4
+
5
+ module Checkoff
6
+ module Internal
7
+ module SearchUrl
8
+ # Convert date parameters - ones where the param name itself
9
+ # doesn't encode any parameters'
10
+ class DateParamConverter
11
+ # @param date_url_params [Hash<String, Array<String>>] the simple params
12
+ def initialize(date_url_params:)
13
+ @date_url_params = date_url_params
14
+ end
15
+
16
+ # @return [Array(Hash<String, String>, Array<[Symbol, Array]>)] See https://developers.asana.com/docs/search-tasks-in-a-workspace
17
+ def convert
18
+ return [{}, []] if date_url_params.empty?
19
+
20
+ # example params:
21
+ # due_date.operator=through_next
22
+ # due_date.value=0
23
+ # due_date.unit=day
24
+ validate_due_date_through_next!
25
+
26
+ value = date_url_params.fetch('due_date.value').fetch(0).to_i
27
+
28
+ # @sg-ignore
29
+ # @type [Date]
30
+ before = Date.today + value
31
+
32
+ validate_unit_is_day!
33
+
34
+ # 'due_on.before' => '2023-01-01',
35
+ # 'due_on.after' => '2023-01-01',
36
+ # [{ 'due_on.before' => '2023-09-01' }, []]
37
+ [{ 'due_on.before' => before.to_s }, []]
38
+ end
39
+
40
+ private
41
+
42
+ # @return [void]
43
+ def validate_unit_is_day!
44
+ unit = date_url_params.fetch('due_date.unit').fetch(0)
45
+
46
+ raise 'Teach me how to handle other time units' unless unit == 'day'
47
+ end
48
+
49
+ # @return [void]
50
+ def validate_due_date_through_next!
51
+ return if date_url_params.fetch('due_date.operator') == ['through_next']
52
+
53
+ raise 'Teach me how to handle other date modes'
54
+ end
55
+
56
+ # @return [Hash<String, Array<String>>]
57
+ attr_reader :date_url_params
58
+ end
59
+ end
60
+ end
61
+ end
@@ -6,6 +6,8 @@ require 'cgi'
6
6
  require 'uri'
7
7
  require_relative 'simple_param_converter'
8
8
  require_relative 'custom_field_param_converter'
9
+ require_relative 'results_merger'
10
+ require_relative 'date_param_converter'
9
11
 
10
12
  module Checkoff
11
13
  module Internal
@@ -13,36 +15,68 @@ module Checkoff
13
15
  # Parse Asana search URLs into parameters suitable to pass into
14
16
  # the /workspaces/{workspace_gid}/tasks/search endpoint
15
17
  class Parser
18
+ # @param _deps [Hash]
16
19
  def initialize(_deps = {})
17
20
  # allow dependencies to be passed in by tests
18
21
  end
19
22
 
23
+ # @param url [String]
24
+ # @return [Array(Hash<String, String>, Hash<String, String>)]
20
25
  def convert_params(url)
21
26
  url_params = CGI.parse(URI.parse(url).query)
27
+ # @type custom_field_params [Hash<String, Array<String>>]
28
+ # @type date_url_params [Hash<String, Array<String>>]
29
+ # @type simple_url_params [Hash<String, Array<String>>]
30
+ # @sg-ignore
31
+ custom_field_params, date_url_params, simple_url_params = partition_url_params(url_params)
32
+ # @type custom_field_args [Hash<String, String>]
33
+ # @type custom_field_task_selector [Hash<String, String>]
22
34
  # @sg-ignore
23
- custom_field_params, simple_url_params = partition_url_params(url_params)
35
+ custom_field_args, custom_field_task_selector = convert_custom_field_params(custom_field_params)
36
+ # @type date_args [Hash<String, String>]
37
+ # @type date_task_selector [Hash<String, String>]
24
38
  # @sg-ignore
25
- custom_field_args, task_selector = convert_custom_field_params(custom_field_params)
39
+ date_url_args, date_task_selector = convert_date_params(date_url_params)
26
40
  simple_url_args = convert_simple_params(simple_url_params)
27
- [custom_field_args.merge(simple_url_args), task_selector]
41
+ # raise 'merge these things'
42
+ [ResultsMerger.merge_args(custom_field_args, date_url_args, simple_url_args),
43
+ ResultsMerger.merge_task_selectors(date_task_selector, custom_field_task_selector)]
28
44
  end
29
45
 
30
46
  private
31
47
 
48
+ # @param date_url_params [Hash<String, Array<String>>]
49
+ # @return [Array(Hash<String, String>, Array<[Symbol, Array]>)]
50
+ def convert_date_params(date_url_params)
51
+ DateParamConverter.new(date_url_params: date_url_params).convert
52
+ end
53
+
54
+ # @param simple_url_params [Hash<String, Array<String>>]
55
+ # @return [Hash<String, String>]
32
56
  def convert_simple_params(simple_url_params)
33
57
  SimpleParamConverter.new(simple_url_params: simple_url_params).convert
34
58
  end
35
59
 
60
+ # @param custom_field_params [Hash<String, Array<String>>]
61
+ # @return [Array(Hash<String, String>, Array<[Symbol, Array]>)]
36
62
  def convert_custom_field_params(custom_field_params)
37
63
  CustomFieldParamConverter.new(custom_field_params: custom_field_params).convert
38
64
  end
39
65
 
40
66
  # @param url_params [Hash<String, String>]
41
- # @return [Array(Hash<String, String>, Hash<String, String>)]
67
+ # @return [Array(Hash<String, String>, Hash<String, String>, Hash<String, String>)]
42
68
  def partition_url_params(url_params)
43
- url_params.to_a.partition do |key, _values|
44
- key.start_with? 'custom_field_'
45
- end.map(&:to_h)
69
+ groups = url_params.to_a.group_by do |key, _values|
70
+ if key.start_with? 'custom_field_'
71
+ :custom_field
72
+ elsif key.include? '_date'
73
+ :date
74
+ else
75
+ :simple
76
+ end
77
+ end.transform_values(&:to_h)
78
+ # @sg-ignore
79
+ [groups.fetch(:custom_field, {}), groups.fetch(:date, {}), groups.fetch(:simple, {})]
46
80
  end
47
81
  end
48
82
  end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Checkoff
4
+ module Internal
5
+ module SearchUrl
6
+ # Merge task selectors and search API arguments
7
+ class ResultsMerger
8
+ # @param args [Array<[Hash<String, String>]>]
9
+ # @return [Hash<String, String>
10
+ def self.merge_args(*args)
11
+ # first element of args
12
+ # @sg-ignore
13
+ # @type [Hash<String, String>]
14
+ f = args.fetch(0)
15
+ # rest of args
16
+ r = args.drop(0)
17
+ f.merge(*r)
18
+ end
19
+
20
+ # @param task_selectors [Array<Array<[Symbol, Array]>>]
21
+ # @return [Array<[Symbol, Array]>]
22
+ def self.merge_task_selectors(*task_selectors)
23
+ return [] if task_selectors.empty?
24
+
25
+ first_task_selector = task_selectors.fetch(0)
26
+
27
+ return merge_task_selectors(*task_selectors.drop(1)) if first_task_selector.empty?
28
+
29
+ return first_task_selector if task_selectors.length == 1
30
+
31
+ rest_task_selectors = merge_task_selectors(*task_selectors.drop(1))
32
+
33
+ return first_task_selector if rest_task_selectors.empty?
34
+
35
+ [:and, first_task_selector, rest_task_selectors]
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -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.45.1'
6
+ VERSION = '0.46.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.45.1
4
+ version: 0.46.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-08-29 00:00:00.000000000 Z
11
+ date: 2023-09-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -135,7 +135,9 @@ files:
135
135
  - lib/checkoff/internal/search_url.rb
136
136
  - lib/checkoff/internal/search_url/custom_field_param_converter.rb
137
137
  - lib/checkoff/internal/search_url/custom_field_variant.rb
138
+ - lib/checkoff/internal/search_url/date_param_converter.rb
138
139
  - lib/checkoff/internal/search_url/parser.rb
140
+ - lib/checkoff/internal/search_url/results_merger.rb
139
141
  - lib/checkoff/internal/search_url/simple_param_converter.rb
140
142
  - lib/checkoff/internal/task_selector_evaluator.rb
141
143
  - lib/checkoff/my_tasks.rb