notion-ruby-client 0.0.8 → 1.0.0.pre.beta2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/.devcontainer/Dockerfile +5 -0
  3. data/.devcontainer/boot.sh +1 -0
  4. data/.devcontainer/devcontainer.json +30 -0
  5. data/.github/workflows/ci.yml +1 -0
  6. data/.gitignore +7 -0
  7. data/.rubocop.yml +9 -0
  8. data/CHANGELOG.md +43 -0
  9. data/CONTRIBUTING.md +51 -0
  10. data/Gemfile.lock +38 -11
  11. data/README.md +354 -108
  12. data/bin/console +31 -0
  13. data/lib/notion/api/endpoints/blocks.rb +51 -7
  14. data/lib/notion/api/endpoints/databases.rb +60 -53
  15. data/lib/notion/api/endpoints/pages.rb +24 -7
  16. data/lib/notion/api/endpoints/search.rb +41 -0
  17. data/lib/notion/api/endpoints/users.rb +14 -3
  18. data/lib/notion/api/endpoints.rb +3 -1
  19. data/lib/notion/api/errors/too_many_requests.rb +15 -0
  20. data/lib/notion/api/errors.rb +0 -2
  21. data/lib/notion/config.rb +2 -0
  22. data/lib/notion/pagination/cursor.rb +5 -2
  23. data/lib/notion/version.rb +2 -2
  24. data/lib/notion-ruby-client.rb +2 -0
  25. data/notion-ruby-client.gemspec +5 -3
  26. data/spec/fixtures/notion/block.yml +146 -0
  27. data/spec/fixtures/notion/block_append_children.yml +76 -62
  28. data/spec/fixtures/notion/block_children.yml +80 -65
  29. data/spec/fixtures/notion/create_database.yml +67 -58
  30. data/spec/fixtures/notion/create_page.yml +68 -59
  31. data/spec/fixtures/notion/database.yml +78 -61
  32. data/spec/fixtures/notion/database_query.yml +81 -62
  33. data/spec/fixtures/notion/delete_block.yml +145 -0
  34. data/spec/fixtures/notion/page.yml +70 -57
  35. data/spec/fixtures/notion/page_property_item.yml +143 -0
  36. data/spec/fixtures/notion/paginated_block_children.yml +296 -242
  37. data/spec/fixtures/notion/paginated_database_query.yml +79 -62
  38. data/spec/fixtures/notion/paginated_databases_list.yml +78 -61
  39. data/spec/fixtures/notion/paginated_search.yml +301 -0
  40. data/spec/fixtures/notion/paginated_users_list.yml +143 -130
  41. data/spec/fixtures/notion/search.yml +160 -0
  42. data/spec/fixtures/notion/search_with_query.yml +152 -0
  43. data/spec/fixtures/notion/update_block.yml +148 -0
  44. data/spec/fixtures/notion/update_database.yml +152 -0
  45. data/spec/fixtures/notion/update_page.yml +71 -59
  46. data/spec/fixtures/notion/users.yml +69 -56
  47. data/spec/fixtures/notion/users_list.yml +143 -130
  48. data/spec/fixtures/notion/users_me.yml +144 -0
  49. data/spec/notion/api/endpoints/blocks_spec.rb +44 -12
  50. data/spec/notion/api/endpoints/databases_spec.rb +22 -27
  51. data/spec/notion/api/endpoints/pages_spec.rb +13 -16
  52. data/spec/notion/api/endpoints/search_spec.rb +26 -0
  53. data/spec/notion/api/endpoints/users_spec.rb +9 -4
  54. data/spec/notion/pagination/cursor_spec.rb +126 -0
  55. metadata +67 -15
  56. data/.rspec_status +0 -19
  57. data/notion-ruby-client-0.0.4.gem +0 -0
  58. data/scratchpad.rb +0 -22
  59. data/screenshots/create_notion_bot.png +0 -0
  60. data/spec/fixtures/notion/databases_list.yml +0 -133
@@ -4,6 +4,50 @@ module Notion
4
4
  module Api
5
5
  module Endpoints
6
6
  module Blocks
7
+ #
8
+ # Retrieves a Block object using the ID specified.
9
+ #
10
+ # @option options [id] :block_id
11
+ # Block to get children info on.
12
+ def block(options = {})
13
+ throw ArgumentError.new('Required arguments :block_id missing') if options[:block_id].nil?
14
+ get("blocks/#{options[:block_id]}")
15
+ end
16
+
17
+ #
18
+ # Updates the content for the specified block_id based on
19
+ # the block type. Supported fields based on the block object
20
+ # type (see Block object for available fields and the
21
+ # expected input for each field).
22
+ #
23
+ # @option options [id] :block_id
24
+ # Block to get children info on.
25
+ #
26
+ # @option options [string] {type}
27
+ # The block object type value with the properties to be
28
+ # updated. Currently only text (for supported block types)
29
+ # and checked (for to_do blocks) fields can be updated.
30
+ def update_block(options = {})
31
+ throw ArgumentError.new('Required arguments :block_id missing') if options[:block_id].nil?
32
+ patch("blocks/#{options[:block_id]}", options.except(:block_id))
33
+ end
34
+
35
+ #
36
+ # Sets a Block object, including page blocks, to archived: true
37
+ # using the ID specified. Note: in the Notion UI application, this
38
+ # moves the block to the "Trash" where it can still be accessed and
39
+ # restored.
40
+ #
41
+ # To restore the block with the API, use the Update a block or
42
+ # Update page respectively.
43
+ #
44
+ # @option options [id] :block_id
45
+ # Block to get children info on.
46
+ def delete_block(options = {})
47
+ throw ArgumentError.new('Required arguments :block_id missing') if options[:block_id].nil?
48
+ delete("blocks/#{options[:block_id]}")
49
+ end
50
+
7
51
  #
8
52
  # Returns a paginated array of Block objects contained in the
9
53
  # block of the requested path using the ID specified.
@@ -14,16 +58,16 @@ module Notion
14
58
  #
15
59
  # Returns a 400 or 429 HTTP response if the request exceeds Notion's Request limits.
16
60
  #
17
- # @option options [id] :id
61
+ # @option options [id] :block_id
18
62
  # Block to get children info on.
19
63
  def block_children(options = {})
20
- throw ArgumentError.new('Required arguments :id missing') if options[:id].nil?
64
+ throw ArgumentError.new('Required arguments :block_id missing') if options[:block_id].nil?
21
65
  if block_given?
22
66
  Pagination::Cursor.new(self, :block_children, options).each do |page|
23
67
  yield page
24
68
  end
25
69
  else
26
- get("blocks/#{options[:id]}/children", options)
70
+ get("blocks/#{options[:block_id]}/children", options.except(:block_id))
27
71
  end
28
72
  end
29
73
 
@@ -38,14 +82,14 @@ module Notion
38
82
  #
39
83
  # Returns a 400 or 429 HTTP response if the request exceeds Notion's Request limits.
40
84
  #
41
- # @option options [id] :id
42
- # Block to get children info on.
85
+ # @option options [id] :block_id
86
+ # Block to append children to.
43
87
  #
44
88
  # @option options [[Object]] :children
45
89
  # Children blocks to append
46
90
  def block_append_children(options = {})
47
- throw ArgumentError.new('Required arguments :id missing') if options[:id].nil?
48
- patch("blocks/#{options[:id]}/children", options)
91
+ throw ArgumentError.new('Required arguments :block_id missing') if options[:block_id].nil?
92
+ patch("blocks/#{options[:block_id]}/children", options.except(:block_id))
49
93
  end
50
94
  end
51
95
  end
@@ -4,42 +4,6 @@ module Notion
4
4
  module Api
5
5
  module Endpoints
6
6
  module Databases
7
- #
8
- # Retrieves a Database object using the ID specified in the request.
9
- #
10
- # Returns a 404 HTTP response if the database doesn't exist, or if the bot
11
- # doesn't have access to the database. Returns a 429 HTTP response if the
12
- # request exceeds Notion's Request limits.
13
- #
14
- # @option options [id] :id
15
- # Database to get info on.
16
- def database(options = {})
17
- throw ArgumentError.new('Required arguments :id missing') if options[:id].nil?
18
- get("databases/#{options[:id]}")
19
- end
20
-
21
- #
22
- # Creates a new database in the specified page.
23
- #
24
- # @option options [Object] :parent
25
- # Parent of the database, which is always going to be a page.
26
- #
27
- # @option options [Object] :title
28
- # Title of this database.
29
- #
30
- # @option options [Object] :properties
31
- # Property schema of database.
32
- # The keys are the names of properties as they appear in Notion and the values are
33
- # property schema objects. Property Schema Object is a metadata that controls
34
- # how a database property behaves, e.g. {"checkbox": {}}.
35
- # Each database must have exactly one database property schema object of type "title".
36
- def create_database(options = {})
37
- throw ArgumentError.new('Required arguments :parent.page_id missing') if options.dig(:parent, :page_id).nil?
38
- throw ArgumentError.new('Required arguments :title missing') if options.dig(:title).nil?
39
- throw ArgumentError.new('Required arguments :properties missing') if options.dig(:properties).nil?
40
- post('databases', options)
41
- end
42
-
43
7
  #
44
8
  # Gets a paginated array of Page object s contained in the requested database,
45
9
  # filtered and ordered according to the filter and sort objects provided in the request.
@@ -52,7 +16,7 @@ module Notion
52
16
  # database properties and can be combined. The order of the sorts in the request
53
17
  # matter, with earlier sorts taking precedence over later ones.
54
18
  #
55
- # @option options [id] :id
19
+ # @option options [id] :database_id
56
20
  # Database to query.
57
21
  #
58
22
  # @option options [Object] :filter
@@ -66,33 +30,76 @@ module Notion
66
30
  # to a start_cursor attribute returned by a previous request's next_cursor.
67
31
  # Default value fetches the first "page" of the collection.
68
32
  # See pagination for more detail.
33
+ #
34
+ # @option options [integer] :page_size
35
+ # The number of items from the full list desired in the response. Maximum: 100
69
36
  def database_query(options = {})
70
- throw ArgumentError.new('Required arguments :id missing') if options[:id].nil?
37
+ throw ArgumentError.new('Required arguments :database_id missing') if options[:database_id].nil?
71
38
  if block_given?
72
39
  Pagination::Cursor.new(self, :database_query, options).each do |page|
73
40
  yield page
74
41
  end
75
42
  else
76
- post("databases/#{options[:id]}/query", options)
43
+ post("databases/#{options[:database_id]}/query", options.except(:database_id))
77
44
  end
78
45
  end
79
46
 
80
47
  #
81
- # Returns a paginated list of Databases objects for the workspace.
48
+ # Creates a new database in the specified page.
82
49
  #
83
- # @option options [UUID] :start_cursor
84
- # Paginate through collections of data by setting the cursor parameter
85
- # to a start_cursor attribute returned by a previous request's next_cursor.
86
- # Default value fetches the first "page" of the collection.
87
- # See pagination for more detail.
88
- def databases_list(options = {})
89
- if block_given?
90
- Pagination::Cursor.new(self, :databases_list, options).each do |page|
91
- yield page
92
- end
93
- else
94
- get('databases', options)
95
- end
50
+ # @option options [Object] :parent
51
+ # Parent of the database, which is always going to be a page.
52
+ #
53
+ # @option options [Object] :title
54
+ # Title of this database.
55
+ #
56
+ # @option options [Object] :properties
57
+ # Property schema of database.
58
+ # The keys are the names of properties as they appear in Notion and the values are
59
+ # property schema objects. Property Schema Object is a metadata that controls
60
+ # how a database property behaves, e.g. {"checkbox": {}}.
61
+ # Each database must have exactly one database property schema object of type "title".
62
+ def create_database(options = {})
63
+ throw ArgumentError.new('Required arguments :parent.page_id missing') if options.dig(:parent, :page_id).nil?
64
+ throw ArgumentError.new('Required arguments :title missing') if options.dig(:title).nil?
65
+ throw ArgumentError.new('Required arguments :properties missing') if options.dig(:properties).nil?
66
+ post('databases', options)
67
+ end
68
+
69
+ #
70
+ # Updates an existing database as specified by the parameters.
71
+ #
72
+ # @option options [id] :database_id
73
+ # Database to update.
74
+ #
75
+ # @option options [Object] :title
76
+ # Title of database as it appears in Notion. An array of rich text objects.
77
+ # If omitted, the database title will remain unchanged.
78
+ #
79
+ # @option options [Object] :properties
80
+ # Updates to the property schema of a database.
81
+ # If updating an existing property, the keys are the names or IDs
82
+ # of the properties as they appear in Notion and the values
83
+ # are property schema objects. If adding a new property, the key is
84
+ # the name of the database property and the value is a property schema object.
85
+ #
86
+ def update_database(options = {})
87
+ throw ArgumentError.new('Required arguments :database_id missing') if options.dig(:database_id).nil?
88
+ patch("databases/#{options[:database_id]}", options.except(:database_id))
89
+ end
90
+
91
+ #
92
+ # Retrieves a Database object using the ID specified in the request.
93
+ #
94
+ # Returns a 404 HTTP response if the database doesn't exist, or if the bot
95
+ # doesn't have access to the database. Returns a 429 HTTP response if the
96
+ # request exceeds Notion's Request limits.
97
+ #
98
+ # @option options [id] :database_id
99
+ # Database to get info on.
100
+ def database(options = {})
101
+ throw ArgumentError.new('Required arguments :database_id missing') if options[:database_id].nil?
102
+ get("databases/#{options[:database_id]}")
96
103
  end
97
104
  end
98
105
  end
@@ -8,15 +8,15 @@ module Notion
8
8
  # Retrieves a 📄Page object using the ID specified in the request path.
9
9
  # Note that this version of the API only exposes page properties, not page content
10
10
  #
11
- # @option options [id] :id
11
+ # @option options [id] :page_id
12
12
  # Page to get info on.
13
13
  #
14
14
  # @option options [bool] :archived
15
15
  # Set to true to retrieve an archived page; must be false or omitted to
16
16
  # retrieve a page that has not been archived. Defaults to false.
17
17
  def page(options = {})
18
- throw ArgumentError.new('Required arguments :id missing') if options[:id].nil?
19
- get("pages/#{options[:id]}")
18
+ throw ArgumentError.new('Required argument :page_id missing') if options[:page_id].nil?
19
+ get("pages/#{options[:page_id]}")
20
20
  end
21
21
 
22
22
  #
@@ -38,7 +38,7 @@ module Notion
38
38
  # @option options [Object] :children
39
39
  # An optional array of Block objects representing the Page’s content
40
40
  def create_page(options = {})
41
- throw ArgumentError.new('Required arguments :parent.database_id missing') if options.dig(:parent, :database_id).nil?
41
+ throw ArgumentError.new('Required argument :parent.database_id missing') if options.dig(:parent, :database_id).nil?
42
42
  post("pages", options)
43
43
  end
44
44
 
@@ -50,7 +50,7 @@ module Notion
50
50
  # Note that this iteration of the API will only expose page properties, not page
51
51
  # content, as described in the data model.
52
52
  #
53
- # @option options [id] :id
53
+ # @option options [id] :page_id
54
54
  # Page to get info on.
55
55
  #
56
56
  # @option options [Object] :properties
@@ -60,8 +60,25 @@ module Notion
60
60
  # appears in Notion, or property ID. value object Object containing a value
61
61
  # specific to the property type, e.g. {"checkbox": true}.
62
62
  def update_page(options = {})
63
- throw ArgumentError.new('Required arguments :id missing') if options[:id].nil?
64
- patch("pages/#{options[:id]}", options)
63
+ throw ArgumentError.new('Required argument :page_id missing') if options[:page_id].nil?
64
+ patch("pages/#{options[:page_id]}", options.except(:page_id))
65
+ end
66
+
67
+ #
68
+ # Retrieves a `property_item` object for a given `page_id` and `property_id`.
69
+ # Depending on the property type, the object returned will either be a value
70
+ # or a paginated list of property item values.
71
+ #
72
+ # @option options [id] :page_id
73
+ # Page to get info on.
74
+ #
75
+ # @option options [id] :property_id
76
+ # Property to get info on.
77
+ #
78
+ def page_property_item(options = {})
79
+ throw ArgumentError.new('Required argument :page_id missing') if options[:page_id].nil?
80
+ throw ArgumentError.new('Required argument :property_id missing') if options[:property_id].nil?
81
+ get("pages/#{options[:page_id]}/properties/#{options[:property_id]}")
65
82
  end
66
83
  end
67
84
  end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Notion
4
+ module Api
5
+ module Endpoints
6
+ module Search
7
+ #
8
+ # Searches all pages and child pages that are shared with the integration.
9
+ # The results may include databases.
10
+ #
11
+ # @option options [string] :query
12
+ # When supplied, limits which pages are returned by comparing the query to the page title.
13
+ #
14
+ # @option options [Object] :filter
15
+ # When supplied, filters the results based on the provided criteria.
16
+ #
17
+ # @option options [[Object]] :sorts
18
+ # When supplied, sorts the results based on the provided criteria.
19
+ # Limitation: Currently only a single sort is allowed and is limited to last_edited_time.
20
+ #
21
+ # @option options [UUID] :start_cursor
22
+ # Paginate through collections of data by setting the cursor parameter
23
+ # to a start_cursor attribute returned by a previous request's next_cursor.
24
+ # Default value fetches the first "page" of the collection.
25
+ # See pagination for more detail.
26
+ #
27
+ # @option options [integer] :page_size
28
+ # The number of items from the full list desired in the response. Maximum: 100
29
+ def search(options = {})
30
+ if block_given?
31
+ Pagination::Cursor.new(self, :search, options).each do |page|
32
+ yield page
33
+ end
34
+ else
35
+ post('search', options)
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -4,14 +4,22 @@ module Notion
4
4
  module Api
5
5
  module Endpoints
6
6
  module Users
7
+ #
8
+ # Retrieves the bot User associated with the API token provided in
9
+ # the authorization header. The bot will have an `owner` field with
10
+ # information about the person who authorized the integration.
11
+ def me
12
+ get("users/me")
13
+ end
14
+
7
15
  #
8
16
  # Retrieves a User object using the ID specified in the request.
9
17
  #
10
- # @option options [id] :id
18
+ # @option options [id] :user_id
11
19
  # User to get info on.
12
20
  def user(options = {})
13
- throw ArgumentError.new('Required arguments :id missing') if options[:id].nil?
14
- get("users/#{options[:id]}")
21
+ throw ArgumentError.new('Required arguments :user_id missing') if options[:user_id].nil?
22
+ get("users/#{options[:user_id]}")
15
23
  end
16
24
 
17
25
  #
@@ -22,6 +30,9 @@ module Notion
22
30
  # to a start_cursor attribute returned by a previous request's next_cursor.
23
31
  # Default value fetches the first "page" of the collection.
24
32
  # See pagination for more detail.
33
+ #
34
+ # @option options [integer] :page_size
35
+ # The number of items from the full list desired in the response. Maximum: 100
25
36
  def users_list(options = {})
26
37
  if block_given?
27
38
  Pagination::Cursor.new(self, :users_list, options).each do |page|
@@ -4,6 +4,7 @@ require_relative 'endpoints/blocks'
4
4
  require_relative 'endpoints/databases'
5
5
  require_relative 'endpoints/pages'
6
6
  require_relative 'endpoints/users'
7
+ require_relative 'endpoints/search'
7
8
 
8
9
  module Notion
9
10
  module Api
@@ -12,6 +13,7 @@ module Notion
12
13
  include Databases
13
14
  include Pages
14
15
  include Users
16
+ include Search
15
17
  end
16
18
  end
17
- end
19
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+ module Notion
3
+ module Api
4
+ module Errors
5
+ class TooManyRequests < ::Faraday::Error
6
+ attr_reader :response
7
+
8
+ def initialize(response)
9
+ @response = response
10
+ super 'Too many requests'
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -8,7 +8,6 @@ module Notion
8
8
  class InternalError < NotionError; end
9
9
  class InvalidRequest < NotionError; end
10
10
  class ObjectNotFound < NotionError; end
11
- class TooManyRequests < NotionError; end
12
11
  class Unauthorized < NotionError; end
13
12
 
14
13
  ERROR_CLASSES = {
@@ -17,7 +16,6 @@ module Notion
17
16
  'internal_error' => InternalError,
18
17
  'invalid_request' => InvalidRequest,
19
18
  'object_not_found' => ObjectNotFound,
20
- 'rate_limited' => TooManyRequests,
21
19
  'unauthorized' => Unauthorized
22
20
  }.freeze
23
21
  end
data/lib/notion/config.rb CHANGED
@@ -15,6 +15,7 @@ module Notion
15
15
  open_timeout
16
16
  default_page_size
17
17
  default_max_retries
18
+ default_retry_after
18
19
  adapter
19
20
  ].freeze
20
21
 
@@ -32,6 +33,7 @@ module Notion
32
33
  self.open_timeout = nil
33
34
  self.default_page_size = 100
34
35
  self.default_max_retries = 100
36
+ self.default_retry_after = 10
35
37
  self.adapter = ::Faraday.default_adapter
36
38
  end
37
39
 
@@ -9,6 +9,7 @@ module Notion
9
9
  attr_reader :verb
10
10
  attr_reader :sleep_interval
11
11
  attr_reader :max_retries
12
+ attr_reader :retry_after
12
13
  attr_reader :params
13
14
 
14
15
  def initialize(client, verb, params = {})
@@ -17,13 +18,15 @@ module Notion
17
18
  @params = params.dup
18
19
  @sleep_interval = @params.delete(:sleep_interval)
19
20
  @max_retries = @params.delete(:max_retries) || client.default_max_retries
21
+ @retry_after = @params.delete(:retry_after) || client.default_retry_after
20
22
  end
21
23
 
22
24
  def each
23
25
  next_cursor = nil
24
26
  retry_count = 0
25
27
  loop do
26
- query = next_cursor.nil? ? params : params.merge(start_cursor: next_cursor)
28
+ query = { page_size: client.default_page_size }.merge(params)
29
+ query = query.merge(start_cursor: next_cursor) unless next_cursor.nil?
27
30
  begin
28
31
  response = client.send(verb, query)
29
32
  rescue Notion::Api::Errors::TooManyRequests => e
@@ -31,7 +34,7 @@ module Notion
31
34
 
32
35
  client.logger.debug("#{self.class}##{__method__}") { e.to_s }
33
36
  retry_count += 1
34
- sleep(e.retry_after)
37
+ sleep(retry_after)
35
38
  next
36
39
  end
37
40
  yield response
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
  module Notion
3
- VERSION = '0.0.8'
4
- NOTION_REQUEST_VERSION = '2021-05-13'
3
+ VERSION = '1.0.0-beta2'
4
+ NOTION_REQUEST_VERSION = '2022-02-22'
5
5
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ require 'active_support/core_ext/hash/except'
2
3
  require 'faraday'
3
4
  require 'faraday_middleware'
4
5
  require 'json'
@@ -17,6 +18,7 @@ require_relative 'notion/api/errors/notion_error'
17
18
  require_relative 'notion/api/error'
18
19
  require_relative 'notion/api/errors'
19
20
  require_relative 'notion/api/errors/internal_error'
21
+ require_relative 'notion/api/errors/too_many_requests'
20
22
  require_relative 'notion/faraday/response/raise_error'
21
23
  require_relative 'notion/faraday/response/wrap_error'
22
24
  require_relative 'notion/faraday/connection'
@@ -15,10 +15,12 @@ Gem::Specification.new do |s|
15
15
  s.homepage = 'http://github.com/orbit-love/notion-ruby-client'
16
16
  s.licenses = ['MIT']
17
17
  s.summary = 'Notion API client for Ruby.'
18
+ s.add_dependency 'activesupport', '>= 6'
19
+ s.add_dependency 'dotenv'
18
20
  s.add_dependency 'faraday', '>= 1.0'
19
21
  s.add_dependency 'faraday_middleware'
20
- s.add_dependency 'hashie'
21
- s.add_development_dependency 'rake', '~> 10'
22
+ s.add_dependency 'hashie', '~> 5'
23
+ s.add_development_dependency 'rake', '~> 13'
22
24
  s.add_development_dependency 'rspec'
23
25
  s.add_development_dependency 'rubocop', '~> 0.82.0'
24
26
  s.add_development_dependency 'rubocop-performance', '~> 1.5.2'
@@ -26,4 +28,4 @@ Gem::Specification.new do |s|
26
28
  s.add_development_dependency 'timecop'
27
29
  s.add_development_dependency 'vcr'
28
30
  s.add_development_dependency 'webmock'
29
- end
31
+ end