Skip to content

Commit c4756cc

Browse files
authored
Require datafiles to be parsed with symbolized names (#1)
1 parent b283a6a commit c4756cc

File tree

8 files changed

+223
-137
lines changed

8 files changed

+223
-137
lines changed

README.md

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,14 +81,29 @@ require 'json'
8181
# Fetch datafile from URL
8282
datafile_url = 'https://cdn.yoursite.com/datafile.json'
8383
response = Net::HTTP.get_response(URI(datafile_url))
84-
datafile_content = JSON.parse(response.body)
84+
85+
# Parse JSON with symbolized keys (required)
86+
datafile_content = JSON.parse(response.body, symbolize_names: true)
8587

8688
# Create SDK instance
8789
f = Featurevisor.create_instance(
8890
datafile: datafile_content
8991
)
9092
```
9193

94+
**Important**: When parsing JSON datafiles, you must use `symbolize_names: true` to ensure proper key handling by the SDK.
95+
96+
Alternatively, you can pass a JSON string directly and the SDK will parse it automatically:
97+
98+
```ruby
99+
# Option 1: Parse JSON yourself (recommended)
100+
datafile_content = JSON.parse(json_string, symbolize_names: true)
101+
f = Featurevisor.create_instance(datafile: datafile_content)
102+
103+
# Option 2: Pass JSON string directly (automatic parsing)
104+
f = Featurevisor.create_instance(datafile: json_string)
105+
```
106+
92107
## Evaluation types
93108

94109
We can evaluate 3 types of values against a particular [feature](https://featurevisor.com/docs/features/):
@@ -334,9 +349,16 @@ f.set_sticky({
334349
You may also initialize the SDK without passing `datafile`, and set it later on:
335350

336351
```ruby
352+
# Parse with symbolized keys before setting
353+
datafile_content = JSON.parse(json_string, symbolize_names: true)
337354
f.set_datafile(datafile_content)
355+
356+
# Or pass JSON string directly for automatic parsing
357+
f.set_datafile(json_string)
338358
```
339359

360+
**Important**: When calling `set_datafile()`, ensure JSON is parsed with `symbolize_names: true` if you're parsing it yourself.
361+
340362
### Updating datafile
341363

342364
You can set the datafile as many times as you want in your application, which will result in emitting a [`datafile_set`](#datafile_set) event that you can listen and react to accordingly.

bin/commands/assess_distribution.rb

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ def run
5858

5959
# Initialize evaluation counters
6060
flag_evaluations = {
61-
"enabled" => 0,
62-
"disabled" => 0
61+
enabled: 0,
62+
disabled: 0
6363
}
6464
variation_evaluations = {}
6565

@@ -78,9 +78,9 @@ def run
7878
# Evaluate flag
7979
flag_evaluation = instance.is_enabled(@options.feature, context_copy)
8080
if flag_evaluation
81-
flag_evaluations["enabled"] += 1
81+
flag_evaluations[:enabled] += 1
8282
else
83-
flag_evaluations["disabled"] += 1
83+
flag_evaluations[:disabled] += 1
8484
end
8585

8686
# Evaluate variation if feature has variations
@@ -147,7 +147,7 @@ def build_datafile(environment)
147147
end
148148

149149
begin
150-
JSON.parse(stdout)
150+
JSON.parse(stdout, symbolize_names: true)
151151
rescue JSON::ParserError => e
152152
puts "Error: Failed to parse datafile JSON: #{e.message}"
153153
exit 1
@@ -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: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ def build_datafile(environment)
120120

121121
# Parse the JSON output
122122
begin
123-
JSON.parse(datafile_output)
123+
JSON.parse(datafile_output, symbolize_names: true)
124124
rescue JSON::ParserError => e
125125
puts "Error: Failed to parse datafile JSON: #{e.message}"
126126
puts "Command output: #{datafile_output}"
@@ -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

0 commit comments

Comments
 (0)