whatsapp_sdk 0.1.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,25 +6,45 @@ require "oj"
6
6
  module WhatsappSdk
7
7
  module Api
8
8
  class Client
9
- API_VERSION = "v13.0"
9
+ API_VERSION = "v14.0"
10
10
  API_CLIENT = "https://graph.facebook.com/#{API_VERSION}/"
11
11
 
12
12
  def initialize(access_token)
13
13
  @access_token = access_token
14
14
  end
15
15
 
16
- def client
17
- @client ||= ::Faraday.new(API_CLIENT) do |client|
16
+ def send_request(endpoint: "", full_url: nil, http_method: "post", params: {})
17
+ url = full_url || API_CLIENT
18
+
19
+ response = faraday(url).public_send(http_method, endpoint, params)
20
+ Oj.load(response.body)
21
+ end
22
+
23
+ def download_file(url, path_to_file_name = nil)
24
+ uri = URI.parse(url)
25
+ request = Net::HTTP::Get.new(uri)
26
+ request["Authorization"] = "Bearer #{@access_token}"
27
+ req_options = { use_ssl: uri.scheme == "https" }
28
+
29
+ response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
30
+ http.request(request)
31
+ end
32
+
33
+ File.write(path_to_file_name, response.body) if response.code == "200" && path_to_file_name
34
+
35
+ response
36
+ end
37
+
38
+ private
39
+
40
+ def faraday(url)
41
+ ::Faraday.new(url) do |client|
42
+ client.request :multipart
18
43
  client.request :url_encoded
19
44
  client.adapter ::Faraday.default_adapter
20
45
  client.headers['Authorization'] = "Bearer #{@access_token}" unless @access_token.nil?
21
46
  end
22
47
  end
23
-
24
- def send_request(endpoint:, http_method: "post", params: {})
25
- response = client.public_send(http_method, endpoint, params)
26
- Oj.load(response.body)
27
- end
28
48
  end
29
49
  end
30
50
  end
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "faraday"
4
+ require "faraday/multipart"
5
+
6
+ require_relative "request"
7
+ require_relative "response"
8
+ require_relative '../../../lib/whatsapp_sdk/api/responses/media_data_response'
9
+ require_relative '../../../lib/whatsapp_sdk/api/responses/success_response'
10
+
11
+ module WhatsappSdk
12
+ module Api
13
+ class Medias < Request
14
+ class FileNotFoundError < StandardError
15
+ attr_reader :file_path
16
+
17
+ def initialize(file_path)
18
+ @file_path = file_path
19
+ super("Couldn't find file_path: #{file_path}")
20
+ end
21
+ end
22
+
23
+ # Get Media by ID.
24
+ #
25
+ # @param media_id [Integer] Media Id.
26
+ # @return [WhatsappSdk::Api::Response] Response object.
27
+ def media(media_id:)
28
+ response = send_request(
29
+ http_method: "get",
30
+ endpoint: "/#{media_id}"
31
+ )
32
+
33
+ WhatsappSdk::Api::Response.new(
34
+ response: response,
35
+ data_class_type: WhatsappSdk::Api::Responses::MediaDataResponse
36
+ )
37
+ end
38
+
39
+ # Download Media by URL.
40
+ #
41
+ # @param media_id [Integer] Media Id.
42
+ # @param file_path [String] The file_path to download the media e.g. "tmp/downloaded_image.png".
43
+ # @return [WhatsappSdk::Api::Response] Response object.
44
+ def download(url:, file_path:)
45
+ response = download_file(url, file_path)
46
+
47
+ response = if response.code.to_i == 200
48
+ { "success" => true }
49
+ else
50
+ { "error" => true, "status" => response.code }
51
+ end
52
+
53
+ WhatsappSdk::Api::Response.new(
54
+ response: response,
55
+ data_class_type: WhatsappSdk::Api::Responses::SuccessResponse,
56
+ error_class_type: WhatsappSdk::Api::Responses::ErrorResponse
57
+ )
58
+ end
59
+
60
+ # Upload a media.
61
+ # @param sender_id [Integer] Sender' phone number.
62
+ # @param file_path [String] Path to the file stored in your local directory. For example: "tmp/whatsapp.png".
63
+ # @param type [String] Media type e.g. text/plain, video/3gp, image/jpeg, image/png. For more information,
64
+ # see the official documentation https://developers.facebook.com/docs/whatsapp/cloud-api/reference/media#supported-media-types.
65
+ #
66
+ # @return [WhatsappSdk::Api::Response] Response object.
67
+ def upload(sender_id:, file_path:, type:)
68
+ raise FileNotFoundError, file_path unless File.file?(file_path)
69
+
70
+ params = {
71
+ messaging_product: "whatsapp",
72
+ file: Faraday::FilePart.new(file_path, type),
73
+ type: type
74
+ }
75
+
76
+ response = send_request(http_method: "post", endpoint: "#{sender_id}/media", params: params)
77
+
78
+ WhatsappSdk::Api::Response.new(
79
+ response: response,
80
+ data_class_type: WhatsappSdk::Api::Responses::MediaDataResponse
81
+ )
82
+ end
83
+
84
+ # Delete a Media by ID.
85
+ #
86
+ # @param media_id [Integer] Media Id.
87
+ # @return [WhatsappSdk::Api::Response] Response object.
88
+ def delete(media_id:)
89
+ response = send_request(
90
+ http_method: "delete",
91
+ endpoint: "/#{media_id}"
92
+ )
93
+
94
+ WhatsappSdk::Api::Response.new(
95
+ response: response,
96
+ data_class_type: WhatsappSdk::Api::Responses::SuccessResponse
97
+ )
98
+ end
99
+ end
100
+ end
101
+ end
@@ -27,7 +27,7 @@ module WhatsappSdk
27
27
  to: recipient_number,
28
28
  recipient_type: "individual",
29
29
  type: "text",
30
- "text": { body: message }
30
+ text: { body: message }
31
31
  }
32
32
 
33
33
  response = send_request(
@@ -35,7 +35,10 @@ module WhatsappSdk
35
35
  params: params
36
36
  )
37
37
 
38
- WhatsappSdk::Api::Response.new(response: response, class_type: WhatsappSdk::Api::Responses::MessageDataResponse)
38
+ WhatsappSdk::Api::Response.new(
39
+ response: response,
40
+ data_class_type: WhatsappSdk::Api::Responses::MessageDataResponse
41
+ )
39
42
  end
40
43
 
41
44
  # Send location.
@@ -53,11 +56,11 @@ module WhatsappSdk
53
56
  to: recipient_number,
54
57
  recipient_type: "individual",
55
58
  type: "location",
56
- "location": {
57
- "longitude": longitude,
58
- "latitude": latitude,
59
- "name": name,
60
- "address": address
59
+ location: {
60
+ longitude: longitude,
61
+ latitude: latitude,
62
+ name: name,
63
+ address: address
61
64
  }
62
65
  }
63
66
 
@@ -66,7 +69,10 @@ module WhatsappSdk
66
69
  params: params
67
70
  )
68
71
 
69
- WhatsappSdk::Api::Response.new(response: response, class_type: WhatsappSdk::Api::Responses::MessageDataResponse)
72
+ WhatsappSdk::Api::Response.new(
73
+ response: response,
74
+ data_class_type: WhatsappSdk::Api::Responses::MessageDataResponse
75
+ )
70
76
  end
71
77
 
72
78
  # Send an image.
@@ -97,7 +103,10 @@ module WhatsappSdk
97
103
  params: params
98
104
  )
99
105
 
100
- WhatsappSdk::Api::Response.new(response: response, class_type: WhatsappSdk::Api::Responses::MessageDataResponse)
106
+ WhatsappSdk::Api::Response.new(
107
+ response: response,
108
+ data_class_type: WhatsappSdk::Api::Responses::MessageDataResponse
109
+ )
101
110
  end
102
111
 
103
112
  # Send an audio.
@@ -123,7 +132,10 @@ module WhatsappSdk
123
132
  params: params
124
133
  )
125
134
 
126
- WhatsappSdk::Api::Response.new(response: response, class_type: WhatsappSdk::Api::Responses::MessageDataResponse)
135
+ WhatsappSdk::Api::Response.new(
136
+ response: response,
137
+ data_class_type: WhatsappSdk::Api::Responses::MessageDataResponse
138
+ )
127
139
  end
128
140
 
129
141
  # Send a video.
@@ -154,7 +166,10 @@ module WhatsappSdk
154
166
  params: params
155
167
  )
156
168
 
157
- WhatsappSdk::Api::Response.new(response: response, class_type: WhatsappSdk::Api::Responses::MessageDataResponse)
169
+ WhatsappSdk::Api::Response.new(
170
+ response: response,
171
+ data_class_type: WhatsappSdk::Api::Responses::MessageDataResponse
172
+ )
158
173
  end
159
174
 
160
175
  # Send a document.
@@ -185,7 +200,10 @@ module WhatsappSdk
185
200
  params: params
186
201
  )
187
202
 
188
- WhatsappSdk::Api::Response.new(response: response, class_type: WhatsappSdk::Api::Responses::MessageDataResponse)
203
+ WhatsappSdk::Api::Response.new(
204
+ response: response,
205
+ data_class_type: WhatsappSdk::Api::Responses::MessageDataResponse
206
+ )
189
207
  end
190
208
 
191
209
  # Send a document.
@@ -210,7 +228,10 @@ module WhatsappSdk
210
228
  params: params
211
229
  )
212
230
 
213
- WhatsappSdk::Api::Response.new(response: response, class_type: WhatsappSdk::Api::Responses::MessageDataResponse)
231
+ WhatsappSdk::Api::Response.new(
232
+ response: response,
233
+ data_class_type: WhatsappSdk::Api::Responses::MessageDataResponse
234
+ )
214
235
  end
215
236
 
216
237
  # Send contacts.
@@ -235,7 +256,10 @@ module WhatsappSdk
235
256
  params: params
236
257
  )
237
258
 
238
- WhatsappSdk::Api::Response.new(response: response, class_type: WhatsappSdk::Api::Responses::MessageDataResponse)
259
+ WhatsappSdk::Api::Response.new(
260
+ response: response,
261
+ data_class_type: WhatsappSdk::Api::Responses::MessageDataResponse
262
+ )
239
263
  end
240
264
 
241
265
  def send_interactive_button
@@ -269,7 +293,7 @@ module WhatsappSdk
269
293
 
270
294
  WhatsappSdk::Api::Response.new(
271
295
  response: response,
272
- class_type: WhatsappSdk::Api::Responses::ReadMessageDataResponse
296
+ data_class_type: WhatsappSdk::Api::Responses::ReadMessageDataResponse
273
297
  )
274
298
  end
275
299
 
@@ -309,7 +333,7 @@ module WhatsappSdk
309
333
 
310
334
  WhatsappSdk::Api::Response.new(
311
335
  response: response,
312
- class_type: WhatsappSdk::Api::Responses::MessageDataResponse
336
+ data_class_type: WhatsappSdk::Api::Responses::MessageDataResponse
313
337
  )
314
338
  end
315
339
 
@@ -16,8 +16,10 @@ module WhatsappSdk
16
16
  endpoint: "#{business_id}/phone_numbers"
17
17
  )
18
18
 
19
- WhatsappSdk::Api::Response.new(response: response,
20
- class_type: WhatsappSdk::Api::Responses::PhoneNumbersDataResponse)
19
+ WhatsappSdk::Api::Response.new(
20
+ response: response,
21
+ data_class_type: WhatsappSdk::Api::Responses::PhoneNumbersDataResponse
22
+ )
21
23
  end
22
24
 
23
25
  # Get the registered number id.
@@ -30,8 +32,10 @@ module WhatsappSdk
30
32
  endpoint: phone_number_id.to_s
31
33
  )
32
34
 
33
- WhatsappSdk::Api::Response.new(response: response,
34
- class_type: WhatsappSdk::Api::Responses::PhoneNumberDataResponse)
35
+ WhatsappSdk::Api::Response.new(
36
+ response: response,
37
+ data_class_type: WhatsappSdk::Api::Responses::PhoneNumberDataResponse
38
+ )
35
39
  end
36
40
  end
37
41
  end
@@ -3,15 +3,21 @@
3
3
  module WhatsappSdk
4
4
  module Api
5
5
  class Request
6
- API_VERSION = "v13.0"
6
+ API_VERSION = "v14.0"
7
7
  API_CLIENT = "https://graph.facebook.com/#{API_VERSION}/"
8
8
 
9
- def initialize(client)
9
+ def initialize(client = WhatsappSdk.configuration.client)
10
10
  @client = client
11
11
  end
12
12
 
13
- def send_request(endpoint:, http_method: "post", params: {})
14
- @client.send_request(http_method: http_method, endpoint: endpoint, params: params)
13
+ def download_file(url, path_to_file_name = nil)
14
+ @client.download_file(url, path_to_file_name)
15
+ end
16
+
17
+ def send_request(endpoint: nil, full_url: nil, http_method: "post", params: {})
18
+ @client.send_request(
19
+ http_method: http_method, full_url: full_url, endpoint: endpoint, params: params
20
+ )
15
21
  end
16
22
  end
17
23
  end
@@ -4,31 +4,24 @@ require_relative "responses/message_data_response"
4
4
  require_relative "responses/phone_number_data_response"
5
5
  require_relative "responses/phone_numbers_data_response"
6
6
  require_relative "responses/read_message_data_response"
7
- require_relative "responses/error_response"
7
+ require_relative "responses/message_error_response"
8
8
 
9
9
  module WhatsappSdk
10
10
  module Api
11
11
  class Response
12
12
  attr_accessor :error, :data
13
13
 
14
- CLASS_TYPE = {
15
- message_data_response: Responses::MessageDataResponse,
16
- phone_number_data_response: Responses::PhoneNumberDataResponse,
17
- phone_numbers_data_response: Responses::PhoneNumbersDataResponse,
18
- read_message_data_response: Responses::ReadMessageDataResponse
19
- }.freeze
20
-
21
- def initialize(response:, class_type:)
22
- @data = class_type.build_from_response(response: response)
23
- @error = Responses::ErrorResponse.build_from_response(response: response)
14
+ def initialize(response:, data_class_type:, error_class_type: Responses::MessageErrorResponse)
15
+ @data = data_class_type.build_from_response(response: response)
16
+ @error = error_class_type.build_from_response(response: response)
24
17
  end
25
18
 
26
- # Whether or not the response is successful.
19
+ # @return [Boolean] Whether or not the response is successful.
27
20
  def ok?
28
21
  @error.nil?
29
22
  end
30
23
 
31
- # Whether or not the response has an error.
24
+ # @return [Boolean] Whether or not the response has an error.
32
25
  def error?
33
26
  !!@error
34
27
  end
@@ -1,32 +1,23 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "data_response"
4
+
3
5
  module WhatsappSdk
4
6
  module Api
5
7
  module Responses
6
- class ErrorResponse
7
- attr_reader :code, :subcode, :message, :type, :data, :fbtrace_id
8
+ class ErrorResponse < DataResponse
9
+ attr_accessor :error, :status
8
10
 
9
- def initialize(code:, subcode:, message:, type:, data:, fbtrace_id:)
10
- @code = code
11
- @subcode = subcode
12
- @message = message
13
- @type = type
14
- @data = data
15
- @fbtrace_id = fbtrace_id
11
+ def initialize(response:)
12
+ @error = response["error"]
13
+ @status = response["status"]
14
+ super(response)
16
15
  end
17
16
 
18
17
  def self.build_from_response(response:)
19
- error_response = response["error"]
20
- return unless error_response
18
+ return unless response["error"]
21
19
 
22
- new(
23
- code: error_response["code"],
24
- subcode: error_response["error_subcode"],
25
- message: error_response["message"],
26
- type: error_response["type"],
27
- data: error_response["data"],
28
- fbtrace_id: error_response["fbtrace_id"]
29
- )
20
+ new(response: response)
30
21
  end
31
22
  end
32
23
  end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "data_response"
4
+
5
+ module WhatsappSdk
6
+ module Api
7
+ module Responses
8
+ class MediaDataResponse < DataResponse
9
+ attr_accessor :id, :url, :mime_type, :sha256, :file_size, :messaging_product
10
+
11
+ def initialize(response)
12
+ @id = response["id"]
13
+ @messaging_product = response["messaging_product"]
14
+ @url = response["url"]
15
+ @mime_type = response["mime_type"]
16
+ @sha256 = response["sha256"]
17
+ @file_size = response["file_size"]
18
+ super(response)
19
+ end
20
+
21
+ def self.build_from_response(response:)
22
+ return unless response["id"]
23
+
24
+ new(response)
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "error_response"
4
+
5
+ module WhatsappSdk
6
+ module Api
7
+ module Responses
8
+ class MessageErrorResponse < ErrorResponse
9
+ attr_reader :code, :subcode, :message, :type, :data, :fbtrace_id
10
+
11
+ def initialize(response:)
12
+ @code = response["code"]
13
+ @subcode = response["error_subcode"]
14
+ @message = response["message"]
15
+ @type = response["type"]
16
+ @data = response["data"]
17
+ @fbtrace_id = response["fbtrace_id"]
18
+ super(response: response)
19
+ end
20
+
21
+ def self.build_from_response(response:)
22
+ error_response = response["error"]
23
+ return unless error_response
24
+
25
+ new(response: error_response)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -9,10 +9,10 @@ module WhatsappSdk
9
9
  module Api
10
10
  module Responses
11
11
  class ReadMessageDataResponse < DataResponse
12
- attr_reader :sucess
12
+ attr_reader :success
13
13
 
14
14
  def initialize(response:)
15
- @sucess = response["sucess"]
15
+ @success = response["success"]
16
16
  super(response)
17
17
  end
18
18
 
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "data_response"
4
+
5
+ module WhatsappSdk
6
+ module Api
7
+ module Responses
8
+ class SuccessResponse < DataResponse
9
+ def initialize(response:)
10
+ @success = response["success"]
11
+ super(response)
12
+ end
13
+
14
+ def self.build_from_response(response:)
15
+ return unless response["success"]
16
+
17
+ new(response: response)
18
+ end
19
+
20
+ def success?
21
+ @success
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WhatsappSdk
4
+ # This module allows client instantiating the client as a singleton like the following example:
5
+ # WhatsappSdk.configure do |config|
6
+ # config.access_token = ACCESS_TOKEN
7
+ # end
8
+ #
9
+ # The gem have access to the client through WhatsappSdk.configuration.client
10
+ class Configuration
11
+ attr_accessor :access_token
12
+
13
+ def initialize(access_token = nil)
14
+ @access_token = access_token
15
+ end
16
+
17
+ def client
18
+ return unless access_token
19
+
20
+ WhatsappSdk::Api::Client.new(access_token)
21
+ end
22
+ end
23
+ end
data/lib/whatsapp_sdk.rb CHANGED
@@ -1,31 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # APIs
4
- require_relative "whatsapp_sdk/api/phone_numbers"
5
- require_relative "whatsapp_sdk/api/messages"
6
- require_relative "whatsapp_sdk/api/client"
3
+ require "zeitwerk"
4
+ loader = Zeitwerk::Loader.for_gem
5
+ loader.setup # ready!
7
6
 
8
- # APIs responses
9
- require_relative "whatsapp_sdk/api/responses/message_data_response"
10
- require_relative "whatsapp_sdk/api/responses/phone_number_data_response"
11
- require_relative "whatsapp_sdk/api/responses/phone_numbers_data_response"
12
- require_relative "whatsapp_sdk/api/responses/error_response"
13
- require_relative "whatsapp_sdk/api/responses/data_response"
14
- require_relative "whatsapp_sdk/api/responses/read_message_data_response"
7
+ module WhatsappSdk
8
+ class << self
9
+ def configuration
10
+ @configuration ||= Configuration.new
11
+ end
15
12
 
16
- # Resources
17
- require_relative "whatsapp_sdk/resource/address"
18
- require_relative "whatsapp_sdk/resource/button_parameter"
19
- require_relative "whatsapp_sdk/resource/component"
20
- require_relative "whatsapp_sdk/resource/contact_response"
21
- require_relative "whatsapp_sdk/resource/contact"
22
- require_relative "whatsapp_sdk/resource/currency"
23
- require_relative "whatsapp_sdk/resource/date_time"
24
- require_relative "whatsapp_sdk/resource/email"
25
- require_relative "whatsapp_sdk/resource/media"
26
- require_relative "whatsapp_sdk/resource/message"
27
- require_relative "whatsapp_sdk/resource/name"
28
- require_relative "whatsapp_sdk/resource/org"
29
- require_relative "whatsapp_sdk/resource/parameter_object"
30
- require_relative "whatsapp_sdk/resource/phone_number"
31
- require_relative "whatsapp_sdk/resource/url"
13
+ def configure
14
+ yield(configuration)
15
+ end
16
+ end
17
+ end
data/tmp/whatsapp.png ADDED
Binary file
data/whatsapp_sdk.gemspec CHANGED
@@ -9,10 +9,12 @@ Gem::Specification.new do |spec|
9
9
  spec.version = WhatsappSdk::VERSION
10
10
  spec.authors = ["ignacio-chiazzo"]
11
11
  spec.email = ["ignaciochiazzo@gmail.com"]
12
-
13
- spec.summary = "Use the Whatsapp SDK to comunicate with Whatsapp API"
14
- spec.description = "Ruby Whatsapp SDK. Use the Whatsapp API through this library"
15
- spec.homepage = "https://github.com/ignacio-chiazzo/whatsapp_sdk"
12
+ spec.summary = "Use the Ruby Whatsapp SDK to comunicate with Whatsapp API using the Cloud API"
13
+ spec.description = <<-DESCRIPTION
14
+ Use the Ruby Whatsapp SDK to comunicate with Whatsapp API using the Cloud API.
15
+ Create bots to send and receive messages using the Whatsapp SDK in a few minutes.
16
+ DESCRIPTION
17
+ spec.homepage = "https://github.com/ignacio-chiazzo/ruby_whatsapp_sdk"
16
18
  spec.license = "MIT"
17
19
  spec.required_ruby_version = '>= 1.8.6'
18
20
 
@@ -20,11 +22,11 @@ Gem::Specification.new do |spec|
20
22
  # to allow pushing to a single host or delete this section to allow pushing to any host.
21
23
  if spec.respond_to?(:metadata)
22
24
  spec.metadata["homepage_uri"] = spec.homepage
23
- spec.metadata["source_code_uri"] = "https://github.com/ignacio-chiazzo/whatsapp_sdk"
24
- spec.metadata["changelog_uri"] = "https://github.com/ignacio-chiazzo/whatsapp_sdk/blob/main/CHANGELOG.md"
25
+ spec.metadata["source_code_uri"] = "https://github.com/ignacio-chiazzo/ruby_whatsapp_sdk"
26
+ spec.metadata["changelog_uri"] = "https://github.com/ignacio-chiazzo/ruby_whatsapp_sdk/blob/main/CHANGELOG.md"
25
27
  else
26
28
  raise "RubyGems 2.0 or newer is required to protect against " \
27
- "public gem pushes."
29
+ "public gem pushes."
28
30
  end
29
31
 
30
32
  # Specify which files should be added to the gem when it is released.
@@ -38,8 +40,11 @@ Gem::Specification.new do |spec|
38
40
 
39
41
  spec.add_development_dependency "bundler", "~> 2.3"
40
42
  spec.add_development_dependency "minitest", "~> 5.0"
41
- spec.add_development_dependency "rake", "~> 10.0"
43
+ spec.add_development_dependency "rake", "~> 12.3.3"
42
44
 
43
45
  spec.add_dependency("faraday", "~> 2.3.0")
46
+ spec.add_dependency("faraday-multipart", "~> 1.0.4")
44
47
  spec.add_dependency("oj", "~> 3.13.13")
48
+ spec.add_dependency("zeitwerk", "~> 2.6.0")
49
+ spec.metadata['rubygems_mfa_required'] = 'true'
45
50
  end