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 +4 -4
- data/GLOSSARY.md +11 -0
- data/Gemfile.lock +1 -1
- data/lib/checkoff/internal/section_selector_evaluator.rb +56 -0
- data/lib/checkoff/internal/selector_classes/section/function_evaluator.rb +33 -0
- data/lib/checkoff/internal/selector_classes/section.rb +31 -0
- data/lib/checkoff/internal/selector_classes/task.rb +3 -1
- data/lib/checkoff/my_tasks.rb +2 -1
- data/lib/checkoff/project_selectors.rb +0 -2
- data/lib/checkoff/section_selectors.rb +77 -0
- data/lib/checkoff/sections.rb +7 -4
- data/lib/checkoff/task_selectors.rb +0 -2
- data/lib/checkoff/tasks.rb +10 -0
- data/lib/checkoff/version.rb +1 -1
- data/lib/checkoff.rb +1 -0
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 63b887dd83f103cab32923b8326be62de742bc54b4e137a390d005366d57d1c6
|
4
|
+
data.tar.gz: b65f844a89f4bb5821fec1845d417838b61ef317e59b93c1b4825daf97a59ac2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
@@ -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 =
|
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]
|
data/lib/checkoff/my_tasks.rb
CHANGED
@@ -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:
|
data/lib/checkoff/sections.rb
CHANGED
@@ -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
|
-
|
60
|
-
|
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
|
data/lib/checkoff/tasks.rb
CHANGED
@@ -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)
|
data/lib/checkoff/version.rb
CHANGED
data/lib/checkoff.rb
CHANGED
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.
|
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-
|
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
|