devcycle-ruby-server-sdk 2.0.3 → 2.1.1

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: 960c105106387fcb10b360f0befbb77d2dda8c80dce5a51a5eed3c8c49528253
4
- data.tar.gz: 1c9274022cece19d953ceba7adfed10cd6418e4a3097ad3305f1a539ace32e23
3
+ metadata.gz: bd92e3883469ddd7a7f1ca4a16012b1527d823c5d026db1830c597c32f740047
4
+ data.tar.gz: 6a064d33d9a4a3e260294a484c24e4c6f6899d70b226c2656726f7c1af7505f4
5
5
  SHA512:
6
- metadata.gz: 67cb4a92cb5c9247bd10c838cfa0979d89d331c75c5626967af9b4602c55c30a2842f94f2c15471bb459686382be20432e43bf9951f1c27f516cbc5b2d8a504e
7
- data.tar.gz: 802ec0ab8f6b2a7623fe58c94cd007484832c06c5742a38831bebd0991ef2c3b57cc99563ffcee89a545742c0fe1080beea95be01aab88f27983d5d808b359f1
6
+ metadata.gz: d566f41de3940df34ff782de63e05223bead0ca334fd8c31b59eeef074bf35dbefbcd03682fa178d709a0f637fa945f723b04eb80a3e80e794d2c05fa95cdd06
7
+ data.tar.gz: 7e8f10ff94003890b2350032ef06e997ec1aec81ce82c390fad9d762d47638166db61365b1040ad57944afc6f273122768cc94831623056167ef1b387a6c192d
@@ -32,8 +32,8 @@ module DevCycle
32
32
  @api_client.config.enable_edge_db = @dvc_options.enable_edge_db
33
33
  @api_client.config.logger = @logger
34
34
  else
35
- @localbucketing = LocalBucketing.new(@sdkKey, dvc_options, wait_for_init)
36
- @event_queue = EventQueue.new(@sdkKey, dvc_options.event_queue_options, @localbucketing)
35
+ @local_bucketing = LocalBucketing.new(@sdkKey, dvc_options, wait_for_init)
36
+ @event_queue = EventQueue.new(@sdkKey, dvc_options.event_queue_options, @local_bucketing)
37
37
  end
38
38
  end
39
39
 
@@ -42,15 +42,15 @@ module DevCycle
42
42
  @logger.info("Cloud Bucketing does not require closing.")
43
43
  return
44
44
  end
45
- if @localbucketing != nil
46
- if !@localbucketing.initialized
45
+ if @local_bucketing != nil
46
+ if !@local_bucketing.initialized
47
47
  @logger.info("Awaiting client initialization before closing")
48
- while !@localbucketing.initialized
48
+ while !@local_bucketing.initialized
49
49
  sleep(0.5)
50
50
  end
51
51
  end
52
- @localbucketing.close
53
- @localbucketing = nil
52
+ @local_bucketing.close
53
+ @local_bucketing = nil
54
54
  @logger.info("Closed DevCycle Local Bucketing Engine.")
55
55
  end
56
56
 
@@ -65,7 +65,7 @@ module DevCycle
65
65
  end
66
66
 
67
67
  if local_bucketing_initialized?
68
- @localbucketing.set_client_custom_data(customdata)
68
+ @local_bucketing.set_client_custom_data(customdata)
69
69
  else
70
70
  @logger.warn("Local bucketing not initialized. Unable to set client custom data.")
71
71
  end
@@ -93,8 +93,8 @@ module DevCycle
93
93
  return data
94
94
  end
95
95
 
96
- if local_bucketing_initialized? && @localbucketing.has_config
97
- bucketed_config = @localbucketing.generate_bucketed_config(user_data)
96
+ if local_bucketing_initialized? && @local_bucketing.has_config
97
+ bucketed_config = @local_bucketing.generate_bucketed_config(user_data)
98
98
  bucketed_config.features
99
99
  else
100
100
  {}
@@ -176,60 +176,38 @@ module DevCycle
176
176
  return data
177
177
  end
178
178
 
179
- if local_bucketing_initialized? && @localbucketing.has_config
180
- bucketed_config = @localbucketing.generate_bucketed_config(user_data)
181
- variable_json = bucketed_config.variables[key]
179
+ value = default
180
+ type = determine_variable_type(default)
181
+ defaulted = true
182
+ if local_bucketing_initialized? && @local_bucketing.has_config
183
+ type_code = variable_type_code_from_type(type)
184
+ variable_json = variable_for_user(user_data, key, type_code)
182
185
  if variable_json == nil
183
- @logger.warn("No variable found for key #{key}, returning default value")
184
- variable_event = Event.new({ type: DevCycle::EventTypes[:agg_variable_defaulted], target: key })
185
- @event_queue.queue_aggregate_event(variable_event, bucketed_config)
186
-
187
- return Variable.new({
188
- key: key,
189
- type: determine_variable_type(default),
190
- value: default,
191
- defaultValue: default,
192
- isDefaulted: true
193
- })
186
+ @logger.warn("No variable found or type mismatch for key #{key}, returning default value")
187
+ else
188
+ value = variable_json['value']
189
+ defaulted = false
194
190
  end
195
- default_type = determine_variable_type(default)
196
- variable_type = variable_json['type']
197
- if default_type != variable_type
198
- @logger.warn("Type mismatch for variable #{key}, returning default value")
199
- variable_event = Event.new({ type: DevCycle::EventTypes[:agg_variable_defaulted], target: key })
200
- @event_queue.queue_aggregate_event(variable_event, bucketed_config)
201
-
202
- return Variable.new({
203
- key: key,
204
- type: default_type,
205
- value: default,
206
- defaultValue: default,
207
- isDefaulted: true
208
- })
209
- end
210
- variable_event = Event.new({ type: DevCycle::EventTypes[:agg_variable_evaluated], target: key })
211
- @event_queue.queue_aggregate_event(variable_event, bucketed_config)
212
-
213
- Variable.new({
214
- key: key,
215
- type: variable_type,
216
- value: variable_json['value'],
217
- defaultValue: default,
218
- isDefaulted: false
219
- })
220
191
  else
221
192
  @logger.warn("Local bucketing not initialized, returning default value for variable #{key}")
222
193
  variable_event = Event.new({ type: DevCycle::EventTypes[:agg_variable_defaulted], target: key })
194
+ bucketed_config = BucketedUserConfig.new({}, {}, {}, {}, {}, {}, [])
223
195
  @event_queue.queue_aggregate_event(variable_event, bucketed_config)
224
-
225
- Variable.new({
226
- key: key,
227
- type: determine_variable_type(default),
228
- value: default,
229
- defaultValue: default,
230
- isDefaulted: true
231
- })
232
196
  end
197
+
198
+ Variable.new({
199
+ key: key,
200
+ value: value,
201
+ type: type,
202
+ defaultValue: default,
203
+ isDefaulted: defaulted
204
+ })
205
+ end
206
+
207
+ def variable_for_user(user, key, variable_type_code)
208
+ json_str = @local_bucketing.variable_for_user(user, key, variable_type_code)
209
+ return nil if json_str.nil?
210
+ JSON.parse(json_str)
233
211
  end
234
212
 
235
213
  # Get variable by key for user data
@@ -319,8 +297,8 @@ module DevCycle
319
297
  return data
320
298
  end
321
299
 
322
- if local_bucketing_initialized? && @localbucketing.has_config
323
- bucketed_config = @localbucketing.generate_bucketed_config(user_data)
300
+ if local_bucketing_initialized? && @local_bucketing.has_config
301
+ bucketed_config = @local_bucketing.generate_bucketed_config(user_data)
324
302
  bucketed_config.variables
325
303
  else
326
304
  {}
@@ -486,7 +464,7 @@ module DevCycle
486
464
  end
487
465
 
488
466
  def local_bucketing_initialized?
489
- !@localbucketing.nil? && @localbucketing.initialized
467
+ !@local_bucketing.nil? && @local_bucketing.initialized
490
468
  end
491
469
 
492
470
  def determine_variable_type(variable_value)
@@ -502,5 +480,20 @@ module DevCycle
502
480
  raise ArgumentError, "Invalid type for variable: #{variable_value}"
503
481
  end
504
482
  end
483
+
484
+ def variable_type_code_from_type(type)
485
+ case type
486
+ when 'String'
487
+ @local_bucketing.variable_type_codes[:string]
488
+ when 'Boolean'
489
+ @local_bucketing.variable_type_codes[:boolean]
490
+ when 'Number'
491
+ @local_bucketing.variable_type_codes[:number]
492
+ when 'JSON'
493
+ @local_bucketing.variable_type_codes[:json]
494
+ else
495
+ raise ArgumentError.new("Invalid type for variable: #{type}")
496
+ end
497
+ end
505
498
  end
506
499
  end
@@ -1,5 +1,3 @@
1
- require 'oj'
2
-
3
1
  module DevCycle
4
2
  class DVCOptions
5
3
  attr_reader :config_polling_interval_ms
@@ -13,6 +13,7 @@ module DevCycle
13
13
  extend T::Sig
14
14
 
15
15
  attr_reader :options
16
+ attr_reader :variable_type_codes
16
17
  attr_accessor :initialized
17
18
  attr_accessor :has_config
18
19
 
@@ -48,6 +49,8 @@ module DevCycle
48
49
  result
49
50
  }
50
51
 
52
+ @@stack_tracer_raise = lambda { |message| raise message }
53
+ # each method reassigns stack_tracer so the call stack is properly displayed
51
54
  @@stack_tracer = lambda {}
52
55
 
53
56
  @@linker.func_new("env", "abort", [:i32, :i32, :i32, :i32], []) do |_caller, messagePtr, filenamePtr, lineNum, colNum|
@@ -91,6 +94,13 @@ module DevCycle
91
94
  @sdkkey = sdkkey
92
95
  @options = options
93
96
  @logger = options.logger
97
+ @wasm_mutex = Mutex.new
98
+ @variable_type_codes = {
99
+ boolean: @@instance.export("VariableType.Boolean").to_global.get.to_i,
100
+ string: @@instance.export("VariableType.String").to_global.get.to_i,
101
+ number: @@instance.export("VariableType.Number").to_global.get.to_i,
102
+ json: @@instance.export("VariableType.JSON").to_global.get.to_i
103
+ }
94
104
  set_sdk_key_internal(sdkkey)
95
105
  platform_data = PlatformData.new('server', VERSION, RUBY_VERSION, nil, 'Ruby', Socket.gethostname)
96
106
  set_platform_data(platform_data)
@@ -104,123 +114,158 @@ module DevCycle
104
114
 
105
115
  sig { params(user: UserData).returns(BucketedUserConfig) }
106
116
  def generate_bucketed_config(user)
107
- user_addr = malloc_asc_string(user.to_json)
108
- @@stack_tracer = lambda { |message| raise message }
109
- config_addr = @@instance.invoke("generateBucketedConfigForUser", @sdkKeyAddr, user_addr)
110
- bucketed_config_json = read_asc_string(config_addr)
111
- bucketed_config_hash = Oj.load(bucketed_config_json)
112
-
113
- BucketedUserConfig.new(bucketed_config_hash['project'],
114
- bucketed_config_hash['environment'],
115
- bucketed_config_hash['features'],
116
- bucketed_config_hash['featureVariationMap'],
117
- bucketed_config_hash['variableVariationMap'],
118
- bucketed_config_hash['variables'],
119
- bucketed_config_hash['knownVariableKeys'])
117
+ @wasm_mutex.synchronize do
118
+ user_addr = malloc_asc_string(user.to_json)
119
+ @@stack_tracer = @@stack_tracer_raise
120
+ config_addr = @@instance.invoke("generateBucketedConfigForUser", @sdkKeyAddr, user_addr)
121
+ bucketed_config_json = read_asc_string(config_addr)
122
+ bucketed_config_hash = Oj.load(bucketed_config_json)
123
+
124
+ BucketedUserConfig.new(bucketed_config_hash['project'],
125
+ bucketed_config_hash['environment'],
126
+ bucketed_config_hash['features'],
127
+ bucketed_config_hash['featureVariationMap'],
128
+ bucketed_config_hash['variableVariationMap'],
129
+ bucketed_config_hash['variables'],
130
+ bucketed_config_hash['knownVariableKeys'])
131
+ end
132
+ end
133
+
134
+ sig { params(user: UserData, key: String, variable_type: Integer).returns(T.nilable(String)) }
135
+ def variable_for_user(user, key, variable_type)
136
+ @wasm_mutex.synchronize do
137
+ user_addr = malloc_asc_string(user.to_json)
138
+ key_addr = malloc_asc_string(key)
139
+ @@stack_tracer = @@stack_tracer_raise
140
+ var_addr = @@instance.invoke("variableForUser", @sdkKeyAddr, user_addr, key_addr, variable_type, 1)
141
+ read_asc_string(var_addr)
142
+ end
120
143
  end
121
144
 
122
145
  sig { returns(T::Array[EventsPayload]) }
123
146
  def flush_event_queue
124
- @@stack_tracer = lambda { |message| raise message }
125
- payload_addr = @@instance.invoke("flushEventQueue", @sdkKeyAddr)
126
- raw_json = read_asc_string(payload_addr)
127
- raw_payloads = Oj.load(raw_json)
128
-
129
- if raw_payloads == nil
130
- return []
147
+ @wasm_mutex.synchronize do
148
+ @@stack_tracer = @@stack_tracer_raise
149
+ payload_addr = @@instance.invoke("flushEventQueue", @sdkKeyAddr)
150
+ raw_json = read_asc_string(payload_addr)
151
+ raw_payloads = Oj.load(raw_json)
152
+
153
+ if raw_payloads == nil
154
+ return []
155
+ end
156
+ raw_payloads.map { |raw_payload| EventsPayload.new(raw_payload["records"], raw_payload["payloadId"], raw_payload["eventCount"]) }
131
157
  end
132
- raw_payloads.map { |raw_payload| EventsPayload.new(raw_payload["records"], raw_payload["payloadId"], raw_payload["eventCount"]) }
133
158
  end
134
159
 
135
160
  sig { returns(Integer) }
136
161
  def check_event_queue_size
137
- @@stack_tracer = lambda { |message| raise message }
138
- @@instance.invoke("eventQueueSize", @sdkKeyAddr)
162
+ @wasm_mutex.synchronize do
163
+ @@stack_tracer = @@stack_tracer_raise
164
+ @@instance.invoke("eventQueueSize", @sdkKeyAddr)
165
+ end
139
166
  end
140
167
 
141
168
  sig { params(payload_id: String).returns(NilClass) }
142
169
  def on_payload_success(payload_id)
143
- payload_addr = malloc_asc_string(payload_id)
144
- @@stack_tracer = lambda { |message| raise message }
145
- @@instance.invoke("onPayloadSuccess", @sdkKeyAddr, payload_addr)
170
+ @wasm_mutex.synchronize do
171
+ payload_addr = malloc_asc_string(payload_id)
172
+ @@stack_tracer = @@stack_tracer_raise
173
+ @@instance.invoke("onPayloadSuccess", @sdkKeyAddr, payload_addr)
174
+ end
175
+ end
176
+
177
+ sig { params(payload_id: String, retryable: Object).returns(NilClass) }
178
+ def on_payload_failure(payload_id, retryable)
179
+ @wasm_mutex.synchronize do
180
+ payload_addr = malloc_asc_string(payload_id)
181
+ @@stack_tracer = @@stack_tracer_raise
182
+ @@instance.invoke("onPayloadFailure", @sdkKeyAddr, payload_addr, retryable ? 1 : 0)
183
+ end
146
184
  end
147
185
 
148
186
  sig { params(user: UserData, event: Event).returns(NilClass) }
149
187
  def queue_event(user, event)
150
- begin
151
- user_addr = malloc_asc_string(Oj.dump(user))
152
- asc_pin(user_addr)
153
- event_addr = malloc_asc_string(Oj.dump(event))
154
- @@stack_tracer = lambda { |message| raise message }
155
- @@instance.invoke("queueEvent", @sdkKeyAddr, user_addr, event_addr)
156
- ensure
157
- asc_unpin(user_addr)
188
+ @wasm_mutex.synchronize do
189
+ begin
190
+ user_addr = malloc_asc_string(user.to_json)
191
+ asc_pin(user_addr)
192
+ event_addr = malloc_asc_string(event.to_json)
193
+ @@stack_tracer = @@stack_tracer_raise
194
+ @@instance.invoke("queueEvent", @sdkKeyAddr, user_addr, event_addr)
195
+ ensure
196
+ asc_unpin(user_addr)
197
+ end
158
198
  end
159
199
  end
160
200
 
161
201
  sig { params(event: Event, bucketeduser: T.nilable(BucketedUserConfig)).returns(NilClass) }
162
202
  def queue_aggregate_event(event, bucketeduser)
163
- begin
164
- variable_variation_map =
165
- if !bucketeduser.nil?
166
- bucketeduser.variable_variation_map
167
- else
168
- {}
169
- end
170
- varmap_addr = malloc_asc_string(Oj.dump(variable_variation_map))
171
- asc_pin(varmap_addr)
172
- event_addr = malloc_asc_string(Oj.dump(event))
173
- @@stack_tracer = lambda { |message| raise message }
174
- @@instance.invoke("queueAggregateEvent", @sdkKeyAddr, event_addr, varmap_addr)
175
- ensure
176
- asc_unpin(varmap_addr)
203
+ @wasm_mutex.synchronize do
204
+ begin
205
+ variable_variation_map =
206
+ if !bucketeduser.nil?
207
+ bucketeduser.variable_variation_map
208
+ else
209
+ {}
210
+ end
211
+ varmap_addr = malloc_asc_string(Oj.dump(variable_variation_map))
212
+ asc_pin(varmap_addr)
213
+ event_addr = malloc_asc_string(event.to_json)
214
+ @@stack_tracer = @@stack_tracer_raise
215
+ @@instance.invoke("queueAggregateEvent", @sdkKeyAddr, event_addr, varmap_addr)
216
+ ensure
217
+ asc_unpin(varmap_addr)
218
+ end
177
219
  end
178
220
  end
179
221
 
180
- sig { params(payload_id: String, retryable: Object).returns(NilClass) }
181
- def on_payload_failure(payload_id, retryable)
182
- payload_addr = malloc_asc_string(payload_id)
183
- @@stack_tracer = lambda { |message| raise message }
184
- @@instance.invoke("onPayloadFailure", @sdkKeyAddr, payload_addr, retryable ? 1 : 0)
185
- end
186
-
187
222
  sig { params(config: String).returns(NilClass) }
188
223
  def store_config(config)
189
- config_addr = malloc_asc_string(config)
190
- @@stack_tracer = lambda { |message| raise message }
191
- @@instance.invoke("setConfigData", @sdkKeyAddr, config_addr)
224
+ @wasm_mutex.synchronize do
225
+ config_addr = malloc_asc_string(config)
226
+ @@stack_tracer = @@stack_tracer_raise
227
+ @@instance.invoke("setConfigData", @sdkKeyAddr, config_addr)
228
+ end
192
229
  end
193
230
 
194
231
  sig { params(options: EventQueueOptions).returns(NilClass) }
195
232
  def init_event_queue(options)
196
- options_json = Oj.dump(options)
197
- options_addr = malloc_asc_string(options_json)
198
- @@stack_tracer = lambda { |message| raise message }
199
- @@instance.invoke("initEventQueue", @sdkKeyAddr, options_addr)
233
+ @wasm_mutex.synchronize do
234
+ options_json = Oj.dump(options)
235
+ options_addr = malloc_asc_string(options_json)
236
+ @@stack_tracer = @@stack_tracer_raise
237
+ @@instance.invoke("initEventQueue", @sdkKeyAddr, options_addr)
238
+ end
200
239
  end
201
240
 
202
241
  sig { params(customdata: Hash).returns(NilClass) }
203
242
  def set_client_custom_data(customdata)
204
- customdata_json = Oj.dump(customdata)
205
- customdata_addr = malloc_asc_string(customdata_json)
206
- @@stack_tracer = lambda { |message| raise message }
207
- @@instance.invoke("setClientCustomData", customdata_addr)
243
+ @wasm_mutex.synchronize do
244
+ customdata_json = Oj.dump(customdata)
245
+ customdata_addr = malloc_asc_string(customdata_json)
246
+ @@stack_tracer = @@stack_tracer_raise
247
+ @@instance.invoke("setClientCustomData", @sdkKeyAddr, customdata_addr)
248
+ end
208
249
  end
209
250
 
210
251
  private
211
252
 
212
253
  sig { params(platformdata: PlatformData).returns(NilClass) }
213
254
  def set_platform_data(platformdata)
214
- platformdata_json = Oj.dump(platformdata)
215
- platformdata_addr = malloc_asc_string(platformdata_json)
216
- @@stack_tracer = lambda { |message| raise message }
217
- @@instance.invoke("setPlatformData", platformdata_addr)
255
+ @wasm_mutex.synchronize do
256
+ platformdata_json = Oj.dump(platformdata)
257
+ platformdata_addr = malloc_asc_string(platformdata_json)
258
+ @@stack_tracer = @@stack_tracer_raise
259
+ @@instance.invoke("setPlatformData", platformdata_addr)
260
+ end
218
261
  end
219
262
 
220
263
  def set_sdk_key_internal(sdkKey)
221
- addr = malloc_asc_string(sdkKey)
222
- @sdkKeyAddr = addr
223
- asc_pin(addr)
264
+ @wasm_mutex.synchronize do
265
+ addr = malloc_asc_string(sdkKey)
266
+ @sdkKeyAddr = addr
267
+ asc_pin(addr)
268
+ end
224
269
  end
225
270
 
226
271
  def asc_pin(addr)
@@ -236,7 +281,7 @@ module DevCycle
236
281
  sig { params(string: String).returns(Integer) }
237
282
  def malloc_asc_string(string)
238
283
  wasm_object_id = 1
239
- @@stack_tracer = lambda { |message| raise message }
284
+ @@stack_tracer = @@stack_tracer_raise
240
285
  wasm_new = @@instance.export("__new").to_func
241
286
  utf8_bytes = string.bytes
242
287
  byte_len = utf8_bytes.length
@@ -244,8 +289,8 @@ module DevCycle
244
289
  start_addr = wasm_new.call(byte_len * 2, wasm_object_id)
245
290
  i = 0
246
291
  while i < byte_len
247
- @@stack_tracer = lambda { |message| raise message }
248
- @@memory.write(start_addr + (i * 2), [utf8_bytes[i]].pack('U'))
292
+ @@stack_tracer = @@stack_tracer_raise
293
+ @@memory.write(start_addr + (i * 2), [utf8_bytes[i]].pack('c'))
249
294
  i += 1
250
295
  end
251
296
  start_addr
@@ -253,23 +298,23 @@ module DevCycle
253
298
 
254
299
  # @param [Integer] address start address of string.
255
300
  # @return [String] resulting string
256
- sig { params(address: Integer).returns(String) }
301
+ sig { params(address: Integer).returns(T.nilable(String)) }
257
302
  def read_asc_string(address)
258
- @@stack_tracer = lambda { |message| raise message }
303
+ if address == 0
304
+ @logger.debug("null address passed to read_asc_string")
305
+ return nil
306
+ end
307
+
308
+ @@stack_tracer = @@stack_tracer_raise
259
309
  raw_bytes = @@memory.read(address - 4, 4).bytes.reverse
260
310
  len = 0
261
311
  raw_bytes.each { |j|
262
312
  len = (len << 8) + (j & 0xFF)
263
313
  }
264
- result = ""
265
- i = 0
266
- while i < len
267
- @@stack_tracer = lambda { |message| raise message }
268
- result += @@memory.read(address + i, 1)
269
- i += 2
270
- end
271
- result
314
+
315
+ @@stack_tracer = @@stack_tracer_raise
316
+ result = @@memory.read(address, len).bytes
317
+ result.select.with_index { |_, i| i.even? }.pack('c*')
272
318
  end
273
319
  end
274
320
  end
275
-
@@ -12,6 +12,7 @@ OpenAPI Generator version: 5.3.0
12
12
 
13
13
  require 'date'
14
14
  require 'time'
15
+ require 'oj'
15
16
 
16
17
  module DevCycle
17
18
  class Event
@@ -259,6 +260,9 @@ module DevCycle
259
260
  end
260
261
  end
261
262
 
263
+ def to_json
264
+ Oj.dump(to_hash, mode: :json)
265
+ end
262
266
  end
263
267
 
264
268
  end
@@ -17,9 +17,6 @@ require 'oj'
17
17
  module DevCycle
18
18
  class UserData
19
19
 
20
- def to_json
21
- Oj.dump(self)
22
- end
23
20
  # Unique id to identify the user
24
21
  attr_accessor :user_id
25
22
 
@@ -414,5 +411,9 @@ module DevCycle
414
411
  value
415
412
  end
416
413
  end
414
+
415
+ def to_json
416
+ Oj.dump(to_hash, mode: :json)
417
+ end
417
418
  end
418
419
  end
@@ -11,5 +11,5 @@ OpenAPI Generator version: 5.3.0
11
11
  =end
12
12
 
13
13
  module DevCycle
14
- VERSION = '2.0.3'
14
+ VERSION = '2.1.1'
15
15
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: devcycle-ruby-server-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.3
4
+ version: 2.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - DevCycleHQ
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-03-08 00:00:00.000000000 Z
11
+ date: 2023-03-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: typhoeus