magick-feature-flags 0.8.8 → 0.9.2

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: 876436714b054435d68ac40f18eab6597165640e5f4ab2cb666474f7b03cb92f
4
- data.tar.gz: 1cb04e84837d1faf72fa9566fe852ce484d20035b763b9cec4896ec1cb24b62e
3
+ metadata.gz: cf5b93d36c4bd726730dffae18e5af58cb9937c5579ce4acbadbdf35adfac3ce
4
+ data.tar.gz: a11dda7f5779416efad1a59256f2df0c2086d40e52dca36cb2af538123b75f1d
5
5
  SHA512:
6
- metadata.gz: b541dbee500ab1e93969791326ca2f02ab7b4bd9595f5a903ec954018166cf5de9f26cde857325e2698fdcfe311533e31f3eb201027594e4a66007246a14248a
7
- data.tar.gz: 701320125c33d03df6238e010ee9ce274f59fc56d4b423ebb6ffec131b2edda19fb1214dc532b875259f63848e4cbfa61ddbbf9b1354b6384fa139cd17c06840
6
+ metadata.gz: 4e86e55dfbd8c5671d5d0808fa5109d8d5688a71a7d1db3b42c28a88e89b6302cc2a18500452060424a66ed93bbe9d58e433a13c329dd923057b1e87b7520eb7
7
+ data.tar.gz: bfec5102e084898856fe860574602c75cd8e9674fe456d24aa89f7937455dcbfe463417cca6cd040eb61b5675f57df95bbf8071a8a2b3d2ab8ebbef12471f0b9
@@ -20,6 +20,7 @@ module Magick
20
20
  @display_name = options[:name] || options[:display_name]
21
21
  @targeting = {}
22
22
  @dependencies = options[:dependencies] ? Array(options[:dependencies]) : []
23
+ @stored_value_initialized = false # Track if @stored_value has been explicitly set
23
24
 
24
25
  validate_type!
25
26
  validate_default_value!
@@ -64,7 +65,9 @@ module Magick
64
65
  duration = (Time.now - start_time) * 1000
65
66
  Magick.performance_metrics.record(name, 'enabled?', duration, success: false)
66
67
  end
67
- raise e
68
+ # Return false on any error (fail-safe)
69
+ warn "Magick: Error checking feature '#{name}': #{e.message}" if defined?(Rails) && Rails.env.development?
70
+ false
68
71
  end
69
72
 
70
73
  def check_enabled(context = {})
@@ -99,6 +102,10 @@ module Magick
99
102
  else
100
103
  false
101
104
  end
105
+ rescue StandardError => e
106
+ # Return false on any error (fail-safe)
107
+ warn "Magick: Error in check_enabled for '#{name}': #{e.message}" if defined?(Rails) && Rails.env.development?
108
+ false
102
109
  end
103
110
 
104
111
  def disabled?(context = {})
@@ -126,11 +133,26 @@ module Magick
126
133
  targeting_result = check_targeting(context)
127
134
  return targeting_result unless targeting_result.nil?
128
135
 
129
- # Use instance variable if set, otherwise load from adapter
130
- # This ensures we use the most recent value set via set_value/disable/enable
131
- value = @stored_value
132
- value = load_value_from_adapter if value.nil?
133
- value || default_value
136
+ # Use instance variable if it has been set (check using defined? to handle nil vs uninitialized)
137
+ # We use a special check: if @stored_value was explicitly set (even to false), use it
138
+ # We track this by checking if @stored_value_initialized flag is set
139
+ return @stored_value if defined?(@stored_value_initialized) && @stored_value_initialized
140
+
141
+ # Load from adapter if instance variable hasn't been initialized
142
+ loaded_value = load_value_from_adapter
143
+ if loaded_value.nil?
144
+ # Value not found in adapter, use default
145
+ default_value
146
+ else
147
+ # Value found in adapter, use it and mark as initialized
148
+ @stored_value = loaded_value
149
+ @stored_value_initialized = true
150
+ loaded_value
151
+ end
152
+ rescue StandardError => e
153
+ # Return default value on error (fail-safe)
154
+ warn "Magick: Error in get_value for '#{name}': #{e.message}" if defined?(Rails) && Rails.env.development?
155
+ default_value
134
156
  end
135
157
 
136
158
  def enable_for_user(user_id)
@@ -326,11 +348,13 @@ module Magick
326
348
  adapter_registry.set(name, 'description', description) if description
327
349
  adapter_registry.set(name, 'display_name', display_name) if display_name
328
350
  @stored_value = value
351
+ @stored_value_initialized = true # Mark as initialized
329
352
 
330
353
  # Update registered feature instance if it exists
331
354
  if Magick.features.key?(name)
332
355
  registered = Magick.features[name]
333
356
  registered.instance_variable_set(:@stored_value, value)
357
+ registered.instance_variable_set(:@stored_value_initialized, true)
334
358
  registered.instance_variable_set(:@targeting, @targeting.dup) if @targeting
335
359
  end
336
360
 
@@ -354,6 +378,21 @@ module Magick
354
378
  end
355
379
 
356
380
  def enable(user_id: nil)
381
+ # Check if this feature is a dependency of any disabled features
382
+ # If a main feature that depends on this feature is disabled, prevent enabling this dependency
383
+ dependent_features = find_dependent_features
384
+ disabled_dependents = dependent_features.select do |dep_feature_name|
385
+ dep_feature = Magick.features[dep_feature_name.to_s] || Magick[dep_feature_name]
386
+ # Check if the dependent feature (main feature) is disabled
387
+ dep_feature && !dep_feature.enabled?
388
+ end
389
+
390
+ unless disabled_dependents.empty?
391
+ # Return false if any main feature that depends on this feature is disabled
392
+ # This prevents enabling a dependency when the main feature is disabled
393
+ return false
394
+ end
395
+
357
396
  # Clear all targeting to enable globally
358
397
  @targeting = {}
359
398
  save_targeting
@@ -434,6 +473,7 @@ module Magick
434
473
  if Magick.features.key?(name)
435
474
  registered = Magick.features[name]
436
475
  registered.instance_variable_set(:@stored_value, @stored_value)
476
+ registered.instance_variable_set(:@stored_value_initialized, @stored_value_initialized)
437
477
  registered.instance_variable_set(:@status, @status)
438
478
  registered.instance_variable_set(:@description, @description)
439
479
  registered.instance_variable_set(:@display_name, @display_name)
@@ -466,19 +506,31 @@ module Magick
466
506
  end
467
507
 
468
508
  def load_from_adapter
469
- # Clear cached value to force reload from adapter (which checks version)
470
- @stored_value = nil
471
- @stored_value = load_value_from_adapter
509
+ # Load value from adapter
510
+ loaded_value = load_value_from_adapter
511
+ # Set @stored_value if we got a value from adapter (can be false, true, '', 0, etc.)
512
+ # Only set if loaded_value is not nil (nil means not found in adapter)
513
+ unless loaded_value.nil?
514
+ @stored_value = loaded_value
515
+ @stored_value_initialized = true
516
+ end
517
+
472
518
  status_value = adapter_registry.get(name, 'status')
473
519
  @status = status_value ? status_value.to_sym : status
474
520
 
475
- # Load description from adapter (override initial value if present in adapter)
476
- description_value = adapter_registry.get(name, 'description')
477
- @description = description_value if description_value
521
+ # Load description from adapter only if not provided in DSL
522
+ # DSL (features.rb) is the source of truth, so don't override DSL values
523
+ unless @description
524
+ description_value = adapter_registry.get(name, 'description')
525
+ @description = description_value if description_value
526
+ end
478
527
 
479
- # Load display_name from adapter (override initial value if present in adapter)
480
- display_name_value = adapter_registry.get(name, 'display_name')
481
- @display_name = display_name_value if display_name_value
528
+ # Load display_name from adapter only if not provided in DSL
529
+ # DSL (features.rb) is the source of truth, so don't override DSL values
530
+ unless @display_name
531
+ display_name_value = adapter_registry.get(name, 'display_name')
532
+ @display_name = display_name_value if display_name_value
533
+ end
482
534
 
483
535
  targeting_value = adapter_registry.get(name, 'targeting')
484
536
  if targeting_value.is_a?(Hash)
@@ -493,12 +545,11 @@ module Magick
493
545
  end
494
546
 
495
547
  def save_metadata_if_new
496
- # Save description and display_name to adapter if they were provided in options
497
- # but don't exist in adapter yet (to avoid overwriting existing values)
498
- if @description && !adapter_registry.get(name, 'description')
499
- adapter_registry.set(name, 'description', @description)
500
- end
501
- return unless @display_name && !adapter_registry.get(name, 'display_name')
548
+ # Always save description and display_name from DSL to adapter
549
+ # The features.rb file is the source of truth for metadata
550
+ # This ensures metadata is always up-to-date even if feature already exists
551
+ adapter_registry.set(name, 'description', @description) if @description
552
+ return unless @display_name
502
553
 
503
554
  adapter_registry.set(name, 'display_name', @display_name)
504
555
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Magick
4
- VERSION = '0.8.8'
4
+ VERSION = '0.9.2'
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.8.8
4
+ version: 0.9.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Lobanov