asana 2.0.0 → 2.0.2

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.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/build.yml +1 -1
  3. data/.rubocop.yml +38 -3
  4. data/.ruby-version +1 -1
  5. data/Appraisals +8 -3
  6. data/Gemfile +7 -3
  7. data/Gemfile.lock +54 -64
  8. data/Guardfile +12 -10
  9. data/README.md +24 -12
  10. data/Rakefile +14 -17
  11. data/VERSION +1 -1
  12. data/asana.gemspec +20 -18
  13. data/examples/cli_app.rb +2 -2
  14. data/examples/events.rb +3 -3
  15. data/examples/personal_access_token.rb +2 -2
  16. data/lib/asana/authentication/oauth2/access_token_authentication.rb +4 -1
  17. data/lib/asana/authentication/oauth2/bearer_token_authentication.rb +3 -2
  18. data/lib/asana/authentication/oauth2/client.rb +2 -0
  19. data/lib/asana/authentication/oauth2.rb +6 -4
  20. data/lib/asana/authentication/token_authentication.rb +3 -1
  21. data/lib/asana/authentication.rb +2 -0
  22. data/lib/asana/client/configuration.rb +6 -5
  23. data/lib/asana/client.rb +13 -11
  24. data/lib/asana/errors.rb +16 -11
  25. data/lib/asana/http_client/environment_info.rb +9 -8
  26. data/lib/asana/http_client/error_handling.rb +23 -24
  27. data/lib/asana/http_client/response.rb +2 -0
  28. data/lib/asana/http_client.rb +66 -65
  29. data/lib/asana/resource_includes/attachment_uploading.rb +6 -6
  30. data/lib/asana/resource_includes/collection.rb +4 -4
  31. data/lib/asana/resource_includes/event.rb +2 -0
  32. data/lib/asana/resource_includes/event_subscription.rb +2 -0
  33. data/lib/asana/resource_includes/events.rb +4 -1
  34. data/lib/asana/resource_includes/registry.rb +2 -0
  35. data/lib/asana/resource_includes/resource.rb +8 -5
  36. data/lib/asana/resource_includes/response_helper.rb +2 -0
  37. data/lib/asana/resources/audit_log_api.rb +42 -0
  38. data/lib/asana/resources/gen/attachments_base.rb +1 -1
  39. data/lib/asana/resources/gen/audit_log_api_base.rb +1 -1
  40. data/lib/asana/resources/gen/memberships_base.rb +71 -0
  41. data/lib/asana/resources/gen/tasks_base.rb +1 -1
  42. data/lib/asana/resources/goal.rb +54 -0
  43. data/lib/asana/resources/goal_relationship.rb +32 -0
  44. data/lib/asana/resources/membership.rb +20 -0
  45. data/lib/asana/resources/project_brief.rb +30 -0
  46. data/lib/asana/resources/project_template.rb +36 -0
  47. data/lib/asana/resources/status_update.rb +54 -0
  48. data/lib/asana/resources/time_period.rb +30 -0
  49. data/lib/asana/resources/typeahead.rb +1 -1
  50. data/lib/asana/resources.rb +4 -4
  51. data/lib/asana/ruby2_0_0_compatibility.rb +2 -0
  52. data/lib/asana/version.rb +1 -1
  53. data/lib/asana.rb +2 -0
  54. data/samples/memberships_sample.yaml +41 -0
  55. metadata +57 -46
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Asana
2
4
  module Authentication
3
5
  module OAuth2
@@ -24,8 +26,7 @@ module Asana
24
26
  #
25
27
  # Returns nothing.
26
28
  def configure(connection)
27
- connection.authorization :Bearer, @token
28
- connection.request :oauth2, token_type: 'bearer'
29
+ connection.request :authorization, 'Bearer', @token
29
30
  end
30
31
  end
31
32
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'oauth2'
2
4
 
3
5
  module Asana
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'oauth2/bearer_token_authentication'
2
4
  require_relative 'oauth2/access_token_authentication'
3
5
  require_relative 'oauth2/client'
@@ -31,10 +33,10 @@ module Asana
31
33
  client = Client.new(client_id: client_id,
32
34
  client_secret: client_secret,
33
35
  redirect_uri: 'urn:ietf:wg:oauth:2.0:oob')
34
- STDOUT.puts '1. Go to the following URL to authorize the ' \
35
- " application: #{client.authorize_url}"
36
- STDOUT.puts '2. Paste the authorization code here: '
37
- auth_code = STDIN.gets.chomp
36
+ $stdout.puts '1. Go to the following URL to authorize the ' \
37
+ "application: #{client.authorize_url}"
38
+ $stdout.puts '2. Paste the authorization code here: '
39
+ auth_code = $stdin.gets.chomp
38
40
  client.token_from_auth_code(auth_code)
39
41
  end
40
42
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Asana
2
4
  module Authentication
3
5
  # Public: Represents an API token authentication mechanism.
@@ -13,7 +15,7 @@ module Asana
13
15
  #
14
16
  # Returns nothing.
15
17
  def configure(connection)
16
- connection.basic_auth(@token, '')
18
+ connection.request :authorization, :basic, @token, ''
17
19
  end
18
20
  end
19
21
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'authentication/oauth2'
2
4
  require_relative 'authentication/token_authentication'
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Asana
2
4
  class Client
3
5
  # Internal: Represents a configuration DSL for an Asana::Client.
@@ -17,7 +19,7 @@ module Asana
17
19
  # Public: Initializes an empty configuration object.
18
20
  def initialize
19
21
  @configuration = {
20
- :log_asana_change_warnings => true
22
+ log_asana_change_warnings: true
21
23
  }
22
24
  end
23
25
 
@@ -100,7 +102,6 @@ module Asana
100
102
  #
101
103
  # Raises ArgumentError if the OAuth2 configuration arguments are invalid.
102
104
  #
103
- # rubocop:disable Metrics/MethodLength
104
105
  def oauth2(value)
105
106
  case value
106
107
  when ::OAuth2::AccessToken
@@ -111,8 +112,8 @@ module Asana
111
112
  from_bearer_token(value[:bearer_token])
112
113
  else
113
114
  error 'Invalid OAuth2 configuration: pass in either an ' \
114
- '::OAuth2::AccessToken object of your own or a hash ' \
115
- 'containing :refresh_token or :bearer_token.'
115
+ '::OAuth2::AccessToken object of your own or a hash ' \
116
+ 'containing :refresh_token or :bearer_token.'
116
117
  end
117
118
  end
118
119
 
@@ -158,7 +159,7 @@ module Asana
158
159
  end
159
160
 
160
161
  def requiring(hash, *keys)
161
- missing_keys = keys.select { |k| !hash.key?(k) }
162
+ missing_keys = keys.reject { |k| hash.key?(k) }
162
163
  missing_keys.any? && error("Missing keys: #{missing_keys.join(', ')}")
163
164
  keys.map { |k| hash[k] }
164
165
  end
data/lib/asana/client.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'authentication'
2
4
  require_relative 'client/configuration'
3
5
  require_relative 'resources'
@@ -59,12 +61,12 @@ module Asana
59
61
  @resource = resource
60
62
  end
61
63
 
62
- def method_missing(m, *args, **kwargs, &block)
63
- @resource.public_send(m, *([@client] + args), **kwargs, &block)
64
+ def method_missing(method_name, *args, **kwargs, &block)
65
+ @resource.public_send(method_name, *([@client] + args), **kwargs, &block)
64
66
  end
65
67
 
66
- def respond_to_missing?(m, *)
67
- @resource.respond_to?(m)
68
+ def respond_to_missing?(method_name, *)
69
+ @resource.respond_to?(method_name)
68
70
  end
69
71
  end
70
72
 
@@ -72,15 +74,15 @@ module Asana
72
74
  #
73
75
  # Yields a {Asana::Client::Configuration} object as a configuration
74
76
  # DSL. See {Asana::Client} for usage examples.
75
- def initialize
76
- config = Configuration.new.tap { |c| yield c }.to_h
77
+ def initialize(&block)
78
+ config = Configuration.new.tap(&block).to_h
77
79
  @http_client =
78
- HttpClient.new(authentication: config.fetch(:authentication),
79
- adapter: config[:faraday_adapter],
80
- user_agent: config[:user_agent],
81
- debug_mode: config[:debug_mode],
80
+ HttpClient.new(authentication: config.fetch(:authentication),
81
+ adapter: config[:faraday_adapter],
82
+ user_agent: config[:user_agent],
83
+ debug_mode: config[:debug_mode],
82
84
  log_asana_change_warnings: config[:log_asana_change_warnings],
83
- default_headers: config[:default_headers],
85
+ default_headers: config[:default_headers],
84
86
  &config[:faraday_configuration])
85
87
  end
86
88
 
data/lib/asana/errors.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Asana
2
4
  # Public: Defines the different errors that the Asana API may throw, which the
3
5
  # client code may want to catch.
@@ -19,8 +21,8 @@ module Asana
19
21
  # user could not be authenticated.
20
22
  NotAuthorized = Class.new(APIError) do
21
23
  def to_s
22
- 'Valid credentials were not provided with the request, so the API could '\
23
- 'not associate a user with the request.'
24
+ 'Valid credentials were not provided with the request, so the API could ' \
25
+ 'not associate a user with the request.'
24
26
  end
25
27
  end
26
28
 
@@ -28,8 +30,8 @@ module Asana
28
30
  # that requires a premium account (Payment Required).
29
31
  PremiumOnly = Class.new(APIError) do
30
32
  def to_s
31
- 'The endpoint that is being requested is only available to premium '\
32
- 'users.'
33
+ 'The endpoint that is being requested is only available to premium ' \
34
+ 'users.'
33
35
  end
34
36
  end
35
37
 
@@ -37,18 +39,18 @@ module Asana
37
39
  # access the requested resource or to perform the requested action on it.
38
40
  Forbidden = Class.new(APIError) do
39
41
  def to_s
40
- 'The authorization and request syntax was valid but the server is refusing '\
41
- 'to complete the request. This can happen if you try to read or write '\
42
- 'to objects or properties that the user does not have access to.'
42
+ 'The authorization and request syntax was valid but the server is refusing ' \
43
+ 'to complete the request. This can happen if you try to read or write ' \
44
+ 'to objects or properties that the user does not have access to.'
43
45
  end
44
46
  end
45
47
 
46
48
  # Public: A 404 error. Raised when the requested resource doesn't exist.
47
49
  NotFound = Class.new(APIError) do
48
50
  def to_s
49
- 'Either the request method and path supplied do not specify a known '\
50
- 'action in the API, or the object specified by the request does not '\
51
- 'exist.'
51
+ 'Either the request method and path supplied do not specify a known ' \
52
+ 'action in the API, or the object specified by the request does not ' \
53
+ 'exist.'
52
54
  end
53
55
  end
54
56
 
@@ -59,11 +61,12 @@ module Asana
59
61
  attr_accessor :phrase
60
62
 
61
63
  def initialize(phrase)
64
+ super()
62
65
  @phrase = phrase
63
66
  end
64
67
 
65
68
  def to_s
66
- "There has been an error on Asana's end. Use this unique phrase to "\
69
+ "There has been an error on Asana's end. Use this unique phrase to " \
67
70
  'identify the problem when contacting support: ' + %("#{@phrase}")
68
71
  end
69
72
  end
@@ -74,6 +77,7 @@ module Asana
74
77
  attr_accessor :errors
75
78
 
76
79
  def initialize(errors)
80
+ super()
77
81
  @errors = errors
78
82
  end
79
83
 
@@ -89,6 +93,7 @@ module Asana
89
93
  attr_accessor :retry_after_seconds
90
94
 
91
95
  def initialize(retry_after_seconds)
96
+ super()
92
97
  @retry_after_seconds = retry_after_seconds
93
98
  end
94
99
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative '../version'
2
4
  require 'openssl'
3
5
 
@@ -6,7 +8,7 @@ module Asana
6
8
  # Internal: Adds environment information to a Faraday request.
7
9
  class EnvironmentInfo
8
10
  # Internal: The default user agent to use in all requests to the API.
9
- USER_AGENT = "ruby-asana v#{Asana::VERSION}".freeze
11
+ USER_AGENT = "ruby-asana v#{Asana::VERSION}"
10
12
 
11
13
  def initialize(user_agent = nil)
12
14
  @user_agent = user_agent || USER_AGENT
@@ -19,7 +21,7 @@ module Asana
19
21
  # environment.
20
22
  def configure(builder)
21
23
  builder.headers[:user_agent] = @user_agent
22
- builder.headers[:"X-Asana-Client-Lib"] = header
24
+ builder.headers[:'X-Asana-Client-Lib'] = header
23
25
  end
24
26
 
25
27
  private
@@ -33,21 +35,20 @@ module Asana
33
35
  .map { |k, v| "#{k}=#{v}" }.join('&')
34
36
  end
35
37
 
36
- # rubocop:disable Metrics/MethodLength
37
38
  def os
38
- if RUBY_PLATFORM =~ /win32/ || RUBY_PLATFORM =~ /mingw/
39
+ case RUBY_PLATFORM
40
+ when /win32/, /mingw/
39
41
  'windows'
40
- elsif RUBY_PLATFORM =~ /linux/
42
+ when /linux/
41
43
  'linux'
42
- elsif RUBY_PLATFORM =~ /darwin/
44
+ when /darwin/
43
45
  'darwin'
44
- elsif RUBY_PLATFORM =~ /freebsd/
46
+ when /freebsd/
45
47
  'freebsd'
46
48
  else
47
49
  'unknown'
48
50
  end
49
51
  end
50
- # rubocop:enable Metrics/MethodLength
51
52
  end
52
53
  end
53
54
  end
@@ -1,4 +1,4 @@
1
- require 'multi_json'
1
+ # frozen_string_literal: true
2
2
 
3
3
  require_relative '../errors'
4
4
 
@@ -27,37 +27,34 @@ module Asana
27
27
  # Raises [Asana::Errors::ServerError] when there's a server problem.
28
28
  # Raises [Asana::Errors::APIError] when the API returns an unknown error.
29
29
  #
30
- # rubocop:disable all
31
- def handle(num_retries=0, &request)
30
+ # rubocop:disable Metrics/AbcSize
31
+ def handle(num_retries = 0, &request)
32
32
  request.call
33
33
  rescue Faraday::ClientError => e
34
34
  raise e unless e.response
35
+
35
36
  case e.response[:status]
36
- when 400 then raise invalid_request(e.response)
37
- when 401 then raise not_authorized(e.response)
38
- when 402 then raise payment_required(e.response)
39
- when 403 then raise forbidden(e.response)
40
- when 404 then raise not_found(e.response)
41
- when 412 then recover_response(e.response)
42
- when 429 then raise rate_limit_enforced(e.response)
43
- when 500 then raise server_error(e.response)
44
- else raise api_error(e.response)
37
+ when 400 then raise invalid_request(e.response)
38
+ when 401 then raise not_authorized(e.response)
39
+ when 402 then raise payment_required(e.response)
40
+ when 403 then raise forbidden(e.response)
41
+ when 404 then raise not_found(e.response)
42
+ when 412 then recover_response(e.response)
43
+ when 429 then raise rate_limit_enforced(e.response)
44
+ when 500 then raise server_error(e.response)
45
+ else raise api_error(e.response)
45
46
  end
46
47
  # Retry for timeouts or 500s from Asana
47
48
  rescue Faraday::ServerError => e
48
- if num_retries < MAX_RETRIES
49
- handle(num_retries + 1, &request)
50
- else
51
- raise server_error(e.response)
52
- end
49
+ raise server_error(e.response) unless num_retries < MAX_RETRIES
50
+
51
+ handle(num_retries + 1, &request)
53
52
  rescue Net::ReadTimeout => e
54
- if num_retries < MAX_RETRIES
55
- handle(num_retries + 1, &request)
56
- else
57
- raise e
58
- end
53
+ raise e unless num_retries < MAX_RETRIES
54
+
55
+ handle(num_retries + 1, &request)
59
56
  end
60
- # rubocop:enable all
57
+ # rubocop:enable Metrics/AbcSize
61
58
 
62
59
  # Internal: Returns an InvalidRequest exception including a list of
63
60
  # errors.
@@ -112,13 +109,15 @@ module Asana
112
109
 
113
110
  # Internal: Parser a response body from JSON.
114
111
  def body(response)
115
- MultiJson.load(response[:body])
112
+ JSON.parse(response[:body])
116
113
  end
117
114
 
115
+ # rubocop:disable Style/OpenStructUse
118
116
  def recover_response(response)
119
117
  r = response.dup.tap { |res| res[:body] = body(response) }
120
118
  Response.new(OpenStruct.new(env: OpenStruct.new(r)))
121
119
  end
120
+ # rubocop:enable Style/OpenStructUse
122
121
  end
123
122
  end
124
123
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Asana
2
4
  class HttpClient
3
5
  # Internal: Represents a response from the Asana API.
@@ -1,6 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'faraday'
2
- require 'faraday_middleware'
3
- require 'faraday_middleware/multi_json'
4
+ require 'faraday/follow_redirects'
4
5
 
5
6
  require_relative 'http_client/error_handling'
6
7
  require_relative 'http_client/environment_info'
@@ -11,7 +12,7 @@ module Asana
11
12
  # parsing and common options.
12
13
  class HttpClient
13
14
  # Internal: The API base URI.
14
- BASE_URI = 'https://app.asana.com/api/1.0'.freeze
15
+ BASE_URI = 'https://app.asana.com/api/1.0'
15
16
 
16
17
  # Public: Initializes an HttpClient to make requests to the Asana API.
17
18
  #
@@ -130,7 +131,8 @@ module Asana
130
131
  yield builder if request_config
131
132
  configure_format(builder)
132
133
  add_middleware(builder)
133
- @config.call(builder) if @config
134
+ configure_redirects(builder)
135
+ @config&.call(builder)
134
136
  use_adapter(builder, @adapter)
135
137
  end
136
138
  end
@@ -147,13 +149,16 @@ module Asana
147
149
  end
148
150
 
149
151
  def configure_format(builder)
150
- builder.request :multi_json
151
- builder.response :multi_json
152
+ builder.request :json
153
+ builder.response :json
152
154
  end
153
155
 
154
156
  def add_middleware(builder)
155
157
  builder.use Faraday::Response::RaiseError
156
- builder.use FaradayMiddleware::FollowRedirects
158
+ end
159
+
160
+ def configure_redirects(builder)
161
+ builder.response :follow_redirects
157
162
  end
158
163
 
159
164
  def use_adapter(builder, adapter)
@@ -170,79 +175,75 @@ module Asana
170
175
  end
171
176
 
172
177
  def log_request(method, url, body)
173
- STDERR.puts format('[%s] %s %s (%s)',
174
- self.class,
175
- method.to_s.upcase,
176
- url,
177
- body.inspect)
178
+ warn format('[%<klass>s] %<method>s %<url>s (%<bodt>s)',
179
+ klass: self.class,
180
+ method: method.to_s.upcase,
181
+ url: url,
182
+ body: body.inspect)
178
183
  end
179
184
 
185
+ # rubocop:disable Metrics/AbcSize
186
+ # rubocop:disable Metrics/MethodLength
180
187
  def log_asana_change_headers(request_headers, response_headers)
181
188
  change_header_key = nil
182
189
 
183
190
  response_headers.each_key do |key|
184
- if key.downcase == 'asana-change'
185
- change_header_key = key
186
- end
191
+ change_header_key = key if key.downcase == 'asana-change'
187
192
  end
188
193
 
189
- if change_header_key != nil
190
- accounted_for_flags = Array.new
194
+ return if change_header_key.nil?
191
195
 
192
- if request_headers == nil
193
- request_headers = {}
194
- end
195
- # Grab the request's asana-enable flags
196
- request_headers.each_key do |req_header|
197
- if req_header.downcase == 'asana-enable'
198
- request_headers[req_header].split(',').each do |flag|
199
- accounted_for_flags.push(flag)
200
- end
201
- elsif req_header.downcase == 'asana-disable'
202
- request_headers[req_header].split(',').each do |flag|
203
- accounted_for_flags.push(flag)
204
- end
196
+ accounted_for_flags = []
197
+
198
+ request_headers = {} if request_headers.nil?
199
+ # Grab the request's asana-enable flags
200
+ request_headers.each_key do |req_header|
201
+ case req_header.downcase
202
+ when 'asana-enable', 'asana-disable'
203
+ request_headers[req_header].split(',').each do |flag|
204
+ accounted_for_flags.push(flag)
205
205
  end
206
206
  end
207
+ end
208
+
209
+ changes = response_headers[change_header_key].split(',')
207
210
 
208
- changes = response_headers[change_header_key].split(',')
209
-
210
- changes.each do |unsplit_change|
211
- change = unsplit_change.split(';')
212
-
213
- name = nil
214
- info = nil
215
- affected = nil
216
-
217
- change.each do |unsplit_field|
218
- field = unsplit_field.split('=')
219
-
220
- field[0].strip!
221
- field[1].strip!
222
- if field[0] == 'name'
223
- name = field[1]
224
- elsif field[0] == 'info'
225
- info = field[1]
226
- elsif field[0] == 'affected'
227
- affected = field[1]
228
- end
229
-
230
- # Only show the error if the flag was not in the request's asana-enable header
231
- if !(accounted_for_flags.include? name) && (affected == 'true')
232
- message1 = 'This request is affected by the "%s"' +
233
- ' deprecation. Please visit this url for more info: %s'
234
- message2 = 'Adding "%s" to your "Asana-Enable" or ' +
235
- '"Asana-Disable" header will opt in/out to this deprecation ' +
236
- 'and suppress this warning.'
237
-
238
- STDERR.puts format(message1, name, info)
239
- STDERR.puts format(message2, name)
240
- end
211
+ changes.each do |unsplit_change|
212
+ change = unsplit_change.split(';')
213
+
214
+ name = nil
215
+ info = nil
216
+ affected = nil
217
+
218
+ change.each do |unsplit_field|
219
+ field = unsplit_field.split('=')
220
+
221
+ field[0].strip!
222
+ field[1].strip!
223
+ case field[0]
224
+ when 'name'
225
+ name = field[1]
226
+ when 'info'
227
+ info = field[1]
228
+ when 'affected'
229
+ affected = field[1]
241
230
  end
231
+
232
+ # Only show the error if the flag was not in the request's asana-enable header
233
+ next unless !(accounted_for_flags.include? name) && (affected == 'true')
234
+
235
+ message1 = 'This request is affected by the "%s" ' \
236
+ 'deprecation. Please visit this url for more info: %s'
237
+ message2 = 'Adding "%s" to your "Asana-Enable" or ' \
238
+ '"Asana-Disable" header will opt in/out to this deprecation ' \
239
+ 'and suppress this warning.'
240
+
241
+ warn format(message1, name, info)
242
+ warn format(message2, name)
242
243
  end
243
244
  end
244
245
  end
246
+ # rubocop:enable Metrics/AbcSize
247
+ # rubocop:enable Metrics/MethodLength
245
248
  end
246
249
  end
247
-
248
-
@@ -1,3 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'faraday/multipart'
4
+
1
5
  module Asana
2
6
  module Resources
3
7
  # Internal: Mixin to add the ability to upload an attachment to a specific
@@ -11,8 +15,6 @@ module Asana
11
15
  # options - [Hash] the request I/O options
12
16
  # data - [Hash] extra attributes to post
13
17
  #
14
- # rubocop:disable Metrics/AbcSize
15
- # rubocop:disable Metrics/MethodLength
16
18
  def attach(filename: required('filename'),
17
19
  mime: required('mime'),
18
20
  io: nil, options: {}, **data)
@@ -21,9 +23,9 @@ module Asana
21
23
  path = File.expand_path(filename)
22
24
  raise ArgumentError, "file #{filename} doesn't exist" unless File.exist?(path)
23
25
 
24
- Faraday::FilePart.new(path, mime)
26
+ Faraday::Multipart::FilePart.new(path, mime)
25
27
  else
26
- Faraday::FilePart.new(io, mime, filename)
28
+ Faraday::Multipart::FilePart.new(io, mime, filename)
27
29
  end
28
30
 
29
31
  response = client.post("/#{self.class.plural_name}/#{gid}/attachments",
@@ -33,8 +35,6 @@ module Asana
33
35
 
34
36
  Attachment.new(parse(response).first, client: client)
35
37
  end
36
- # rubocop:enable Metrics/MethodLength
37
- # rubocop:enable Metrics/AbcSize
38
38
  end
39
39
  end
40
40
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'response_helper'
2
4
 
3
5
  module Asana
@@ -40,7 +42,7 @@ module Asana
40
42
  def last
41
43
  @elements.last
42
44
  end
43
-
45
+
44
46
  # Public: Returns the size of the collection.
45
47
  def size
46
48
  to_a.size
@@ -49,9 +51,7 @@ module Asana
49
51
 
50
52
  # Public: Returns a String representation of the collection.
51
53
  def to_s
52
- "#<Asana::Collection<#{@type}> " \
53
- "[#{@elements.map(&:inspect).join(', ')}" +
54
- (@next_page_data ? ', ...' : '') + ']>'
54
+ "#<Asana::Collection<#{@type}> [#{@elements.map(&:inspect).join(', ')}#{@next_page_data ? ', ...' : ''}]>"
55
55
  end
56
56
  alias inspect to_s
57
57
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'events'
2
4
 
3
5
  module Asana
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'events'
2
4
 
3
5
  module Asana
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'event'
2
4
 
3
5
  module Asana
@@ -89,13 +91,14 @@ module Asana
89
91
 
90
92
  # Internal: Returns the formatted params for the poll request.
91
93
  def params
92
- { resource: @resource, sync: @sync }.reject { |_, v| v.nil? }
94
+ { resource: @resource, sync: @sync }.compact
93
95
  end
94
96
 
95
97
  # Internal: Executes a block if at least @wait seconds have passed since
96
98
  # @last_poll.
97
99
  def rate_limiting
98
100
  return if @last_poll && Time.now - @last_poll <= @wait
101
+
99
102
  yield.tap { @last_poll = Time.now }
100
103
  end
101
104
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'resource'
2
4
  require 'set'
3
5