checkoff 0.65.0 → 0.67.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: 4505355c1c82cd6052ef5fd0996ecf25a415df8846ce7e21f4d80f5a9b1c788f
4
- data.tar.gz: 2837a88035c53d49ef8ee4bef2cbd2b1c2007f1b2d5441d4640a8680785ef438
3
+ metadata.gz: 651d344e64e8f9b999d1c8d1f235c6657428e11164844e85ea3f53f31dca581b
4
+ data.tar.gz: bd94b2f08680af330190beb09c6659787e500d7d561a15a80a363a8c4675d158
5
5
  SHA512:
6
- metadata.gz: 999cc4babf24a98ab16cbed5349e536e4e7d9a9b08b16c50a73df63dac135dde8740e799c2ea7630d0682685775a9eff984830a0bfcca884900ee604a62f443b
7
- data.tar.gz: df41ae1e0e59e3efa637c06114a9b4370c2e093c932ff022be61f773af3a617c6eecc65ec5f147987bb229701aeea88fcf60163923309e92a19ba0b8b4e3db3e
6
+ metadata.gz: '086458eef1a121b9cf27c79d78d18a65289cb7658d37126647a363d784ecaec3251ca05aba3b4f22512a07a35ee012d7fdf58b585950845be0742560e3d0dd50'
7
+ data.tar.gz: 05e1b5637f49ffd9c0dea9110705a43e79f875cedc699df023e1cc1d68480a7b9b68eb974faf201bc4e0c9efce1ba5333adbeca8bcf84ff0f7c076d57fb07753
data/Gemfile.lock CHANGED
@@ -12,7 +12,7 @@ GIT
12
12
  PATH
13
13
  remote: .
14
14
  specs:
15
- checkoff (0.65.0)
15
+ checkoff (0.67.0)
16
16
  activesupport
17
17
  asana (> 0.10.0)
18
18
  cache_method
@@ -51,6 +51,7 @@ module Checkoff
51
51
  'is_not' => CustomFieldVariant::IsNot,
52
52
  'less_than' => CustomFieldVariant::LessThan,
53
53
  'greater_than' => CustomFieldVariant::GreaterThan,
54
+ 'equals' => CustomFieldVariant::Equals,
54
55
  'doesnt_contain_any' => CustomFieldVariant::DoesntContainAny,
55
56
  'contains_any' => CustomFieldVariant::ContainsAny,
56
57
  'contains_all' => CustomFieldVariant::ContainsAll,
@@ -7,6 +7,8 @@ module Checkoff
7
7
  module CustomFieldVariant
8
8
  # base class for handling different custom_field_#{gid}.variant params
9
9
  class CustomFieldVariant
10
+ # @param [String] gid
11
+ # @param [Hash] remaining_params
10
12
  def initialize(gid, remaining_params)
11
13
  @gid = gid
12
14
  @remaining_params = remaining_params
@@ -14,17 +16,27 @@ module Checkoff
14
16
 
15
17
  private
16
18
 
17
- attr_reader :gid, :remaining_params
19
+ # @return [String]
20
+ attr_reader :gid
18
21
 
22
+ # @return [Hash]
23
+ attr_reader :remaining_params
24
+
25
+ # @return [void]
19
26
  def ensure_no_remaining_params!
20
27
  return if remaining_params.empty?
21
28
 
22
29
  raise "Teach me how to handle these remaining keys: #{remaining_params}"
23
30
  end
24
31
 
32
+ # @param [String] param_name
33
+ #
34
+ # @return [String]
25
35
  def fetch_solo_param(param_name)
26
36
  case remaining_params.keys
27
37
  when [param_name]
38
+ # @sg-ignore
39
+ # @type [Array<String>]
28
40
  param_values = remaining_params.fetch(param_name)
29
41
  unless param_values.length == 1
30
42
  raise "Teach me how to handle these remaining keys for #{param_name}: #{remaining_params}"
@@ -39,6 +51,7 @@ module Checkoff
39
51
 
40
52
  # custom_field_#{gid}.variant = 'less_than'
41
53
  class LessThan < CustomFieldVariant
54
+ # @return [Array<(Hash, Array)>]
42
55
  def convert
43
56
  max_value = fetch_solo_param("custom_field_#{gid}.max")
44
57
  empty_task_selector = []
@@ -48,6 +61,7 @@ module Checkoff
48
61
 
49
62
  # custom_field_#{gid}.variant = 'greater_than'
50
63
  class GreaterThan < CustomFieldVariant
64
+ # @return [Array<(Hash, Array)>]
51
65
  def convert
52
66
  max_value = fetch_solo_param("custom_field_#{gid}.min")
53
67
  empty_task_selector = []
@@ -55,10 +69,21 @@ module Checkoff
55
69
  end
56
70
  end
57
71
 
72
+ # custom_field_#{gid}.variant = 'equals'
73
+ class Equals < CustomFieldVariant
74
+ # @return [Array<(Hash, Array)>]
75
+ def convert
76
+ value = fetch_solo_param("custom_field_#{gid}.value")
77
+ empty_task_selector = []
78
+ [{ "custom_fields.#{gid}.value" => value }, empty_task_selector]
79
+ end
80
+ end
81
+
58
82
  # This is used in the UI for select fields
59
83
  #
60
84
  # custom_field_#{gid}.variant = 'is_not'
61
85
  class IsNot < CustomFieldVariant
86
+ # @return [Array<(Hash, Array)>]
62
87
  def convert
63
88
  selected_options = fetch_solo_param("custom_field_#{gid}.selected_options").split('~')
64
89
 
@@ -75,6 +100,7 @@ module Checkoff
75
100
  #
76
101
  # custom_field_#{gid}.variant = 'doesnt_contain_any'
77
102
  class DoesntContainAny < CustomFieldVariant
103
+ # @return [Array<(Hash, Array)>]
78
104
  def convert
79
105
  selected_options = fetch_solo_param("custom_field_#{gid}.selected_options").split('~')
80
106
 
@@ -90,6 +116,7 @@ module Checkoff
90
116
  #
91
117
  # custom_field_#{gid}.variant = 'contains_any'
92
118
  class ContainsAny < CustomFieldVariant
119
+ # @return [Array<(Hash, Array)>]
93
120
  def convert
94
121
  selected_options = fetch_solo_param("custom_field_#{gid}.selected_options").split('~')
95
122
 
@@ -104,6 +131,7 @@ module Checkoff
104
131
  #
105
132
  # custom_field_#{gid}.variant = 'contains_all'
106
133
  class ContainsAll < CustomFieldVariant
134
+ # @return [Array<(Hash, Array)>]
107
135
  def convert
108
136
  selected_options = fetch_solo_param("custom_field_#{gid}.selected_options").split('~')
109
137
 
@@ -116,6 +144,7 @@ module Checkoff
116
144
 
117
145
  # custom_field_#{gid}.variant = 'no_value'
118
146
  class NoValue < CustomFieldVariant
147
+ # @return [Array<(Hash, Array)>]
119
148
  def convert
120
149
  ensure_no_remaining_params!
121
150
 
@@ -135,6 +164,7 @@ module Checkoff
135
164
  #
136
165
  # Not used for multi-select fields
137
166
  class AnyValue < CustomFieldVariant
167
+ # @return [Array<(Hash, Array)>]
138
168
  def convert
139
169
  ensure_no_remaining_params!
140
170
 
@@ -146,6 +176,7 @@ module Checkoff
146
176
 
147
177
  # custom_field_#{gid}.variant = 'is'
148
178
  class Is < CustomFieldVariant
179
+ # @return [Array<(Hash, Array)>]
149
180
  def convert
150
181
  selected_options = fetch_solo_param("custom_field_#{gid}.selected_options").split('~')
151
182
 
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'selector_classes/common'
4
+ require_relative 'selector_classes/section'
5
+ require_relative 'selector_evaluator'
6
+
7
+ module Checkoff
8
+ # Evaluates section selectors against a section
9
+ class SectionSelectorEvaluator < SelectorEvaluator
10
+ # @param section [Asana::Resources::Project]
11
+ # @param client [Asana::Client]
12
+ # @param projects [Checkoff::Projects]
13
+ # @param sections [Checkoff::Sections]
14
+ def initialize(section:,
15
+ client:,
16
+ projects: Checkoff::Projects.new(client: client),
17
+ sections: Checkoff::Sections.new)
18
+ @item = section
19
+ @client = client
20
+ @projects = projects
21
+ @sections = sections
22
+ super()
23
+ end
24
+
25
+ private
26
+
27
+ COMMON_FUNCTION_EVALUATORS = (Checkoff::SelectorClasses::Common.constants.map do |const|
28
+ Checkoff::SelectorClasses::Common.const_get(const)
29
+ end - [Checkoff::SelectorClasses::Common::FunctionEvaluator]).freeze
30
+
31
+ SECTION_FUNCTION_EVALUATORS = (Checkoff::SelectorClasses::Section.constants.map do |const|
32
+ Checkoff::SelectorClasses::Section.const_get(const)
33
+ end - [Checkoff::SelectorClasses::Section::FunctionEvaluator]).freeze
34
+
35
+ FUNCTION_EVALUTORS = (COMMON_FUNCTION_EVALUATORS + SECTION_FUNCTION_EVALUATORS).freeze
36
+
37
+ # @return [Array<Class<ProjectSelectorClasses::FunctionEvaluator>>]
38
+ def function_evaluators
39
+ FUNCTION_EVALUTORS
40
+ end
41
+
42
+ # @return [Hash]
43
+ def initializer_kwargs
44
+ { sections: sections, projects: projects, client: client }
45
+ end
46
+
47
+ # @return [Asana::Resources::Project]
48
+ attr_reader :item
49
+ # @return [Checkoff::Sections]
50
+ attr_reader :sections
51
+ # @return [Checkoff::Projects]
52
+ attr_reader :projects
53
+ # @return [Asana::Client]
54
+ attr_reader :client
55
+ end
56
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../function_evaluator'
4
+
5
+ module Checkoff
6
+ module SelectorClasses
7
+ module Section
8
+ # Base class to evaluate a project selector function given fully evaluated arguments
9
+ class FunctionEvaluator < ::Checkoff::SelectorClasses::FunctionEvaluator
10
+ # @param selector [Array<(Symbol, Array)>,String]
11
+ # @param client [Asana::Client]
12
+ # @param sections [Checkoff::Sections]
13
+ def initialize(selector:,
14
+ sections:,
15
+ client:,
16
+ **)
17
+ @selector = selector
18
+ @sections = sections
19
+ @client = client
20
+ super()
21
+ end
22
+
23
+ private
24
+
25
+ # @return [Array<(Symbol, Array)>]
26
+ attr_reader :selector
27
+
28
+ # @return [Asana::Client]
29
+ attr_reader :client
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'section/function_evaluator'
4
+
5
+ module Checkoff
6
+ module SelectorClasses
7
+ # Section selector classes
8
+ module Section
9
+ # :ends_with_milestone function
10
+ class DueDateFunctionEvaluator < FunctionEvaluator
11
+ FUNCTION_NAME = :ends_with_milestone
12
+
13
+ def matches?
14
+ fn?(selector, FUNCTION_NAME)
15
+ end
16
+
17
+ # @param section [Asana::Resources::Section]
18
+ #
19
+ # @sg-ignore
20
+ # @return [Boolean]
21
+ def evaluate(section)
22
+ tasks = client.tasks.get_tasks(section: section.gid,
23
+ per_page: 100,
24
+ options: { fields: ['resource_subtype'] })
25
+ # @sg-ignore
26
+ tasks.last&.resource_subtype == 'milestone'
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -61,7 +61,8 @@ module Checkoff
61
61
  # @return [Hash<String, Enumerable<Asana::Resources::Task>>]
62
62
  def by_my_tasks_section(tasks, project_gid)
63
63
  by_section = {}
64
- sections = client.sections.get_sections_for_project(project_gid: project_gid)
64
+ sections = client.sections.get_sections_for_project(project_gid: project_gid,
65
+ options: { fields: ['name'] })
65
66
  sections.each_entry { |section| by_section[section_key(section.name)] = [] }
66
67
  tasks.each do |task|
67
68
  assignee_section = task.assignee_section
@@ -9,8 +9,6 @@ require_relative 'internal/project_selector_evaluator'
9
9
  require_relative 'workspaces'
10
10
  require_relative 'clients'
11
11
 
12
- # https://developers.asana.com/docs/project-selectors
13
-
14
12
  module Checkoff
15
13
  # Filter lists of projects using declarative selectors.
16
14
  class ProjectSelectors
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # frozen_string_literal: true
4
+
5
+ require 'forwardable'
6
+ require 'cache_method'
7
+ require_relative 'internal/config_loader'
8
+ require_relative 'internal/section_selector_evaluator'
9
+ require_relative 'workspaces'
10
+ require_relative 'clients'
11
+
12
+ module Checkoff
13
+ # Filter lists of sections using declarative selectors.
14
+ class SectionSelectors
15
+ MINUTE = 60
16
+ HOUR = MINUTE * 60
17
+ DAY = 24 * HOUR
18
+ REALLY_LONG_CACHE_TIME = HOUR * 1
19
+ LONG_CACHE_TIME = MINUTE * 15
20
+ SHORT_CACHE_TIME = MINUTE
21
+
22
+ # @param config [Hash<Symbol, Object>]
23
+ # @param workspaces [Checkoff::Workspaces]
24
+ # @param sections [Checkoff::Sections]
25
+ # @param clients [Checkoff::Clients]
26
+ # @param client [Asana::Client]
27
+ def initialize(config: Checkoff::Internal::ConfigLoader.load(:asana),
28
+ workspaces: Checkoff::Workspaces.new(config: config),
29
+ sections: Checkoff::Sections.new(config: config),
30
+ clients: Checkoff::Clients.new(config: config),
31
+ client: clients.client)
32
+ @workspaces = workspaces
33
+ @sections = sections
34
+ @client = client
35
+ end
36
+
37
+ # @param [Asana::Resources::Section] section
38
+ # @param [Array<(Symbol, Array)>] section_selector Filter based on
39
+ # section details. Examples: [:tag, 'foo'] [:not, [:tag, 'foo']] [:tag, 'foo']
40
+ # @return [Boolean]
41
+ def filter_via_section_selector(section, section_selector)
42
+ # @sg-ignore
43
+ evaluator = SectionSelectorEvaluator.new(section: section, sections: sections, client: client)
44
+ evaluator.evaluate(section_selector)
45
+ end
46
+
47
+ private
48
+
49
+ # @return [Checkoff::Workspaces]
50
+ attr_reader :workspaces
51
+
52
+ # @return [Checkoff::Sections]
53
+ attr_reader :sections
54
+
55
+ # @return [Asana::Client]
56
+ attr_reader :client
57
+
58
+ # bundle exec ./section_selectors.rb
59
+ # :nocov:
60
+ class << self
61
+ # @return [void]
62
+ def run
63
+ # workspace_name = ARGV[0] || raise('Please pass workspace name as first argument')
64
+ # section_selector_name = ARGV[1] || raise('Please pass section_selector name as second argument')
65
+ # section_selectors = Checkoff::SectionSelectors.new
66
+ # section_selector = section_selectors.section_selector_or_raise(workspace_name, section_selector_name)
67
+ # puts "Results: #{section_selector}"
68
+ end
69
+ end
70
+ # :nocov:
71
+ end
72
+ end
73
+
74
+ # :nocov:
75
+ abs_program_name = File.expand_path($PROGRAM_NAME)
76
+ Checkoff::SectionSelectors.run if abs_program_name == File.expand_path(__FILE__)
77
+ # :nocov:
@@ -52,12 +52,14 @@ module Checkoff
52
52
  # Returns a list of Asana API section objects for a given project
53
53
  # @param workspace_name [String]
54
54
  # @param project_name [String, Symbol]
55
+ # @param extra_fields [Array<String>]
55
56
  #
56
57
  # @return [Enumerable<Asana::Resources::Section>]
57
- def sections_or_raise(workspace_name, project_name)
58
+ def sections_or_raise(workspace_name, project_name, extra_fields: [])
59
+ fields = %w[name] + extra_fields
58
60
  project = project_or_raise(workspace_name, project_name)
59
- # @sg-ignore
60
- client.sections.get_sections_for_project(project_gid: project.gid)
61
+ client.sections.get_sections_for_project(project_gid: project.gid,
62
+ options: { fields: fields })
61
63
  end
62
64
  cache_method :sections_or_raise, SHORT_CACHE_TIME
63
65
 
@@ -173,7 +175,8 @@ module Checkoff
173
175
  def by_section(tasks, project_gid)
174
176
  by_section = {}
175
177
  # @sg-ignore
176
- sections = client.sections.get_sections_for_project(project_gid: project_gid)
178
+ sections = client.sections.get_sections_for_project(project_gid: project_gid,
179
+ options: { fields: ['name'] })
177
180
  sections.each_entry { |section| by_section[section_key(section.name)] = [] }
178
181
  tasks.each { |task| file_task_by_section(by_section, task, project_gid) }
179
182
  by_section
@@ -9,8 +9,6 @@ require_relative 'internal/config_loader'
9
9
  require_relative 'internal/task_selector_evaluator'
10
10
  require_relative 'tasks'
11
11
 
12
- # https://developers.asana.com/docs/task-selectors
13
-
14
12
  module Checkoff
15
13
  # Filter lists of tasks using declarative selectors.
16
14
  class TaskSelectors
@@ -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.65.0'
6
+ VERSION = '0.67.0'
7
7
  end
data/lib/checkoff.rb CHANGED
@@ -11,4 +11,5 @@ require 'checkoff/custom_fields'
11
11
  require 'checkoff/tags'
12
12
  require 'checkoff/task_selectors'
13
13
  require 'checkoff/project_selectors'
14
+ require 'checkoff/section_selectors'
14
15
  require 'checkoff/task_searches'
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.65.0
4
+ version: 0.67.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-10-18 00:00:00.000000000 Z
11
+ date: 2023-10-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -140,11 +140,14 @@ files:
140
140
  - lib/checkoff/internal/search_url/parser.rb
141
141
  - lib/checkoff/internal/search_url/results_merger.rb
142
142
  - lib/checkoff/internal/search_url/simple_param_converter.rb
143
+ - lib/checkoff/internal/section_selector_evaluator.rb
143
144
  - lib/checkoff/internal/selector_classes/common.rb
144
145
  - lib/checkoff/internal/selector_classes/common/function_evaluator.rb
145
146
  - lib/checkoff/internal/selector_classes/function_evaluator.rb
146
147
  - lib/checkoff/internal/selector_classes/project.rb
147
148
  - lib/checkoff/internal/selector_classes/project/function_evaluator.rb
149
+ - lib/checkoff/internal/selector_classes/section.rb
150
+ - lib/checkoff/internal/selector_classes/section/function_evaluator.rb
148
151
  - lib/checkoff/internal/selector_classes/task.rb
149
152
  - lib/checkoff/internal/selector_classes/task/function_evaluator.rb
150
153
  - lib/checkoff/internal/selector_evaluator.rb
@@ -152,6 +155,7 @@ files:
152
155
  - lib/checkoff/my_tasks.rb
153
156
  - lib/checkoff/project_selectors.rb
154
157
  - lib/checkoff/projects.rb
158
+ - lib/checkoff/section_selectors.rb
155
159
  - lib/checkoff/sections.rb
156
160
  - lib/checkoff/subtasks.rb
157
161
  - lib/checkoff/tags.rb