@@ -41,94 +41,94 @@ class Interface
4141 # Initialize a new interface.
4242 def initialize
4343 @observer = nil
44- @values = Hash . new ( 0 )
44+ @metrics = { }
4545
4646 @guard = Mutex . new
4747 end
4848
4949 # @attribute [Object | Nil] The registered observer.
5050 attr :observer
5151
52- # @attribute [Hash] The current values for all fields.
53- attr :values
52+ # @attribute [Mutex] The mutex for thread safety.
53+ attr :guard
54+
55+ # Get the current values for all metrics.
56+ #
57+ # @returns [Hash] Hash mapping field names to their current values.
58+ def values
59+ @metrics . transform_values do |metric |
60+ metric . guard . synchronize { metric . value }
61+ end
62+ end
5463
5564 # Set the observer for the interface.
5665 #
57- # When an observer is set, it is notified of all current values
66+ # When an observer is set, it is notified of all current metric values
5867 # so it can sync its state. The observer must implement `set(field, value)`.
68+ # All cached metrics are invalidated when the observer changes.
5969 #
6070 # @parameter observer [#set] The observer to set.
6171 def observer = ( observer )
6272 @guard . synchronize do
63- @observer = observer
64-
65- @values . each do |field , value |
66- observer . set ( field , value )
73+ # Invalidate all cached metrics
74+ @metrics . each_value do |metric |
75+ metric . invalidate
6776 end
77+
78+ @observer = observer
79+ end
80+
81+ # Notify observer of all current metric values (outside guard to avoid deadlock)
82+ @metrics . each do |name , metric |
83+ value = metric . guard . synchronize { metric . value }
84+ observer . set ( name , value )
6885 end
6986 end
7087
7188 # Set a field value.
7289 #
73- # Updates the interface's value and notifies the registered observer .
90+ # Delegates to the metric instance for the given field .
7491 #
7592 # @parameter field [Symbol] The field name to set.
7693 # @parameter value [Numeric] The value to set.
7794 def set ( field , value )
78- field = field . to_sym
79-
80- @guard . synchronize do
81- @values [ field ] = value
82- @observer &.set ( field , value )
83- end
95+ metric ( field ) . set ( value )
8496 end
8597
8698 # Increment a field value, optionally with a block that auto-decrements.
8799 #
88- # Updates the interface's value and notifies the registered observer .
100+ # Delegates to the metric instance for the given field .
89101 #
90102 # @parameter field [Symbol] The field name to increment.
91103 # @yield Optional block - if provided, decrements the field after the block completes.
92104 # @returns [Integer] The new value of the field.
93- def increment ( field )
94- field = field . to_sym
95-
96- new_value = nil
97- @guard . synchronize do
98- new_value = @values [ field ] + 1
99- @values [ field ] = new_value
100- @observer &.set ( field , new_value )
101- end
102-
103- if block_given?
104- begin
105- yield
106- ensure
107- # Decrement after block completes
108- decrement ( field )
109- end
110- end
111-
112- new_value
105+ def increment ( field , &block )
106+ metric ( field ) . increment ( &block )
113107 end
114108
115109 # Decrement a field value.
116110 #
117- # Updates the interface's value and notifies the registered observer .
111+ # Delegates to the metric instance for the given field .
118112 #
119113 # @parameter field [Symbol] The field name to decrement.
120114 # @returns [Integer] The new value of the field.
121115 def decrement ( field )
116+ metric ( field ) . decrement
117+ end
118+
119+ # Get a cached metric reference for a field.
120+ #
121+ # Returns a {Metric} instance that caches all details needed for fast writes.
122+ # Metrics are cached per field and invalidated when the observer changes.
123+ #
124+ # @parameter field [Symbol] The field name to get a metric for.
125+ # @returns [Metric] A metric instance for the given field.
126+ def metric ( field )
122127 field = field . to_sym
123128
124- new_value = nil
125129 @guard . synchronize do
126- new_value = @values [ field ] - 1
127- @values [ field ] = new_value
128- @observer &.set ( field , new_value )
130+ @metrics [ field ] ||= Metric . new ( field , self )
129131 end
130-
131- new_value
132132 end
133133 end
134134 end
0 commit comments