abstract_feature_branch 1.5.1 → 1.6.0
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 +4 -4
- data/CHANGELOG.md +5 -0
- data/README.md +11 -7
- data/VERSION +1 -1
- data/abstract_feature_branch.gemspec +13 -24
- data/lib/abstract_feature_branch/configuration.rb +16 -6
- data/lib/abstract_feature_branch/memoizable.rb +23 -0
- data/lib/abstract_feature_branch.rb +66 -23
- metadata +8 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6bb188fdad68361367ec4bb43a495957ccd7eaa3c89355b5a0d2812055dbef07
|
4
|
+
data.tar.gz: 26b576a9a85f5eadac24f46d39086d5d871036b1c8e6b3cfef5ca7b26202373a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 265ad74dc47a31670c8088b119c3b1966d895e91eb451d3ff5074a594f29e4f682b26ddd87606c8b17d1c783f082fcc78170a290af6935482f2286ce3b487918
|
7
|
+
data.tar.gz: 3b782bfaf2efe15b87707060c22da8995761c8e8267b40a2e02cb43a492ead632a403423d02a7ae7a93ce4999be6af7169e0cb5d7c39ad1f1e537f9d27309584
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
## 1.6.0
|
4
|
+
|
5
|
+
- Support Ruby 3.3 - Ruby 1.9.1
|
6
|
+
- Thread-Safe Support for Multi-Threaded Usage of `feature_enabled?` and `feature_branch` (fixes issue with multi-threaded usage of `feature_enabled?` causing a `merge` method invocation error due to a `features[environment]` `nil` value that should have been a `Hash` value instead)
|
7
|
+
|
3
8
|
## 1.5.1
|
4
9
|
|
5
10
|
- `AbstractFeatureBranch.toggled_features_for_scope(scope)` API method that returns toggled features for a scope (String)
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Abstract Feature Branch 1.
|
1
|
+
# Abstract Feature Branch 1.6.0
|
2
2
|
[](http://badge.fury.io/rb/abstract_feature_branch)
|
3
3
|
[](https://travis-ci.org/AndyObtiva/abstract_feature_branch)
|
4
4
|
[](https://coveralls.io/r/AndyObtiva/abstract_feature_branch?branch=master)
|
@@ -25,7 +25,7 @@ context-specific feature files if needed.
|
|
25
25
|
|
26
26
|
Requirements
|
27
27
|
------------
|
28
|
-
- Ruby (between `~> 3.
|
28
|
+
- Ruby (between `~> 3.3.0` and `~> 1.9.1`)
|
29
29
|
- [Optional] Rails (between `~> 7.0` and `~> 2.0`)
|
30
30
|
- [Optional] Redis Server (between `~> 7.0` and `~> 2.0`)
|
31
31
|
- [Optional] Redis client gem (between `~> 5.0` and `~> 3.0`)
|
@@ -36,8 +36,8 @@ Setup
|
|
36
36
|
### Rails Application Use
|
37
37
|
|
38
38
|
1. Configure Rubygem
|
39
|
-
- With `rails` between `~> 7.0` and `~> 2.0`: Add the following to Gemfile <pre>gem 'abstract_feature_branch', '~> 1.
|
40
|
-
- With `rails` `~> 2.0` only: Add the following to config/environment.rb <pre>config.gem 'abstract_feature_branch', :version => '1.
|
39
|
+
- With `rails` between `~> 7.0` and `~> 2.0`: Add the following to Gemfile <pre>gem 'abstract_feature_branch', '~> 1.6.0'</pre>
|
40
|
+
- With `rails` `~> 2.0` only: Add the following to config/environment.rb <pre>config.gem 'abstract_feature_branch', :version => '1.6.0'</pre>
|
41
41
|
2. Generate <code>config/initializers/abstract_feature_branch.rb</code>, <code>lib/tasks/abstract_feature_branch.rake</code>, <code>config/features.yml</code> and <code>config/features.local.yml</code> in your Rails app directory by running <pre>rails g abstract_feature_branch:install</pre>
|
42
42
|
3. [Optional] Generate <code>config/features/[context_path].yml</code> in your Rails app directory by running <pre>rails g abstract_feature_branch:context context_path</pre> (more details under [**instructions**](#instructions))
|
43
43
|
4. [Optional] Customize configuration in <code>config/initializers/abstract_feature_branch.rb</code> (can be useful for changing location of feature files in Rails application, configuring Redis with a Redis or ConnectionPool instance to use for overrides, and [scoped feature enablement](#scoped-feature-enablement) (e.g. per-user), or troubleshooting a specific Rails environment feature configuration)
|
@@ -46,7 +46,7 @@ Setup
|
|
46
46
|
|
47
47
|
### Ruby Application General Use
|
48
48
|
|
49
|
-
1. <pre>gem install abstract_feature_branch -v 1.
|
49
|
+
1. <pre>gem install abstract_feature_branch -v 1.6.0</pre>
|
50
50
|
2. Add code <code>require 'abstract_feature_branch'</code>
|
51
51
|
3. Create <code>config/features.yml</code> under <code>AbstractFeatureBranch.application_root</code> and fill it with content similar to that of the sample <code>config/features.yml</code> mentioned under [**instructions**](#instructions).
|
52
52
|
4. [Optional] Create <code>config/features.local.yml</code> under <code>AbstractFeatureBranch.application_root</code> (more details under [**instructions**](#instructions))
|
@@ -112,7 +112,9 @@ multi-line logic:
|
|
112
112
|
single-line logic:
|
113
113
|
> feature_branch(:feature1) { # perform logic }
|
114
114
|
|
115
|
-
Note that <code>feature_branch</code> returns nil and does not execute the block if the feature is disabled or non-existent.
|
115
|
+
Note that <code>feature_branch</code> returns `nil` and does not execute the block if the feature is disabled or non-existent.
|
116
|
+
|
117
|
+
`feature_branch` supports multi-threaded code (i.e. usage from multiple parallel threads, as possible in JRuby).
|
116
118
|
|
117
119
|
- Imperatively check if a feature is enabled or not:
|
118
120
|
|
@@ -122,7 +124,9 @@ Note that <code>feature_branch</code> returns nil and does not execute the block
|
|
122
124
|
> # perform alternate logic
|
123
125
|
> end
|
124
126
|
|
125
|
-
Note that <code>feature_enabled?</code> returns false if the feature is disabled and nil if the feature is non-existent (practically the same effect, but nil can sometimes be useful to detect if a feature is referenced).
|
127
|
+
Note that <code>feature_enabled?</code> returns `false` if the feature is disabled and `nil` if the feature is non-existent (practically the same effect, but nil can sometimes be useful to detect if a feature is referenced).
|
128
|
+
|
129
|
+
`feature_enabled?` supports multi-threaded code (i.e. usage from multiple parallel threads, as possible in JRuby).
|
126
130
|
|
127
131
|
- List all configured features for a particular environment:
|
128
132
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.6.0
|
@@ -2,16 +2,16 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: abstract_feature_branch 1.
|
5
|
+
# stub: abstract_feature_branch 1.6.0 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "abstract_feature_branch".freeze
|
9
|
-
s.version = "1.
|
9
|
+
s.version = "1.6.0".freeze
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
12
12
|
s.require_paths = ["lib".freeze]
|
13
13
|
s.authors = ["Andy Maleh".freeze]
|
14
|
-
s.date = "
|
14
|
+
s.date = "2024-01-22"
|
15
15
|
s.description = "abstract_feature_branch is a Ruby gem that provides a unique variation on the Branch by Abstraction Pattern by Paul Hammant and the Feature Toggles Pattern by Martin Fowler to enhance team productivity and improve software fault tolerance.\n\nIt provides the ability to wrap blocks of code with an abstract feature branch name, and then specify in a configuration file which features to be switched on or off.\n\nThe goal is to build out upcoming features in the same source code repository branch (i.e. Continuous Integration and Trunk-Based Development), regardless of whether all are completed by the next release date or not, thus increasing team productivity by preventing integration delays. Developers then disable in-progress features until they are ready to be switched on in production, yet enable them locally and in staging environments for in-progress testing.\n\nThis gives developers the added benefit of being able to switch a feature off after release should big problems arise for a high risk feature.\n\nabstract_feature_branch additionally supports Domain Driven Design's pattern of Bounded Contexts by allowing developers to configure context-specific feature files if needed.\n\nabstract_feature_branch is one of the simplest and most minimalistic \"Feature Flags\" Ruby gems out there as it enables you to get started very quickly by simply leveraging YAML files without having to set up a data store if you do not need it (albeit, you also have the option to use Redis as a very fast in-memory data store).\n".freeze
|
16
16
|
s.extra_rdoc_files = [
|
17
17
|
"CHANGELOG.md",
|
@@ -27,6 +27,7 @@ Gem::Specification.new do |s|
|
|
27
27
|
"lib/abstract_feature_branch.rb",
|
28
28
|
"lib/abstract_feature_branch/configuration.rb",
|
29
29
|
"lib/abstract_feature_branch/file_beautifier.rb",
|
30
|
+
"lib/abstract_feature_branch/memoizable.rb",
|
30
31
|
"lib/abstract_feature_branch/redis/connection_pool_to_redis_adapter.rb",
|
31
32
|
"lib/ext/feature_branch.rb",
|
32
33
|
"lib/generators/abstract_feature_branch/context_generator.rb",
|
@@ -40,29 +41,17 @@ Gem::Specification.new do |s|
|
|
40
41
|
s.homepage = "http://github.com/AndyObtiva/abstract_feature_branch".freeze
|
41
42
|
s.licenses = ["MIT".freeze]
|
42
43
|
s.post_install_message = "\nRails-only post-install instructions:\n\n1) Run the following command to generate the Rails initializer and basic feature files:\n\nrails g abstract_feature_branch:install\n\n2) Optionally, you may run this command to generate feature files per context:\n\nrails g abstract_feature_branch:context context_path\n \n3) Optionally, install Redis server with [Homebrew](https://brew.sh/) by running:\n\nbrew install redis\n\n4) Optionally, install redis client gem (required with Redis server) by adding the following line to Gemfile above abstract_feature_branch:\n\ngem 'redis', '~> 5.0.5'\n\nAfterwards, run:\n\nbundle\n\n5) Optionally, customize configuration in config/initializers/abstract_feature_branch.rb\n\n(can be useful for changing location of feature files in Rails application,\nconfiguring Redis with a Redis or ConnectionPool instance to use for overrides and scoped feature enablement (e.g. per-user),\nand/or troubleshooting specific Rails environment feature configurations)\n\n".freeze
|
43
|
-
s.rubygems_version = "3.3
|
44
|
+
s.rubygems_version = "3.5.3".freeze
|
44
45
|
s.summary = "abstract_feature_branch is a Ruby gem that provides a variation on the Branch by Abstraction Pattern by Paul Hammant and the Feature Toggles Pattern by Martin Fowler (aka Feature Flags) to enable Continuous Integration and Trunk-Based Development.".freeze
|
45
46
|
|
46
|
-
|
47
|
-
s.specification_version = 4
|
48
|
-
end
|
47
|
+
s.specification_version = 4
|
49
48
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
s.add_development_dependency(%q<rake-tui>.freeze, ["~> 0.2"])
|
58
|
-
else
|
59
|
-
s.add_dependency(%q<deep_merge>.freeze, [">= 1.0.0", "< 2.0.0"])
|
60
|
-
s.add_dependency(%q<jeweler>.freeze, ["~> 2.3.9"])
|
61
|
-
s.add_dependency(%q<bundler>.freeze, [">= 2.1.4"])
|
62
|
-
s.add_dependency(%q<rspec>.freeze, ["= 2.14.1"])
|
63
|
-
s.add_dependency(%q<rdoc>.freeze, ["= 5.1.0"])
|
64
|
-
s.add_dependency(%q<psych>.freeze, ["= 3.3.4"])
|
65
|
-
s.add_dependency(%q<rake-tui>.freeze, ["~> 0.2"])
|
66
|
-
end
|
49
|
+
s.add_runtime_dependency(%q<deep_merge>.freeze, [">= 1.0.0".freeze, "< 2.0.0".freeze])
|
50
|
+
s.add_development_dependency(%q<jeweler>.freeze, ["~> 2.3.9".freeze])
|
51
|
+
s.add_development_dependency(%q<bundler>.freeze, [">= 2.1.4".freeze])
|
52
|
+
s.add_development_dependency(%q<rspec>.freeze, ["~> 3.12.0".freeze])
|
53
|
+
s.add_development_dependency(%q<rdoc>.freeze, ["= 5.1.0".freeze])
|
54
|
+
s.add_development_dependency(%q<psych>.freeze, ["= 3.3.4".freeze])
|
55
|
+
s.add_development_dependency(%q<rake-tui>.freeze, ["~> 0.2".freeze])
|
67
56
|
end
|
68
57
|
|
@@ -1,9 +1,20 @@
|
|
1
|
+
require 'abstract_feature_branch/memoizable'
|
1
2
|
require 'abstract_feature_branch/redis/connection_pool_to_redis_adapter'
|
2
3
|
|
3
4
|
module AbstractFeatureBranch
|
4
5
|
class Configuration
|
6
|
+
include Memoizable
|
7
|
+
|
8
|
+
MUTEX = {
|
9
|
+
'@application_root': Mutex.new,
|
10
|
+
'@application_environment': Mutex.new,
|
11
|
+
'@logger': Mutex.new,
|
12
|
+
'@cacheable': Mutex.new,
|
13
|
+
'@feature_store_live_fetching': Mutex.new,
|
14
|
+
}
|
15
|
+
|
5
16
|
def application_root
|
6
|
-
|
17
|
+
memoize_thread_safe(:@application_root, :initialize_application_root)
|
7
18
|
end
|
8
19
|
def application_root=(path)
|
9
20
|
@application_root = path
|
@@ -12,7 +23,7 @@ module AbstractFeatureBranch
|
|
12
23
|
self.application_root = defined?(Rails) ? Rails.root : '.'
|
13
24
|
end
|
14
25
|
def application_environment
|
15
|
-
|
26
|
+
memoize_thread_safe(:@application_environment, :initialize_application_environment)
|
16
27
|
end
|
17
28
|
def application_environment=(environment)
|
18
29
|
@application_environment = environment
|
@@ -21,7 +32,7 @@ module AbstractFeatureBranch
|
|
21
32
|
self.application_environment = defined?(Rails) ? Rails.env.to_s : ENV['APP_ENV'] || 'development'
|
22
33
|
end
|
23
34
|
def logger
|
24
|
-
|
35
|
+
memoize_thread_safe(:@logger, :initialize_logger)
|
25
36
|
end
|
26
37
|
def logger=(logger)
|
27
38
|
@logger = logger
|
@@ -30,7 +41,7 @@ module AbstractFeatureBranch
|
|
30
41
|
self.logger = defined?(Rails) && Rails.logger ? Rails.logger : Logger.new(STDOUT)
|
31
42
|
end
|
32
43
|
def cacheable
|
33
|
-
|
44
|
+
memoize_thread_safe(:@cacheable, :initialize_cacheable)
|
34
45
|
end
|
35
46
|
def cacheable=(cacheable)
|
36
47
|
@cacheable = cacheable
|
@@ -64,8 +75,7 @@ module AbstractFeatureBranch
|
|
64
75
|
alias user_features_storage= feature_store=
|
65
76
|
|
66
77
|
def feature_store_live_fetching
|
67
|
-
initialize_feature_store_live_fetching
|
68
|
-
@feature_store_live_fetching
|
78
|
+
memoize_thread_safe(:@feature_store_live_fetching, :initialize_feature_store_live_fetching)
|
69
79
|
end
|
70
80
|
alias feature_store_live_fetching? feature_store_live_fetching
|
71
81
|
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module AbstractFeatureBranch
|
2
|
+
module Memoizable
|
3
|
+
private
|
4
|
+
|
5
|
+
# memoizes a variable thread-safe
|
6
|
+
# expects a MUTEX constant on the class including this moddule, which pre-initializes
|
7
|
+
# mutexes at class definition time
|
8
|
+
# Example:
|
9
|
+
# MUTEX = { '@varname' => Mutex.new }
|
10
|
+
def memoize_thread_safe(variable, variable_build_method_name = nil, &variable_builder)
|
11
|
+
variable_builder ||= method(variable_build_method_name)
|
12
|
+
if instance_variable_get(variable).nil?
|
13
|
+
mutex_hash = self.is_a?(Module) ? self::MUTEX : self.class::MUTEX
|
14
|
+
mutex_hash[variable].synchronize do
|
15
|
+
if instance_variable_get(variable).nil?
|
16
|
+
instance_variable_set(variable, variable_builder.call)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
instance_variable_get(variable)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -15,13 +15,28 @@ require 'forwardable'
|
|
15
15
|
|
16
16
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
17
17
|
|
18
|
+
require 'abstract_feature_branch/memoizable'
|
18
19
|
require 'abstract_feature_branch/configuration'
|
19
20
|
|
20
21
|
module AbstractFeatureBranch
|
22
|
+
extend Memoizable
|
23
|
+
|
21
24
|
ENV_FEATURE_PREFIX = "abstract_feature_branch_"
|
22
25
|
REDIS_HKEY = "abstract_feature_branch"
|
23
26
|
VALUE_SCOPED = 'scoped'
|
24
27
|
SCOPED_SPECIAL_VALUES = [VALUE_SCOPED, 'per_user', 'per-user', 'per user']
|
28
|
+
MUTEX = {
|
29
|
+
'@configuration': Mutex.new,
|
30
|
+
'@redis_overrides': Mutex.new,
|
31
|
+
'@environment_variable_overrides': Mutex.new,
|
32
|
+
'@local_features': Mutex.new,
|
33
|
+
'@features': Mutex.new,
|
34
|
+
'@environment_features': Mutex.new,
|
35
|
+
'@redis_scoped_features': Mutex.new,
|
36
|
+
'environment_features': Mutex.new,
|
37
|
+
'load_application_features': Mutex.new,
|
38
|
+
'unload_application_features': Mutex.new,
|
39
|
+
}
|
25
40
|
|
26
41
|
class << self
|
27
42
|
extend Forwardable
|
@@ -31,11 +46,11 @@ module AbstractFeatureBranch
|
|
31
46
|
:feature_store_live_fetching, :feature_store_live_fetching=
|
32
47
|
|
33
48
|
def configuration
|
34
|
-
|
49
|
+
memoize_thread_safe(:@configuration) { Configuration.new }
|
35
50
|
end
|
36
51
|
|
37
52
|
def redis_overrides
|
38
|
-
|
53
|
+
memoize_thread_safe(:@redis_overrides, :load_redis_overrides)
|
39
54
|
end
|
40
55
|
def load_redis_overrides
|
41
56
|
return (@redis_overrides = {}) if feature_store.nil?
|
@@ -51,14 +66,14 @@ module AbstractFeatureBranch
|
|
51
66
|
end
|
52
67
|
|
53
68
|
def environment_variable_overrides
|
54
|
-
|
69
|
+
memoize_thread_safe(:@environment_variable_overrides, :load_environment_variable_overrides)
|
55
70
|
end
|
56
71
|
def load_environment_variable_overrides
|
57
72
|
@environment_variable_overrides = featureize_keys(downcase_keys(booleanize_values(select_feature_keys(ENV))))
|
58
73
|
end
|
59
74
|
|
60
75
|
def local_features
|
61
|
-
|
76
|
+
memoize_thread_safe(:@local_features, :load_local_features)
|
62
77
|
end
|
63
78
|
def load_local_features
|
64
79
|
@local_features = {}
|
@@ -66,7 +81,7 @@ module AbstractFeatureBranch
|
|
66
81
|
end
|
67
82
|
|
68
83
|
def features
|
69
|
-
|
84
|
+
memoize_thread_safe(:@features, :load_features)
|
70
85
|
end
|
71
86
|
def load_features
|
72
87
|
@features = {}
|
@@ -75,8 +90,15 @@ module AbstractFeatureBranch
|
|
75
90
|
|
76
91
|
# performance optimization via caching of feature values resolved through environment variable overrides and local features
|
77
92
|
def environment_features(environment)
|
78
|
-
|
79
|
-
|
93
|
+
if environment_features_for_all_environments[environment].nil?
|
94
|
+
MUTEX[:environment_features].synchronize do
|
95
|
+
if environment_features_for_all_environments[environment].nil?
|
96
|
+
environment_features_for_all_environments[environment] = load_environment_features(environment)
|
97
|
+
end
|
98
|
+
@unload_application_features = nil
|
99
|
+
end
|
100
|
+
end
|
101
|
+
environment_features_for_all_environments[environment]
|
80
102
|
end
|
81
103
|
def load_environment_features(environment)
|
82
104
|
@environment_features ||= {}
|
@@ -88,8 +110,12 @@ module AbstractFeatureBranch
|
|
88
110
|
merge(redis_overrides)
|
89
111
|
end
|
90
112
|
|
113
|
+
def environment_features_for_all_environments
|
114
|
+
memoize_thread_safe(:@environment_features) { {} }
|
115
|
+
end
|
116
|
+
|
91
117
|
def redis_scoped_features
|
92
|
-
|
118
|
+
memoize_thread_safe(:@redis_scoped_features, :load_redis_scoped_features)
|
93
119
|
end
|
94
120
|
def load_redis_scoped_features
|
95
121
|
@redis_scoped_features = {}
|
@@ -114,27 +140,44 @@ module AbstractFeatureBranch
|
|
114
140
|
end
|
115
141
|
|
116
142
|
def application_features
|
117
|
-
unload_application_features
|
143
|
+
unload_application_features if !cacheable?
|
118
144
|
environment_features(application_environment)
|
119
145
|
end
|
120
146
|
def load_application_features
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
147
|
+
if @load_application_features.nil?
|
148
|
+
MUTEX[:load_application_features].synchronize do
|
149
|
+
if @load_application_features.nil?
|
150
|
+
AbstractFeatureBranch.load_redis_overrides
|
151
|
+
AbstractFeatureBranch.load_environment_variable_overrides
|
152
|
+
AbstractFeatureBranch.load_features
|
153
|
+
AbstractFeatureBranch.load_local_features
|
154
|
+
AbstractFeatureBranch.load_environment_features(application_environment)
|
155
|
+
AbstractFeatureBranch.load_redis_scoped_features
|
156
|
+
@unload_application_features = nil
|
157
|
+
@load_application_features = true
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
127
161
|
end
|
128
162
|
def unload_application_features
|
129
|
-
@
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
163
|
+
if @unload_application_features.nil?
|
164
|
+
MUTEX[:unload_application_features].synchronize do
|
165
|
+
if @unload_application_features.nil?
|
166
|
+
@redis_overrides = nil
|
167
|
+
@environment_variable_overrides = nil
|
168
|
+
@features = nil
|
169
|
+
@local_features = nil
|
170
|
+
@environment_features = nil
|
171
|
+
@redis_scoped_features = nil
|
172
|
+
@load_application_features = nil
|
173
|
+
@unload_application_features = true
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
135
177
|
end
|
136
178
|
|
137
179
|
def cacheable?
|
180
|
+
# TODO Make thread-safe
|
138
181
|
value = downcase_keys(cacheable)[application_environment]
|
139
182
|
value = (application_environment != 'development') if value.nil?
|
140
183
|
value
|
@@ -218,13 +261,13 @@ module AbstractFeatureBranch
|
|
218
261
|
end
|
219
262
|
|
220
263
|
private
|
221
|
-
|
264
|
+
|
222
265
|
def load_specific_features(features_hash, extension)
|
223
266
|
Dir.glob(File.join(application_root, 'config', 'features', '**', "*#{extension}")).each do |feature_configuration_file|
|
224
267
|
features_hash.deep_merge!(downcase_feature_hash_keys(YAML.load_file(feature_configuration_file)))
|
225
268
|
end
|
226
269
|
main_local_features_file = File.join(application_root, 'config', "features#{extension}")
|
227
|
-
features_hash.deep_merge!(downcase_feature_hash_keys(YAML.load_file(main_local_features_file))) if File.
|
270
|
+
features_hash.deep_merge!(downcase_feature_hash_keys(YAML.load_file(main_local_features_file))) if File.exist?(main_local_features_file)
|
228
271
|
features_hash
|
229
272
|
end
|
230
273
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: abstract_feature_branch
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andy Maleh
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-01-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: deep_merge
|
@@ -62,16 +62,16 @@ dependencies:
|
|
62
62
|
name: rspec
|
63
63
|
requirement: !ruby/object:Gem::Requirement
|
64
64
|
requirements:
|
65
|
-
- -
|
65
|
+
- - "~>"
|
66
66
|
- !ruby/object:Gem::Version
|
67
|
-
version:
|
67
|
+
version: 3.12.0
|
68
68
|
type: :development
|
69
69
|
prerelease: false
|
70
70
|
version_requirements: !ruby/object:Gem::Requirement
|
71
71
|
requirements:
|
72
|
-
- -
|
72
|
+
- - "~>"
|
73
73
|
- !ruby/object:Gem::Version
|
74
|
-
version:
|
74
|
+
version: 3.12.0
|
75
75
|
- !ruby/object:Gem::Dependency
|
76
76
|
name: rdoc
|
77
77
|
requirement: !ruby/object:Gem::Requirement
|
@@ -142,6 +142,7 @@ files:
|
|
142
142
|
- lib/abstract_feature_branch.rb
|
143
143
|
- lib/abstract_feature_branch/configuration.rb
|
144
144
|
- lib/abstract_feature_branch/file_beautifier.rb
|
145
|
+
- lib/abstract_feature_branch/memoizable.rb
|
145
146
|
- lib/abstract_feature_branch/redis/connection_pool_to_redis_adapter.rb
|
146
147
|
- lib/ext/feature_branch.rb
|
147
148
|
- lib/generators/abstract_feature_branch/context_generator.rb
|
@@ -181,7 +182,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
181
182
|
- !ruby/object:Gem::Version
|
182
183
|
version: '0'
|
183
184
|
requirements: []
|
184
|
-
rubygems_version: 3.3
|
185
|
+
rubygems_version: 3.5.3
|
185
186
|
signing_key:
|
186
187
|
specification_version: 4
|
187
188
|
summary: abstract_feature_branch is a Ruby gem that provides a variation on the Branch
|