checkoff 0.66.0 → 0.67.1

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: fc25937a7534eda70c7729a9844ef9a8d9dd5443f91a90272a0071558255b369
4
- data.tar.gz: 380cb06602f7b984f60ad18fa095ccc69e1f3df67273ee09c6a7eff862879d45
3
+ metadata.gz: 63b887dd83f103cab32923b8326be62de742bc54b4e137a390d005366d57d1c6
4
+ data.tar.gz: b65f844a89f4bb5821fec1845d417838b61ef317e59b93c1b4825daf97a59ac2
5
5
  SHA512:
6
- metadata.gz: 5de5eb2dc6849012b9440fb583186a83d7a1123d2d77f254f293be3158c509ea947ae54386510f6b75957f90dd1d664248b8716122c8a8ea744e6216b96d7204
7
- data.tar.gz: '088c35ad378b6e2fc57196e58e8071b5814a59c6fe680fdb96212a6571a7de09b497235eeacb048e824a337b5e05f57698417f3864d4670c9a8dd255dace68fa'
6
+ metadata.gz: 27ecc27a347c29621c95690e93c3614955295b231dec563703f5db8b2a7647c013eacf70b79c6756b6a39dfb5f1b7bcdbfe2fe56a70ab668e40c2ff66d339f22
7
+ data.tar.gz: 8633ada2cb84d24b32ab6fa1585a648902718d4cf318f5c15ebb6fc1d36bcce076aff818e4406a7931c3450136cd04f4f3d47a4e3e13f2cfb9c60b9b827028a3
data/GLOSSARY.md ADDED
@@ -0,0 +1,11 @@
1
+ # Glossary
2
+
3
+ * ready/due: See tasks.rb#task_ready?. Indicates a task is ready for
4
+ a person to work on it. This is subtly different than what is used
5
+ by Asana to mark a date as red/green! A task is ready if it is not
6
+ dependent on an incomplete task and one of these is true:
7
+
8
+ * start is null and due on is today
9
+ * start is null and due at is after now
10
+ * start on is today
11
+ * start at is after now
data/Gemfile.lock CHANGED
@@ -12,7 +12,7 @@ GIT
12
12
  PATH
13
13
  remote: .
14
14
  specs:
15
- checkoff (0.66.0)
15
+ checkoff (0.67.1)
16
16
  activesupport
17
17
  asana (> 0.10.0)
18
18
  cache_method
@@ -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
@@ -335,7 +335,9 @@ module Checkoff
335
335
  # @param task [Asana::Resources::Task]
336
336
  # @return [Boolean]
337
337
  def evaluate(task)
338
- custom_field = pull_custom_field_by_name_or_raise(task, 'Estimated time')
338
+ custom_field = pull_custom_field_by_name(task, 'Estimated time')
339
+
340
+ return false if custom_field.nil?
339
341
 
340
342
  # @sg-ignore
341
343
  # @type [Integer, nil]
@@ -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
@@ -42,6 +42,16 @@ module Checkoff
42
42
  @workspaces = workspaces
43
43
  end
44
44
 
45
+ # Indicates a task is ready for a person to work on it. This is
46
+ # subtly different than what is used by Asana to mark a date as
47
+ # red/green! A task is ready if it is not dependent on an
48
+ # incomplete task and one of these is true:
49
+ #
50
+ # * start is null and due on is today
51
+ # * start is null and due at is after now
52
+ # * start on is today
53
+ # * start at is after now
54
+ #
45
55
  # @param task [Asana::Resources::Task]
46
56
  # @param ignore_dependencies [Boolean]
47
57
  def task_ready?(task, ignore_dependencies: false)
@@ -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.66.0'
6
+ VERSION = '0.67.1'
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.66.0
4
+ version: 0.67.1
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-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -103,6 +103,7 @@ files:
103
103
  - CODE_OF_CONDUCT.md
104
104
  - CONTRIBUTING.rst
105
105
  - DEVELOPMENT.md
106
+ - GLOSSARY.md
106
107
  - Gemfile
107
108
  - Gemfile.lock
108
109
  - LICENSE
@@ -140,11 +141,14 @@ files:
140
141
  - lib/checkoff/internal/search_url/parser.rb
141
142
  - lib/checkoff/internal/search_url/results_merger.rb
142
143
  - lib/checkoff/internal/search_url/simple_param_converter.rb
144
+ - lib/checkoff/internal/section_selector_evaluator.rb
143
145
  - lib/checkoff/internal/selector_classes/common.rb
144
146
  - lib/checkoff/internal/selector_classes/common/function_evaluator.rb
145
147
  - lib/checkoff/internal/selector_classes/function_evaluator.rb
146
148
  - lib/checkoff/internal/selector_classes/project.rb
147
149
  - lib/checkoff/internal/selector_classes/project/function_evaluator.rb
150
+ - lib/checkoff/internal/selector_classes/section.rb
151
+ - lib/checkoff/internal/selector_classes/section/function_evaluator.rb
148
152
  - lib/checkoff/internal/selector_classes/task.rb
149
153
  - lib/checkoff/internal/selector_classes/task/function_evaluator.rb
150
154
  - lib/checkoff/internal/selector_evaluator.rb
@@ -152,6 +156,7 @@ files:
152
156
  - lib/checkoff/my_tasks.rb
153
157
  - lib/checkoff/project_selectors.rb
154
158
  - lib/checkoff/projects.rb
159
+ - lib/checkoff/section_selectors.rb
155
160
  - lib/checkoff/sections.rb
156
161
  - lib/checkoff/subtasks.rb
157
162
  - lib/checkoff/tags.rb