asana 2.0.0 → 2.0.2

Sign up to get free protection for your applications and to get access to all the features.
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