checkoff 0.109.0 → 0.111.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: 199142d4090e6eb4196958d2c73958fefdfa864c0e7e69a5e8a589f198465b2e
4
- data.tar.gz: aa0739c73ce5359fe1f965e4c46674bf3a7d79a603d7bcc683f671cd5e039fd9
3
+ metadata.gz: 6e758f72d1a6f7cd1c2dd5b6ebb4b52964e9fa2ee6e24f9e17aa613f6c6fe23b
4
+ data.tar.gz: 9354f3874da0b13ec8662042475d60f67d0b67be9d22ddca07ee9938e81777f0
5
5
  SHA512:
6
- metadata.gz: fce61c75d5175ad6c7ae37263f3065efc796dc496dd290616bd6cf1bb69518149231e6da378f6ee5573a8f17d1a55e73179da30e46820a61b237038b62483ff3
7
- data.tar.gz: e7e2cadb887aaacb9fea39058bea689f087da8719ceba75931b768f92b170ca16bf2f93fe7731a18c4a5ebd00660ece4bfdf4f466f712bf98f7d74dc66d1e0b6
6
+ metadata.gz: 6d5945f70f231c337708a252597ffb2623c9fdc7e96996ca1acfe6337ac1082f53fd3fcc2fc0ae8fcab75c3af4b0eed5e8e469eb8ef0537558d1dfb4e5e56d36
7
+ data.tar.gz: e84eda5a4713bea660373ff2fc3829d861f61e4d88dd71b9127be5e077d0c9ca621fff32ec067e4890d37d1c65c67a47952f9e8478e129b3f2eae7a1c77443a6
data/Gemfile.lock CHANGED
@@ -12,7 +12,7 @@ GIT
12
12
  PATH
13
13
  remote: .
14
14
  specs:
15
- checkoff (0.109.0)
15
+ checkoff (0.111.0)
16
16
  activesupport
17
17
  asana (> 0.10.0)
18
18
  cache_method
@@ -37,6 +37,8 @@
37
37
  # def portfolios; end
38
38
  # # @return [Asana::ProxiedResourceClasses::User]
39
39
  # def users; end
40
+ # # @return [Asana::ProxiedResourceClasses::CustomField]
41
+ # def custom_fields; end
40
42
  # end
41
43
  # class Collection < Asana::Resources::Collection; end
42
44
  # module Resources
@@ -79,6 +81,15 @@
79
81
  # end
80
82
  # end
81
83
  # module ProxiedResourceClasses
84
+ # class CustomField
85
+ # # Get a workspace's custom fields
86
+ # #
87
+ # # @param workspace_gid [String] (required) Globally unique identifier for the workspace or organization.
88
+ # # @param options [Hash] the request I/O options
89
+ # #
90
+ # # @return [Enumerable<Asana::Resources::CustomField>]
91
+ # def get_custom_fields_for_workspace(workspace_gid: required("workspace_gid"), options: {}); end
92
+ # end
82
93
  # class Task
83
94
  # # Returns the complete task record for a single task.
84
95
  # #
@@ -30,11 +30,17 @@ module Checkoff
30
30
  # extend CacheMethod::ClassMethods
31
31
 
32
32
  MINUTE = 60
33
+ private_constant :MINUTE
33
34
  HOUR = MINUTE * 60
35
+ private_constant :HOUR
34
36
  DAY = 24 * HOUR
37
+ private_constant :DAY
35
38
  REALLY_LONG_CACHE_TIME = HOUR * 1
39
+ private_constant :REALLY_LONG_CACHE_TIME
36
40
  LONG_CACHE_TIME = MINUTE * 15
41
+ private_constant :LONG_CACHE_TIME
37
42
  SHORT_CACHE_TIME = MINUTE
43
+ private_constant :SHORT_CACHE_TIME
38
44
 
39
45
  # @param config [Hash]
40
46
  # @param workspaces [Checkoff::Workspaces]
@@ -13,6 +13,9 @@ require_relative 'clients'
13
13
  module Checkoff
14
14
  # Work with custom fields in Asana
15
15
  class CustomFields
16
+ # @!parse
17
+ # extend CacheMethod::ClassMethods
18
+
16
19
  MINUTE = 60
17
20
  HOUR = MINUTE * 60
18
21
  DAY = 24 * HOUR
@@ -20,22 +23,36 @@ module Checkoff
20
23
  LONG_CACHE_TIME = MINUTE * 15
21
24
  SHORT_CACHE_TIME = MINUTE
22
25
 
26
+ # @param config [Hash]
27
+ # @param workspaces [Checkoff::Workspaces]
28
+ # @param clients [Checkoff::Clients]
29
+ # @param client [Asana::Client]
23
30
  def initialize(config: Checkoff::Internal::ConfigLoader.load(:asana),
24
- workspaces: Checkoff::Workspaces.new(config: config),
25
31
  clients: Checkoff::Clients.new(config: config),
26
- client: clients.client)
32
+ client: clients.client,
33
+ workspaces: Checkoff::Workspaces.new(config: config,
34
+ client: client))
27
35
  @workspaces = workspaces
28
36
  @client = client
29
37
  end
30
38
 
39
+ # @param workspace_name [String]
40
+ # @param custom_field_name [String]
41
+ #
42
+ # @return [Asana::Resources::CustomField]
31
43
  def custom_field_or_raise(workspace_name, custom_field_name)
32
- custom_field = custom_field(workspace_name, custom_field_name)
33
- raise "Could not find custom_field #{custom_field_name} under workspace #{workspace_name}." if custom_field.nil?
44
+ cf = custom_field(workspace_name, custom_field_name)
45
+ raise "Could not find custom_field #{custom_field_name} under workspace #{workspace_name}." if cf.nil?
34
46
 
35
- custom_field
47
+ cf
36
48
  end
37
49
  cache_method :custom_field_or_raise, LONG_CACHE_TIME
38
50
 
51
+ # @param workspace_name [String]
52
+ # @param custom_field_name [String]
53
+ #
54
+ # @sg-ignore
55
+ # @return [Asana::Resources::CustomField,nil]
39
56
  def custom_field(workspace_name, custom_field_name)
40
57
  workspace = workspaces.workspace_or_raise(workspace_name)
41
58
  custom_fields = client.custom_fields.get_custom_fields_for_workspace(workspace_gid: workspace.gid)
@@ -43,15 +60,133 @@ module Checkoff
43
60
  end
44
61
  cache_method :custom_field, LONG_CACHE_TIME
45
62
 
63
+ # @param resource [Asana::Resources::Project,Asana::Resources::Task]
64
+ # @param custom_field_gid [String]
65
+ #
66
+ # @return [Array<String>]
67
+ def resource_custom_field_values_gids_or_raise(resource, custom_field_gid)
68
+ custom_field = resource_custom_field_by_gid_or_raise(resource, custom_field_gid)
69
+
70
+ resource_custom_field_enum_values(custom_field).flat_map do |enum_value|
71
+ find_gids(custom_field, enum_value)
72
+ end
73
+ end
74
+
75
+ # @param resource [Asana::Resources::Project,Asana::Resources::Task]
76
+ # @param custom_field_name [String]
77
+ # @return [Array<String>]
78
+ def resource_custom_field_values_names_by_name(resource, custom_field_name)
79
+ custom_field = resource_custom_field_by_name(resource, custom_field_name)
80
+ return [] if custom_field.nil?
81
+
82
+ resource_custom_field_enum_values(custom_field).flat_map do |enum_value|
83
+ find_names(enum_value)
84
+ end
85
+ end
86
+
87
+ # @sg-ignore
88
+ # @param project [Asana::Resources::Task,Asana::Resources::Project]
89
+ # @param custom_field_name [String]
90
+ # @return [Hash, nil]
91
+ def resource_custom_field_by_name(resource, custom_field_name)
92
+ # @sg-ignore
93
+ # @type [Array<Hash>]
94
+ custom_fields = resource.custom_fields
95
+ if custom_fields.nil?
96
+ raise "custom fields not found on resource - did you add 'custom_fields' in your extra_fields argument?"
97
+ end
98
+
99
+ # @sg-ignore
100
+ # @type [Hash, nil]
101
+ custom_fields.find { |field| field.fetch('name') == custom_field_name }
102
+ end
103
+
104
+ # @param resource [Asana::Resources::Task,Asana::Resources::Project]
105
+ # @param custom_field_name [String]
106
+ # @return [Hash]
107
+ def resource_custom_field_by_name_or_raise(resource, custom_field_name)
108
+ custom_field = resource_custom_field_by_name(resource, custom_field_name)
109
+ if custom_field.nil?
110
+ raise "Could not find custom field with name #{custom_field_name} " \
111
+ "in gid #{resource.gid} with custom fields #{resource.custom_fields}"
112
+ end
113
+ custom_field
114
+ end
115
+
116
+ # @param resource [Asana::Resources::Project,Asana::Resources::Task]
117
+ # @param custom_field_gid [String]
118
+ # @return [Hash]
119
+ def resource_custom_field_by_gid_or_raise(resource, custom_field_gid)
120
+ # @type [Array<Hash>]
121
+ custom_fields = resource.custom_fields
122
+ if custom_fields.nil?
123
+ raise "Could not find custom_fields under project (was 'custom_fields' included in 'extra_fields'?)"
124
+ end
125
+
126
+ # @sg-ignore
127
+ # @type [Hash, nil]
128
+ matched_custom_field = custom_fields.find { |data| data.fetch('gid') == custom_field_gid }
129
+ if matched_custom_field.nil?
130
+ raise "Could not find custom field with gid #{custom_field_gid} " \
131
+ "in gid #{resource.gid} with custom fields #{custom_fields}"
132
+ end
133
+
134
+ matched_custom_field
135
+ end
136
+
46
137
  private
47
138
 
48
- attr_reader :workspaces, :client
139
+ # @sg-ignore
140
+ # @param custom_field [Hash]
141
+ # @return [Array<String>]
142
+ def resource_custom_field_enum_values(custom_field)
143
+ resource_subtype = custom_field.fetch('resource_subtype')
144
+ case resource_subtype
145
+ when 'enum'
146
+ [custom_field.fetch('enum_value')]
147
+ when 'multi_enum'
148
+ custom_field.fetch('multi_enum_values')
149
+ else
150
+ raise "Teach me how to handle resource_subtype #{resource_subtype}"
151
+ end
152
+ end
153
+
154
+ # @param custom_field [Hash]
155
+ # @param enum_value [Object, nil]
156
+ # @return [Array<String>]
157
+ def find_gids(custom_field, enum_value)
158
+ if enum_value.nil?
159
+ []
160
+ else
161
+ raise "Unexpected enabled value on custom field: #{custom_field}" if enum_value.fetch('enabled') == false
162
+
163
+ [enum_value.fetch('gid')]
164
+ end
165
+ end
166
+
167
+ # @param custom_field [Hash]
168
+ # @param enum_value [Object, nil]
169
+ # @return [Array<String>]
170
+ def find_names(enum_value)
171
+ [enum_value.fetch('name')]
172
+ end
173
+
174
+ # @return [Checkoff::Workspaces]
175
+ attr_reader :workspaces
176
+
177
+ # @return [Asana::Client]
178
+ attr_reader :client
49
179
 
50
180
  # bundle exec ./custom_fields.rb
51
181
  # :nocov:
52
182
  class << self
183
+ # @return [void]
53
184
  def run
185
+ # @sg-ignore
186
+ # @type [String]
54
187
  workspace_name = ARGV[0] || raise('Please pass workspace name as first argument')
188
+ # @sg-ignore
189
+ # @type [String]
55
190
  custom_field_name = ARGV[1] || raise('Please pass custom_field name as second argument')
56
191
  custom_fields = Checkoff::CustomFields.new
57
192
  custom_field = custom_fields.custom_field_or_raise(workspace_name, custom_field_name)
@@ -9,10 +9,13 @@ module Checkoff
9
9
  class ProjectSelectorEvaluator < SelectorEvaluator
10
10
  # @param project [Asana::Resources::Project]
11
11
  # @param projects [Checkoff::Projects]
12
+ # @param custom_fields [Checkoff::CustomFields]
12
13
  def initialize(project:,
13
- projects: Checkoff::Projects.new)
14
+ projects: Checkoff::Projects.new,
15
+ custom_fields: Checkoff::CustomFields.new)
14
16
  @item = project
15
17
  @projects = projects
18
+ @custom_fields = custom_fields
16
19
  super()
17
20
  end
18
21
 
@@ -35,12 +38,14 @@ module Checkoff
35
38
 
36
39
  # @return [Hash]
37
40
  def initializer_kwargs
38
- { projects: projects }
41
+ { projects: projects, custom_fields: custom_fields }
39
42
  end
40
43
 
41
44
  # @return [Asana::Resources::Project]
42
45
  attr_reader :item
43
46
  # @return [Checkoff::Projects]
44
47
  attr_reader :projects
48
+ # @return [Checkoff::CustomFields]
49
+ attr_reader :custom_fields
45
50
  end
46
51
  end
@@ -5,14 +5,14 @@ module Checkoff
5
5
  # Determine whether a task is due within a relative date range
6
6
  class ReadyBetweenRelative
7
7
  # @param config [Hash<Symbol, Object>]
8
- # @param clients [Checkoff::Clients]
8
+ # @param client [Asana::Client]
9
9
  # @param task_timing [Checkoff::Internal::TaskTiming]
10
10
  # @param tasks [Checkoff::Tasks]
11
11
  def initialize(config: Checkoff::Internal::ConfigLoader.load(:asana),
12
- clients: Checkoff::Clients.new(config: config),
13
- task_timing: ::Checkoff::Internal::TaskTiming.new,
12
+ client: Checkoff::Clients.new(config: config).client,
13
+ task_timing: ::Checkoff::Internal::TaskTiming.new(client: client),
14
14
  tasks: ::Checkoff::Tasks.new(config: config,
15
- client: clients.client))
15
+ client: client))
16
16
  @task_timing = task_timing
17
17
  @tasks = tasks
18
18
  end
@@ -11,14 +11,18 @@ module Checkoff
11
11
  # @param client [Asana::Client]
12
12
  # @param projects [Checkoff::Projects]
13
13
  # @param sections [Checkoff::Sections]
14
+ # @param custom_fields [Checkoff::CustomFields]
14
15
  def initialize(section:,
15
16
  client:,
16
17
  projects: Checkoff::Projects.new(client: client),
17
- sections: Checkoff::Sections.new)
18
+ sections: Checkoff::Sections.new(client: client),
19
+ custom_fields: Checkoff::CustomFields.new(client: client),
20
+ **_kwargs)
18
21
  @item = section
19
22
  @client = client
20
23
  @projects = projects
21
24
  @sections = sections
25
+ @custom_fields = custom_fields
22
26
  super()
23
27
  end
24
28
 
@@ -41,7 +45,7 @@ module Checkoff
41
45
 
42
46
  # @return [Hash]
43
47
  def initializer_kwargs
44
- { sections: sections, projects: projects, client: client }
48
+ { sections: sections, projects: projects, client: client, custom_fields: custom_fields }
45
49
  end
46
50
 
47
51
  # @return [Asana::Resources::Project]
@@ -50,6 +54,8 @@ module Checkoff
50
54
  attr_reader :sections
51
55
  # @return [Checkoff::Projects]
52
56
  attr_reader :projects
57
+ # @return [Checkoff::CustomFields]
58
+ attr_reader :custom_fields
53
59
  # @return [Asana::Client]
54
60
  attr_reader :client
55
61
  end
@@ -8,122 +8,17 @@ module Checkoff
8
8
  # Base class to evaluate a project selector function given fully evaluated arguments
9
9
  class FunctionEvaluator < ::Checkoff::SelectorClasses::FunctionEvaluator
10
10
  # @param selector [Array<(Symbol, Array)>,String]
11
- def initialize(selector:, **_kwargs)
11
+ # @param custom_fields [Checkoff::CustomFields]
12
+ def initialize(selector:, custom_fields:, **_kwargs)
12
13
  @selector = selector
14
+ @custom_fields = custom_fields
13
15
  super()
14
16
  end
15
17
 
16
18
  private
17
19
 
18
- # @sg-ignore
19
- # @param project [Asana::Resources::Project]
20
- # @param custom_field_gid [String]
21
- # @return [Hash]
22
- def pull_custom_field_or_raise(project, custom_field_gid)
23
- # @type [Array<Hash>]
24
- custom_fields = project.custom_fields
25
- if custom_fields.nil?
26
- raise "Could not find custom_fields under project (was 'custom_fields' included in 'extra_fields'?)"
27
- end
28
-
29
- # @sg-ignore
30
- # @type [Hash, nil]
31
- matched_custom_field = custom_fields.find { |data| data.fetch('gid') == custom_field_gid }
32
- if matched_custom_field.nil?
33
- raise "Could not find custom field with gid #{custom_field_gid} " \
34
- "in project #{project.gid} with custom fields #{custom_fields}"
35
- end
36
-
37
- matched_custom_field
38
- end
39
-
40
20
  # @return [Array<(Symbol, Array)>]
41
21
  attr_reader :selector
42
-
43
- # @sg-ignore
44
- # @param custom_field [Hash]
45
- # @return [Array<String>]
46
- def pull_enum_values(custom_field)
47
- resource_subtype = custom_field.fetch('resource_subtype')
48
- case resource_subtype
49
- when 'enum'
50
- [custom_field.fetch('enum_value')]
51
- when 'multi_enum'
52
- custom_field.fetch('multi_enum_values')
53
- else
54
- raise "Teach me how to handle resource_subtype #{resource_subtype}"
55
- end
56
- end
57
-
58
- # @param custom_field [Hash]
59
- # @param enum_value [Object, nil]
60
- # @return [Array<String>]
61
- def find_gids(custom_field, enum_value)
62
- if enum_value.nil?
63
- []
64
- else
65
- raise "Unexpected enabled value on custom field: #{custom_field}" if enum_value.fetch('enabled') == false
66
-
67
- [enum_value.fetch('gid')]
68
- end
69
- end
70
-
71
- # @param custom_field [Hash]
72
- # @param enum_value [Object, nil]
73
- # @return [Array<String>]
74
- def find_names(enum_value)
75
- [enum_value.fetch('name')]
76
- end
77
-
78
- # @param project [Asana::Resources::Project,Asana::Resources::Task]
79
- # @param custom_field_gid [String]
80
- # @return [Array<String>]
81
- def pull_custom_field_values_gids_or_raise(project, custom_field_gid)
82
- custom_field = pull_custom_field_or_raise(project, custom_field_gid)
83
-
84
- pull_enum_values(custom_field).flat_map do |enum_value|
85
- find_gids(custom_field, enum_value)
86
- end
87
- end
88
-
89
- # @param resource [Asana::Resources::Project,Asana::Resources::Task]
90
- # @param custom_field_name [String]
91
- # @return [Array<String>]
92
- def pull_custom_field_values_names_by_name(resource, custom_field_name)
93
- custom_field = pull_custom_field_by_name(resource, custom_field_name)
94
- return [] if custom_field.nil?
95
-
96
- pull_enum_values(custom_field).flat_map do |enum_value|
97
- find_names(enum_value)
98
- end
99
- end
100
-
101
- # @sg-ignore
102
- # @param project [Asana::Resources::Project]
103
- # @param custom_field_name [String]
104
- # @return [Hash, nil]
105
- def pull_custom_field_by_name(project, custom_field_name)
106
- custom_fields = project.custom_fields
107
- if custom_fields.nil?
108
- raise "custom fields not found on project - did you add 'custom_fields' in your extra_fields argument?"
109
- end
110
-
111
- # @sg-ignore
112
- # @type [Hash, nil]
113
- custom_fields.find { |field| field.fetch('name') == custom_field_name }
114
- end
115
-
116
- # @param project [Asana::Resources::Project]
117
- # @param custom_field_name [String]
118
- # @return [Hash]
119
- def pull_custom_field_by_name_or_raise(project, custom_field_name)
120
- custom_field = pull_custom_field_by_name(project, custom_field_name)
121
- if custom_field.nil?
122
- raise "Could not find custom field with name #{custom_field_name} " \
123
- "in project #{project.gid} with custom fields #{project.custom_fields}"
124
- end
125
- custom_field
126
- end
127
22
  end
128
23
  end
129
24
  end
@@ -105,7 +105,7 @@ module Checkoff
105
105
  # @param custom_field_name [String]
106
106
  # @return [String, nil]
107
107
  def evaluate(resource, custom_field_name)
108
- custom_field = pull_custom_field_by_name(resource, custom_field_name)
108
+ custom_field = @custom_fields.resource_custom_field_by_name(resource, custom_field_name)
109
109
  return nil if custom_field.nil?
110
110
 
111
111
  custom_field['display_value']
@@ -127,7 +127,7 @@ module Checkoff
127
127
  # @param custom_field_gid [String]
128
128
  # @return [String, nil]
129
129
  def evaluate(resource, custom_field_gid)
130
- custom_field = pull_custom_field_or_raise(resource, custom_field_gid)
130
+ custom_field = @custom_fields.resource_custom_field_by_gid_or_raise(resource, custom_field_gid)
131
131
  custom_field['display_value']
132
132
  end
133
133
  end
@@ -149,7 +149,8 @@ module Checkoff
149
149
  # @param custom_field_values_gids [Array<String>]
150
150
  # @return [Boolean]
151
151
  def evaluate(resource, custom_field_gid, custom_field_values_gids)
152
- actual_custom_field_values_gids = pull_custom_field_values_gids_or_raise(resource, custom_field_gid)
152
+ actual_custom_field_values_gids = @custom_fields.resource_custom_field_values_gids_or_raise(resource,
153
+ custom_field_gid)
153
154
 
154
155
  actual_custom_field_values_gids.any? do |custom_field_value|
155
156
  custom_field_values_gids.include?(custom_field_value)
@@ -174,7 +175,9 @@ module Checkoff
174
175
  # @param custom_field_value_names [Array<String>]
175
176
  # @return [Boolean]
176
177
  def evaluate(resource, custom_field_name, custom_field_value_names)
177
- actual_custom_field_values_names = pull_custom_field_values_names_by_name(resource, custom_field_name)
178
+ actual_custom_field_values_names =
179
+ @custom_fields.resource_custom_field_values_names_by_name(resource,
180
+ custom_field_name)
178
181
 
179
182
  actual_custom_field_values_names.any? do |custom_field_value|
180
183
  custom_field_value_names.include?(custom_field_value)
@@ -199,7 +202,9 @@ module Checkoff
199
202
  # @param custom_field_values_gids [Array<String>]
200
203
  # @return [Boolean]
201
204
  def evaluate(resource, custom_field_gid, custom_field_values_gids)
202
- actual_custom_field_values_gids = pull_custom_field_values_gids_or_raise(resource, custom_field_gid)
205
+ actual_custom_field_values_gids =
206
+ @custom_fields.resource_custom_field_values_gids_or_raise(resource,
207
+ custom_field_gid)
203
208
 
204
209
  custom_field_values_gids.all? do |custom_field_value|
205
210
  actual_custom_field_values_gids.include?(custom_field_value)
@@ -10,7 +10,8 @@ module Checkoff
10
10
  # @param selector [Array<(Symbol, Array)>,String]
11
11
  # @param projects [Checkoff::Projects]
12
12
  def initialize(selector:,
13
- projects:)
13
+ projects:,
14
+ **_kwargs)
14
15
  @selector = selector
15
16
  @projects = projects
16
17
  super()
@@ -18,95 +19,8 @@ module Checkoff
18
19
 
19
20
  private
20
21
 
21
- # @sg-ignore
22
- # @param project [Asana::Resources::Project]
23
- # @param custom_field_gid [String]
24
- # @return [Hash]
25
- def pull_custom_field_or_raise(project, custom_field_gid)
26
- # @type [Array<Hash>]
27
- custom_fields = project.custom_fields
28
- if custom_fields.nil?
29
- raise "Could not find custom_fields under project (was 'custom_fields' included in 'extra_fields'?)"
30
- end
31
-
32
- # @sg-ignore
33
- # @type [Hash, nil]
34
- matched_custom_field = custom_fields.find { |data| data.fetch('gid') == custom_field_gid }
35
- if matched_custom_field.nil?
36
- raise "Could not find custom field with gid #{custom_field_gid} " \
37
- "in project #{project.gid} with custom fields #{custom_fields}"
38
- end
39
-
40
- matched_custom_field
41
- end
42
-
43
22
  # @return [Array<(Symbol, Array)>]
44
23
  attr_reader :selector
45
-
46
- # @sg-ignore
47
- # @param custom_field [Hash]
48
- # @return [Array<String>]
49
- def pull_enum_values(custom_field)
50
- resource_subtype = custom_field.fetch('resource_subtype')
51
- case resource_subtype
52
- when 'enum'
53
- [custom_field.fetch('enum_value')]
54
- when 'multi_enum'
55
- custom_field.fetch('multi_enum_values')
56
- else
57
- raise "Teach me how to handle resource_subtype #{resource_subtype}"
58
- end
59
- end
60
-
61
- # @param custom_field [Hash]
62
- # @param enum_value [Object, nil]
63
- # @return [Array<String>]
64
- def find_gids(custom_field, enum_value)
65
- if enum_value.nil?
66
- []
67
- else
68
- raise "Unexpected enabled value on custom field: #{custom_field}" if enum_value.fetch('enabled') == false
69
-
70
- [enum_value.fetch('gid')]
71
- end
72
- end
73
-
74
- # @param project [Asana::Resources::Project]
75
- # @param custom_field_gid [String]
76
- # @return [Array<String>]
77
- def pull_custom_field_values_gids(project, custom_field_gid)
78
- custom_field = pull_custom_field_or_raise(project, custom_field_gid)
79
- pull_enum_values(custom_field).flat_map do |enum_value|
80
- find_gids(custom_field, enum_value)
81
- end
82
- end
83
-
84
- # @sg-ignore
85
- # @param project [Asana::Resources::Project]
86
- # @param custom_field_name [String]
87
- # @return [Hash, nil]
88
- def pull_custom_field_by_name(project, custom_field_name)
89
- custom_fields = project.custom_fields
90
- if custom_fields.nil?
91
- raise "custom fields not found on project - did you add 'custom_fields' in your extra_fields argument?"
92
- end
93
-
94
- # @sg-ignore
95
- # @type [Hash, nil]
96
- custom_fields.find { |field| field.fetch('name') == custom_field_name }
97
- end
98
-
99
- # @param project [Asana::Resources::Project]
100
- # @param custom_field_name [String]
101
- # @return [Hash]
102
- def pull_custom_field_by_name_or_raise(project, custom_field_name)
103
- custom_field = pull_custom_field_by_name(project, custom_field_name)
104
- if custom_field.nil?
105
- raise "Could not find custom field with name #{custom_field_name} " \
106
- "in project #{project.gid} with custom fields #{project.custom_fields}"
107
- end
108
- custom_field
109
- end
110
24
  end
111
25
  end
112
26
  end
@@ -7,7 +7,7 @@ module Checkoff
7
7
  # Section selector classes
8
8
  module Section
9
9
  # :ends_with_milestone function
10
- class DueDateFunctionEvaluator < FunctionEvaluator
10
+ class EndsWithMilestoneFunctionEvaluator < FunctionEvaluator
11
11
  FUNCTION_NAME = :ends_with_milestone
12
12
 
13
13
  def matches?
@@ -10,106 +10,23 @@ module Checkoff
10
10
  # @param selector [Array<(Symbol, Array)>,String]
11
11
  # @param tasks [Checkoff::Tasks]
12
12
  # @param timelines [Checkoff::Timelines]
13
+ # @param custom_fields [Checkoff::CustomFields]
13
14
  def initialize(selector:,
14
15
  tasks:,
15
- timelines:)
16
+ timelines:,
17
+ custom_fields:,
18
+ **_kwargs)
16
19
  @selector = selector
17
20
  @tasks = tasks
18
21
  @timelines = timelines
22
+ @custom_fields = custom_fields
19
23
  super()
20
24
  end
21
25
 
22
26
  private
23
27
 
24
- # @sg-ignore
25
- # @param task [Asana::Resources::Task]
26
- # @param custom_field_gid [String]
27
- # @return [Hash]
28
- def pull_custom_field_or_raise(task, custom_field_gid)
29
- # @type [Array<Hash>]
30
- custom_fields = task.custom_fields
31
- if custom_fields.nil?
32
- raise "Could not find custom_fields under task (was 'custom_fields' included in 'extra_fields'?)"
33
- end
34
-
35
- # @sg-ignore
36
- # @type [Hash, nil]
37
- matched_custom_field = custom_fields.find { |data| data.fetch('gid') == custom_field_gid }
38
- if matched_custom_field.nil?
39
- raise "Could not find custom field with gid #{custom_field_gid} " \
40
- "in task #{task.gid} with custom fields #{custom_fields}"
41
- end
42
-
43
- matched_custom_field
44
- end
45
-
46
28
  # @return [Array<(Symbol, Array)>]
47
29
  attr_reader :selector
48
-
49
- # @sg-ignore
50
- # @param custom_field [Hash]
51
- # @return [Array<String>]
52
- def pull_enum_values(custom_field)
53
- resource_subtype = custom_field.fetch('resource_subtype')
54
- case resource_subtype
55
- when 'enum'
56
- [custom_field.fetch('enum_value')]
57
- when 'multi_enum'
58
- custom_field.fetch('multi_enum_values')
59
- else
60
- raise "Teach me how to handle resource_subtype #{resource_subtype}"
61
- end
62
- end
63
-
64
- # @param custom_field [Hash]
65
- # @param enum_value [Object, nil]
66
- # @return [Array<String>]
67
- def find_gids(custom_field, enum_value)
68
- if enum_value.nil?
69
- []
70
- else
71
- raise "Unexpected enabled value on custom field: #{custom_field}" if enum_value.fetch('enabled') == false
72
-
73
- [enum_value.fetch('gid')]
74
- end
75
- end
76
-
77
- # @param task [Asana::Resources::Task]
78
- # @param custom_field_gid [String]
79
- # @return [Array<String>]
80
- def pull_custom_field_values_gids(task, custom_field_gid)
81
- custom_field = pull_custom_field_or_raise(task, custom_field_gid)
82
- pull_enum_values(custom_field).flat_map do |enum_value|
83
- find_gids(custom_field, enum_value)
84
- end
85
- end
86
-
87
- # @sg-ignore
88
- # @param task [Asana::Resources::Task]
89
- # @param custom_field_name [String]
90
- # @return [Hash, nil]
91
- def pull_custom_field_by_name(task, custom_field_name)
92
- custom_fields = task.custom_fields
93
- if custom_fields.nil?
94
- raise "custom fields not found on task - did you add 'custom_fields' in your extra_fields argument?"
95
- end
96
-
97
- # @sg-ignore
98
- # @type [Hash, nil]
99
- custom_fields.find { |field| field.fetch('name') == custom_field_name }
100
- end
101
-
102
- # @param task [Asana::Resources::Task]
103
- # @param custom_field_name [String]
104
- # @return [Hash]
105
- def pull_custom_field_by_name_or_raise(task, custom_field_name)
106
- custom_field = pull_custom_field_by_name(task, custom_field_name)
107
- if custom_field.nil?
108
- raise "Could not find custom field with name #{custom_field_name} " \
109
- "in task #{task.gid} with custom fields #{task.custom_fields}"
110
- end
111
- custom_field
112
- end
113
30
  end
114
31
  end
115
32
  end
@@ -166,73 +166,14 @@ module Checkoff
166
166
  #
167
167
  # @return [Boolean]
168
168
  def evaluate(task, beginning_num_days_from_now, end_num_days_from_now, ignore_dependencies: false)
169
- ready_between_relative = Checkoff::Internal::ReadyBetweenRelative.new(tasks: @tasks)
169
+ ready_between_relative = Checkoff::Internal::ReadyBetweenRelative.new(tasks: @tasks,
170
+ client: @client)
170
171
  ready_between_relative.ready_between_relative?(task,
171
172
  beginning_num_days_from_now, end_num_days_from_now,
172
173
  ignore_dependencies: ignore_dependencies)
173
174
  end
174
175
  end
175
176
 
176
- # :custom_field_less_than_n_days_from_now function
177
- class CustomFieldLessThanNDaysFromNowFunctionEvaluator < FunctionEvaluator
178
- FUNCTION_NAME = :custom_field_less_than_n_days_from_now
179
-
180
- def matches?
181
- fn?(selector, FUNCTION_NAME)
182
- end
183
-
184
- def evaluate_arg?(_index)
185
- false
186
- end
187
-
188
- # @param task [Asana::Resources::Task]
189
- # @param custom_field_name [String]
190
- # @param num_days [Integer]
191
- # @return [Boolean]
192
- def evaluate(task, custom_field_name, num_days)
193
- custom_field = pull_custom_field_by_name_or_raise(task, custom_field_name)
194
-
195
- # @sg-ignore
196
- # @type [String, nil]
197
- time_str = custom_field.fetch('display_value')
198
- return false if time_str.nil?
199
-
200
- time = Time.parse(time_str)
201
- n_days_from_now = (Time.now + (num_days * 24 * 60 * 60))
202
- time < n_days_from_now
203
- end
204
- end
205
-
206
- # :custom_field_greater_than_or_equal_to_n_days_from_now function
207
- class CustomFieldGreaterThanOrEqualToNDaysFromNowFunctionEvaluator < FunctionEvaluator
208
- FUNCTION_NAME = :custom_field_greater_than_or_equal_to_n_days_from_now
209
-
210
- def matches?
211
- fn?(selector, FUNCTION_NAME)
212
- end
213
-
214
- def evaluate_arg?(_index)
215
- false
216
- end
217
-
218
- # @param task [Asana::Resources::Task]
219
- # @param custom_field_name [String]
220
- # @param num_days [Integer]
221
- # @return [Boolean]
222
- def evaluate(task, custom_field_name, num_days)
223
- custom_field = pull_custom_field_by_name_or_raise(task, custom_field_name)
224
-
225
- # @sg-ignore
226
- # @type [String, nil]
227
- time_str = custom_field.fetch('display_value')
228
- return false if time_str.nil?
229
-
230
- time = Time.parse(time_str)
231
- n_days_from_now = (Time.now + (num_days * 24 * 60 * 60))
232
- time >= n_days_from_now
233
- end
234
- end
235
-
236
177
  # :last_story_created_less_than_n_days_ago function
237
178
  class LastStoryCreatedLessThanNDaysAgoFunctionEvaluator < FunctionEvaluator
238
179
  FUNCTION_NAME = :last_story_created_less_than_n_days_ago
@@ -289,7 +230,7 @@ module Checkoff
289
230
  # @param task [Asana::Resources::Task]
290
231
  # @return [Boolean]
291
232
  def evaluate(task)
292
- custom_field = pull_custom_field_by_name(task, 'Estimated time')
233
+ custom_field = @custom_fields.resource_custom_field_by_name(task, 'Estimated time')
293
234
 
294
235
  return false if custom_field.nil?
295
236
 
@@ -10,12 +10,15 @@ module Checkoff
10
10
  # @param task [Asana::Resources::Task]
11
11
  # @param tasks [Checkoff::Tasks]
12
12
  # @param timelines [Checkoff::Timelines]
13
+ # @param custom_fields [Checkoff::CustomFields]
13
14
  def initialize(task:,
14
15
  tasks: Checkoff::Tasks.new,
15
- timelines: Checkoff::Timelines.new)
16
+ timelines: Checkoff::Timelines.new,
17
+ custom_fields: Checkoff::CustomFields.new)
16
18
  @item = task
17
19
  @tasks = tasks
18
20
  @timelines = timelines
21
+ @custom_fields = custom_fields
19
22
  super()
20
23
  end
21
24
 
@@ -38,7 +41,7 @@ module Checkoff
38
41
 
39
42
  # @return [Hash]
40
43
  def initializer_kwargs
41
- { tasks: tasks, timelines: timelines }
44
+ { tasks: tasks, timelines: timelines, custom_fields: custom_fields }
42
45
  end
43
46
 
44
47
  # @return [Asana::Resources::Task]
@@ -47,5 +50,7 @@ module Checkoff
47
50
  attr_reader :tasks
48
51
  # @return [Checkoff::Timelines]
49
52
  attr_reader :timelines
53
+ # @return [Checkoff::CustomFields]
54
+ attr_reader :custom_fields
50
55
  end
51
56
  end
@@ -6,9 +6,14 @@ module Checkoff
6
6
  class TaskTiming
7
7
  # @param time_class [Class<Time>]
8
8
  # @param date_class [Class<Date>]
9
- def initialize(time_class: Time, date_class: Date)
9
+ # @param client [Asana::Client]
10
+ # @param custom_fields [Checkoff::CustomFields]
11
+ def initialize(time_class: Time, date_class: Date,
12
+ client: Checkoff::Clients.new.client,
13
+ custom_fields: Checkoff::CustomFields.new(client: client))
10
14
  @time_class = time_class
11
15
  @date_class = date_class
16
+ @custom_fields = custom_fields
12
17
  end
13
18
 
14
19
  # @param task [Asana::Resources::Task]
@@ -56,6 +61,20 @@ module Checkoff
56
61
  return @time_class.parse(task.modified_at) unless task.modified_at.nil?
57
62
  end
58
63
 
64
+ # @param task [Asana::Resources::Task]
65
+ # @param custom_field_name [String]
66
+ #
67
+ # @return [Time, Date, nil]
68
+ def custom_field(task, custom_field_name)
69
+ custom_field = @custom_fields.resource_custom_field_by_name_or_raise(task, custom_field_name)
70
+ # @sg-ignore
71
+ # @type [String, nil]
72
+ time_str = custom_field.fetch('display_value')
73
+ return nil if time_str.nil?
74
+
75
+ Time.parse(time_str)
76
+ end
77
+
59
78
  # @param task [Asana::Resources::Task]
60
79
  # @param field_name [Symbol]
61
80
  #
@@ -70,6 +89,15 @@ module Checkoff
70
89
 
71
90
  return start_date_or_time(task) || due_date_or_time(task) if field_name == :ready
72
91
 
92
+ if field_name.is_a?(Array)
93
+ # @sg-ignore
94
+ # @type [Symbol]
95
+ actual_field_name = field_name.first
96
+ args = field_name[1..]
97
+
98
+ return custom_field(task, *args) if actual_field_name == :custom_field
99
+ end
100
+
73
101
  raise "Teach me how to handle field #{field_name}"
74
102
  end
75
103
  end
@@ -22,15 +22,18 @@ module Checkoff
22
22
  # @param config [Hash<Symbol, Object>]
23
23
  # @param workspaces [Checkoff::Workspaces]
24
24
  # @param projects [Checkoff::Projects]
25
+ # @param custom_fields [Checkoff::CustomFields]
25
26
  # @param clients [Checkoff::Clients]
26
27
  # @param client [Asana::Client]
27
28
  def initialize(config: Checkoff::Internal::ConfigLoader.load(:asana),
28
29
  workspaces: Checkoff::Workspaces.new(config: config),
29
30
  projects: Checkoff::Projects.new(config: config),
31
+ custom_fields: Checkoff::CustomFields.new(config: config),
30
32
  clients: Checkoff::Clients.new(config: config),
31
33
  client: clients.client)
32
34
  @workspaces = workspaces
33
35
  @projects = projects
36
+ @custom_fields = custom_fields
34
37
  @client = client
35
38
  end
36
39
 
@@ -39,7 +42,7 @@ module Checkoff
39
42
  # project details. Examples: [:tag, 'foo'] [:not, [:tag, 'foo']] [:tag, 'foo']
40
43
  # @return [Boolean]
41
44
  def filter_via_project_selector(project, project_selector)
42
- evaluator = ProjectSelectorEvaluator.new(project: project, projects: projects)
45
+ evaluator = ProjectSelectorEvaluator.new(project: project, projects: projects, custom_fields: custom_fields)
43
46
  evaluator.evaluate(project_selector)
44
47
  end
45
48
 
@@ -51,6 +54,9 @@ module Checkoff
51
54
  # @return [Checkoff::Projects]
52
55
  attr_reader :projects
53
56
 
57
+ # @return [Checkoff::CustomFields]
58
+ attr_reader :custom_fields
59
+
54
60
  # @return [Asana::Client]
55
61
  attr_reader :client
56
62
 
@@ -22,15 +22,18 @@ module Checkoff
22
22
  # @param config [Hash<Symbol, Object>]
23
23
  # @param workspaces [Checkoff::Workspaces]
24
24
  # @param sections [Checkoff::Sections]
25
+ # @param custom_fields [Checkoff::CustomFields]
25
26
  # @param clients [Checkoff::Clients]
26
27
  # @param client [Asana::Client]
27
28
  def initialize(config: Checkoff::Internal::ConfigLoader.load(:asana),
28
29
  workspaces: Checkoff::Workspaces.new(config: config),
29
30
  sections: Checkoff::Sections.new(config: config),
31
+ custom_fields: Checkoff::CustomFields.new(config: config),
30
32
  clients: Checkoff::Clients.new(config: config),
31
33
  client: clients.client)
32
34
  @workspaces = workspaces
33
35
  @sections = sections
36
+ @custom_fields = custom_fields
34
37
  @client = client
35
38
  end
36
39
 
@@ -40,7 +43,8 @@ module Checkoff
40
43
  # @return [Boolean]
41
44
  def filter_via_section_selector(section, section_selector)
42
45
  # @sg-ignore
43
- evaluator = SectionSelectorEvaluator.new(section: section, sections: sections, client: client)
46
+ evaluator = SectionSelectorEvaluator.new(section: section, sections: sections, custom_fields: custom_fields,
47
+ client: client)
44
48
  evaluator.evaluate(section_selector)
45
49
  end
46
50
 
@@ -52,6 +56,9 @@ module Checkoff
52
56
  # @return [Checkoff::Sections]
53
57
  attr_reader :sections
54
58
 
59
+ # @return [Checkoff::CustomFields]
60
+ attr_reader :custom_fields
61
+
55
62
  # @return [Asana::Client]
56
63
  attr_reader :client
57
64
 
@@ -29,10 +29,13 @@ module Checkoff
29
29
  tasks: Checkoff::Tasks.new(config: config,
30
30
  client: client),
31
31
  timelines: Checkoff::Timelines.new(config: config,
32
- client: client))
32
+ client: client),
33
+ custom_fields: Checkoff::CustomFields.new(config: config,
34
+ client: client))
33
35
  @config = config
34
36
  @tasks = tasks
35
37
  @timelines = timelines
38
+ @custom_fields = custom_fields
36
39
  end
37
40
 
38
41
  # @param [Asana::Resources::Task] task
@@ -40,7 +43,8 @@ module Checkoff
40
43
  # task details. Examples: [:tag, 'foo'] [:not, [:tag, 'foo']] [:tag, 'foo']
41
44
  # @return [Boolean]
42
45
  def filter_via_task_selector(task, task_selector)
43
- evaluator = TaskSelectorEvaluator.new(task: task, tasks: tasks, timelines: timelines)
46
+ evaluator = TaskSelectorEvaluator.new(task: task, tasks: tasks, timelines: timelines,
47
+ custom_fields: custom_fields)
44
48
  evaluator.evaluate(task_selector)
45
49
  end
46
50
 
@@ -52,6 +56,9 @@ module Checkoff
52
56
  # @return [Checkoff::Timelines]
53
57
  attr_reader :timelines
54
58
 
59
+ # @return [Checkoff::CustomFields]
60
+ attr_reader :custom_fields
61
+
55
62
  # bundle exec ./task_selectors.rb
56
63
  # :nocov:
57
64
  class << self
@@ -28,6 +28,7 @@ module Checkoff
28
28
  # @param workspaces [Checkoff::Workspaces]
29
29
  # @param sections [Checkoff::Sections]
30
30
  # @param portfolios [Checkoff::Portfolios]
31
+ # @param custom_fields [Checkoff::CustomFields]
31
32
  # @param time_class [Class<Time>]
32
33
  # @param date_class [Class<Date>]
33
34
  # @param asana_task [Class<Asana::Resources::Task>]
@@ -39,6 +40,8 @@ module Checkoff
39
40
  client: client),
40
41
  portfolios: Checkoff::Portfolios.new(config: config,
41
42
  client: client),
43
+ custom_fields: Checkoff::CustomFields.new(config: config,
44
+ client: client),
42
45
  time_class: Time,
43
46
  date_class: Date,
44
47
  asana_task: Asana::Resources::Task)
@@ -49,6 +52,7 @@ module Checkoff
49
52
  @asana_task = asana_task
50
53
  @client = client
51
54
  @portfolios = portfolios
55
+ @custom_fields = custom_fields
52
56
  @workspaces = workspaces
53
57
  @timing = Timing.new(today_getter: date_class, now_getter: time_class)
54
58
  end
@@ -73,7 +77,7 @@ module Checkoff
73
77
  end
74
78
 
75
79
  # @param task [Asana::Resources::Task]
76
- # @param field_name [Symbol]
80
+ # @param field_name [Symbol,Array]
77
81
  # @param period [Symbol<:now_or_before,:this_week>,Array] See Checkoff::Timing#in_period?_
78
82
  def in_period?(task, field_name, period)
79
83
  # @type [Date,Time,nil]
@@ -210,7 +214,9 @@ module Checkoff
210
214
 
211
215
  # @return [Checkoff::Internal::TaskTiming]
212
216
  def task_timing
213
- @task_timing ||= Checkoff::Internal::TaskTiming.new(time_class: @time_class, date_class: @date_class)
217
+ @task_timing ||= Checkoff::Internal::TaskTiming.new(time_class: @time_class, date_class: @date_class,
218
+ client: client,
219
+ custom_fields: custom_fields)
214
220
  end
215
221
 
216
222
  # @return [Checkoff::Internal::TaskHashes]
@@ -246,6 +252,9 @@ module Checkoff
246
252
  # @return [Checkoff::Timing]
247
253
  attr_reader :timing
248
254
 
255
+ # @return [Checkoff::CustomFields]
256
+ attr_reader :custom_fields
257
+
249
258
  # @return [Checkoff::Projects]
250
259
  def projects
251
260
  @projects ||= @sections.projects
@@ -68,6 +68,15 @@ module Checkoff
68
68
  date >= n_days_from_today
69
69
  end
70
70
 
71
+ # @param date_or_time [Date,Time,nil]
72
+ # @param num_days [Integer]
73
+ def greater_than_or_equal_to_n_days_from_now?(date_or_time, num_days)
74
+ return false if date_or_time.nil?
75
+
76
+ n_days_from_now = (@now_getter.now + (num_days * 24 * 60 * 60))
77
+ date_or_time >= n_days_from_now
78
+ end
79
+
71
80
  # @param date_or_time [Date,Time,nil]
72
81
  # @param num_days [Integer]
73
82
  def less_than_n_days_ago?(date_or_time, num_days)
@@ -81,6 +90,15 @@ module Checkoff
81
90
  date < n_days_ago
82
91
  end
83
92
 
93
+ # @param date_or_time [Date,Time,nil]
94
+ # @param num_days [Integer]
95
+ def less_than_n_days_from_now?(date_or_time, num_days)
96
+ return false if date_or_time.nil?
97
+
98
+ n_days_from_now = (@now_getter.now + (num_days * 24 * 60 * 60))
99
+ date_or_time < n_days_from_now
100
+ end
101
+
84
102
  # @param date_or_time [Date,Time,nil]
85
103
  def this_week?(date_or_time)
86
104
  return true if date_or_time.nil?
@@ -112,10 +130,17 @@ module Checkoff
112
130
  # @sg-ignore
113
131
  return less_than_n_days_ago?(date_or_time, *args) if period_name == :less_than_n_days_ago
114
132
 
133
+ return less_than_n_days_from_now?(date_or_time, *args) if period_name == :less_than_n_days_from_now
134
+
135
+ if period_name == :greater_than_or_equal_to_n_days_from_now
136
+ return greater_than_or_equal_to_n_days_from_now?(date_or_time,
137
+ *args)
138
+ end
139
+
115
140
  if period_name == :greater_than_or_equal_to_n_days_from_today
116
- return greater_than_or_equal_to_n_days_from_today?(date_or_time,
117
- *args)
141
+ return greater_than_or_equal_to_n_days_from_today?(date_or_time, *args)
118
142
  end
143
+
119
144
  raise "Teach me how to handle period [#{period_name.inspect}, #{args.join(', ')}]"
120
145
  end
121
146
 
@@ -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.109.0'
6
+ VERSION = '0.111.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.109.0
4
+ version: 0.111.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-28 00:00:00.000000000 Z
11
+ date: 2023-10-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport