Skip to content

Commit be83e72

Browse files
committed
handle symbolizing internally in SDK
1 parent b283a6a commit be83e72

5 files changed

Lines changed: 104 additions & 49 deletions

File tree

bin/commands/assess_distribution.rb

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -160,27 +160,13 @@ def execute_command(command)
160160
end
161161

162162
def create_instance(datafile)
163-
# Convert datafile to proper format for the SDK
164-
symbolized_datafile = symbolize_keys(datafile)
165-
166163
# Create SDK instance
167164
Featurevisor.create_instance(
168-
datafile: symbolized_datafile,
165+
datafile: datafile,
169166
log_level: get_logger_level
170167
)
171168
end
172169

173-
def symbolize_keys(obj)
174-
case obj
175-
when Hash
176-
obj.transform_keys(&:to_sym).transform_values { |v| symbolize_keys(v) }
177-
when Array
178-
obj.map { |item| symbolize_keys(item) }
179-
else
180-
obj
181-
end
182-
end
183-
184170
def get_logger_level
185171
if @options.verbose
186172
"debug"

bin/commands/benchmark.rb

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -143,16 +143,13 @@ def execute_command(command)
143143
end
144144

145145
def create_instance(datafile)
146-
# Convert string keys to symbols for the SDK
147-
symbolized_datafile = symbolize_keys(datafile)
148-
149146
# Create a real Featurevisor instance
150147
instance = Featurevisor.create_instance(
151148
log_level: get_logger_level
152149
)
153150

154151
# Explicitly set the datafile
155-
instance.set_datafile(symbolized_datafile)
152+
instance.set_datafile(datafile)
156153

157154
instance
158155
end
@@ -167,17 +164,6 @@ def get_logger_level
167164
end
168165
end
169166

170-
def symbolize_keys(obj)
171-
case obj
172-
when Hash
173-
obj.transform_keys(&:to_sym).transform_values { |v| symbolize_keys(v) }
174-
when Array
175-
obj.map { |item| symbolize_keys(item) }
176-
else
177-
obj
178-
end
179-
end
180-
181167
def benchmark_feature_flag(instance, feature_key, context, n)
182168
start_time = Time.now
183169

bin/commands/test.rb

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -161,12 +161,9 @@ def create_sdk_instances(environments, datafiles_by_environment, level)
161161
environments.each do |environment|
162162
datafile = datafiles_by_environment[environment]
163163

164-
# Convert string keys to symbols for the SDK
165-
symbolized_datafile = symbolize_keys(datafile)
166-
167164
# Create SDK instance
168165
instance = Featurevisor.create_instance(
169-
datafile: symbolized_datafile,
166+
datafile: datafile,
170167
log_level: level,
171168
hooks: [
172169
{
@@ -214,10 +211,9 @@ def run_tests(tests, sdk_instances_by_environment, datafiles_by_environment, seg
214211
# If "at" parameter is provided, create a new instance with the specific hook
215212
if assertion["at"]
216213
datafile = datafiles_by_environment[environment]
217-
symbolized_datafile = symbolize_keys(datafile)
218214

219215
instance = Featurevisor.create_instance(
220-
datafile: symbolized_datafile,
216+
datafile: datafile,
221217
log_level: level,
222218
hooks: [
223219
{
@@ -549,7 +545,7 @@ def run_test_segment(assertion, segment, level)
549545

550546
# Create SDK instance for segment testing
551547
instance = Featurevisor.create_instance(
552-
datafile: symbolize_keys(datafile),
548+
datafile: datafile,
553549
log_level: level
554550
)
555551

@@ -765,16 +761,7 @@ def normalize_hash_keys(obj)
765761
end
766762
end
767763

768-
def symbolize_keys(obj)
769-
case obj
770-
when Hash
771-
obj.transform_keys(&:to_sym).transform_values { |v| symbolize_keys(v) }
772-
when Array
773-
obj.map { |v| symbolize_keys(v) }
774-
else
775-
obj
776-
end
777-
end
764+
778765

779766
def execute_command(command)
780767
stdout, stderr, status = Open3.capture3(command)

lib/featurevisor/instance.rb

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def initialize(options = {})
4242

4343
if options[:datafile]
4444
@datafile_reader = Featurevisor::DatafileReader.new(
45-
datafile: options[:datafile].is_a?(String) ? JSON.parse(options[:datafile]) : options[:datafile],
45+
datafile: parse_datafile(options[:datafile]),
4646
logger: @logger
4747
)
4848
end
@@ -61,7 +61,7 @@ def set_log_level(level)
6161
def set_datafile(datafile)
6262
begin
6363
new_datafile_reader = Featurevisor::DatafileReader.new(
64-
datafile: datafile.is_a?(String) ? JSON.parse(datafile) : datafile,
64+
datafile: parse_datafile(datafile),
6565
logger: @logger
6666
)
6767

@@ -409,6 +409,32 @@ def get_all_evaluations(context = {}, feature_keys = [], options = {})
409409

410410
private
411411

412+
# Parse and symbolize datafile keys
413+
# @param datafile [Hash, String] Datafile content or JSON string
414+
# @return [Hash] Datafile with symbolized keys
415+
def parse_datafile(datafile)
416+
if datafile.is_a?(String)
417+
parsed = JSON.parse(datafile)
418+
symbolize_keys(parsed)
419+
else
420+
symbolize_keys(datafile)
421+
end
422+
end
423+
424+
# Recursively symbolize hash keys
425+
# @param obj [Object] Object to symbolize keys for
426+
# @return [Object] Object with symbolized keys
427+
def symbolize_keys(obj)
428+
case obj
429+
when Hash
430+
obj.transform_keys(&:to_sym).transform_values { |v| symbolize_keys(v) }
431+
when Array
432+
obj.map { |v| symbolize_keys(v) }
433+
else
434+
obj
435+
end
436+
end
437+
412438
# Get evaluation dependencies
413439
# @param context [Hash] Context
414440
# @param options [Hash] Override options

spec/instance_spec.rb

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1197,4 +1197,74 @@
11971197
expect(sdk.is_enabled("test", { userId: "123", country: "nl" })).to be true
11981198
expect(sdk.is_enabled("test", { userId: "123", country: "us", device: "iphone" })).to be true
11991199
end
1200+
1201+
it "should automatically symbolize keys when parsing JSON string datafile" do
1202+
json_datafile = '{
1203+
"schemaVersion": "2",
1204+
"revision": "1.0",
1205+
"features": {
1206+
"test": {
1207+
"key": "test",
1208+
"bucketBy": "userId",
1209+
"variations": [
1210+
{ "value": "control" },
1211+
{ "value": "treatment" }
1212+
],
1213+
"traffic": [
1214+
{
1215+
"key": "1",
1216+
"segments": "*",
1217+
"percentage": 100000,
1218+
"allocation": [
1219+
{ "variation": "control", "range": [0, 100000] },
1220+
{ "variation": "treatment", "range": [0, 0] }
1221+
]
1222+
}
1223+
]
1224+
}
1225+
},
1226+
"segments": {}
1227+
}'
1228+
1229+
sdk = Featurevisor.create_instance(datafile: json_datafile)
1230+
1231+
expect(sdk.get_revision).to eq("1.0")
1232+
expect(sdk.get_feature("test")).to be_a(Hash)
1233+
expect(sdk.get_feature("test")[:key]).to eq("test")
1234+
expect(sdk.get_feature("test")[:bucketBy]).to eq("userId")
1235+
expect(sdk.is_enabled("test", { userId: "123" })).to be true
1236+
expect(sdk.get_variation("test", { userId: "123" })).to eq("control")
1237+
end
1238+
1239+
it "should automatically symbolize keys when setting JSON string datafile" do
1240+
sdk = Featurevisor.create_instance
1241+
1242+
json_datafile = '{
1243+
"schemaVersion": "2",
1244+
"revision": "2.0",
1245+
"features": {
1246+
"newFeature": {
1247+
"key": "newFeature",
1248+
"bucketBy": "userId",
1249+
"traffic": [
1250+
{
1251+
"key": "1",
1252+
"segments": "*",
1253+
"percentage": 100000,
1254+
"allocation": []
1255+
}
1256+
]
1257+
}
1258+
},
1259+
"segments": {}
1260+
}'
1261+
1262+
sdk.set_datafile(json_datafile)
1263+
1264+
expect(sdk.get_revision).to eq("2.0")
1265+
expect(sdk.get_feature("newFeature")).to be_a(Hash)
1266+
expect(sdk.get_feature("newFeature")[:key]).to eq("newFeature")
1267+
expect(sdk.get_feature("newFeature")[:bucketBy]).to eq("userId")
1268+
expect(sdk.is_enabled("newFeature", { userId: "123" })).to be true
1269+
end
12001270
end

0 commit comments

Comments
 (0)