rtx-api 0.5.1 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA256:
3
- metadata.gz: 9501dcc7112fefb26fa0cfea1259aa23e1b8cc45b64971e39f426cf11913bc13
4
- data.tar.gz: d4b91f77fb51cca1d8dd067e8ab87372921c72c380d3bf210091132e8adf44da
2
+ SHA1:
3
+ metadata.gz: e4279a13081baee795c2b772bf06c88a5b9d877f
4
+ data.tar.gz: 731c9f4173350abb8526165550fb77b7ee2fde45
5
5
  SHA512:
6
- metadata.gz: fd462a434c9feced48e18a238d5edef6a1e84b64c4763e1f8fe0b6ed8c4a10bcb17bf95b7b834264aa4082aebb785cfd4324e125f7df5b209f9e56852dbc8e00
7
- data.tar.gz: ec4008817753110b2d22d8fd4eee9262182cc2c0d97ae673bb22d37c6368a6dde3dc7c8db738b3518ea6a0422c6f77763647053dfce35df0b0b2fc6ac81bd173
6
+ metadata.gz: e02e69164b1cd3b4c5b5fb96952d22c4c051446aee22bd4afa4f8107a8ed7e5614d4634e5eead45c66d2cd1a40e7c3c56be2339c470fec6c61bdd86ac7cd5c11
7
+ data.tar.gz: fa7d7355f20300d8b4b1870c2bb8ad254b154cfe98c9a42d6b366d5e324f6031ee390cc4a9a251a59f3a8d8c76968481938707d24ea18ba684b339ee22022572
data/.rubocop.yml ADDED
@@ -0,0 +1,58 @@
1
+ StringLiterals:
2
+ EnforcedStyle: single_quotes
3
+
4
+ Style/RegexpLiteral:
5
+ EnforcedStyle: percent_r
6
+
7
+ Style/Documentation:
8
+ Enabled: false
9
+
10
+ Naming/VariableName:
11
+ EnforcedStyle: snake_case
12
+
13
+ Naming/PredicateName:
14
+ Enabled: false
15
+
16
+ Metrics/ParameterLists:
17
+ Max: 8
18
+
19
+ Metrics/BlockLength:
20
+ Enabled: false
21
+
22
+ Metrics/MethodLength:
23
+ Max: 20
24
+
25
+ Metrics/AbcSize:
26
+ Max: 50
27
+
28
+ Metrics/ModuleLength:
29
+ Max: 100
30
+ Exclude:
31
+ - spec/data/**
32
+
33
+ Metrics/ClassLength:
34
+ Max: 200
35
+
36
+ Metrics/LineLength:
37
+ Max: 100
38
+ IgnoredPatterns: ['\A#']
39
+ Exclude:
40
+ - spec/**/**_spec.rb
41
+ - spec/data/**
42
+ - bin/**/*
43
+
44
+ Style/NumericLiterals:
45
+ Enabled: false
46
+
47
+ Style/NegatedIf:
48
+ Enabled: false
49
+
50
+ AllCops:
51
+ DisplayCopNames: true
52
+ TargetRubyVersion: 2.5.0
53
+ Exclude:
54
+ - .git/**/*
55
+ - vendor/**/*
56
+ - Gemfile
57
+ - Rakefile
58
+ - rtx-api.gemspec
data/.travis.yml CHANGED
@@ -5,11 +5,11 @@ addons:
5
5
  gemfile:
6
6
  - Gemfile
7
7
  rvm:
8
- - 2.1
9
- - 2.2
10
8
  - 2.3.0
9
+ - 2.5.0
10
+ - 2.6.0
11
11
  script:
12
- - bundle exec rake test
12
+ - bundle exec rubocop && bundle exec rake test
13
13
  env:
14
14
  global:
15
15
  - COVERAGE=1
data/Gemfile CHANGED
@@ -2,13 +2,14 @@ source 'https://rubygems.org'
2
2
  gemspec
3
3
 
4
4
  group :development do
5
- gem 'pry'
6
5
  gem 'httparty'
7
6
  gem 'oj'
7
+ gem 'pry'
8
8
  end
9
9
 
10
10
  group :development, :test, :rake do
11
11
  gem 'bundler'
12
+ gem 'rubocop', require: false
12
13
  end
13
14
 
14
15
  group :rake do
@@ -17,8 +18,8 @@ end
17
18
 
18
19
  group :test do
19
20
  gem 'minitest'
20
- gem 'minitest-spec-context'
21
21
  gem 'minitest-reporters', require: 'minitest/reporters'
22
+ gem 'minitest-spec-context'
22
23
  gem 'mocha', require: 'mocha/setup'
23
24
  gem 'vcr', require: false
24
25
  gem 'webmock', require: false
data/README.md CHANGED
@@ -26,6 +26,8 @@ In order to test changes to your gem without having to release, you can update t
26
26
 
27
27
  ## Releasing new version
28
28
 
29
+ We have a higher expectation of testing in this repo than others due to the lower volume of releases and nature of the product. When you are submitting your PR, take a more conservative approach to testing and make sure you are adding tests for all new/changed methods.
30
+
29
31
  Bump the version of the gem within `./lib/rtx/api/version.rb` based on the changes you've made. Once your changes have been merged into master, you can release updated version of your gem. In order to release, you will need to be an owner of the RubyGems project and need to have your API credentials setup in your bash profile. Once complete, run the following command release command.
30
32
 
31
33
  bundle exec rake release
data/bin/console CHANGED
@@ -1,8 +1,10 @@
1
- #!/usr/bin/env ruby
1
+ # frozen_string_literal: true
2
+
3
+ # !/usr/bin/env ruby
2
4
  ENV['RACK_ENV'] ||= 'development'
3
5
  # load path
4
- lib_path = File.expand_path('../../lib', __FILE__)
5
- ($:.unshift lib_path) unless ($:.include? lib_path)
6
+ lib_path = File.expand_path('../lib', __dir__)
7
+ ($LOAD_PATH.unshift lib_path) unless $LOAD_PATH.include? lib_path
6
8
 
7
9
  # require farm
8
10
  require 'bundler'
@@ -1,10 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'csv'
4
+
1
5
  module RTX
2
6
  module API
3
7
  class Client
4
8
  include HTTParty
5
9
  attr_accessor :email, :password, :api_url, :token, :expires, :account_id, :profile_id
6
10
 
7
- def initialize(email = ENV["RTX_USER_EMAIL"], password = ENV["RTX_USER_PASSWORD"], api_url = ENV["RTX_API_URL"])
11
+ def initialize(email = ENV['RTX_USER_EMAIL'], password = ENV['RTX_USER_PASSWORD'],
12
+ api_url = ENV['RTX_API_URL'])
8
13
  @email = email
9
14
  @password = password
10
15
  @api_url = api_url
@@ -17,26 +22,36 @@ module RTX
17
22
  end
18
23
 
19
24
  def authenticate
20
- request = self.class.post("#{rtx_api_url}/auth", headers: default_headers, basic_auth: {username: email, password: password})
25
+ request = self.class.post("#{rtx_api_url}/auth", headers: default_headers,
26
+ basic_auth: {
27
+ username: email,
28
+ password: password
29
+ })
21
30
  response = Oj.load(request.body, symbol_keys: true)
22
31
  if request.code != 201
23
- raise API::Errors::AuthenticationError.new("Authentication Login Error: #{response}")
32
+ raise API::Errors::AuthenticationError, "Authentication Login Error: #{response}"
24
33
  end
25
- set_attributes(response[:token], response[:expires_at], response[:account_id], response[:profile_id])
34
+
35
+ set_attributes(response[:token], response[:expires_at], response[:account_id],
36
+ response[:profile_id])
26
37
  end
27
38
 
28
39
  def authenticate_as(email, &block)
29
40
  authenticate if !authenticated?
30
41
  response = collection(:users, email: email)
31
- if response[:_total] == 1
32
- user = response[:_embedded][:users][0]
33
- auth_response = post(:auth_tokens, account_id: user[:account_id], user_id: user[:id])
34
- client = self.class.new(auth_response[:email], auth_response[:token])
35
- client.set_attributes(auth_response[:token], auth_response[:expires_at], auth_response[:account_id], auth_response[:profile_id])
36
- block.call(client)
37
- else
38
- raise API::Errors::ClientError.new("User not found with associated email address: #{email}")
42
+
43
+ unless response[:_total] == 1
44
+ raise API::Errors::ClientError,
45
+ "User not found with associated email address: #{email}"
39
46
  end
47
+
48
+ user = response[:_embedded][:users][0]
49
+ auth_response = post(:auth_tokens, account_id: user[:account_id], user_id: user[:id])
50
+ client = self.class.new(auth_response[:email], auth_response[:token])
51
+ client.set_attributes(auth_response[:token], auth_response[:expires_at],
52
+ auth_response[:account_id], auth_response[:profile_id])
53
+ block.call(client)
54
+
40
55
  true
41
56
  end
42
57
 
@@ -45,80 +60,111 @@ module RTX
45
60
  end
46
61
 
47
62
  def logout
48
- if token
49
- request = self.class.delete("#{rtx_api_url}/auth", options(:delete))
50
- if request.code != 204
51
- raise API::Errors::AuthenticationError.new("Authentication Logout Error: #{request}")
52
- end
53
- @token, @expires, @account_id, @profile_id = nil, nil, nil, nil
63
+ return unless token
64
+
65
+ request = self.class.delete("#{rtx_api_url}/auth", options(:delete))
66
+ if request.code != 204
67
+ raise API::Errors::AuthenticationError, "Authentication Logout Error: #{request}"
54
68
  end
55
- end
56
69
 
57
- def method_missing(method, *args, &block)
58
- if resource_path(method)
59
- attrs = {}
60
- if args.size > 0
61
- attrs = args.last.is_a?(Hash) ? args.pop : {}
62
- end
70
+ @token = nil
71
+ @expires = nil
72
+ @account_id = nil
73
+ @profile_id = nil
74
+ end
63
75
 
64
- # Use V2 Collection if prefixed with V2
65
- return RTX::API::CollectionV2.new(self, method, attrs) if method.to_s.start_with?('v2_')
76
+ # rubocop:disable Lint/RedundantCopDisableDirective
77
+ # rubocop:disable Style/MissingRespondToMissing
78
+ # rubocop:disable Style/MethodMissingSuper
79
+ def method_missing(method, *args)
80
+ return unless resource_path(method)
66
81
 
67
- RTX::API::Collection.new(self, method, attrs)
82
+ attrs = {}
83
+ if args.size.zero?
84
+ attrs = args.last.is_a?(Hash) ? args.pop : {}
68
85
  end
86
+
87
+ # Use V2 Collection if prefixed with V2
88
+ return RTX::API::CollectionV2.new(self, method, attrs) if method.to_s.start_with?('v2_')
89
+
90
+ RTX::API::Collection.new(self, method, attrs)
69
91
  end
92
+ # rubocop:enable Style/MissingRespondToMissing
93
+ # rubocop:enable Style/MethodMissingSuper
94
+ # rubocop:enable Lint/RedundantCopDisableDirective
70
95
 
71
96
  def collection(resource_name, attrs = {})
72
- request = self.class.get("#{rtx_api_url}/#{resource_path(resource_name)}", options(:get, attrs))
97
+ request = self.class.get("#{rtx_api_url}/#{resource_path(resource_name)}",
98
+ options(:get, attrs))
73
99
  handle_request(request)
74
100
  end
75
101
 
76
102
  def detail(resource_name, resource_id, attrs = {})
77
- raise API::Errors::RequestError.new("id was not provided") if resource_id.nil?
78
- request = self.class.get("#{rtx_api_url}/#{resource_path(resource_name)}/#{resource_id}", options(:get, attrs))
103
+ raise API::Errors::RequestError, 'id was not provided' if resource_id.nil?
104
+
105
+ request = self.class.get("#{rtx_api_url}/#{resource_path(resource_name)}/#{resource_id}",
106
+ options(:get, attrs))
79
107
  handle_request(request)
80
108
  end
81
109
 
82
110
  def post(resource_name, attrs = {})
83
- request = self.class.post("#{rtx_api_url}/#{resource_path(resource_name)}", options(:post, attrs))
111
+ request = self.class.post("#{rtx_api_url}/#{resource_path(resource_name)}",
112
+ options(:post, attrs))
84
113
  handle_request(request)
85
114
  end
86
115
 
87
116
  def put(resource_name, resource_id, attrs = {})
88
- raise API::Errors::RequestError.new("id was not provided") if resource_id.nil?
89
- request = self.class.put("#{rtx_api_url}/#{resource_path(resource_name)}/#{resource_id}", options(:put, attrs))
117
+ raise API::Errors::RequestError, 'id was not provided' if resource_id.nil?
118
+
119
+ request = self.class.put("#{rtx_api_url}/#{resource_path(resource_name)}/#{resource_id}",
120
+ options(:put, attrs))
90
121
  handle_request(request)
91
122
  end
92
123
 
93
124
  def patch(resource_name, resource_id, attrs = {})
94
- raise API::Errors::RequestError.new("id was not provided") if resource_id.nil?
95
- request = self.class.patch("#{rtx_api_url}/#{resource_path(resource_name)}/#{resource_id}", options(:patch, attrs))
125
+ raise API::Errors::RequestError, 'id was not provided' if resource_id.nil?
126
+
127
+ request = self.class.patch("#{rtx_api_url}/#{resource_path(resource_name)}/#{resource_id}",
128
+ options(:patch, attrs))
96
129
  handle_request(request)
97
130
  end
98
131
 
99
132
  def delete(resource_name, resource_id)
100
- raise API::Errors::RequestError.new("id was not provided") if resource_id.nil?
101
- request = self.class.delete("#{rtx_api_url}/#{resource_path(resource_name)}/#{resource_id}", options(:delete))
133
+ raise API::Errors::RequestError, 'id was not provided' if resource_id.nil?
134
+
135
+ request = self.class.delete(
136
+ "#{rtx_api_url}/#{resource_path(resource_name)}/#{resource_id}", options(:delete)
137
+ )
102
138
  handle_request(request)
103
139
  end
104
140
 
105
- def handle_request(request)
106
- if !request.success?
107
- raise API::Errors::RequestError.new("#{request.parsed_response}")
108
- end
141
+ def get(resource_name, attrs = {}, file_type = 'json')
142
+ request = self.class.get("#{rtx_api_url}/#{resource_path(resource_name)}",
143
+ options(:get, attrs))
109
144
 
110
- if request.parsed_response.nil?
111
- return true
112
- end
145
+ handle_request(request, file_type)
146
+ end
147
+
148
+ def handle_request(request, file_type = 'json')
149
+ raise API::Errors::RequestError, request.parsed_response.to_s if !request.success?
113
150
 
114
- Oj.load(request.body, symbol_keys: true)
151
+ return true if request.parsed_response.nil?
152
+
153
+ case file_type
154
+ when 'json'
155
+ Oj.load(request.body, symbol_keys: true)
156
+ when 'csv'
157
+ CSV.parse(request.body)
158
+ end
115
159
  end
116
160
 
117
161
  def resource_path(resource_name)
118
162
  path = API::Resources.allowed_resources[resource_name.to_sym]
119
163
  if !path
120
- raise API::Errors::InvalidResourceError.new("The resource provided (#{resource_name}) is not allowed")
164
+ raise API::Errors::InvalidResourceError,
165
+ "The resource provided (#{resource_name}) is not allowed"
121
166
  end
167
+
122
168
  path
123
169
  end
124
170
 
@@ -133,14 +179,14 @@ module RTX
133
179
 
134
180
  def default_headers
135
181
  {
136
- 'Content-Type' => "application/hal+json",
137
- 'Accept' => "application/hal+json",
182
+ 'Content-Type' => 'application/hal+json',
183
+ 'Accept' => 'application/hal+json',
138
184
  'User-Agent' => "rtx-api-client-ruby/#{API::VERSION}"
139
185
  }.freeze
140
186
  end
141
187
 
142
188
  def options(action, attrs = {})
143
- options = {headers: default_headers, basic_auth: {username: email, password: token}}
189
+ options = { headers: default_headers, basic_auth: { username: email, password: token } }
144
190
  if write_request?(action)
145
191
  options[:body] = Oj.dump(attrs, mode: :compat)
146
192
  else
@@ -150,11 +196,11 @@ module RTX
150
196
  end
151
197
 
152
198
  def rtx_api_url
153
- api_url || ENV["RTX_API_URL"] || "https://api-gateway.reviewtrackers.com"
199
+ api_url || ENV['RTX_API_URL'] || 'https://api-gateway.reviewtrackers.com'
154
200
  end
155
201
 
156
202
  def write_request?(action)
157
- (action == :post || action == :put || action == :patch)
203
+ %i[post put patch].include?(action)
158
204
  end
159
205
  end
160
206
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RTX
2
4
  module API
3
5
  class Collection
@@ -40,7 +42,13 @@ module RTX
40
42
  delete(symbolize_hash(attrs))
41
43
  end
42
44
 
43
- # Chainable method that allows you to set the per page number of the collection for your request
45
+ def get!(attrs = {}, file_type = 'json')
46
+ client.authenticate if !client.authenticated?
47
+ get(symbolize_hash(attrs), file_type)
48
+ end
49
+
50
+ # Chainable method that allows you to set the per page number of
51
+ # the collection for your request
44
52
  def per_page(num)
45
53
  clear if !num.nil?
46
54
  @options[:per_page] = num
@@ -65,22 +73,18 @@ module RTX
65
73
  def meta
66
74
  client.authenticate if !client.authenticated?
67
75
  collection if !has_response?
68
- response.reject {|key,_| key == :_embedded}
76
+ response.reject { |key, _| key == :_embedded }
69
77
  end
70
78
 
71
79
  # For moving forward one page with the collection
72
80
  def next
73
- if has_next?
74
- page(options[:page] += 1)
75
- end
81
+ page(options[:page] += 1) if has_next?
76
82
  self
77
83
  end
78
84
 
79
85
  # For moving backward one page with the collection
80
86
  def prev
81
- if has_previous?
82
- page(options[:page] -= 1)
83
- end
87
+ page(options[:page] -= 1) if has_previous?
84
88
  self
85
89
  end
86
90
 
@@ -116,7 +120,8 @@ module RTX
116
120
  end
117
121
  end
118
122
 
119
- # Allows you to loop through all of the resources within the pages specified and retrieve the records
123
+ # Allows you to loop through all of the resources
124
+ # within the pages specified and retrieve the records
120
125
  def all_resources(initial_page = 1, &block)
121
126
  all_pages(initial_page) do |page|
122
127
  page.each do |resource|
@@ -164,12 +169,16 @@ module RTX
164
169
  client.delete(resource_name, resource_id)
165
170
  end
166
171
 
172
+ def get(attrs = {}, file_type = 'json')
173
+ client.get(resource_name, attrs, file_type)
174
+ end
175
+
167
176
  def has_response?
168
177
  response != {}
169
178
  end
170
179
 
171
180
  def symbolize_hash(hash)
172
- Hash[hash.map{|(key,value)| [key.to_sym,value]}]
181
+ Hash[hash.map { |(key, value)| [key.to_sym, value] }]
173
182
  end
174
183
  end
175
184
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RTX
2
4
  module API
3
5
  class CollectionV2
@@ -10,7 +12,8 @@ module RTX
10
12
  @response = {}
11
13
  end
12
14
 
13
- # Chainable method that allows you to set the per page number of the collection for your request
15
+ # Chainable method that allows you to set
16
+ # the per page number of the collection for your request
14
17
  def per_page(num)
15
18
  clear if !num.nil?
16
19
  @options[:per_page] = num
@@ -33,17 +36,13 @@ module RTX
33
36
 
34
37
  # For moving forward one page with the collection
35
38
  def next
36
- if has_next?
37
- next_page(after_token)
38
- end
39
+ next_page(after_token) if has_next?
39
40
  self
40
41
  end
41
42
 
42
43
  # For moving backward one page with the collection
43
44
  def prev
44
- if has_previous?
45
- previous_page(before_token)
46
- end
45
+ previous_page(before_token) if has_previous?
47
46
  self
48
47
  end
49
48
 
@@ -71,7 +70,8 @@ module RTX
71
70
  end
72
71
  end
73
72
 
74
- # Allows you to loop through all of the resources within the pages specified and retrieve the records
73
+ # Allows you to loop through all of
74
+ # the resources within the pages specified and retrieve the records
75
75
  def all_resources(&block)
76
76
  all_pages do |page|
77
77
  page.each do |resource|
@@ -123,8 +123,8 @@ module RTX
123
123
  end
124
124
 
125
125
  def symbolize_hash(hash)
126
- Hash[hash.map{|(key,value)| [key.to_sym,value]}]
126
+ Hash[hash.map { |(key, value)| [key.to_sym, value] }]
127
127
  end
128
128
  end
129
129
  end
130
- end
130
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RTX
2
4
  module API
3
5
  module Errors
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RTX
2
4
  module API
3
5
  module Errors
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RTX
2
4
  module API
3
5
  module Errors
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RTX
2
4
  module API
3
5
  module Errors
@@ -21,6 +21,8 @@ module RTX
21
21
  items: 'items',
22
22
  layouts: 'layouts',
23
23
  locations: 'locations',
24
+ metric_locations: 'export/csv/location_metrics',
25
+ metric_groups: 'export/csv/group_metrics',
24
26
  notes: 'notes',
25
27
  passwords: 'passwords',
26
28
  permissions: 'permissions',
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RTX
4
4
  module API
5
- VERSION = '0.5.1'
5
+ VERSION = '0.6.0'
6
6
  end
7
7
  end
data/lib/rtx/api.rb CHANGED
@@ -1,21 +1,23 @@
1
- require "oj"
2
- require "httparty"
3
- require "rtx/api/version"
1
+ # frozen_string_literal: true
2
+
3
+ require 'oj'
4
+ require 'httparty'
5
+ require 'rtx/api/version'
4
6
 
5
7
  # client
6
- require "rtx/api/client"
8
+ require 'rtx/api/client'
7
9
 
8
10
  # resources
9
- require "rtx/api/resources"
10
- require "rtx/api/collection"
11
- require "rtx/api/collection_v2"
11
+ require 'rtx/api/resources'
12
+ require 'rtx/api/collection'
13
+ require 'rtx/api/collection_v2'
12
14
 
13
15
  # errors
14
- require "rtx/api/errors/client_error"
15
- require "rtx/api/errors/authentication_error"
16
- require "rtx/api/errors/request_error"
17
- require "rtx/api/errors/invalid_resource_error"
16
+ require 'rtx/api/errors/client_error'
17
+ require 'rtx/api/errors/authentication_error'
18
+ require 'rtx/api/errors/request_error'
19
+ require 'rtx/api/errors/invalid_resource_error'
18
20
 
19
21
  module RTX
20
22
  module API; end
21
- end
23
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rtx-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Review Trackers Engineering
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-07-16 00:00:00.000000000 Z
11
+ date: 2021-09-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -74,6 +74,7 @@ extensions: []
74
74
  extra_rdoc_files: []
75
75
  files:
76
76
  - ".gitignore"
77
+ - ".rubocop.yml"
77
78
  - ".travis.yml"
78
79
  - Gemfile
79
80
  - LICENSE
@@ -111,7 +112,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
111
112
  - !ruby/object:Gem::Version
112
113
  version: '0'
113
114
  requirements: []
114
- rubygems_version: 3.1.1
115
+ rubyforge_project:
116
+ rubygems_version: 2.6.8
115
117
  signing_key:
116
118
  specification_version: 4
117
119
  summary: Ruby Client for the Review Trackers RTX API.