promoted-ruby-client 0.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 4494d298c8907ddb04588f1430d93ff2e83dd1978df0cfcb419df63db0cf302a
4
+ data.tar.gz: ab8105ad6c2dc8c8fc6992f5a312b240dcda3f13624fa3258fc769685ba9bdf3
5
+ SHA512:
6
+ metadata.gz: 97a95326b32122f9d81292881c139cd0902f98c92dded7015d8ab7483c83b322f1e668f999da981a59e7c686523c74bf2ece6443e3dab26307cf44470f6a0cb9
7
+ data.tar.gz: 703316787c03c1e30eec766fda2f2247d357b8ad4e8c9b99765421a7d0fc119f998ba2cbb342044e229ad8067672a174a2f31f8cf62ce9206f545ba005fc1a11
data/.gitignore ADDED
@@ -0,0 +1,57 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /spec/examples.txt
9
+ /test/tmp/
10
+ /test/version_tmp/
11
+ /tmp/
12
+
13
+ # Used by dotenv library to load environment variables.
14
+ # .env
15
+
16
+ # Ignore Byebug command history file.
17
+ .byebug_history
18
+
19
+ ## Specific to RubyMotion:
20
+ .dat*
21
+ .repl_history
22
+ build/
23
+ *.bridgesupport
24
+ build-iPhoneOS/
25
+ build-iPhoneSimulator/
26
+
27
+ ## Specific to RubyMotion (use of CocoaPods):
28
+ #
29
+ # We recommend against adding the Pods directory to your .gitignore. However
30
+ # you should judge for yourself, the pros and cons are mentioned at:
31
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
32
+ #
33
+ # vendor/Pods/
34
+
35
+ ## Documentation cache and generated files:
36
+ /.yardoc/
37
+ /_yardoc/
38
+ /doc/
39
+ /rdoc/
40
+
41
+ ## Environment normalization:
42
+ /.bundle/
43
+ /vendor/bundle
44
+ /lib/bundler/man/
45
+
46
+ # for a library or gem, you might want to ignore these files since the code is
47
+ # intended to run in multiple environments; otherwise, check them in:
48
+ # Gemfile.lock
49
+ # .ruby-version
50
+ # .ruby-gemset
51
+
52
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
53
+ .rvmrc
54
+ .rspec_status
55
+
56
+ # Used by RuboCop. Remote config files pulled in from inherit_from directive.
57
+ # .rubocop-https?--*
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in promoted-ruby-client.gemspec
6
+ gemspec
7
+
8
+ gem 'faraday', '~> 1.4.1'
9
+ gem 'byebug'
data/Gemfile.lock ADDED
@@ -0,0 +1,49 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ promoted-ruby-client (0.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ byebug (11.1.3)
10
+ diff-lcs (1.4.4)
11
+ faraday (1.4.1)
12
+ faraday-excon (~> 1.1)
13
+ faraday-net_http (~> 1.0)
14
+ faraday-net_http_persistent (~> 1.1)
15
+ multipart-post (>= 1.2, < 3)
16
+ ruby2_keywords (>= 0.0.4)
17
+ faraday-excon (1.1.0)
18
+ faraday-net_http (1.0.1)
19
+ faraday-net_http_persistent (1.1.0)
20
+ multipart-post (2.1.1)
21
+ rake (10.5.0)
22
+ rspec (3.10.0)
23
+ rspec-core (~> 3.10.0)
24
+ rspec-expectations (~> 3.10.0)
25
+ rspec-mocks (~> 3.10.0)
26
+ rspec-core (3.10.1)
27
+ rspec-support (~> 3.10.0)
28
+ rspec-expectations (3.10.1)
29
+ diff-lcs (>= 1.2.0, < 2.0)
30
+ rspec-support (~> 3.10.0)
31
+ rspec-mocks (3.10.2)
32
+ diff-lcs (>= 1.2.0, < 2.0)
33
+ rspec-support (~> 3.10.0)
34
+ rspec-support (3.10.2)
35
+ ruby2_keywords (0.0.4)
36
+
37
+ PLATFORMS
38
+ ruby
39
+
40
+ DEPENDENCIES
41
+ bundler (~> 1.17)
42
+ byebug
43
+ faraday (~> 1.4.1)
44
+ promoted-ruby-client!
45
+ rake (~> 10.0)
46
+ rspec (~> 3.0)
47
+
48
+ BUNDLED WITH
49
+ 1.17.2
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2021 Promoted
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,197 @@
1
+ # promoted-ruby-client
2
+
3
+ Ruby client designed for calling Promoted's Delivery and Metrics API.
4
+
5
+ This version of the library only supports preparing objects for logging. TODO - support Delivery API.
6
+
7
+ ## Expected pseudo-code flow for Metrics logging
8
+
9
+ This example is for the integration where we do not want to modify the list of items to include `insertionId`. TODO - add this example too.
10
+
11
+ ```
12
+ def get_items args
13
+ items = retrieve_items((args))
14
+ async_log_request(items)
15
+ return items
16
+ end
17
+
18
+ # Done async
19
+ def log_request items
20
+ log_request = Promoted::Ruby::Client.prepare_for_logging(input)
21
+ # Send JSON to Metrics API.
22
+ log_to_promoted_event_api(log_request)
23
+ end
24
+ ```
25
+
26
+ ## Naming details
27
+
28
+ `fullInsertion` - for `prepare_for_logging`, this is the current page of `Insertion`s with full `Insertion.properties` filled with the item details. For v1 integrations, it is fine to not fill in the full properties.
29
+
30
+ ## Pagination
31
+
32
+ The `prepare_for_logging` call assumes the client has already handled pagination. It needs a `Request.paging.from` to be passed in for the number of items deep that the page is.
33
+
34
+ ## Example to run the client
35
+
36
+ 1. Clone the repo on your local machine
37
+ 2. `cd promoted-ruby-client`
38
+ 3. `bundle`
39
+ 4. `irb -Ilib -rpromoted/ruby/client`
40
+
41
+ A console will launch with the library loaded. Here is example code to use.
42
+
43
+ ```
44
+ products = [
45
+ {
46
+ id: "123",
47
+ type: "SHOE",
48
+ name: "Blue shoe",
49
+ total_sales: 1000
50
+ },
51
+ {
52
+ id: "124",
53
+ type: "SHIRT",
54
+ name: "Green shirt",
55
+ total_sales: 800
56
+ },
57
+ {
58
+ id: "125",
59
+ type: "DRESS",
60
+ name: "Red dress",
61
+ total_sales: 1200
62
+ }
63
+ ]
64
+
65
+ # Converts the Products to a list of Insertions.
66
+ def to_insertions products
67
+ @to_insertions = []
68
+ products.each_with_index do |product, index|
69
+ @to_insertions << {
70
+ content_id: product[:id],
71
+ properties: {
72
+ struct: {
73
+ product: product.reject { |k, v| [:id].include? k }
74
+ }
75
+ }
76
+ }
77
+ end
78
+ @to_insertions
79
+ end
80
+
81
+ request_input = {
82
+ request: {
83
+ user_info: { user_id: "912", log_user_id: "912191"},
84
+ use_case: "FEED",
85
+ paging: {
86
+ from: 10,
87
+ size: 5
88
+ },
89
+ properties: {
90
+ struct: {
91
+ active: true
92
+ }
93
+ }
94
+ },
95
+ fullInsertion: to_insertions(products)
96
+ }
97
+
98
+ log_request = Promoted::Ruby::Client.prepare_for_logging(request_input)
99
+ log_request.to_json
100
+ ```
101
+
102
+ `log_request.to_json` returns a result that looks like the following
103
+ ```
104
+ => "{\"user_info\":{\"user_id\":\"912\",\"log_user_id\":\"912191\"},\"timing\":{\"client_log_timestamp\":1623306198},\"request\":[{\"user_info\":{\"user_id\":\"912\",\"log_user_id\":\"912191\"},\"use_case\":\"FEED\",\"paging\":{\"from\":10,\"size\":10},\"properties\":{\"struct\":{\"active\":true}}}],\"insertion\":[{\"content_id\":\"123\",\"properties\":{\"struct\":{\"product\":{\"type\":\"SHOE\",\"name\":\"Blue shoe\",\"total_sales\":1000}}},\"user_info\":{\"user_id\":\"912\",\"log_user_id\":\"912191\"},\"timing\":{\"client_log_timestamp\":1623306198},\"insertion_id\":\"a87e1b57-a574-424f-8af6-10e0250aa7ab\",\"request_id\":\"54ff4884-2192-4180-8c72-a805a436980f\",\"position\":10},{\"content_id\":\"124\",\"properties\":{\"struct\":{\"product\":{\"type\":\"SHIRT\",\"name\":\"Green shirt\",\"total_sales\":800}}},\"user_info\":{\"user_id\":\"912\",\"log_user_id\":\"912191\"},\"timing\":{\"client_log_timestamp\":1623306198},\"insertion_id\":\"4495f72a-8101-4cb8-94ce-4db76839b8b6\",\"request_id\":\"54ff4884-2192-4180-8c72-a805a436980f\",\"position\":11},{\"content_id\":\"125\",\"properties\":{\"struct\":{\"product\":{\"type\":\"DRESS\",\"name\":\"Red dress\",\"total_sales\":1200}}},\"user_info\":{\"user_id\":\"912\",\"log_user_id\":\"912191\"},\"timing\":{\"client_log_timestamp\":1623306198},\"insertion_id\":\"d1e4f3f6-1783-4059-8fab-fdf2ba343cdf\",\"request_id\":\"54ff4884-2192-4180-8c72-a805a436980f\",\"position\":12}]}"
105
+ ```
106
+
107
+ ## Other input syntaxes
108
+
109
+ The client should also work if Hash rocket too.
110
+ ```
111
+ products = [
112
+ {
113
+ "id"=>"123",
114
+ "type"=>"SHOE",
115
+ "name"=>"Blue shoe",
116
+ "totalSales"=>1000
117
+ },
118
+ {
119
+ "id"=>"124",
120
+ "type"=>"SHIRT",
121
+ "name"=>"Green shirt",
122
+ "totalSales"=>800
123
+ },
124
+ {
125
+ "id"=>"125",
126
+ "type"=>"DRESS",
127
+ "name"=>"Red dress",
128
+ "totalSales"=>1200
129
+ }
130
+ ]
131
+
132
+ input = {
133
+ "request"=>{
134
+ "user_info"=>{"user_id"=> "912", "log_user_id"=> "912191"},
135
+ "use_case"=>"FEED",
136
+ "properties"=>{
137
+ "struct"=>{
138
+ "active"=>true
139
+ }
140
+ }
141
+ },
142
+ "fullInsertion"=>to_insertions(products)
143
+ }
144
+ ```
145
+
146
+ Or inlined full request.
147
+ ```
148
+ input = {
149
+ "request"=>{
150
+ "user_info"=>{"user_id"=> "912", "log_user_id"=> "912191"},
151
+ "use_case"=>"FEED",
152
+ "properties"=>{
153
+ "struct"=>{
154
+ "active"=>true
155
+ }
156
+ }
157
+ },
158
+ "fullInsertion"=>[
159
+ {
160
+ "contentId"=>"123",
161
+ "properties"=>{
162
+ "struct"=>{
163
+ "product"=>{
164
+ "type"=>"SHOE",
165
+ "name"=>"Blue shoe",
166
+ "totalSales"=>1000
167
+ }
168
+ }
169
+ }
170
+ },
171
+ {
172
+ "contentId"=>"124",
173
+ "properties"=>{
174
+ "struct"=>{
175
+ "product"=>{
176
+ "type"=>"SHIRT",
177
+ "name"=>"Green shirt",
178
+ "totalSales"=>800
179
+ }
180
+ }
181
+ }
182
+ },
183
+ {
184
+ "contentId"=>"125",
185
+ "properties"=>{
186
+ "struct"=>{
187
+ "product"=>{
188
+ "type"=>"DRESS",
189
+ "name"=>"Red dress",
190
+ "totalSales"=>1200
191
+ }
192
+ }
193
+ }
194
+ }
195
+ ]
196
+ }
197
+ ```
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "promoted/ruby/client"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,71 @@
1
+ require "promoted/ruby/client/version"
2
+ require 'faraday'
3
+ require 'json'
4
+
5
+ module Promoted
6
+ module Ruby
7
+ module Client
8
+ class Error < StandardError; end
9
+ attr_accessor :options
10
+ BASE_URL = "http://wh12.lvh.me:3000"
11
+ DELIVERY_ENDPOINT = "#{BASE_URL}/deliver"
12
+ LOGGING_ENDPOINT = "#{BASE_URL}/log_request"
13
+
14
+ def self.send_request payload, endpoint=nil
15
+ endpoint ||= BASE_URL
16
+ response = Faraday.post(endpoint) do |req|
17
+ req.headers['Content-Type'] = 'application/json'
18
+ req.body = payload.to_json
19
+ end
20
+ response
21
+ end
22
+
23
+ def deliver payload={}
24
+ # TODO
25
+ end
26
+
27
+ def self.log_request args={}, options={}
28
+ endpoint = options[:endpoint]
29
+ payload = prepare_for_logging(args)
30
+ send_request(payload, endpoint)
31
+ end
32
+
33
+ def self.prepare_for_logging args
34
+ options.set_request_params(args)
35
+ if options.perform_checks
36
+ Promoted::Ruby::Client::Settings.check_that_log_ids_not_set(args)
37
+ pre_delivery_fillin_fields
38
+ end
39
+ options.log_request_params
40
+ end
41
+
42
+ def self.pre_delivery_fillin_fields
43
+ if !options.timing[:client_log_timestamp].present?
44
+ options.client_log_timestamp = Time.now.to_i
45
+ end
46
+ end
47
+
48
+ def self.options
49
+ @options ||= Options.new
50
+ end
51
+
52
+ def self.promoted_client_impl params={}
53
+ # Dummy implementation
54
+ # TODO will implement it in details
55
+ perform_checks = params[:perform_checks] || true
56
+ only_Log = params[:only_Log] || false
57
+ uuid = params[:uuid]
58
+ now_millis = params[:now_millis] || Time.now.to_i
59
+ delivery_timeout_millis = params[:delivery_timeout_millis] || DEFAULT_DELIVERY_TIMEOUT_MILLIS
60
+ metrics_timeout_millis = params[:metrics_timeout_millis] || DEFAULT_METRICS_TIMEOUT_MILLIS
61
+ should_apply_treatment = params[:should_apply_treatment] || false
62
+ end
63
+ end
64
+ end
65
+ end
66
+
67
+ # dependent /libs
68
+ require "promoted/ruby/client/options"
69
+ require "promoted/ruby/client/settings"
70
+ require 'byebug'
71
+ require 'securerandom'
@@ -0,0 +1,35 @@
1
+ module Promoted
2
+ module Ruby
3
+ module Client
4
+ class RequestError < StandardError
5
+ def message
6
+ 'Request.requestId should not be set'
7
+ end
8
+ end
9
+
10
+ class RequestInsertionError < StandardError
11
+ def message
12
+ 'Do not set Request.insertion. Set fullInsertion.'
13
+ end
14
+ end
15
+
16
+ class InsertionRequestIdError < StandardError
17
+ def message
18
+ 'Insertion.requestId should not be set'
19
+ end
20
+ end
21
+
22
+ class InsertionIdError < StandardError
23
+ def message
24
+ 'Insertion.insertionId should not be set'
25
+ end
26
+ end
27
+
28
+ class InsertionContentId < StandardError
29
+ def message
30
+ 'Insertion.contentId should be set'
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,206 @@
1
+ module Promoted
2
+ module Ruby
3
+ module Client
4
+ DELIVERY_TIMEOUT_MILLIS = 30000
5
+ DEFAULT_METRICS_TIMEOUT_MILLIS = 250
6
+
7
+ class Options
8
+ attr_accessor :delivery_timeout_millis, :session_id, :perform_checks,
9
+ :uuid, :metrics_timeout_millis, :now_millis, :should_apply_treatment,
10
+ :view_id, :user_id, :insertion, :client_log_timestamp,
11
+ :request_id, :full_insertion, :use_case, :request
12
+
13
+ def initialize()
14
+ # TODO
15
+ end
16
+
17
+ def set_request_params args = {}
18
+ args = translate_args(args)
19
+ @request = args[:request]
20
+ @delivery_timeout_millis = args[:delivery_timeout_millis] || DELIVERY_TIMEOUT_MILLIS
21
+ @session_id = args[:session_id]
22
+ @user_id = args[:user_id]
23
+ @log_user_id = args[:log_user_id]
24
+ @view_id = args[:view_id]
25
+ @perform_checks = args[:perform_checks] || false
26
+ @only_Log = args[:only_Log] || false
27
+ @uuid = args[:uuid]
28
+ @use_case = args[:use_case] || 'FEED'
29
+ @now_millis = args[:now_millis] || Time.now.to_i
30
+ @metrics_timeout_millis = args[:metrics_timeout_millis] || DEFAULT_METRICS_TIMEOUT_MILLIS
31
+ @should_apply_treatment = args[:should_apply_treatment] || false
32
+ @full_insertion = args[:full_insertion]
33
+ @insertion = args[:insertion] || []
34
+ @client_log_timestamp = args[:client_log_timestamp] || Time.now.to_i
35
+ @request_id = SecureRandom.uuid
36
+ end
37
+
38
+ def translate_args(args)
39
+ args.transform_keys(&:to_s).transform_keys(&:to_underscore).transform_keys(&:to_sym)
40
+ rescue => e
41
+ raise 'Unable to parse args. Please pass correct arguments. Must be JSON'
42
+ end
43
+
44
+ def validate_request_params
45
+ # TODO
46
+ end
47
+
48
+ def request
49
+ @request
50
+ end
51
+
52
+ def client_log_timestamp
53
+ @client_log_timestamp
54
+ end
55
+
56
+ def view_id
57
+ @view_id
58
+ end
59
+
60
+ def user_id
61
+ return @user_id if @user_id
62
+ @user_id = request.dig(:user_info, :user_id)
63
+ @user_id ||= request.dig('user_info', 'user_id')
64
+ @user_id
65
+ end
66
+
67
+ def session_id
68
+ @session_id
69
+ end
70
+
71
+ # A list of the response Insertions. This client expects lists to be truncated
72
+ # already to request.paging.size. If not truncated, this client will truncate
73
+ # the list.
74
+ def insertion
75
+ @insertion
76
+ end
77
+
78
+ def log_user_id
79
+ return @log_user_id if @log_user_id
80
+ @log_user_id = request.dig(:user_info, :log_user_id)
81
+ @log_user_id ||= request.dig('user_info', 'log_user_id')
82
+ @log_user_id
83
+ end
84
+
85
+ # A way to turn off logging. Defaults to true.
86
+ def enabled?
87
+ @enabled
88
+ end
89
+
90
+ # Performs extra dev checks. Safer but slower. Defaults to true.
91
+ def perform_checks?
92
+ @perform_checks
93
+ end
94
+
95
+ # Default values to use on DeliveryRequests.
96
+ def default_request_values
97
+ @default_request_values
98
+ end
99
+
100
+ # Required as a dependency so clients can load reduce dependency on multiple
101
+ # uuid libraries.
102
+ def uuid
103
+ @uuid
104
+ end
105
+
106
+ # Defaults to 250ms
107
+ def delivery_timeout_millis
108
+ @delivery_timeout_millis
109
+ end
110
+
111
+ # Defaults to 3000ms
112
+ def metrics_timeout_millis
113
+ @metrics_timeout_millis
114
+ end
115
+
116
+ # For testing. Allows for easy mocking of the clock.
117
+ def now_millis
118
+ @now_millis
119
+ end
120
+
121
+ def only_Log
122
+ @only_Log
123
+ end
124
+
125
+ def full_insertion
126
+ @full_insertion
127
+ end
128
+
129
+ def user_info
130
+ {
131
+ user_id: user_id,
132
+ log_user_id: log_user_id
133
+ }
134
+ end
135
+
136
+ def timing
137
+ @timing = {
138
+ client_log_timestamp: client_log_timestamp
139
+ }
140
+ end
141
+
142
+ def request_id
143
+ @request_id
144
+ end
145
+
146
+ def log_request_params
147
+ {
148
+ user_info: user_info,
149
+ timing: timing,
150
+ request: [request],
151
+ insertion: compact_insertions
152
+ }
153
+ end
154
+
155
+ def request_params include_insertion: true
156
+ @request_params = {
157
+ user_info: user_info,
158
+ timing: timing,
159
+ request_id: request_id,
160
+ view_id: view_id,
161
+ session_id: session_id,
162
+ insertion: compact_insertions
163
+ }
164
+ @request_params.merge!({insertion: compact_insertions}) if include_insertion
165
+ @request_params
166
+ end
167
+
168
+ def compact_insertions
169
+ @compact_insertions = []
170
+ insertions_to_compact = full_insertion
171
+ paging = request[:paging] || {}
172
+ size = paging[:size]
173
+ unless size.nil? || size == 0
174
+ insertions_to_compact = insertions_to_compact[0..size-1]
175
+ end
176
+ from = paging[:from].to_i
177
+ insertions_to_compact.each_with_index do |insertion_obj, index|
178
+ # TODO - this does not look performant.
179
+ insertion_obj = insertion_obj.transform_keys{ |key| key.to_s.to_underscore.to_sym }
180
+ insertion_obj[:user_info] = user_info
181
+ insertion_obj[:timing] = timing
182
+ insertion_obj[:insertion_id] = SecureRandom.uuid # generate random UUID
183
+ insertion_obj[:request_id] = request_id
184
+ insertion_obj[:position] = from + index
185
+ @compact_insertions << insertion_obj
186
+ end
187
+ @compact_insertions
188
+ end
189
+
190
+ end
191
+ end
192
+ end
193
+ end
194
+
195
+ class String
196
+ # Ruby mutation methods have the expectation to return self if a mutation occurred, nil otherwise. (see http://www.ruby-doc.org/core-1.9.3/String.html#method-i-gsub-21)
197
+ def to_underscore!
198
+ gsub!(/(.)([A-Z])/,'\1_\2')
199
+ downcase!
200
+ end
201
+
202
+ def to_underscore
203
+ dup.tap { |s| s.to_underscore! }
204
+ end
205
+ end
206
+ require 'securerandom'
@@ -0,0 +1,21 @@
1
+ module Promoted
2
+ module Ruby
3
+ module Client
4
+ class Settings
5
+
6
+ def self.check_that_log_ids_not_set! options_hash
7
+ raise RequestError if options_hash.dig("request", "request_id")
8
+ raise RequestInsertionError if options_hash["insertion"]
9
+
10
+ options_hash["full_insertion"].each do |insertion_hash|
11
+ raise InsertionRequestIdError if insertion_hash["request_id"]
12
+ raise InsertionIdError if insertion_hash["insertion_id"]
13
+ end
14
+ true
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ require "promoted/ruby/client/errors"
@@ -0,0 +1,7 @@
1
+ module Promoted
2
+ module Ruby
3
+ module Client
4
+ VERSION = "0.1.0"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,34 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "promoted/ruby/client/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "promoted-ruby-client"
8
+ spec.version = Promoted::Ruby::Client::VERSION
9
+ spec.authors = ["danbosnichill"]
10
+ spec.email = ["dhill@promoted.ai"]
11
+
12
+ spec.summary = 'A Ruby Client to contact Promoted APIs.'
13
+ spec.description = 'This is primarily intended to be used when logging Requests and Insertions on a backend server.'
14
+ spec.homepage = 'https://github.com/promotedai/promoted-ruby-client'
15
+ spec.license = 'MIT'
16
+
17
+ spec.metadata["homepage_uri"] = spec.homepage
18
+ spec.metadata["source_code_uri"] = "https://github.com/promotedai/promoted-ruby-client"
19
+ spec.metadata["changelog_uri"] = "https://github.com/promotedai/promoted-ruby-client/blob/master/CHANGELOG.md"
20
+
21
+ # Specify which files should be added to the gem when it is released.
22
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
23
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
24
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
25
+ end
26
+ spec.extra_rdoc_files = ['README.md']
27
+ spec.bindir = "exe"
28
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
29
+ spec.require_paths = ["lib"]
30
+
31
+ spec.add_development_dependency "bundler", "~> 1.17"
32
+ spec.add_development_dependency "rake", "~> 10.0"
33
+ spec.add_development_dependency "rspec", "~> 3.0"
34
+ end
metadata ADDED
@@ -0,0 +1,104 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: promoted-ruby-client
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - danbosnichill
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2021-06-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.17'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.17'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ description: This is primarily intended to be used when logging Requests and Insertions
56
+ on a backend server.
57
+ email:
58
+ - dhill@promoted.ai
59
+ executables: []
60
+ extensions: []
61
+ extra_rdoc_files:
62
+ - README.md
63
+ files:
64
+ - ".gitignore"
65
+ - Gemfile
66
+ - Gemfile.lock
67
+ - LICENSE
68
+ - README.md
69
+ - Rakefile
70
+ - bin/console
71
+ - bin/setup
72
+ - lib/promoted/ruby/client.rb
73
+ - lib/promoted/ruby/client/errors.rb
74
+ - lib/promoted/ruby/client/options.rb
75
+ - lib/promoted/ruby/client/settings.rb
76
+ - lib/promoted/ruby/client/version.rb
77
+ - promoted-ruby-client.gemspec
78
+ homepage: https://github.com/promotedai/promoted-ruby-client
79
+ licenses:
80
+ - MIT
81
+ metadata:
82
+ homepage_uri: https://github.com/promotedai/promoted-ruby-client
83
+ source_code_uri: https://github.com/promotedai/promoted-ruby-client
84
+ changelog_uri: https://github.com/promotedai/promoted-ruby-client/blob/master/CHANGELOG.md
85
+ post_install_message:
86
+ rdoc_options: []
87
+ require_paths:
88
+ - lib
89
+ required_ruby_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ required_rubygems_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ requirements: []
100
+ rubygems_version: 3.0.3
101
+ signing_key:
102
+ specification_version: 4
103
+ summary: A Ruby Client to contact Promoted APIs.
104
+ test_files: []