abstract_feature_branch 1.3.0 → 1.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +10 -0
  3. data/README.md +20 -8
  4. data/VERSION +1 -1
  5. data/abstract_feature_branch.gemspec +7 -41
  6. data/lib/abstract_feature_branch/configuration.rb +26 -10
  7. data/lib/abstract_feature_branch/redis/connection_pool_to_redis_adapter.rb +34 -0
  8. data/lib/abstract_feature_branch.rb +12 -5
  9. data/lib/ext/feature_branch.rb +1 -1
  10. data/lib/generators/templates/config/initializers/abstract_feature_branch.rb +8 -1
  11. metadata +6 -40
  12. data/.coveralls.yml +0 -1
  13. data/.travis.yml +0 -30
  14. data/RELEASE_NOTES.md +0 -55
  15. data/TODO.md +0 -3
  16. data/config/features/admin.local.yml +0 -15
  17. data/config/features/admin.yml +0 -17
  18. data/config/features/internal/wiki.local.yml +0 -15
  19. data/config/features/internal/wiki.yml +0 -17
  20. data/config/features/public.local.yml +0 -15
  21. data/config/features/public.yml +0 -17
  22. data/img/BigAstronaut-Logo.png +0 -0
  23. data/img/EarlyShares-Logo.svg +0 -22
  24. data/img/Factor75-Logo.svg +0 -54
  25. data/ruby187.Gemfile +0 -13
  26. data/spec/abstract_feature_branch/file_beautifier_spec.rb +0 -384
  27. data/spec/ext/feature_branch__feature_branch_per_user_spec.rb +0 -122
  28. data/spec/ext/feature_branch__feature_branch_spec.rb +0 -148
  29. data/spec/ext/feature_branch__feature_enabled_spec.rb +0 -274
  30. data/spec/fixtures/application_development_config/config/features.reference.yml +0 -21
  31. data/spec/fixtures/application_no_config/no_config +0 -1
  32. data/spec/fixtures/application_rails_config/config/features.local.yml +0 -16
  33. data/spec/fixtures/application_rails_config/config/features.yml +0 -20
  34. data/spec/fixtures/application_ugly_config_reference/config/another_application_configuration.yml +0 -31
  35. data/spec/fixtures/application_ugly_config_reference/config/database.yml +0 -17
  36. data/spec/fixtures/application_ugly_config_reference/config/features/admin.local.yml +0 -44
  37. data/spec/fixtures/application_ugly_config_reference/config/features/admin.yml +0 -44
  38. data/spec/fixtures/application_ugly_config_reference/config/features/empty.local.yml +0 -0
  39. data/spec/fixtures/application_ugly_config_reference/config/features/feature_empty_config.local.yml +0 -13
  40. data/spec/fixtures/application_ugly_config_reference/config/features/including_comments.local.yml +0 -52
  41. data/spec/fixtures/application_ugly_config_reference/config/features/internal/wiki.local.yml +0 -44
  42. data/spec/fixtures/application_ugly_config_reference/config/features/internal/wiki.yml +0 -44
  43. data/spec/fixtures/application_ugly_config_reference/config/features/public.local.yml +0 -44
  44. data/spec/fixtures/application_ugly_config_reference/config/features/public.yml +0 -44
  45. data/spec/fixtures/application_ugly_config_reference/config/features.local.yml +0 -44
  46. data/spec/fixtures/application_ugly_config_reference/config/features.yml +0 -49
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8f0025726fa5c4de15b39b5b51ba6e180cf156ccccf86d661e3f9e4982d899a4
4
- data.tar.gz: 78dae9664bcce67b70f2768ff9e866d9b47155ec1c8ef7c9d0f7d341f4866249
3
+ metadata.gz: 47e99ade543da399fb1529db07bbecd871e23a1eb7cff9239a578067453dc312
4
+ data.tar.gz: b54ab8066e04ee68d6d40940a84dd69f237354d40523e5003be4f34ef6d4e03b
5
5
  SHA512:
6
- metadata.gz: 96649ca6005883f9765ac18d115e08eb1ac8c9aa165cba039b07aa3d843b29bc8f70cf8ec768bdb6e491e2982eb04f9f0959210418feeccd5da242df6c57bdd9
7
- data.tar.gz: 0d305129dc28c997d740e1a6f0dbe2dfefddd1a379dfc64c4fc42287c3fbaf965dde0358287a91346af7aef201a6b1480be5d02f66dcff91464d64cf7f9e850e
6
+ metadata.gz: a2d9b1f7a36c405bbb7406bd22b4ec29f0f9d4d55a1ecf7d83ee8adb6f77cba28159f20a32be8b1fa36f97422ccdf74a7f93c6c06d8cb617b0f5405d0d833052
7
+ data.tar.gz: d851c77683233aa129261171769b8e693949bf178af7c958995daf8f237fed1d7364db8b805e635e5346acdb26c3944af24aab15aab8c5c1f686efa29aba5bcc
data/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Change Log
2
2
 
3
+ ## 1.3.2
4
+
5
+ - Ensure better performance, fetch Redis Overrides at app/server startup time only by default while providing option to fetch live by setting `AbstractFeatureBranch.feature_store_live_fetching` to `true`
6
+ - Do not automatically pre-init `AbstractFeatureBranch.feature_store` with `Redis.new` if it was `nil` as that is a bad default.
7
+ - Fix issue with crashing when not including the `connection_pool` gem manually if needed with a version of `redis` older than 5
8
+
9
+ ## 1.3.1
10
+
11
+ - Support Redis `ConnectionPool` `AbstractFeatureBranch::Configuration#feature_store`
12
+
3
13
  ## 1.3.0
4
14
 
5
15
  - Officially support newer `redis` client gem version 5
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Abstract Feature Branch 1.3.0
1
+ # Abstract Feature Branch 1.3.2
2
2
  [![Gem Version](https://badge.fury.io/rb/abstract_feature_branch.png)](http://badge.fury.io/rb/abstract_feature_branch)
3
3
  [![Build Status](https://api.travis-ci.org/AndyObtiva/abstract_feature_branch.png?branch=master)](https://travis-ci.org/AndyObtiva/abstract_feature_branch)
4
4
  [![Coverage Status](https://coveralls.io/repos/AndyObtiva/abstract_feature_branch/badge.png?branch=master)](https://coveralls.io/r/AndyObtiva/abstract_feature_branch?branch=master)
@@ -37,17 +37,17 @@ Setup
37
37
  ### Rails Application Use
38
38
 
39
39
  1. Configure Rubygem
40
- - With `rails` between `~> 7.0` and `~> 2.0`: Add the following to Gemfile <pre>gem 'abstract_feature_branch', '~> 1.3.0'</pre>
41
- - With `rails` `~> 2.0` only: Add the following to config/environment.rb <pre>config.gem 'abstract_feature_branch', :version => '1.3.0'</pre>
40
+ - With `rails` between `~> 7.0` and `~> 2.0`: Add the following to Gemfile <pre>gem 'abstract_feature_branch', '~> 1.3.2'</pre>
41
+ - With `rails` `~> 2.0` only: Add the following to config/environment.rb <pre>config.gem 'abstract_feature_branch', :version => '1.3.2'</pre>
42
42
  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>
43
43
  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))
44
- 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 for per-user feature enablement, or troubleshooting a specific Rails environment feature configuration)
44
+ 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 per-user feature enablement, or troubleshooting a specific Rails environment feature configuration)
45
45
  5. [Optional] Redis Server (between `~> 7.0` and `~> 3.0`): Install view [Homebrew](https://brew.sh/) with `brew install redis`
46
46
  6. [Optional] `redis` client gem (between `~> 5.0` and `~> 3.0`): Add the following to Gemfile above `abstract_feature_branch` <pre>gem 'redis', '~> 5.0.5'</pre>
47
47
 
48
48
  ### Ruby Application General Use
49
49
 
50
- 1. <pre>gem install abstract_feature_branch -v 1.3.0</pre>
50
+ 1. <pre>gem install abstract_feature_branch -v 1.3.2</pre>
51
51
  2. Add code <code>require 'abstract_feature_branch'</code>
52
52
  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).
53
53
  4. [Optional] Create <code>config/features.local.yml</code> under <code>AbstractFeatureBranch.application_root</code> (more details under [**instructions**](#instructions))
@@ -57,7 +57,8 @@ Setup
57
57
  8. [Optional] Add code <code>AbstractFeatureBranch.logger = "[your_application_logger]"</code> (it defaults to a new instance of Ruby <code>Logger</code>. Must use a logger with <code>info</code> and <code>warn</code> methods).
58
58
  9. [Optional] Add code <code>AbstractFeatureBranch.cacheable = {[environment] => [true/false]}</code> to indicate cacheability of loaded feature files for enhanced performance (it defaults to true for every environment other than development).
59
59
  10. [Optional] Add code <code>AbstractFeatureBranch.load_application_features</code> to pre-load application features for improved first-use performance
60
- 11. [Optional] Add code <code>AbstractFeatureBranch.feature_store = Redis.new(options)</code> to configure Redis for overrides or per-user feature enablement
60
+ 11. [Optional] Add code <code>AbstractFeatureBranch.feature_store = Redis.new(options)</code> to configure Redis for overrides and/or per-user feature enablement
61
+ 12. [Optional] Set <code>AbstractFeatureBranch.feature_store_live_fetching = true</code> to enable live fetching of features from store (e.g. Redis) to avoid need for app/server restart upon feature changes, with the trade-off of slightly more latency due to making calls to feature store over the network
61
62
 
62
63
  Instructions
63
64
  ------------
@@ -262,12 +263,16 @@ application more easily.
262
263
  Redis Overrides
263
264
  ---------------
264
265
 
265
- Prerequisites: Redis server and client (`redis` gem) and optional Redis configuration of `AbstractFeatureBranch.feature_store` in `config/initializers/abstract_feature_branch.rb`
266
+ Prerequisites: Redis server and client (`redis` gem) and Redis configuration of `AbstractFeatureBranch.feature_store` in `config/initializers/abstract_feature_branch.rb` (`Redis` `ConnectionPool` instance is recommended for Production environments)
266
267
 
267
268
  To be able to override feature configuration in a production environment, you can utilize Redis Overrides.
268
269
 
269
270
  Alternatively, you may use Redis Overrides as your main source of feature configuration if you prefer that instead of relying on YAML files.
270
271
 
272
+ Keep in mind that by default, Redis Overrides are fetched on app/server start to pre-cache for better performance.
273
+
274
+ To enable live fetching of Redis Overrides, set `AbstractFeatureBranch#feature_store_live_fetching` to `true` (e.g. in `config/initializers/abstract_feature_branch.rb`), but keep in mind the trade-off with more latency due to making calls to Redis Server over the network.
275
+
271
276
  You can override feature configuration with Redis hash values by calling `AbstractFeatureBranch#set_store_feature` in `rails console` (or `irb` after requiring `redis` and `abstract_feature_branch`):
272
277
 
273
278
  ```ruby
@@ -349,12 +354,19 @@ Rails Initializer
349
354
 
350
355
  Here is the content of the generated initializer [with `redis` client gem added] (<code>config/initializers/abstract_feature_branch.rb</code>), which contains instructions on how to customize via [dependency injection](http://en.wikipedia.org/wiki/Dependency_injection):
351
356
 
352
- > # Storage system for features (other than YAML/Env-Vars). Right now, only Redis is supported.
357
+ > # Storage system for features (other than YAML/Env-Vars). Right now, only Redis and ConnectionPool are supported.
353
358
  > # AbstractFeatureBranch.feature_store = Redis.new
354
359
  >
360
+ > # Storage can be a Redis ConnectionPool instance
361
+ > # AbstractFeatureBranch.feature_store = ConnectionPool.new { Redis.new }
362
+ >
355
363
  > # The following example line works with Heroku Redis To Go while still operating on local Redis for local development
356
364
  > # AbstractFeatureBranch.feature_store = Redis.new(:url => ENV['REDISTOGO_URL'])
357
365
  >
366
+ > # Enable live fetching of feature configuration from storage system, to update features without app/server restart.
367
+ > # false by default to only load features on app/server start for faster performance (requires restart on change)
368
+ > AbstractFeatureBranch.feature_store_live_fetching = false
369
+ >
358
370
  > # Application root where config/features.yml or config/features/ is found
359
371
  > AbstractFeatureBranch.application_root = Rails.root
360
372
  >
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.3.0
1
+ 1.3.2
@@ -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.3.0 ruby lib
5
+ # stub: abstract_feature_branch 1.3.2 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "abstract_feature_branch".freeze
9
- s.version = "1.3.0"
9
+ s.version = "1.3.2"
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 = ["Annas \"Andy\" Maleh".freeze]
14
- s.date = "2022-12-11"
14
+ s.date = "2022-12-12"
15
15
  s.description = "abstract_feature_branch is a Rails gem that enables developers to easily branch by abstraction as per this pattern:\nhttp://paulhammant.com/blog/branch_by_abstraction.html\n\nIt is a productivity and fault tolerance enhancing team practice.\n\nIt provides the ability to wrap blocks of code with an abstract feature branch name, and then\nspecify 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, regardless of whether all are\ncompleted by the next release date or not, thus increasing team productivity by preventing integration delays.\nDevelopers then disable in-progress features until they are ready to be switched on in production, yet enable them\nlocally 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\nfor a high risk feature.\n\nabstract_feature_branch additionally supports DDD's pattern of\nBounded Contexts by allowing developers to configure\ncontext-specific feature files if needed.\n".freeze
16
16
  s.extra_rdoc_files = [
17
17
  "CHANGELOG.md",
@@ -19,27 +19,15 @@ Gem::Specification.new do |s|
19
19
  "README.md"
20
20
  ]
21
21
  s.files = [
22
- ".coveralls.yml",
23
- ".travis.yml",
24
22
  "CHANGELOG.md",
25
23
  "LICENSE.txt",
26
24
  "README.md",
27
- "RELEASE_NOTES.md",
28
- "TODO.md",
29
25
  "VERSION",
30
26
  "abstract_feature_branch.gemspec",
31
- "config/features/admin.local.yml",
32
- "config/features/admin.yml",
33
- "config/features/internal/wiki.local.yml",
34
- "config/features/internal/wiki.yml",
35
- "config/features/public.local.yml",
36
- "config/features/public.yml",
37
- "img/BigAstronaut-Logo.png",
38
- "img/EarlyShares-Logo.svg",
39
- "img/Factor75-Logo.svg",
40
27
  "lib/abstract_feature_branch.rb",
41
28
  "lib/abstract_feature_branch/configuration.rb",
42
29
  "lib/abstract_feature_branch/file_beautifier.rb",
30
+ "lib/abstract_feature_branch/redis/connection_pool_to_redis_adapter.rb",
43
31
  "lib/ext/feature_branch.rb",
44
32
  "lib/generators/abstract_feature_branch/context_generator.rb",
45
33
  "lib/generators/abstract_feature_branch/install_generator.rb",
@@ -47,34 +35,12 @@ Gem::Specification.new do |s|
47
35
  "lib/generators/templates/config/features.local.yml",
48
36
  "lib/generators/templates/config/features.yml",
49
37
  "lib/generators/templates/config/initializers/abstract_feature_branch.rb",
50
- "lib/generators/templates/lib/tasks/abstract_feature_branch.rake",
51
- "ruby187.Gemfile",
52
- "spec/abstract_feature_branch/file_beautifier_spec.rb",
53
- "spec/ext/feature_branch__feature_branch_per_user_spec.rb",
54
- "spec/ext/feature_branch__feature_branch_spec.rb",
55
- "spec/ext/feature_branch__feature_enabled_spec.rb",
56
- "spec/fixtures/application_development_config/config/features.reference.yml",
57
- "spec/fixtures/application_no_config/no_config",
58
- "spec/fixtures/application_rails_config/config/features.local.yml",
59
- "spec/fixtures/application_rails_config/config/features.yml",
60
- "spec/fixtures/application_ugly_config_reference/config/another_application_configuration.yml",
61
- "spec/fixtures/application_ugly_config_reference/config/database.yml",
62
- "spec/fixtures/application_ugly_config_reference/config/features.local.yml",
63
- "spec/fixtures/application_ugly_config_reference/config/features.yml",
64
- "spec/fixtures/application_ugly_config_reference/config/features/admin.local.yml",
65
- "spec/fixtures/application_ugly_config_reference/config/features/admin.yml",
66
- "spec/fixtures/application_ugly_config_reference/config/features/empty.local.yml",
67
- "spec/fixtures/application_ugly_config_reference/config/features/feature_empty_config.local.yml",
68
- "spec/fixtures/application_ugly_config_reference/config/features/including_comments.local.yml",
69
- "spec/fixtures/application_ugly_config_reference/config/features/internal/wiki.local.yml",
70
- "spec/fixtures/application_ugly_config_reference/config/features/internal/wiki.yml",
71
- "spec/fixtures/application_ugly_config_reference/config/features/public.local.yml",
72
- "spec/fixtures/application_ugly_config_reference/config/features/public.yml"
38
+ "lib/generators/templates/lib/tasks/abstract_feature_branch.rake"
73
39
  ]
74
40
  s.homepage = "http://github.com/AndyObtiva/abstract_feature_branch".freeze
75
41
  s.licenses = ["MIT".freeze]
76
- 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 to use for overrides and per-user feature enablement,\nand/or troubleshooting specific Rails environment feature configurations)\n\n".freeze
77
- s.rubygems_version = "3.3.6".freeze
42
+ 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 per-user feature enablement,\nand/or troubleshooting specific Rails environment feature configurations)\n\n".freeze
43
+ s.rubygems_version = "3.1.4".freeze
78
44
  s.summary = "abstract_feature_branch is a Rails gem that enables developers to easily branch by abstraction as per this pattern: http://paulhammant.com/blog/branch_by_abstraction.html".freeze
79
45
 
80
46
  if s.respond_to? :specification_version then
@@ -1,3 +1,5 @@
1
+ require 'abstract_feature_branch/redis/connection_pool_to_redis_adapter'
2
+
1
3
  module AbstractFeatureBranch
2
4
  class Configuration
3
5
  def application_root
@@ -43,22 +45,36 @@ module AbstractFeatureBranch
43
45
  end
44
46
 
45
47
  def feature_store
46
- @feature_store ||= initialize_feature_store
48
+ @feature_store
47
49
  end
48
50
  alias user_features_storage feature_store
49
51
 
50
52
  def feature_store=(feature_store)
51
- @feature_store = feature_store
53
+ if feature_store.nil?
54
+ @feature_store = nil
55
+ else
56
+ begin
57
+ @feature_store = feature_store.is_a?(::ConnectionPool) ? AbstractFeatureBranch::Redis::ConnectionPoolToRedisAdapter.new(feature_store) : feature_store
58
+ rescue NameError => e
59
+ logger.debug { "connection_pool gem is not available" }
60
+ @feature_store = feature_store
61
+ end
62
+ end
52
63
  end
53
64
  alias user_features_storage= feature_store=
54
65
 
55
- def initialize_feature_store
56
- self.feature_store = Redis.new
57
- rescue => e
58
- logger.debug { "Redis is not enabled!" }
59
- logger.debug { e.full_message }
60
- nil
61
- end
62
- alias initialize_user_features_storage initialize_feature_store
66
+ def feature_store_live_fetching
67
+ initialize_feature_store_live_fetching if @feature_store_live_fetching.nil?
68
+ @feature_store_live_fetching
69
+ end
70
+ alias feature_store_live_fetching? feature_store_live_fetching
71
+
72
+ def feature_store_live_fetching=(value)
73
+ @feature_store_live_fetching = value
74
+ end
75
+
76
+ def initialize_feature_store_live_fetching
77
+ @feature_store_live_fetching = false
78
+ end
63
79
  end
64
80
  end
@@ -0,0 +1,34 @@
1
+ module AbstractFeatureBranch
2
+ module Redis
3
+ # Adapts a ConnectionPool instance to the Redis object interface
4
+ class ConnectionPoolToRedisAdapter
5
+ attr_reader :connection_pool
6
+
7
+ def initialize(connection_pool)
8
+ @connection_pool = connection_pool
9
+ end
10
+
11
+ def respond_to?(method_name, include_private = false, &block)
12
+ result = false
13
+ @connection_pool.with do |connection|
14
+ result ||= connection.respond_to?(method_name, include_private, &block)
15
+ end
16
+ result || super
17
+ end
18
+
19
+ def method_missing(method_name, *args, &block)
20
+ connection_can_respond_to = nil
21
+ result = nil
22
+ @connection_pool.with do |connection|
23
+ connection_can_respond_to = connection.respond_to?(method_name, true)
24
+ result = connection.send(method_name, *args, &block) if connection_can_respond_to
25
+ end
26
+ if connection_can_respond_to
27
+ result
28
+ else
29
+ super
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -13,7 +13,9 @@ require 'logger' unless defined?(Rails) && Rails.logger
13
13
  require 'deep_merge' unless {}.respond_to?(:deep_merge!)
14
14
  require 'forwardable'
15
15
 
16
- require File.join(File.dirname(__FILE__), 'abstract_feature_branch', 'configuration')
16
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
17
+
18
+ require 'abstract_feature_branch/configuration'
17
19
 
18
20
  module AbstractFeatureBranch
19
21
  ENV_FEATURE_PREFIX = "abstract_feature_branch_"
@@ -21,14 +23,16 @@ module AbstractFeatureBranch
21
23
 
22
24
  class << self
23
25
  extend Forwardable
24
- def_delegators :configuration, :application_root, :application_root=, :initialize_application_root, :application_environment, :application_environment=, :initialize_application_environment, :logger, :logger=, :initialize_logger, :cacheable, :cacheable=, :initialize_cacheable, :feature_store, :feature_store=, :initialize_feature_store, :user_features_storage, :user_features_storage=, :initialize_user_features_storage
26
+ def_delegators :configuration, :application_root, :application_root=, :initialize_application_root, :application_environment, :application_environment=, :initialize_application_environment,
27
+ :logger, :logger=, :initialize_logger, :cacheable, :cacheable=, :initialize_cacheable, :feature_store, :feature_store=, :user_features_storage, :user_features_storage=,
28
+ :feature_store_live_fetching, :feature_store_live_fetching=
25
29
 
26
30
  def configuration
27
31
  @configuration ||= Configuration.new
28
32
  end
29
33
 
30
34
  def redis_overrides
31
- load_redis_overrides
35
+ @redis_overrides ||= load_redis_overrides
32
36
  end
33
37
  def load_redis_overrides
34
38
  return {} if feature_store.nil?
@@ -37,7 +41,7 @@ module AbstractFeatureBranch
37
41
  output.merge(feature => get_store_feature(feature))
38
42
  end
39
43
 
40
- downcase_keys(redis_feature_hash)
44
+ @redis_overrides = downcase_keys(redis_feature_hash)
41
45
  end
42
46
 
43
47
  def environment_variable_overrides
@@ -74,19 +78,22 @@ module AbstractFeatureBranch
74
78
  local_features[environment] ||= {}
75
79
  @environment_features[environment] = features[environment].
76
80
  merge(local_features[environment]).
77
- merge(environment_variable_overrides)
81
+ merge(environment_variable_overrides).
82
+ merge(redis_overrides)
78
83
  end
79
84
  def application_features
80
85
  unload_application_features unless cacheable?
81
86
  environment_features(application_environment)
82
87
  end
83
88
  def load_application_features
89
+ AbstractFeatureBranch.load_redis_overrides
84
90
  AbstractFeatureBranch.load_environment_variable_overrides
85
91
  AbstractFeatureBranch.load_features
86
92
  AbstractFeatureBranch.load_local_features
87
93
  AbstractFeatureBranch.load_environment_features(application_environment)
88
94
  end
89
95
  def unload_application_features
96
+ @redis_overrides = nil
90
97
  @environment_variable_overrides = nil
91
98
  @features = nil
92
99
  @local_features = nil
@@ -10,7 +10,7 @@ class Object
10
10
  def self.feature_enabled?(feature_name, user_id = nil)
11
11
  normalized_feature_name = feature_name.to_s.downcase
12
12
 
13
- redis_override_value = AbstractFeatureBranch.get_store_feature(normalized_feature_name) rescue nil
13
+ redis_override_value = (AbstractFeatureBranch.get_store_feature(normalized_feature_name) rescue nil) if AbstractFeatureBranch.configuration.feature_store_live_fetching?
14
14
  value = !redis_override_value.nil? ? redis_override_value : AbstractFeatureBranch.application_features[normalized_feature_name]
15
15
  if value == 'per_user'
16
16
  value = !user_id.nil? && AbstractFeatureBranch.user_features_storage.sismember("#{AbstractFeatureBranch::ENV_FEATURE_PREFIX}#{normalized_feature_name}", user_id)
@@ -1,9 +1,16 @@
1
- # Storage system for features (other than YAML/Env-Vars). Right now, only Redis is supported.
1
+ # Storage system for features (other than YAML/Env-Vars). Right now, only Redis and ConnectionPool are supported.
2
2
  # AbstractFeatureBranch.feature_store = Redis.new
3
3
 
4
+ # Storage can be a Redis ConnectionPool instance
5
+ # AbstractFeatureBranch.feature_store = ConnectionPool.new { Redis.new }
6
+
4
7
  # The following example line works with Heroku Redis To Go while still operating on local Redis for local development
5
8
  # AbstractFeatureBranch.feature_store = Redis.new(:url => ENV['REDISTOGO_URL'])
6
9
 
10
+ # Enable live fetching of feature configuration from storage system, to update features without app/server restart.
11
+ # false by default to only load features on app/server start for faster performance (requires restart on change)
12
+ AbstractFeatureBranch.feature_store_live_fetching = false
13
+
7
14
  # Application root where config/features.yml or config/features/ is found
8
15
  AbstractFeatureBranch.application_root = Rails.root
9
16
 
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.3.0
4
+ version: 1.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Annas "Andy" Maleh
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-12-11 00:00:00.000000000 Z
11
+ date: 2022-12-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: deep_merge
@@ -122,27 +122,15 @@ extra_rdoc_files:
122
122
  - LICENSE.txt
123
123
  - README.md
124
124
  files:
125
- - ".coveralls.yml"
126
- - ".travis.yml"
127
125
  - CHANGELOG.md
128
126
  - LICENSE.txt
129
127
  - README.md
130
- - RELEASE_NOTES.md
131
- - TODO.md
132
128
  - VERSION
133
129
  - abstract_feature_branch.gemspec
134
- - config/features/admin.local.yml
135
- - config/features/admin.yml
136
- - config/features/internal/wiki.local.yml
137
- - config/features/internal/wiki.yml
138
- - config/features/public.local.yml
139
- - config/features/public.yml
140
- - img/BigAstronaut-Logo.png
141
- - img/EarlyShares-Logo.svg
142
- - img/Factor75-Logo.svg
143
130
  - lib/abstract_feature_branch.rb
144
131
  - lib/abstract_feature_branch/configuration.rb
145
132
  - lib/abstract_feature_branch/file_beautifier.rb
133
+ - lib/abstract_feature_branch/redis/connection_pool_to_redis_adapter.rb
146
134
  - lib/ext/feature_branch.rb
147
135
  - lib/generators/abstract_feature_branch/context_generator.rb
148
136
  - lib/generators/abstract_feature_branch/install_generator.rb
@@ -151,28 +139,6 @@ files:
151
139
  - lib/generators/templates/config/features.yml
152
140
  - lib/generators/templates/config/initializers/abstract_feature_branch.rb
153
141
  - lib/generators/templates/lib/tasks/abstract_feature_branch.rake
154
- - ruby187.Gemfile
155
- - spec/abstract_feature_branch/file_beautifier_spec.rb
156
- - spec/ext/feature_branch__feature_branch_per_user_spec.rb
157
- - spec/ext/feature_branch__feature_branch_spec.rb
158
- - spec/ext/feature_branch__feature_enabled_spec.rb
159
- - spec/fixtures/application_development_config/config/features.reference.yml
160
- - spec/fixtures/application_no_config/no_config
161
- - spec/fixtures/application_rails_config/config/features.local.yml
162
- - spec/fixtures/application_rails_config/config/features.yml
163
- - spec/fixtures/application_ugly_config_reference/config/another_application_configuration.yml
164
- - spec/fixtures/application_ugly_config_reference/config/database.yml
165
- - spec/fixtures/application_ugly_config_reference/config/features.local.yml
166
- - spec/fixtures/application_ugly_config_reference/config/features.yml
167
- - spec/fixtures/application_ugly_config_reference/config/features/admin.local.yml
168
- - spec/fixtures/application_ugly_config_reference/config/features/admin.yml
169
- - spec/fixtures/application_ugly_config_reference/config/features/empty.local.yml
170
- - spec/fixtures/application_ugly_config_reference/config/features/feature_empty_config.local.yml
171
- - spec/fixtures/application_ugly_config_reference/config/features/including_comments.local.yml
172
- - spec/fixtures/application_ugly_config_reference/config/features/internal/wiki.local.yml
173
- - spec/fixtures/application_ugly_config_reference/config/features/internal/wiki.yml
174
- - spec/fixtures/application_ugly_config_reference/config/features/public.local.yml
175
- - spec/fixtures/application_ugly_config_reference/config/features/public.yml
176
142
  homepage: http://github.com/AndyObtiva/abstract_feature_branch
177
143
  licenses:
178
144
  - MIT
@@ -186,8 +152,8 @@ post_install_message: "\nRails-only post-install instructions:\n\n1) Run the fol
186
152
  following line to Gemfile above abstract_feature_branch:\n\ngem 'redis', '~> 5.0.5'\n\nAfterwards,
187
153
  run:\n\nbundle\n\n5) Optionally, customize configuration in config/initializers/abstract_feature_branch.rb\n\n(can
188
154
  be useful for changing location of feature files in Rails application,\nconfiguring
189
- Redis to use for overrides and per-user feature enablement,\nand/or troubleshooting
190
- specific Rails environment feature configurations)\n\n"
155
+ Redis with a Redis or ConnectionPool instance to use for overrides and per-user
156
+ feature enablement,\nand/or troubleshooting specific Rails environment feature configurations)\n\n"
191
157
  rdoc_options: []
192
158
  require_paths:
193
159
  - lib
@@ -202,7 +168,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
202
168
  - !ruby/object:Gem::Version
203
169
  version: '0'
204
170
  requirements: []
205
- rubygems_version: 3.3.6
171
+ rubygems_version: 3.1.4
206
172
  signing_key:
207
173
  specification_version: 4
208
174
  summary: 'abstract_feature_branch is a Rails gem that enables developers to easily
data/.coveralls.yml DELETED
@@ -1 +0,0 @@
1
- repo_token: ylr6gphUkEVGf9nvY5Hfz48RHZnOf0Jjv
data/.travis.yml DELETED
@@ -1,30 +0,0 @@
1
- language: ruby
2
- services:
3
- - redis-server
4
- addons:
5
- code_climate:
6
- repo_token: 535ff40cf55554362b2f48b85e913a7362f0cf3e51638455dab456006258c5a0
7
- rvm:
8
- - 2.2.1
9
- - 2.1.5
10
- - 2.0.0
11
- - 1.9.3
12
- - 1.8.7
13
- - ree
14
- gemfile:
15
- - Gemfile
16
- - ruby187.Gemfile
17
- matrix:
18
- exclude:
19
- - rvm: 2.2.1
20
- gemfile: ruby187.Gemfile
21
- - rvm: 2.1.5
22
- gemfile: ruby187.Gemfile
23
- - rvm: 2.0.0
24
- gemfile: ruby187.Gemfile
25
- - rvm: 1.9.3
26
- gemfile: ruby187.Gemfile
27
- - rvm: 1.8.7
28
- gemfile: Gemfile
29
- - rvm: ree
30
- gemfile: Gemfile
data/RELEASE_NOTES.md DELETED
@@ -1,55 +0,0 @@
1
- Release Notes
2
- -------------
3
-
4
- Version 1.0.0:
5
- - Added configuration support for feature cacheability. Completed documentation, adding more details.
6
-
7
- Version 0.9.0:
8
- - Added support for runtime read of feature files in development to ease local testing (trading off performance)
9
-
10
- Version 0.8.0:
11
- - Added rake task for beautifying feature files, sorting feature names within environment sections and eliminating extra empty lines. Added support for externalized logger.
12
-
13
- Version 0.7.1:
14
- - Fixed undefined method issue with using <code>AbstractFeatureBranch.load_application_features</code> to improve first use performance
15
-
16
- Version 0.7.0:
17
- - Added support for general Ruby use (without Rails) by externalizing AbstractFeatureBranch.application_root and AbstractFeatureBranch.application_environment. Added initializer to optionally configure them. Supported case-insensitive feature names.
18
-
19
- Version 0.6.1 - 0.6.4:
20
- - Fixed issues including making feature configuration files optional (in case one wants to get rid of <code>features.local.yml</code> or even <code>features.yml</code>)
21
-
22
- Version 0.6.0:
23
- - Added a context generator and support for reading feature configuration from context files <code>config/features/**/*.yml</code> and <code>config/features/**/*.local.yml</code>
24
-
25
- Version 0.5.0:
26
- - Added support for local configuration feature ignored by git + some performance optimizations via configuration caching and better algorithms.
27
-
28
- Version 0.4.0:
29
- - Added support for overwriting feature configuration with environment variable overrides. Very useful on Heroku to quickly enable/disable features without a redeploy.
30
-
31
- Version 0.3.6:
32
- - Fixed feature_branch issue with invalid feature name, preventing block execution and returning nil instead
33
-
34
- Version 0.3.5:
35
- - Fixed issue with generator not allowing consuming client app to start Rails server successfully
36
-
37
- Version 0.3.4:
38
- - Added <code>abstract_feature_branch:install</code> generator to easily get started with a sample <code>config/features.yml</code>
39
-
40
- Version 0.3.3:
41
- - Removed version from README title
42
-
43
- Version 0.3.2:
44
- - Added <code>AbstractFeatureBranch.features</code> to delay YAML load until <code>Rails.root</code> has been established
45
-
46
- Version 0.3.1:
47
- - Removed dependency on the rails_config gem
48
-
49
- Version 0.3.0:
50
- - Simplified <code>features.yml</code> requirement to have a features header under each environment
51
- - Moved feature storage from Settings object to <code>AbstractFeatureBranch::FEATURES</code>
52
-
53
- Version 0.2.0:
54
- - Support an "else" block to execute when a feature is off (via <code>:true</code> and <code>:false</code> lambda arguments)
55
- - Support ability to check if a feature is enabled or not (via <code>feature_enabled?</code>)
data/TODO.md DELETED
@@ -1,3 +0,0 @@
1
- # TODO
2
-
3
- - Support `connection_pool` gem to enable working with a Redis `ConnectionPool`
@@ -1,15 +0,0 @@
1
- defaults: &defaults
2
- admin_feature3: true
3
-
4
- development:
5
- <<: *defaults
6
-
7
- test:
8
- <<: *defaults
9
-
10
- staging:
11
- <<: *defaults
12
-
13
- production:
14
- <<: *defaults
15
-
@@ -1,17 +0,0 @@
1
- defaults: &defaults
2
- admin_feature1: true
3
- admin_feature2: false
4
- admin_feature3: false
5
-
6
- development:
7
- <<: *defaults
8
-
9
- test:
10
- <<: *defaults
11
-
12
- staging:
13
- <<: *defaults
14
-
15
- production:
16
- <<: *defaults
17
-
@@ -1,15 +0,0 @@
1
- defaults: &defaults
2
- wiki_feature3: true
3
-
4
- development:
5
- <<: *defaults
6
-
7
- test:
8
- <<: *defaults
9
-
10
- staging:
11
- <<: *defaults
12
-
13
- production:
14
- <<: *defaults
15
-
@@ -1,17 +0,0 @@
1
- defaults: &defaults
2
- wiki_feature1: true
3
- wiki_feature2: false
4
- wiki_feature3: false
5
-
6
- development:
7
- <<: *defaults
8
-
9
- test:
10
- <<: *defaults
11
-
12
- staging:
13
- <<: *defaults
14
-
15
- production:
16
- <<: *defaults
17
-