Class: Featurevisor::Instance
- Inherits:
-
Object
- Object
- Featurevisor::Instance
- Defined in:
- lib/featurevisor/instance.rb
Overview
Instance class for managing feature flag evaluations
Constant Summary collapse
- EMPTY_DATAFILE =
Empty datafile template
{ schemaVersion: "2", revision: "unknown", segments: {}, features: {} }.freeze
Instance Method Summary collapse
-
#add_module(mod) ⇒ Proc?
Add a module.
-
#close ⇒ Object
Close the instance.
-
#evaluate_flag(feature_key, context = {}, options = {}) ⇒ Hash
Evaluate a flag.
-
#evaluate_variable(feature_key, variable_key, context = {}, options = {}) ⇒ Hash
Evaluate a variable.
-
#evaluate_variation(feature_key, context = {}, options = {}) ⇒ Hash
Evaluate a variation.
-
#get_all_evaluations(context = {}, feature_keys = [], options = {}) ⇒ Hash
Get all evaluations.
-
#get_context(context = nil) ⇒ Hash
Get context.
-
#get_feature(feature_key) ⇒ Hash?
Get a feature by key.
- #get_feature_keys ⇒ Object
-
#get_revision ⇒ String
Get the revision.
- #get_schema_version ⇒ Object
- #get_segment(segment_key) ⇒ Object
-
#get_variable(feature_key, variable_key, context = {}, options = {}) ⇒ Object?
Get variable value.
-
#get_variable_array(feature_key, variable_key, context = {}, options = {}) ⇒ Array?
Get variable as array.
-
#get_variable_boolean(feature_key, variable_key, context = {}, options = {}) ⇒ Boolean?
Get variable as boolean.
-
#get_variable_double(feature_key, variable_key, context = {}, options = {}) ⇒ Float?
Get variable as double.
-
#get_variable_integer(feature_key, variable_key, context = {}, options = {}) ⇒ Integer?
Get variable as integer.
-
#get_variable_json(feature_key, variable_key, context = {}, options = {}) ⇒ Object?
Get variable as JSON.
- #get_variable_keys(feature_key) ⇒ Object
-
#get_variable_object(feature_key, variable_key, context = {}, options = {}) ⇒ Hash?
Get variable as object.
-
#get_variable_string(feature_key, variable_key, context = {}, options = {}) ⇒ String?
Get variable as string.
-
#get_variation(feature_key, context = {}, options = {}) ⇒ String?
Get variation value.
- #has_variations?(feature_key) ⇒ Boolean
-
#initialize(options = {}) ⇒ Instance
constructor
Initialize a new Featurevisor instance.
-
#is_enabled(feature_key, context = {}, options = {}) ⇒ Boolean
Check if a feature is enabled.
-
#on(event_name, callback) ⇒ Proc
Subscribe to an event.
- #remove_module(name_or_module) ⇒ Object
-
#set_context(context, replace = false) ⇒ Object
Set context.
-
#set_datafile(datafile, replace = false) ⇒ Object
Set the datafile.
-
#set_log_level(level) ⇒ Object
Set the log level.
-
#set_sticky(sticky, replace = false) ⇒ Object
Set sticky features.
-
#spawn(context = {}, options = {}) ⇒ ChildInstance
Spawn a child instance.
Constructor Details
#initialize(options = {}) ⇒ Instance
Initialize a new Featurevisor instance
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/featurevisor/instance.rb', line 25 def initialize( = {}) # from options @context = [:context] || {} @logger = Logger.new( level: [:log_level] || "info", handler: method(:handle_internal_log) ) @on_diagnostic = [:on_diagnostic] || [:onDiagnostic] @emitter = Featurevisor::Emitter.new @sticky = [:sticky] || {} @closed = false @module_diagnostic_subscriptions = [] # datafile @datafile_reader = DatafileReader.new( datafile: EMPTY_DATAFILE, logger: @logger ) @modules_manager = Featurevisor::Modules::ModulesManager.new( modules: [:modules] || [], report_diagnostic: method(:report_diagnostic), module_api_factory: method(:create_module_api), clear_module_diagnostic_subscriptions: method(:clear_module_diagnostic_subscriptions) ) if [:datafile] set_datafile([:datafile], true) end report_diagnostic( level: "info", code: "sdk_initialized", message: "SDK initialized" ) end |
Instance Method Details
#add_module(mod) ⇒ Proc?
Add a module
188 189 190 |
# File 'lib/featurevisor/instance.rb', line 188 def add_module(mod) @modules_manager.add(mod) end |
#close ⇒ Object
Close the instance
205 206 207 208 209 210 |
# File 'lib/featurevisor/instance.rb', line 205 def close @closed = true @modules_manager.close_all @module_diagnostic_subscriptions = [] @emitter.clear_all end |
#evaluate_flag(feature_key, context = {}, options = {}) ⇒ Hash
Evaluate a flag
269 270 271 272 273 274 275 276 |
# File 'lib/featurevisor/instance.rb', line 269 def evaluate_flag(feature_key, context = {}, = {}) Featurevisor::Evaluate.evaluate_with_modules( get_evaluation_dependencies(context, ).merge( type: "flag", feature_key: feature_key ) ) end |
#evaluate_variable(feature_key, variable_key, context = {}, options = {}) ⇒ Hash
Evaluate a variable
335 336 337 338 339 340 341 342 343 |
# File 'lib/featurevisor/instance.rb', line 335 def evaluate_variable(feature_key, variable_key, context = {}, = {}) Featurevisor::Evaluate.evaluate_with_modules( get_evaluation_dependencies(context, ).merge( type: "variable", feature_key: feature_key, variable_key: variable_key ) ) end |
#evaluate_variation(feature_key, context = {}, options = {}) ⇒ Hash
Evaluate a variation
298 299 300 301 302 303 304 305 |
# File 'lib/featurevisor/instance.rb', line 298 def evaluate_variation(feature_key, context = {}, = {}) Featurevisor::Evaluate.evaluate_with_modules( get_evaluation_dependencies(context, ).merge( type: "variation", feature_key: feature_key ) ) end |
#get_all_evaluations(context = {}, feature_keys = [], options = {}) ⇒ Hash
Get all evaluations
454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 |
# File 'lib/featurevisor/instance.rb', line 454 def get_all_evaluations(context = {}, feature_keys = [], = {}) result = {} keys = feature_keys.size > 0 ? feature_keys : @datafile_reader.get_feature_keys keys.each do |feature_key| # Convert symbol keys to strings for evaluation functions feature_key_str = feature_key.to_s # isEnabled evaluated_feature = { enabled: is_enabled(feature_key_str, context, ) } # variation if @datafile_reader.has_variations?(feature_key_str) variation = get_variation(feature_key_str, context, ) evaluated_feature[:variation] = variation if variation end # variables variable_keys = @datafile_reader.get_variable_keys(feature_key_str) if variable_keys.size > 0 evaluated_feature[:variables] = {} variable_keys.each do |variable_key| evaluated_feature[:variables][variable_key] = get_variable( feature_key_str, variable_key, context, ) end end result[feature_key] = evaluated_feature end result end |
#get_context(context = nil) ⇒ Hash
Get context
241 242 243 244 245 246 247 248 249 250 |
# File 'lib/featurevisor/instance.rb', line 241 def get_context(context = nil) if context { **@context, **context } else @context end end |
#get_feature(feature_key) ⇒ Hash?
Get a feature by key
181 182 183 |
# File 'lib/featurevisor/instance.rb', line 181 def get_feature(feature_key) @datafile_reader.get_feature(feature_key) end |
#get_feature_keys ⇒ Object
166 167 168 |
# File 'lib/featurevisor/instance.rb', line 166 def get_feature_keys @datafile_reader.get_feature_keys end |
#get_revision ⇒ String
Get the revision
154 155 156 |
# File 'lib/featurevisor/instance.rb', line 154 def get_revision @datafile_reader.get_revision end |
#get_schema_version ⇒ Object
158 159 160 |
# File 'lib/featurevisor/instance.rb', line 158 def get_schema_version @datafile_reader.get_schema_version end |
#get_segment(segment_key) ⇒ Object
162 163 164 |
# File 'lib/featurevisor/instance.rb', line 162 def get_segment(segment_key) @datafile_reader.get_segment(segment_key) end |
#get_variable(feature_key, variable_key, context = {}, options = {}) ⇒ Object?
Get variable value
351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 |
# File 'lib/featurevisor/instance.rb', line 351 def get_variable(feature_key, variable_key, context = {}, = {}) begin evaluation = evaluate_variable(feature_key, variable_key, context, ) if !evaluation[:variable_value].nil? if evaluation[:variable_schema] && evaluation[:variable_schema][:type] == "json" && evaluation[:variable_value].is_a?(String) JSON.parse(evaluation[:variable_value], symbolize_names: true) else evaluation[:variable_value] end else nil end rescue => e @logger.error("getVariable", { feature_key: feature_key, variable_key: variable_key, error: e }) nil end end |
#get_variable_array(feature_key, variable_key, context = {}, options = {}) ⇒ Array?
Get variable as array
422 423 424 425 |
# File 'lib/featurevisor/instance.rb', line 422 def get_variable_array(feature_key, variable_key, context = {}, = {}) variable_value = get_variable(feature_key, variable_key, context, ) get_value_by_type(variable_value, "array") end |
#get_variable_boolean(feature_key, variable_key, context = {}, options = {}) ⇒ Boolean?
Get variable as boolean
378 379 380 381 |
# File 'lib/featurevisor/instance.rb', line 378 def get_variable_boolean(feature_key, variable_key, context = {}, = {}) variable_value = get_variable(feature_key, variable_key, context, ) get_value_by_type(variable_value, "boolean") end |
#get_variable_double(feature_key, variable_key, context = {}, options = {}) ⇒ Float?
Get variable as double
411 412 413 414 |
# File 'lib/featurevisor/instance.rb', line 411 def get_variable_double(feature_key, variable_key, context = {}, = {}) variable_value = get_variable(feature_key, variable_key, context, ) get_value_by_type(variable_value, "double") end |
#get_variable_integer(feature_key, variable_key, context = {}, options = {}) ⇒ Integer?
Get variable as integer
400 401 402 403 |
# File 'lib/featurevisor/instance.rb', line 400 def get_variable_integer(feature_key, variable_key, context = {}, = {}) variable_value = get_variable(feature_key, variable_key, context, ) get_value_by_type(variable_value, "integer") end |
#get_variable_json(feature_key, variable_key, context = {}, options = {}) ⇒ Object?
Get variable as JSON
444 445 446 447 |
# File 'lib/featurevisor/instance.rb', line 444 def get_variable_json(feature_key, variable_key, context = {}, = {}) variable_value = get_variable(feature_key, variable_key, context, ) get_value_by_type(variable_value, "json") end |
#get_variable_keys(feature_key) ⇒ Object
170 171 172 |
# File 'lib/featurevisor/instance.rb', line 170 def get_variable_keys(feature_key) @datafile_reader.get_variable_keys(feature_key) end |
#get_variable_object(feature_key, variable_key, context = {}, options = {}) ⇒ Hash?
Get variable as object
433 434 435 436 |
# File 'lib/featurevisor/instance.rb', line 433 def get_variable_object(feature_key, variable_key, context = {}, = {}) variable_value = get_variable(feature_key, variable_key, context, ) get_value_by_type(variable_value, "object") end |
#get_variable_string(feature_key, variable_key, context = {}, options = {}) ⇒ String?
Get variable as string
389 390 391 392 |
# File 'lib/featurevisor/instance.rb', line 389 def get_variable_string(feature_key, variable_key, context = {}, = {}) variable_value = get_variable(feature_key, variable_key, context, ) get_value_by_type(variable_value, "string") end |
#get_variation(feature_key, context = {}, options = {}) ⇒ String?
Get variation value
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 |
# File 'lib/featurevisor/instance.rb', line 312 def get_variation(feature_key, context = {}, = {}) begin evaluation = evaluate_variation(feature_key, context, ) if evaluation[:variation_value] evaluation[:variation_value] elsif evaluation[:variation] evaluation[:variation][:value] else nil end rescue => e @logger.error("getVariation", { feature_key: feature_key, error: e }) nil end end |
#has_variations?(feature_key) ⇒ Boolean
174 175 176 |
# File 'lib/featurevisor/instance.rb', line 174 def has_variations?(feature_key) @datafile_reader.has_variations?(feature_key) end |
#is_enabled(feature_key, context = {}, options = {}) ⇒ Boolean
Check if a feature is enabled
283 284 285 286 287 288 289 290 291 |
# File 'lib/featurevisor/instance.rb', line 283 def is_enabled(feature_key, context = {}, = {}) begin evaluation = evaluate_flag(feature_key, context, ) evaluation[:enabled] == true rescue => e @logger.error("isEnabled", { feature_key: feature_key, error: e }) false end end |
#on(event_name, callback) ⇒ Proc
Subscribe to an event
200 201 202 |
# File 'lib/featurevisor/instance.rb', line 200 def on(event_name, callback) @emitter.on(event_name, callback) end |
#remove_module(name_or_module) ⇒ Object
192 193 194 |
# File 'lib/featurevisor/instance.rb', line 192 def remove_module(name_or_module) @modules_manager.remove(name_or_module) end |
#set_context(context, replace = false) ⇒ Object
Set context
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 |
# File 'lib/featurevisor/instance.rb', line 215 def set_context(context, replace = false) if replace @context = context else @context = { **@context, **context } end @emitter.trigger("context_set", { context: @context, replaced: replace }) report_diagnostic( level: "debug", code: "context_set", message: replace ? "Context replaced" : "Context updated", details: { context: @context, replaced: replace } ) end |
#set_datafile(datafile, replace = false) ⇒ Object
Set the datafile
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
# File 'lib/featurevisor/instance.rb', line 84 def set_datafile(datafile, replace = false) return if @closed begin parsed_datafile = if datafile.is_a?(String) JSON.parse(datafile, symbolize_names: true) elsif datafile.is_a?(Hash) JSON.parse(JSON.generate(datafile), symbolize_names: true) else datafile end unless parsed_datafile.is_a?(Hash) && parsed_datafile[:schemaVersion].is_a?(String) && parsed_datafile[:revision].is_a?(String) && parsed_datafile[:segments].is_a?(Hash) && parsed_datafile[:features].is_a?(Hash) raise ArgumentError, "Invalid datafile" end next_datafile = replace ? parsed_datafile : merge_datafiles(@datafile_reader.get_datafile, parsed_datafile) new_datafile_reader = DatafileReader.new( datafile: next_datafile, logger: @logger ) details = Featurevisor::Events.get_params_for_datafile_set_event(@datafile_reader, new_datafile_reader, replace) @datafile_reader = new_datafile_reader report_diagnostic( level: "info", code: "datafile_set", message: "Datafile set", details: details ) @emitter.trigger("datafile_set", details) rescue => e report_diagnostic( level: "error", code: "invalid_datafile", message: "Could not parse datafile", original_error: e ) end end |
#set_log_level(level) ⇒ Object
Set the log level
64 65 66 |
# File 'lib/featurevisor/instance.rb', line 64 def set_log_level(level) @logger.set_level(level) end |
#set_sticky(sticky, replace = false) ⇒ Object
Set sticky features
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
# File 'lib/featurevisor/instance.rb', line 129 def set_sticky(sticky, replace = false) previous_sticky_features = @sticky || {} if replace @sticky = sticky else @sticky = { **@sticky, **sticky } end params = Featurevisor::Events.get_params_for_sticky_set_event(previous_sticky_features, @sticky, replace) report_diagnostic( level: "info", code: "sticky_set", message: "Sticky features set", details: params ) @emitter.trigger("sticky_set", params) end |
#spawn(context = {}, options = {}) ⇒ ChildInstance
Spawn a child instance
256 257 258 259 260 261 262 |
# File 'lib/featurevisor/instance.rb', line 256 def spawn(context = {}, = {}) Featurevisor::ChildInstance.new( parent: self, context: get_context(context), sticky: [:sticky] ) end |