@@ -14,6 +14,7 @@ def initialize(sdkKey, dvc_options = Options.new, wait_for_init = false)
1414 @sdkKey = sdkKey
1515 @dvc_options = dvc_options
1616 @logger = dvc_options . logger
17+ @eval_hooks_runner = EvalHooksRunner . new
1718
1819 if @dvc_options . enable_cloud_bucketing
1920 @api_client = ApiClient . default
@@ -172,35 +173,68 @@ def variable(user, key, default, opts = {})
172173
173174 validate_model ( user )
174175
175- if @dvc_options . enable_cloud_bucketing
176- data , _status_code , _headers = variable_with_http_info ( key , user , default , opts )
177- return data
176+ # Create hook context
177+ hook_context = HookContext . new ( key : key , user : user , default_value : default )
178+
179+ before_hook_error = nil
180+ # Run before hooks
181+ begin
182+ hook_context = @eval_hooks_runner . run_before_hooks ( hook_context )
183+ rescue BeforeHookError => e
184+ before_hook_error = e
185+ @logger . warn ( "Error in before hooks: #{ e . message } " )
178186 end
179187
180- value = default
181- type = determine_variable_type ( default )
182- defaulted = true
183- if local_bucketing_initialized? && @local_bucketing . has_config
184- type_code = variable_type_code_from_type ( type )
185- variable_pb = variable_for_user_pb ( user , key , type_code )
186- unless variable_pb . nil?
187- value = get_variable_value ( variable_pb )
188- defaulted = false
188+ variable_result = nil
189+
190+ begin
191+ if @dvc_options . enable_cloud_bucketing
192+ data , _status_code , _headers = variable_with_http_info ( key , user , default , opts )
193+ variable_result = data
194+ else
195+ value = default
196+ type = determine_variable_type ( default )
197+ defaulted = true
198+ if local_bucketing_initialized? && @local_bucketing . has_config
199+ type_code = variable_type_code_from_type ( type )
200+ variable_pb = variable_for_user_pb ( user , key , type_code )
201+ unless variable_pb . nil?
202+ value = get_variable_value ( variable_pb )
203+ defaulted = false
204+ end
205+ else
206+ @logger . warn ( "Local bucketing not initialized, returning default value for variable #{ key } " )
207+ variable_event = Event . new ( { type : DevCycle ::EventTypes [ :agg_variable_defaulted ] , target : key } )
208+ bucketed_config = BucketedUserConfig . new ( { } , { } , { } , { } , { } , { } , [ ] )
209+ @event_queue . queue_aggregate_event ( variable_event , bucketed_config )
210+ end
211+
212+ variable_result = Variable . new ( {
213+ key : key ,
214+ value : value ,
215+ type : type ,
216+ defaultValue : default ,
217+ isDefaulted : defaulted
218+ } )
189219 end
190- else
191- @logger . warn ( "Local bucketing not initialized, returning default value for variable #{ key } " )
192- variable_event = Event . new ( { type : DevCycle ::EventTypes [ :agg_variable_defaulted ] , target : key } )
193- bucketed_config = BucketedUserConfig . new ( { } , { } , { } , { } , { } , { } , [ ] )
194- @event_queue . queue_aggregate_event ( variable_event , bucketed_config )
195- end
196-
197- Variable . new ( {
198- key : key ,
199- value : value ,
200- type : type ,
201- defaultValue : default ,
202- isDefaulted : defaulted
203- } )
220+
221+
222+ # Run after hooks only if no before hook error occurred
223+ if before_hook_error != nil
224+ @logger . info ( "before_hook_error is not nil, skipping after hooks" )
225+ raise before_hook_error
226+ else
227+ @eval_hooks_runner . run_after_hooks ( hook_context )
228+ end
229+ rescue => e
230+ # Run error hooks
231+ @eval_hooks_runner . run_error_hooks ( hook_context , e )
232+ ensure
233+ # Run finally hooks in all cases
234+ @eval_hooks_runner . run_finally_hooks ( hook_context )
235+ end
236+
237+ variable_result
204238 end
205239
206240 def variable_for_user ( user , key , variable_type_code )
@@ -526,6 +560,32 @@ def variable_type_pb_code_from_type_code(type_code)
526560 raise ArgumentError . new ( "Invalid type code for variable: #{ type_code } " )
527561 end
528562 end
563+
564+ def get_variable_value ( variable_pb )
565+ case variable_pb . type
566+ when :Boolean
567+ variable_pb . boolValue
568+ when :Number
569+ variable_pb . doubleValue
570+ when :String
571+ variable_pb . stringValue
572+ when :JSON
573+ JSON . parse variable_pb . stringValue
574+ end
575+ end
576+
577+ # Adds an eval hook to the client
578+ # @param [EvalHook] eval_hook The eval hook to add
579+ # @return [void]
580+ def add_eval_hook ( eval_hook )
581+ @eval_hooks_runner . add_hook ( eval_hook )
582+ end
583+
584+ # Clears all eval hooks from the client
585+ # @return [void]
586+ def clear_eval_hooks
587+ @eval_hooks_runner . clear_hooks
588+ end
529589 end
530590
531591 # @deprecated Use `DevCycle::Client` instead.
0 commit comments