magick-feature-flags 0.9.18 → 0.9.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7df3e59dc8f0736e18fb93603f53038f48b5302769c42cc37ab87f2afcba0307
4
- data.tar.gz: e0235e0c7518860061b7b67a27aee9c1be88346c8292733aae0a2c794c2288d7
3
+ metadata.gz: 3a9bd8f59c8729764a5a1b9876b20bca16dce2670ed477ee64109eda02219f98
4
+ data.tar.gz: 566826dcca95d42a34fd5f95581e5dfd1c3d074a3260def10fda5bb3a68c5ce0
5
5
  SHA512:
6
- metadata.gz: 0a76c637a3cd96cebd6fa91be4f10df8e1174713fabb82c4cdb8df1cecd2d4c6c6ea46e00949cc485e6c0a3d46a9180c718204361a2630c8a71a069a0c6f6bbd
7
- data.tar.gz: f0682f004002eab91412ee9d948e69f3f84de41238ab2d5ca3f06abec1abf2616c86063a66198f8a596f32d8dc2cf545c9db0b62961e6dc98a4d97a39b01e5cc
6
+ metadata.gz: 0b37fb6089b687c08b31aad74d24f43c90d65134c9e68e0de2d521a6357f64d0f3778b8aafe60aca9f912f4610d73a42e4e6a2f96f156f66a8c5d154affa8d91
7
+ data.tar.gz: 267b78151d2017069f1a3e4836ed0016bbdc524ee9fb2d7ea15ec8148df9359604f9acf9dca886aa073fb289309c5f4f90ce39754d8da80d95794606b0a05087
@@ -22,26 +22,35 @@ module Magick
22
22
  @dependencies = options[:dependencies] ? Array(options[:dependencies]) : []
23
23
  @stored_value_initialized = false # Track if @stored_value has been explicitly set
24
24
 
25
+ # Performance optimizations: cache expensive checks
26
+ @_targeting_empty = true # Will be updated after load_from_adapter
27
+ @_rails_events_enabled = false # Cache Rails events availability (only enable in dev)
28
+
25
29
  validate_type!
26
30
  validate_default_value!
27
31
  load_from_adapter
32
+ # Update targeting empty cache after loading
33
+ @_targeting_empty = @targeting.empty?
28
34
  # Save description and display_name to adapter if they were provided and not already in adapter
29
35
  save_metadata_if_new
30
36
  end
31
37
 
32
38
  def enabled?(context = {})
33
- # Track usage if metrics available
34
- start_time = Time.now if Magick.performance_metrics
39
+ # Performance metrics: measure before the check (only if enabled)
40
+ perf_metrics = Magick.performance_metrics
41
+ start_time = perf_metrics ? Process.clock_gettime(Process::CLOCK_MONOTONIC) : nil
35
42
 
43
+ # Fast path: check enabled status
36
44
  result = check_enabled(context)
37
45
 
38
- if Magick.performance_metrics
39
- duration = (Time.now - start_time) * 1000 # milliseconds
40
- Magick.performance_metrics.record(name, 'enabled?', duration, success: true)
46
+ # Record metrics if enabled (after the check to minimize overhead)
47
+ if perf_metrics
48
+ duration = (Process.clock_gettime(Process::CLOCK_MONOTONIC) - start_time) * 1000 # milliseconds
49
+ perf_metrics.record(name, 'enabled?', duration, success: true)
41
50
  end
42
51
 
43
- # Rails 8+ events for enabled/disabled
44
- if defined?(Magick::Rails::Events) && Magick::Rails::Events.rails8?
52
+ # Rails 8+ events (only in development or when explicitly enabled)
53
+ if @_rails_events_enabled
45
54
  if result
46
55
  Magick::Rails::Events.feature_enabled(name, context: context)
47
56
  else
@@ -49,21 +58,17 @@ module Magick
49
58
  end
50
59
  end
51
60
 
52
- # Warn if deprecated
53
- if status == :deprecated && result && !context[:allow_deprecated]
54
- warn "DEPRECATED: Feature '#{name}' is deprecated and will be removed." if Magick.warn_on_deprecated
55
-
56
- # Rails 8+ event for deprecation warning
57
- if defined?(Magick::Rails::Events) && Magick::Rails::Events.rails8?
58
- Magick::Rails::Events.deprecated_warning(name)
59
- end
61
+ # Warn if deprecated (only if enabled)
62
+ if status == :deprecated && result && !context[:allow_deprecated] && Magick.warn_on_deprecated
63
+ warn "DEPRECATED: Feature '#{name}' is deprecated and will be removed."
64
+ Magick::Rails::Events.deprecated_warning(name) if @_rails_events_enabled
60
65
  end
61
66
 
62
67
  result
63
68
  rescue StandardError => e
64
- if Magick.performance_metrics
65
- duration = (Time.now - start_time) * 1000
66
- Magick.performance_metrics.record(name, 'enabled?', duration, success: false)
69
+ if perf_metrics
70
+ duration = start_time ? (Process.clock_gettime(Process::CLOCK_MONOTONIC) - start_time) * 1000 : 0.0
71
+ perf_metrics.record(name, 'enabled?', duration, success: false)
67
72
  end
68
73
  # Return false on any error (fail-safe)
69
74
  warn "Magick: Error checking feature '#{name}': #{e.message}" if defined?(Rails) && Rails.env.development?
@@ -71,28 +76,28 @@ module Magick
71
76
  end
72
77
 
73
78
  def check_enabled(context = {})
79
+ # Fast path: check status first
74
80
  return false if status == :inactive
75
81
  return false if status == :deprecated && !context[:allow_deprecated]
76
82
 
77
- # NOTE: We don't check dependencies here because:
78
- # - Main features can be enabled independently
79
- # - Dependencies are only prevented from being enabled if the main feature is disabled
80
- # - The dependency check is handled in the enable() method, not in enabled?()
81
-
82
- # Check date/time range targeting
83
- return false if targeting[:date_range] && !date_range_active?(targeting[:date_range])
83
+ # Fast path: skip targeting checks if targeting is empty (most common case)
84
+ unless @_targeting_empty
85
+ # Check date/time range targeting
86
+ return false if targeting[:date_range] && !date_range_active?(targeting[:date_range])
84
87
 
85
- # Check IP address targeting
86
- return false if targeting[:ip_address] && context[:ip_address] && !ip_address_matches?(context[:ip_address])
88
+ # Check IP address targeting
89
+ return false if targeting[:ip_address] && context[:ip_address] && !ip_address_matches?(context[:ip_address])
87
90
 
88
- # Check custom attributes
89
- return false if targeting[:custom_attributes] && !custom_attributes_match?(context, targeting[:custom_attributes])
91
+ # Check custom attributes
92
+ return false if targeting[:custom_attributes] && !custom_attributes_match?(context,
93
+ targeting[:custom_attributes])
90
94
 
91
- # Check complex conditions
92
- if targeting[:complex_conditions] && !complex_conditions_match?(context, targeting[:complex_conditions])
93
- return false
95
+ # Check complex conditions
96
+ return false if targeting[:complex_conditions] && !complex_conditions_match?(context,
97
+ targeting[:complex_conditions])
94
98
  end
95
99
 
100
+ # Get value and check based on type
96
101
  value = get_value(context)
97
102
  case type
98
103
  when :boolean
@@ -131,19 +136,21 @@ module Magick
131
136
  end
132
137
 
133
138
  def get_value(context = {})
134
- # Check targeting rules first
135
- targeting_result = check_targeting(context)
136
- return targeting_result unless targeting_result.nil?
139
+ # Fast path: check targeting rules first (only if targeting exists)
140
+ unless @_targeting_empty
141
+ targeting_result = check_targeting(context)
142
+ return targeting_result unless targeting_result.nil?
143
+ end
137
144
 
138
- # Use instance variable if it has been set (check using defined? to handle nil vs uninitialized)
139
- # We use a special check: if @stored_value was explicitly set (even to false), use it
140
- # We track this by checking if @stored_value_initialized flag is set
141
- return @stored_value if defined?(@stored_value_initialized) && @stored_value_initialized
145
+ # Fast path: use cached value if initialized (avoid adapter calls)
146
+ return @stored_value if @stored_value_initialized
142
147
 
143
148
  # Load from adapter if instance variable hasn't been initialized
144
149
  loaded_value = load_value_from_adapter
145
150
  if loaded_value.nil?
146
- # Value not found in adapter, use default
151
+ # Value not found in adapter, use default and cache it
152
+ @stored_value = default_value
153
+ @stored_value_initialized = true
147
154
  default_value
148
155
  else
149
156
  # Value found in adapter, use it and mark as initialized
@@ -827,9 +834,14 @@ module Magick
827
834
  adapter_registry.set(name, 'targeting', targeting)
828
835
 
829
836
  # Update the feature in Magick.features if it's registered
830
- return unless Magick.features.key?(name)
837
+ if Magick.features.key?(name)
838
+ Magick.features[name].instance_variable_set(:@targeting, targeting.dup)
839
+ # Update targeting empty cache for performance
840
+ Magick.features[name].instance_variable_set(:@_targeting_empty, targeting.empty?)
841
+ end
831
842
 
832
- Magick.features[name].instance_variable_set(:@targeting, targeting.dup)
843
+ # Update local targeting empty cache for performance
844
+ @_targeting_empty = targeting.empty?
833
845
 
834
846
  # Explicitly trigger cache invalidation for targeting updates
835
847
  # Targeting changes affect enabled? checks, so we need immediate cache invalidation
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Magick
4
- VERSION = '0.9.18'
4
+ VERSION = '0.9.19'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: magick-feature-flags
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.18
4
+ version: 0.9.19
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Lobanov