checkoff 0.109.0 → 0.111.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: 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