promoted-ruby-client 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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: []