promoted-ruby-client 0.1.18 → 0.1.22

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c49d0a2668c2ac163b2fb9bbfb13fcff75d6a4f558b8e62b633bc590d094c269
4
- data.tar.gz: c0bc6218512f2883bd2fcbdfc60d4f5a9da05b93a9872bd60c1ce65bbd1d6ec9
3
+ metadata.gz: e4cc088a08f160f3a238022f030e042df9a583fdbe22310b007027a9b908b406
4
+ data.tar.gz: 3b9434274cef7986cceea4876170b9061d873bfa533f0047adff546fd1f20d77
5
5
  SHA512:
6
- metadata.gz: d92f40acf137305cbce1c2e66d3f9b40d9ed5d58f97fc84b0beb2a9ecc7a47671316c012c36279bdbed401f8d1f81001dcbf352f70507593c48d14cbd829e6b1
7
- data.tar.gz: 0fddc62d1ea650b98653b8f05680d15e9245d0259c835408113c4b4dbab4baa16360735755656d7fec42466e2254bf3fd69e7187f3dbc44e97f1b435b94afbab
6
+ metadata.gz: b9b3a44c22c7bbbb632024b21aa6062253f2cd9e6f3cba73f015eccb1f4fa3a91bfc14cfdabee57a64510ae53a16fe2f01e30f645002b1dc40ea511f8854e54b
7
+ data.tar.gz: d20bb330c762ea83cf75246a256a20d250d1d3b0e2b1af7fa7ca8d2f5840671505a10584c2d8c3f30fa040daf7d10bbdcd5859454dd822c7898b711e300257eb
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- promoted-ruby-client (0.1.18)
4
+ promoted-ruby-client (0.1.22)
5
5
  concurrent-ruby (~> 1)
6
6
  faraday (>= 0.9.0)
7
7
  faraday_middleware (>= 0.9.0)
data/README.md CHANGED
@@ -49,6 +49,7 @@ Name | Type | Description
49
49
  ```:perform_checks``` | Boolean | Whether or not to perform detailed input validation, defaults to true but may be disabled for performance
50
50
  ```:logger``` | Ruby Logger-compatible logger | Defaults to nil (no logging). Example: ```Logger.new(STDERR, :progname => 'promotedai')```
51
51
  ```:shadow_traffic_delivery_percent``` | Number between 0 and 1 | % of ```prepare_for_logging``` traffic that gets directed to Delivery API as "shadow traffic". Defaults to 0 (no shadow traffic).
52
+ ```:send_shadow_traffic_for_control``` | Boolean | If true, the ```deliver``` method will send shadow traffic for users in the CONTROL arm of an experiment. Defaults to true.
52
53
  ```:default_request_headers``` | Hash | Additional headers to send on the request beyond ```x-api-key```. Defaults to {}
53
54
  ```:default_only_log``` | Boolean | If true, the ```deliver``` method will not direct traffic to Delivery API but rather return a request suitable for logging. Defaults to false.
54
55
  ```:should_apply_treatment_func``` | Proc | Called during delivery, accepts an experiment and returns a Boolean indicating whether the request should be considered part of the control group (false) or in the experiment (true). If nil, the default behavior of checking the experiement ```:arm``` is applied.
@@ -62,6 +63,7 @@ Field Name | Type | Optional? | Description
62
63
  ---------- | ---- | --------- | -----------
63
64
  ```:user_id``` | String | Yes | The platform user id, cleared from Promoted logs.
64
65
  ```:log_user_id``` | String | Yes | A different user id (presumably a UUID) disconnected from the platform user id, good for working with unauthenticated users or implementing right-to-be-forgotten.
66
+ ```:is_internal_user``` | Boolean | Yes | If this user is a test user or not, defaults to false.
65
67
 
66
68
  ---
67
69
  ### CohortMembership
@@ -93,8 +95,76 @@ Field Name | Type | Optional? | Description
93
95
  ```:insertion_id``` | String | Yes | Generated by the SDK (*do not set*)
94
96
  ```:request_id``` | String | Yes | Generated by the SDK when needed (*do not set*)
95
97
  ```:content_id``` | String | No | Identifier for the content to be shown, must be set.
98
+ ```:retrieval_rank``` | Number | Yes | Optional original ranking of this content item.
99
+ ```:retrieval_score``` | Number | Yes | Optional original quality score of this content item.
96
100
  ```:properties``` | Properties | Yes | Any additional custom properties to associate. For v1 integrations, it is fine not to fill in all the properties.
101
+ ---
102
+ ### Size
103
+ User's screen dimensions.
104
+ Field Name | Type | Optional? | Description
105
+ ---------- | ---- | --------- | -----------
106
+ ```:width``` | Integer | No | Screen width
107
+ ```:height``` | Integer | No | Screen height
108
+ ---
97
109
 
110
+ ### Screen
111
+ State of the screen including scaling.
112
+ Field Name | Type | Optional? | Description
113
+ ---------- | ---- | --------- | -----------
114
+ ```:size``` | Size | Yes | Screen size
115
+ ```:scale``` | Float | Yes | Current screen scaling factor
116
+ ---
117
+
118
+ ### ClientHints
119
+ Alternative to user-agent strings. See https://raw.githubusercontent.com/snowplow/iglu-central/master/schemas/org.ietf/http_client_hints/jsonschema/1-0-0
120
+ Field Name | Type | Optional? | Description
121
+ ---------- | ---- | --------- | -----------
122
+ ```:is_mobile``` | Boolean | Yes | Mobile flag
123
+ ```:brand``` | Array of ClientBrandHint | Yes |
124
+ ```:architecture``` | String | Yes |
125
+ ```:model``` | String | Yes |
126
+ ```:platform``` | String | Yes |
127
+ ```:platform_version``` | String | Yes |
128
+ ```:ua_full_version``` | String | Yes |
129
+
130
+ ---
131
+ ### ClientBrandHint
132
+ See https://raw.githubusercontent.com/snowplow/iglu-central/master/schemas/org.ietf/http_client_hints/jsonschema/1-0-0
133
+ Field Name | Type | Optional? | Description
134
+ ---------- | ---- | --------- | -----------
135
+ ```:brand``` | String | Yes | Mobile flag
136
+ ```:version``` | String | Yes |
137
+
138
+ ---
139
+ ### Location
140
+ Information about the user's location.
141
+ Field Name | Type | Optional? | Description
142
+ ---------- | ---- | --------- | -----------
143
+ ```:latitude``` | Float | No | Location latitude
144
+ ```:longitude``` | Float | No | Location longitude
145
+ ```:accuracy_in_meters``` | Integer | Yes | Location accuracy if available
146
+ ---
147
+
148
+ ### Browser
149
+ Information about the user's browser.
150
+ Field Name | Type | Optional? | Description
151
+ ---------- | ---- | --------- | -----------
152
+ ```:user_agent``` | String | Yes | Browser user agent string
153
+ ```:viewport_size``` | Size | Yes | Size of the browser viewport
154
+ ```:client_hints``` | ClientHints | Yes | HTTP client hints structure
155
+ ---
156
+ ### Device
157
+ Information about the user's device.
158
+ Field Name | Type | Optional? | Description
159
+ ---------- | ---- | --------- | -----------
160
+ ```:device_type``` | one of (`UNKNOWN_DEVICE_TYPE`, `DESKTOP`, `MOBILE`, `TABLET`) | Yes | Type of device
161
+ ```:brand``` | String | Yes | "Apple, "google", Samsung", etc.
162
+ ```:manufacturer``` | String | Yes | "Apple", "HTC", Motorola", "HUAWEI", etc.
163
+ ```:identifier``` | String | Yes | Android: android.os.Build.MODEL; iOS: iPhoneXX,YY, etc.
164
+ ```:screen``` | Screen | Yes | Screen dimensions
165
+ ```:ip_address``` | String | Yes | Originating IP address
166
+ ```:location``` | Location | Yes | Location information
167
+ ```:browser``` | Browser | Yes | Browser information
98
168
  ---
99
169
  ### Paging
100
170
  #### TODO
@@ -108,6 +178,7 @@ Field Name | Type | Optional? | Description
108
178
  ```:use_case``` | String | Yes | One of the use case values, i.e. 'FEED' (see [constants.rb](https://github.com/promotedai/promoted-ruby-client/blob/main/lib/promoted/ruby/client/constants.rb)).
109
179
  ```:properties``` | Properties | Yes | Any additional custom properties to associate.
110
180
  ```:paging``` | Paging | Yes | Paging parameters (see TODO)
181
+ ```:device``` | Device | Yes | Device information (as available)
111
182
  ---
112
183
  ### MetricsRequest
113
184
  Input to ```prepare_for_logging```
@@ -142,6 +213,8 @@ Field Name | Type | Optional? | Description
142
213
  ---------- | ---- | --------- | -----------
143
214
  ```:insertion``` | [] of Insertion | No | The insertions, which are from Delivery API (when ```deliver``` was called, i.e. we weren't either only-log or part of an experiment) or the input insertions (when the other conditions don't hold).
144
215
  ```:log_request``` | LogRequest | Yes | A message suitable for logging to Metrics API via ```send_log_request```. If the call to ```deliver``` was made (i.e. the request was not part of the CONTROL arm of an experiment or marked to only log), ```:log_request``` will not be set, as you can assume logging was performed on the server-side by Promoted.
216
+ ```:client_request_id``` | String | Yes | Client-generated request id sent to Delivery API and may be useful for logging and debugging.
217
+ ```:execution_server``` | one of 'API' or 'SDK' | Yes | Indicates if response insertions on a delivery request came from the API or the SDK.
145
218
  ---
146
219
 
147
220
  ### PromotedClient
data/dev.md CHANGED
@@ -4,5 +4,5 @@
4
4
  2. Get credentials for deployment from 1password.
5
5
  3. Modify `promoted-ruby-client.gemspec`'s push block.
6
6
  4. Run `gem build promoted-ruby-client.gemspec` to generate `gem`.
7
- 5. Run (using new output) `gem push promoted-ruby-client-0.1.18.gem`
7
+ 5. Run (using new output) `gem push promoted-ruby-client-0.1.22.gem`
8
8
  6. Update README with new version.
@@ -32,6 +32,13 @@ module Promoted
32
32
  CLIENT_TYPE = {'UNKNOWN_REQUEST_CLIENT' => 'UNKNOWN_REQUEST_CLIENT',
33
33
  'PLATFORM_SERVER' => 'PLATFORM_SERVER',
34
34
  'PLATFORM_CLIENT' => 'PLATFORM_CLIENT'}
35
+
36
+ EXECUTION_SERVER = {'API' => 'API', 'SDK' => 'SDK'}
37
+
38
+ DEVICE_TYPE = {'UNKNOWN_DEVICE_TYPE' => 'UNKNOWN_DEVICE_TYPE',
39
+ 'DESKTOP' => 'DESKTOP',
40
+ 'MOBILE' => 'MOBILE',
41
+ 'TABLET' => 'TABLET'}
35
42
  end
36
43
  end
37
44
  end
@@ -11,13 +11,13 @@ module Promoted
11
11
  end
12
12
 
13
13
  class Pager
14
- def validate_paging (insertions, paging)
14
+ def validate_paging(insertions, paging)
15
15
  if paging && paging[:offset] && paging[:offset] >= insertions.length
16
16
  raise InvalidPagingError.new("Invalid page offset (insertion size #{insertions.length}, offset #{paging[:offset]})", [])
17
17
  end
18
18
  end
19
19
 
20
- def apply_paging (insertions, insertion_page_type, paging = nil)
20
+ def apply_paging(insertions, insertion_page_type, paging = nil)
21
21
  begin
22
22
  validate_paging(insertions, paging)
23
23
  rescue InvalidPagingError => err
@@ -47,7 +47,7 @@ module Promoted
47
47
  size = insertions.length
48
48
  end
49
49
 
50
- final_insertion_size = [size, insertions.length].min
50
+ final_insertion_size = [size, insertions.length - index].min
51
51
  insertion_page = Array.new(final_insertion_size)
52
52
  0.upto(final_insertion_size - 1) {|i|
53
53
  insertion = insertions[index]
@@ -63,5 +63,5 @@ module Promoted
63
63
  end
64
64
  end
65
65
  end
66
- end
66
+ end
67
67
  end
@@ -2,7 +2,7 @@ module Promoted
2
2
  module Ruby
3
3
  module Client
4
4
  class RequestBuilder
5
- attr_reader :session_id, :only_log, :experiment, :client_info,
5
+ attr_reader :session_id, :only_log, :experiment, :client_info, :device,
6
6
  :view_id, :insertion, :to_compact_delivery_properties_func,
7
7
  :request_id, :full_insertion, :use_case, :request, :to_compact_metrics_properties_func
8
8
 
@@ -24,6 +24,7 @@ module Promoted
24
24
  @session_id = request[:session_id]
25
25
  @platform_id = request[:platform_id]
26
26
  @client_info = request[:client_info] || {}
27
+ @device = request[:device] || {}
27
28
  @view_id = request[:view_id]
28
29
  @use_case = Promoted::Ruby::Client::USE_CASES[request[:use_case]] || Promoted::Ruby::Client::USE_CASES['UNKNOWN_USE_CASE']
29
30
  @full_insertion = args[:full_insertion]
@@ -56,7 +57,8 @@ module Promoted
56
57
  params = {
57
58
  user_info: user_info,
58
59
  timing: timing,
59
- client_info: @client_info.merge({ :client_type => Promoted::Ruby::Client::CLIENT_TYPE['PLATFORM_SERVER'] }),
60
+ client_info: merge_client_info_defaults,
61
+ device: @device,
60
62
  platform_id: @platform_id,
61
63
  view_id: @view_id,
62
64
  session_id: @session_id,
@@ -64,7 +66,7 @@ module Promoted
64
66
  search_query: request[:search_query],
65
67
  properties: request[:properties],
66
68
  paging: request[:paging],
67
- client_request_id: request[:client_request_id]
69
+ client_request_id: client_request_id
68
70
  }
69
71
  params[:insertion] = insertions_with_compact_props(@to_compact_delivery_properties_func)
70
72
 
@@ -76,7 +78,7 @@ module Promoted
76
78
  # to the responses.
77
79
  def fill_details_from_response response_insertions
78
80
  if !response_insertions then
79
- response_insertions = full_insertion
81
+ response_insertions = []
80
82
  end
81
83
 
82
84
  props = @full_insertion.each_with_object({}) do |insertion, hash|
@@ -102,7 +104,8 @@ module Promoted
102
104
  params = {
103
105
  user_info: user_info,
104
106
  timing: timing,
105
- client_info: @client_info
107
+ client_info: merge_client_info_defaults,
108
+ device: @device
106
109
  }
107
110
 
108
111
  if @experiment
@@ -175,7 +178,6 @@ module Promoted
175
178
  insertion_obj = Hash[insertion_obj]
176
179
  insertion_obj[:user_info] = user_info
177
180
  insertion_obj[:timing] = timing
178
- insertion_obj[:insertion_id] = @id_generator.newID
179
181
  insertion_obj[:request_id] = request_id
180
182
  insertion_obj[:position] = offset + index
181
183
  insertion_obj = compact_one_insertion(insertion_obj, @to_compact_metrics_properties_func)
@@ -184,14 +186,31 @@ module Promoted
184
186
  @insertion
185
187
  end
186
188
 
189
+ def add_missing_insertion_ids! insertions
190
+ insertions.each do |insertion|
191
+ insertion[:insertion_id] = @id_generator.newID if not insertion[:insertion_id]
192
+ end
193
+ end
194
+
195
+ def client_request_id
196
+ request[:client_request_id]
197
+ end
198
+
187
199
  private
188
200
 
201
+ def merge_client_info_defaults
202
+ return @client_info.merge({
203
+ :client_type => Promoted::Ruby::Client::CLIENT_TYPE['PLATFORM_SERVER'],
204
+ :traffic_type => Promoted::Ruby::Client::TRAFFIC_TYPE['PRODUCTION']
205
+ })
206
+ end
207
+
189
208
  def add_missing_ids_on_insertions! request, insertions
190
209
  insertions.each do |insertion|
191
- insertion[:insertion_id] = @id_generator.newID if not insertion[:insertion_id]
192
210
  insertion[:session_id] = request[:session_id] if request[:session_id]
193
211
  insertion[:request_id] = request[:request_id] if request[:request_id]
194
212
  end
213
+ add_missing_insertion_ids! insertions
195
214
  end
196
215
 
197
216
  # A list of the response Insertions. This client expects lists to be truncated
@@ -14,6 +14,10 @@ module Promoted
14
14
  {
15
15
  :name => :log_user_id,
16
16
  :type => String
17
+ },
18
+ {
19
+ :name => :is_internal_user,
20
+ :type => [TrueClass, FalseClass]
17
21
  }
18
22
  ]
19
23
  )
@@ -133,7 +137,6 @@ module Promoted
133
137
  req[:full_insertion].each do |insertion_hash|
134
138
  raise ValidationError.new("Insertion.requestId should not be set") if insertion_hash[:request_id]
135
139
  raise ValidationError.new("'Insertion.insertionId should not be set") if insertion_hash[:insertion_id]
136
- raise ValidationError.new("Insertion.deliveryScore should not be set") if insertion_hash[:delivery_score]
137
140
  end
138
141
  end
139
142
 
@@ -147,7 +150,11 @@ module Promoted
147
150
 
148
151
  # If a field is provided as non-nil, it should be of the correct type.
149
152
  if field[:type] && obj.has_key?(field[:name]) && obj[field[:name]] != nil then
150
- raise ValidationError.new(field[:name].to_s + " should be a " + field[:type].to_s) if !obj[field[:name]].is_a?(field[:type])
153
+ if field[:type].is_a?(Array) then
154
+ raise ValidationError.new(field[:name].to_s + " should be one of " + field[:type].to_s) if !field[:type].include?(obj[field[:name]].class)
155
+ else
156
+ raise ValidationError.new(field[:name].to_s + " should be a " + field[:type].to_s) if !obj[field[:name]].is_a?(field[:type])
157
+ end
151
158
  end
152
159
  }
153
160
  end
@@ -1,7 +1,7 @@
1
1
  module Promoted
2
2
  module Ruby
3
3
  module Client
4
- VERSION = "0.1.18"
4
+ VERSION = "0.1.22"
5
5
  end
6
6
  end
7
7
  end
@@ -19,7 +19,8 @@ module Promoted
19
19
  class Error < StandardError; end
20
20
 
21
21
  attr_reader :perform_checks, :default_only_log, :delivery_timeout_millis, :metrics_timeout_millis, :should_apply_treatment_func,
22
- :default_request_headers, :http_client, :logger, :shadow_traffic_delivery_percent, :async_shadow_traffic
22
+ :default_request_headers, :http_client, :logger, :shadow_traffic_delivery_percent, :async_shadow_traffic,
23
+ :send_shadow_traffic_for_control
23
24
 
24
25
  attr_accessor :request_logging_on, :enabled
25
26
 
@@ -39,7 +40,7 @@ module Promoted
39
40
 
40
41
  ##
41
42
  # Create and configure a new Promoted client.
42
- def initialize (params={})
43
+ def initialize(params={})
43
44
  @perform_checks = true
44
45
  if params[:perform_checks] != nil
45
46
  @perform_checks = params[:perform_checks]
@@ -79,6 +80,11 @@ module Promoted
79
80
  @async_shadow_traffic = params[:async_shadow_traffic] || false
80
81
  end
81
82
 
83
+ @send_shadow_traffic_for_control = true
84
+ if params[:send_shadow_traffic_for_control] != nil
85
+ @send_shadow_traffic_for_control = params[:send_shadow_traffic_for_control] || false
86
+ end
87
+
82
88
  @pool = nil
83
89
  if @async_shadow_traffic
84
90
  # Thread pool to process delivery of shadow traffic. Will silently drop excess requests beyond the queue
@@ -161,9 +167,8 @@ module Promoted
161
167
  cohort_membership_to_log = delivery_request_builder.new_cohort_membership_to_log
162
168
 
163
169
  if should_apply_treatment(cohort_membership_to_log)
164
- delivery_request_params = delivery_request_builder.delivery_request_params
165
-
166
- # Call Delivery API
170
+ # Call Delivery API to get insertions to use
171
+ delivery_request_params = delivery_request_builder.delivery_request_params
167
172
  begin
168
173
  response = send_request(delivery_request_params, @delivery_endpoint, @delivery_timeout_millis, @delivery_api_key, headers)
169
174
  rescue StandardError => err
@@ -172,17 +177,20 @@ module Promoted
172
177
  deliver_err = true
173
178
  @logger.error("Error calling delivery: " + err.message) if @logger
174
179
  end
175
-
176
- insertions_from_delivery = (response != nil && !deliver_err);
177
- response_insertions = delivery_request_builder.fill_details_from_response(
178
- response ? response[:insertion] : [])
180
+ elsif @send_shadow_traffic_for_control
181
+ # Call Delivery API to send shadow traffic. This will create the request params with traffic type set.
182
+ deliver_shadow_traffic args, headers
179
183
  end
184
+
185
+ insertions_from_delivery = (response != nil && !deliver_err);
186
+ response_insertions = delivery_request_builder.fill_details_from_response(
187
+ response && response[:insertion] || [])
180
188
  end
181
189
 
182
190
  request_to_log = nil
183
191
  if !insertions_from_delivery then
184
192
  request_to_log = delivery_request_builder.request
185
- response_insertions = @pager.apply_paging(delivery_request_builder.full_insertion, Promoted::Ruby::Client::INSERTION_PAGING_TYPE['UNPAGED'], delivery_request_builder.request[:paging])
193
+ response_insertions = build_sdk_response_insertions(delivery_request_builder)
186
194
  end
187
195
 
188
196
  log_req = nil
@@ -210,7 +218,9 @@ module Promoted
210
218
 
211
219
  client_response = {
212
220
  insertion: response_insertions,
213
- log_request: log_req
221
+ log_request: log_req,
222
+ execution_server: insertions_from_delivery ? Promoted::Ruby::Client::EXECUTION_SERVER['API'] : Promoted::Ruby::Client::EXECUTION_SERVER['SDK'],
223
+ client_request_id: delivery_request_builder.client_request_id
214
224
  }
215
225
  return client_response
216
226
  end
@@ -264,6 +274,14 @@ module Promoted
264
274
 
265
275
  private
266
276
 
277
+ ##
278
+ # Creates response insertions for SDK-side delivery, when we don't get response insertions from Delivery API.
279
+ def build_sdk_response_insertions delivery_request_builder
280
+ response_insertions = @pager.apply_paging(delivery_request_builder.full_insertion, Promoted::Ruby::Client::INSERTION_PAGING_TYPE['UNPAGED'], delivery_request_builder.request[:paging])
281
+ delivery_request_builder.add_missing_insertion_ids! response_insertions
282
+ return response_insertions
283
+ end
284
+
267
285
  def do_warmup
268
286
  if !@delivery_endpoint
269
287
  # Warmup only supported when delivery is enabled.
@@ -316,7 +334,7 @@ module Promoted
316
334
 
317
335
  ellapsed_time = Time.now - start_time
318
336
  @logger.debug("Sync send_request completed in #{ellapsed_time.to_f * 1000} ms") if @logger
319
- end
337
+ end
320
338
 
321
339
  return resp
322
340
  end
@@ -355,7 +373,7 @@ module Promoted
355
373
 
356
374
  if !@async_shadow_traffic
357
375
  ellapsed_time = Time.now - start_time
358
- insertions = response ? response[:insertion] : []
376
+ insertions = response && response[:insertion] || []
359
377
  @logger.info("Shadow traffic call completed in #{ellapsed_time.to_f * 1000} ms with #{insertions.length} insertions") if @logger
360
378
  end
361
379
  end
@@ -14,6 +14,7 @@ Gem::Specification.new do |spec|
14
14
  spec.homepage = 'https://github.com/promotedai/promoted-ruby-client'
15
15
  spec.license = 'MIT'
16
16
 
17
+ spec.metadata["allowed_push_host"] = "https://rubygems.org/"
17
18
  spec.metadata["homepage_uri"] = spec.homepage
18
19
  spec.metadata["source_code_uri"] = "https://github.com/promotedai/promoted-ruby-client"
19
20
  spec.metadata["changelog_uri"] = "https://github.com/promotedai/promoted-ruby-client/blob/master/CHANGELOG.md"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: promoted-ruby-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.18
4
+ version: 0.1.22
5
5
  platform: ruby
6
6
  authors:
7
7
  - scottmcmaster
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-08-03 00:00:00.000000000 Z
11
+ date: 2021-09-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -150,6 +150,7 @@ homepage: https://github.com/promotedai/promoted-ruby-client
150
150
  licenses:
151
151
  - MIT
152
152
  metadata:
153
+ allowed_push_host: https://rubygems.org/
153
154
  homepage_uri: https://github.com/promotedai/promoted-ruby-client
154
155
  source_code_uri: https://github.com/promotedai/promoted-ruby-client
155
156
  changelog_uri: https://github.com/promotedai/promoted-ruby-client/blob/master/CHANGELOG.md
@@ -168,7 +169,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
168
169
  - !ruby/object:Gem::Version
169
170
  version: '0'
170
171
  requirements: []
171
- rubygems_version: 3.2.24
172
+ rubygems_version: 3.0.3
172
173
  signing_key:
173
174
  specification_version: 4
174
175
  summary: A Ruby Client to contact Promoted APIs.