checkoff 0.45.1 → 0.46.0

Sign up to get free protection for your applications and to get access to all the features.
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