abstract_feature_branch 1.2.1 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: d4bd986e2f793fa698d09ec8c8da54e65c8453c8
4
- data.tar.gz: bff3c99598c72578ec0ff0c35658f2dff8c2b759
2
+ SHA256:
3
+ metadata.gz: 8f0025726fa5c4de15b39b5b51ba6e180cf156ccccf86d661e3f9e4982d899a4
4
+ data.tar.gz: 78dae9664bcce67b70f2768ff9e866d9b47155ec1c8ef7c9d0f7d341f4866249
5
5
  SHA512:
6
- metadata.gz: 246a4b2c80ef846b32858f8ecf76675dc8b99c1b9fe1f0dec1a24bf0e046a72c305be87b2a5a09959589209b5d937284b1968676079009c6f4884bf93b1e5814
7
- data.tar.gz: 1a373850678a326fe82729093ae6274b6a4519e3ea579fd5fda1c933a42e170ded9474e51872ff8e9ed770b29e22c57690e3b1bffff9d30e78b9c21348320ae7
6
+ metadata.gz: 96649ca6005883f9765ac18d115e08eb1ac8c9aa165cba039b07aa3d843b29bc8f70cf8ec768bdb6e491e2982eb04f9f0959210418feeccd5da242df6c57bdd9
7
+ data.tar.gz: 0d305129dc28c997d740e1a6f0dbe2dfefddd1a379dfc64c4fc42287c3fbaf965dde0358287a91346af7aef201a6b1480be5d02f66dcff91464d64cf7f9e850e
data/.travis.yml CHANGED
@@ -1,40 +1,30 @@
1
1
  language: ruby
2
2
  services:
3
3
  - redis-server
4
+ addons:
5
+ code_climate:
6
+ repo_token: 535ff40cf55554362b2f48b85e913a7362f0cf3e51638455dab456006258c5a0
4
7
  rvm:
8
+ - 2.2.1
9
+ - 2.1.5
5
10
  - 2.0.0
6
11
  - 1.9.3
7
12
  - 1.8.7
8
13
  - ree
9
- - jruby-18mode
10
- - jruby-19mode
11
- - rbx-2.1.1
12
14
  gemfile:
13
15
  - Gemfile
14
16
  - ruby187.Gemfile
15
17
  matrix:
16
18
  exclude:
19
+ - rvm: 2.2.1
20
+ gemfile: ruby187.Gemfile
21
+ - rvm: 2.1.5
22
+ gemfile: ruby187.Gemfile
17
23
  - rvm: 2.0.0
18
24
  gemfile: ruby187.Gemfile
19
25
  - rvm: 1.9.3
20
26
  gemfile: ruby187.Gemfile
21
27
  - rvm: 1.8.7
22
28
  gemfile: Gemfile
23
- - rvm: 1.8.7
24
- gemfile: ruby187.Gemfile
25
- - rvm: ree
26
- gemfile: Gemfile
27
29
  - rvm: ree
28
- gemfile: ruby187.Gemfile
29
- - rvm: jruby-18mode
30
- gemfile: Gemfile
31
- - rvm: jruby-18mode
32
- gemfile: ruby187.Gemfile
33
- - rvm: jruby-19mode
34
- gemfile: ruby187.Gemfile
35
- - rvm: jruby-19mode
36
- gemfile: Gemfile
37
- - rvm: rbx-2.1.1
38
30
  gemfile: Gemfile
39
- - rvm: rbx-2.1.1
40
- gemfile: ruby187.Gemfile
data/CHANGELOG.md ADDED
@@ -0,0 +1,11 @@
1
+ # Change Log
2
+
3
+ ## 1.3.0
4
+
5
+ - Officially support newer `redis` client gem version 5
6
+ - Support (general-user) Redis Overrides (similar to Environment Variable Overrides)
7
+ - Remove `redis` gem from required dependencies to allow using `abstract_feature_branch` without Redis
8
+ - Make configuration of Redis optional in generated Rails initializer
9
+ - Provide alias of `AbstractFeatureBranch::Configuration#feature_store` to `AbstractFeatureBranch::Configuration#user_features_storage` (plus corresponding aliases `feature_store=` and `initialize_feature_store`)
10
+ - Document support for Rails 7 and Redis Server 7
11
+ - Add gem post install instructions, including how to run the Rails generators and install/use Redis
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2012 Annas "Andy" Maleh
1
+ Copyright (c) 2012-2022 Andy Maleh
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -1,14 +1,13 @@
1
- Abstract Feature Branch
2
- =======================
1
+ # Abstract Feature Branch 1.3.0
3
2
  [![Gem Version](https://badge.fury.io/rb/abstract_feature_branch.png)](http://badge.fury.io/rb/abstract_feature_branch)
4
3
  [![Build Status](https://api.travis-ci.org/AndyObtiva/abstract_feature_branch.png?branch=master)](https://travis-ci.org/AndyObtiva/abstract_feature_branch)
5
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)
5
+ [![Code Climate](https://codeclimate.com/github/AndyObtiva/abstract_feature_branch.png)](https://codeclimate.com/github/AndyObtiva/abstract_feature_branch)
6
6
 
7
7
  abstract_feature_branch is a Rails gem that enables developers to easily branch by abstraction as per this pattern:
8
8
  http://paulhammant.com/blog/branch_by_abstraction.html
9
9
 
10
- It is a productivity and fault tolerance enhancing team practice that has been utilized by professional software development
11
- teams at large corporations, such as [Sears](http://www.sears.com) and [Groupon](http://www.groupon.com).
10
+ It is a productivity and fault tolerance enhancing team practice.
12
11
 
13
12
  It provides the ability to wrap blocks of code with an abstract feature branch name, and then
14
13
  specify in a configuration file which features to be switched on or off.
@@ -27,9 +26,10 @@ context-specific feature files if needed.
27
26
 
28
27
  Requirements
29
28
  ------------
30
- - Ruby ~> 2.0.0, ~> 1.9 or ~> 1.8.7
31
- - (Optional) Rails ~> 4.0.0, ~> 3.0 or ~> 2.0
32
- - (Optional) Redis server
29
+ - Ruby (between `~> 3.1.0` and `~> 1.8.7`) ([click for a list of tested Ruby versions](https://travis-ci.org/AndyObtiva/abstract_feature_branch))
30
+ - [Optional] Rails (between `~> 7.0` and `~> 2.0`)
31
+ - [Optional] Redis Server (between `~> 7.0` and `~> 2.0`)
32
+ - [Optional] Redis client gem (between `~> 5.0` and `~> 3.0`)
33
33
 
34
34
  Setup
35
35
  -----
@@ -37,25 +37,27 @@ Setup
37
37
  ### Rails Application Use
38
38
 
39
39
  1. Configure Rubygem
40
- - Rails (~> 4.0.0 or ~> 3.0): Add the following to Gemfile <pre>gem 'abstract_feature_branch', '1.1.1'</pre>
41
- - Rails (~> 2.0): Add the following to config/environment.rb <pre>config.gem 'abstract_feature_branch', :version => '1.1.1'</pre>
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>
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
- 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)
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)
45
+ 5. [Optional] Redis Server (between `~> 7.0` and `~> 3.0`): Install view [Homebrew](https://brew.sh/) with `brew install redis`
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>
45
47
 
46
48
  ### Ruby Application General Use
47
49
 
48
- 1. <pre>gem install abstract_feature_branch -v 1.1.1</pre>
50
+ 1. <pre>gem install abstract_feature_branch -v 1.3.0</pre>
49
51
  2. Add code <code>require 'abstract_feature_branch'</code>
50
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).
51
- 4. (Optional) Create <code>config/features.local.yml</code> under <code>AbstractFeatureBranch.application_root</code> (more details under [**instructions**](#instructions))
52
- 5. (Optional) Create <code>config/features/[context_path].yml</code> under <code>AbstractFeatureBranch.application_root</code> (more details under [**instructions**](#instructions))
53
- 6. (Optional) Add code <code>AbstractFeatureBranch.application_root = "[your_application_path]"</code> to configure the location of feature files (it defaults to <code>'.'</code>)
54
- 7. (Optional) Add code <code>AbstractFeatureBranch.application_environment = "[your_application_environment]"</code> (it defaults to <code>'development'</code>). Alternatively, you can set <code>ENV['APP_ENV']</code> before the <code>require</code> statement or an an external environment variable.
55
- 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).
56
- 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).
57
- 10. (Optional) Add code <code>AbstractFeatureBranch.load_application_features</code> to pre-load application features for improved first-use performance
58
- 11. (Optional) Add code <code>AbstractFeatureBranch.user_features_storage = Redis.new(options)</code> to configure Redis for per-user feature enablement
53
+ 4. [Optional] Create <code>config/features.local.yml</code> under <code>AbstractFeatureBranch.application_root</code> (more details under [**instructions**](#instructions))
54
+ 5. [Optional] Create <code>config/features/[context_path].yml</code> under <code>AbstractFeatureBranch.application_root</code> (more details under [**instructions**](#instructions))
55
+ 6. [Optional] Add code <code>AbstractFeatureBranch.application_root = "[your_application_path]"</code> to configure the location of feature files (it defaults to <code>'.'</code>)
56
+ 7. [Optional] Add code <code>AbstractFeatureBranch.application_environment = "[your_application_environment]"</code> (it defaults to <code>'development'</code>). Alternatively, you can set <code>ENV['APP_ENV']</code> before the <code>require</code> statement or an an external environment variable.
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
+ 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
+ 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
59
61
 
60
62
  Instructions
61
63
  ------------
@@ -257,6 +259,45 @@ The benefits can be achieved more easily via <code>config/features.local.yml</co
257
259
  However, environment variable overrides are implemented to support overriding feature configuration for a Heroku deployed
258
260
  application more easily.
259
261
 
262
+ Redis Overrides
263
+ ---------------
264
+
265
+ Prerequisites: Redis server and client (`redis` gem) and optional Redis configuration of `AbstractFeatureBranch.feature_store` in `config/initializers/abstract_feature_branch.rb`
266
+
267
+ To be able to override feature configuration in a production environment, you can utilize Redis Overrides.
268
+
269
+ 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
+ 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
+
273
+ ```ruby
274
+ AbstractFeatureBranch.set_store_feature('feature1', true)
275
+ ```
276
+
277
+ Behind the scenes, that is the equivalent of the following Redis client invocation, which stores a hash value in a `abstract_feature_branch` key:
278
+
279
+ ```ruby
280
+ AbstractFeatureBranch.configuration.feature_store.hset('abstract_feature_branch', 'feature1', 'true')
281
+ ```
282
+
283
+ To remove a Redis override, you can run the following in `rails console` (or `irb`):
284
+
285
+ ```ruby
286
+ AbstractFeatureBranch.delete_store_feature('feature1')
287
+ ```
288
+
289
+ To get a Redis override value, you can run the following in `rails console` (or `irb`):
290
+
291
+ ```ruby
292
+ AbstractFeatureBranch.get_store_feature('feature1')
293
+ ```
294
+
295
+ To get an array of all Redis Override features, you can run the following in `rails console` (or `irb`):
296
+
297
+ ```ruby
298
+ AbstractFeatureBranch.get_store_features
299
+ ```
300
+
260
301
  Heroku
261
302
  ------
262
303
 
@@ -277,7 +318,7 @@ Removing an environment variable override:
277
318
  ### Recommendation
278
319
 
279
320
  It is recommended that you use environment variable overrides on Heroku only as an emergency or temporary measure.
280
- Afterward, make the change officially in config/features.yml, deploy, and remove the environment variable override for the long term.
321
+ Afterward, make the change official in config/features.yml, deploy, and remove the environment variable override for the long term.
281
322
 
282
323
  ### Gotcha with abstract feature branching in CSS and JS files
283
324
 
@@ -301,18 +342,18 @@ the former if overlap in features occurs:
301
342
  3. Context-specific local feature file overrides: <code>config/features/**/*.local.yml</code>
302
343
  4. Main local feature file override: <code>config/features.local.yml</code>
303
344
  5. Environment variable overrides
345
+ 6. Redis overrides
304
346
 
305
347
  Rails Initializer
306
348
  -----------------
307
349
 
308
- Here is the content of the generated initializer (<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):
350
+ 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):
309
351
 
310
- > require 'redis'
352
+ > # Storage system for features (other than YAML/Env-Vars). Right now, only Redis is supported.
353
+ > # AbstractFeatureBranch.feature_store = Redis.new
311
354
  >
312
- > # Storage for user features, customizable over here. Right now, only a Redis client is supported.
313
355
  > # The following example line works with Heroku Redis To Go while still operating on local Redis for local development
314
- > # AbstractFeatureBranch.user_features_storage = Redis.new(:url => ENV['REDISTOGO_URL'])
315
- > AbstractFeatureBranch.user_features_storage = Redis.new
356
+ > # AbstractFeatureBranch.feature_store = Redis.new(:url => ENV['REDISTOGO_URL'])
316
357
  >
317
358
  > # Application root where config/features.yml or config/features/ is found
318
359
  > AbstractFeatureBranch.application_root = Rails.root
@@ -335,8 +376,6 @@ Here is the content of the generated initializer (<code>config/initializers/abst
335
376
  > # Pre-load application features to improve performance of first web-page hit
336
377
  > AbstractFeatureBranch.load_application_features unless Rails.env.development?
337
378
 
338
- TODO Document in Heroku (:url => ENV['REDISTOGO_URL'])
339
-
340
379
  Rake Task
341
380
  ---------
342
381
 
@@ -430,15 +469,14 @@ after invoking the rake task, **verify** that your feature file contents are to
430
469
  task changes.
431
470
 
432
471
  Feature Branches vs Branch by Abstraction
433
- ---------
472
+ -----------------------------------------
434
473
 
435
- Although feature branches and branching by abstraction are similar, there are different situations that recommend each approach.
474
+ Although feature branches and branching by abstraction are similar, there are different situations that recommend each approach.
436
475
 
437
- Feature branching leverages your version control software (VCS) to create a branch that is independent of your main branch. Once you write your feature, you integrate it with the rest of your code base. Featuring branching is ideal for developing features that can be completed within the one or two iterations. But it can become cumbersome with larger features due to the fact your code is isolated and quickly falls out of sync with your main branch. You will have to regularly rebase with your main branch or devote substantial time to resolving merge conflicts.
476
+ Feature branching leverages your version control software (VCS) to create a branch that is independent of your main branch. Once you write your feature, you integrate it with the rest of your code base. Feature branching is ideal for developing features that can be completed within the one or two iterations. But it can become cumbersome with larger features due to the fact your code is isolated and quickly falls out of sync with your main branch. You will have to regularly rebase with your main branch or devote substantial time to resolving merge conflicts.
438
477
 
439
478
  Branching by abstraction, on the other hand, is ideal for substantial features, i.e. ones which take many iterations to complete. This approach to branching takes place outside of your VCS. Instead, you build your feature, but wrap the code inside configurable flags. These configuration flags will allow for different behavior, depending on the runtime environment. For example, a feature would be set to "on" when your app runs in development mode, but "off" when running in "production" mode. This approach avoids the pain of constantly rebasing or resolving a myriad of merge conflict when you do attempt to integrate your feature into the larger app.
440
479
 
441
-
442
480
  Contributing to abstract_feature_branch
443
481
  ---------------------------------------
444
482
 
@@ -452,17 +490,14 @@ Contributing to abstract_feature_branch
452
490
 
453
491
  Committers
454
492
  ---------------------------------------
455
- * [Annas "Andy" Maleh (Author)](https://github.com/AndyObtiva)
493
+ * [Andy Maleh (Author)](https://github.com/AndyObtiva)
456
494
 
457
495
  Contributors
458
496
  ---------------------------------------
459
- * [Christian Nennemann](https://github.com/XORwell)
460
- * [Ben Downey](https://github.com/bnd5k)
461
497
  * [Mark Moschel](https://github.com/mmosche2)
462
498
 
463
499
  Copyright
464
500
  ---------------------------------------
465
501
 
466
- Copyright (c) 2013 Annas "Andy" Maleh. See LICENSE.txt for
502
+ Copyright (c) 2012-2022 Andy Maleh. See [LICENSE.txt](LICENSE.txt) for
467
503
  further details.
468
-
data/TODO.md ADDED
@@ -0,0 +1,3 @@
1
+ # TODO
2
+
3
+ - Support `connection_pool` gem to enable working with a Redis `ConnectionPool`
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.2.1
1
+ 1.3.0
@@ -2,25 +2,30 @@
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
6
 
6
7
  Gem::Specification.new do |s|
7
- s.name = "abstract_feature_branch"
8
- s.version = "1.2.1"
8
+ s.name = "abstract_feature_branch".freeze
9
+ s.version = "1.3.0"
9
10
 
10
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
- s.authors = ["Annas \"Andy\" Maleh"]
12
- s.date = "2014-01-23"
13
- 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 that has been utilized by professional software development\nteams at large corporations, such as Sears and Groupon.\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"
11
+ s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
12
+ s.require_paths = ["lib".freeze]
13
+ s.authors = ["Annas \"Andy\" Maleh".freeze]
14
+ s.date = "2022-12-11"
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
14
16
  s.extra_rdoc_files = [
17
+ "CHANGELOG.md",
15
18
  "LICENSE.txt",
16
19
  "README.md"
17
20
  ]
18
21
  s.files = [
19
22
  ".coveralls.yml",
20
23
  ".travis.yml",
24
+ "CHANGELOG.md",
21
25
  "LICENSE.txt",
22
26
  "README.md",
23
27
  "RELEASE_NOTES.md",
28
+ "TODO.md",
24
29
  "VERSION",
25
30
  "abstract_feature_branch.gemspec",
26
31
  "config/features/admin.local.yml",
@@ -29,7 +34,11 @@ Gem::Specification.new do |s|
29
34
  "config/features/internal/wiki.yml",
30
35
  "config/features/public.local.yml",
31
36
  "config/features/public.yml",
37
+ "img/BigAstronaut-Logo.png",
38
+ "img/EarlyShares-Logo.svg",
39
+ "img/Factor75-Logo.svg",
32
40
  "lib/abstract_feature_branch.rb",
41
+ "lib/abstract_feature_branch/configuration.rb",
33
42
  "lib/abstract_feature_branch/file_beautifier.rb",
34
43
  "lib/ext/feature_branch.rb",
35
44
  "lib/generators/abstract_feature_branch/context_generator.rb",
@@ -40,7 +49,6 @@ Gem::Specification.new do |s|
40
49
  "lib/generators/templates/config/initializers/abstract_feature_branch.rb",
41
50
  "lib/generators/templates/lib/tasks/abstract_feature_branch.rake",
42
51
  "ruby187.Gemfile",
43
- "ruby187.Gemfile.lock",
44
52
  "spec/abstract_feature_branch/file_beautifier_spec.rb",
45
53
  "spec/ext/feature_branch__feature_branch_per_user_spec.rb",
46
54
  "spec/ext/feature_branch__feature_branch_spec.rb",
@@ -63,28 +71,30 @@ Gem::Specification.new do |s|
63
71
  "spec/fixtures/application_ugly_config_reference/config/features/public.local.yml",
64
72
  "spec/fixtures/application_ugly_config_reference/config/features/public.yml"
65
73
  ]
66
- s.homepage = "http://github.com/AndyObtiva/abstract_feature_branch"
67
- s.licenses = ["MIT"]
68
- s.require_paths = ["lib"]
69
- s.rubygems_version = "2.0.6"
70
- 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"
74
+ s.homepage = "http://github.com/AndyObtiva/abstract_feature_branch".freeze
75
+ 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
78
+ 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
71
79
 
72
80
  if s.respond_to? :specification_version then
73
81
  s.specification_version = 4
82
+ end
74
83
 
75
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
76
- s.add_runtime_dependency(%q<deep_merge>, ["= 1.0.0"])
77
- s.add_runtime_dependency(%q<redis>, ["~> 3.0.0"])
78
- s.add_development_dependency(%q<jeweler>, ["= 1.8.8"])
79
- else
80
- s.add_dependency(%q<deep_merge>, ["= 1.0.0"])
81
- s.add_dependency(%q<redis>, ["~> 3.0.0"])
82
- s.add_dependency(%q<jeweler>, ["= 1.8.8"])
83
- end
84
+ if s.respond_to? :add_runtime_dependency then
85
+ s.add_runtime_dependency(%q<deep_merge>.freeze, ["~> 1.0.0"])
86
+ s.add_development_dependency(%q<jeweler>.freeze, ["~> 2.3.9"])
87
+ s.add_development_dependency(%q<bundler>.freeze, [">= 2.1.4"])
88
+ s.add_development_dependency(%q<rspec>.freeze, ["= 2.14.1"])
89
+ s.add_development_dependency(%q<rdoc>.freeze, ["= 5.1.0"])
90
+ s.add_development_dependency(%q<psych>.freeze, ["= 3.3.4"])
84
91
  else
85
- s.add_dependency(%q<deep_merge>, ["= 1.0.0"])
86
- s.add_dependency(%q<redis>, ["~> 3.0.0"])
87
- s.add_dependency(%q<jeweler>, ["= 1.8.8"])
92
+ s.add_dependency(%q<deep_merge>.freeze, ["~> 1.0.0"])
93
+ s.add_dependency(%q<jeweler>.freeze, ["~> 2.3.9"])
94
+ s.add_dependency(%q<bundler>.freeze, [">= 2.1.4"])
95
+ s.add_dependency(%q<rspec>.freeze, ["= 2.14.1"])
96
+ s.add_dependency(%q<rdoc>.freeze, ["= 5.1.0"])
97
+ s.add_dependency(%q<psych>.freeze, ["= 3.3.4"])
88
98
  end
89
99
  end
90
100
 
Binary file
@@ -0,0 +1,22 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <svg width="181px" height="26px" viewBox="0 0 181 26" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
3
+ <!-- Generator: Sketch 3.1 (8751) - http://www.bohemiancoding.com/sketch -->
4
+ <title>es_logo</title>
5
+ <desc>Created with Sketch.</desc>
6
+ <defs></defs>
7
+ <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
8
+ <g id="es_logo" sketch:type="MSLayerGroup" transform="translate(1.000000, 0.000000)">
9
+ <path d="M-0.0666666667,0.342105263 L15.2666667,0.342105263 L15.2666667,2.12105263 L1.8,2.12105263 L1.8,9.1 L13.7333333,9.1 L13.7333333,10.8789474 L1.8,10.8789474 L1.8,18.6789474 L15.4,18.6789474 L15.4,20.4578947 L-0.0666666667,20.4578947" id="Shape" fill="#3c3f40" sketch:type="MSShapeGroup"></path>
10
+ <path d="M31.4666667,20.4578947 L31.4666667,18.3368421 C30.1333333,19.9105263 28.2,20.7315789 25.8,20.7315789 C23.5333333,20.7315789 21.6666667,19.9789474 20.3333333,18.5421053 C19.0666667,17.1736842 18.4666667,15.3947368 18.4666667,13.2052632 C18.4666667,11.0157895 19.0666667,9.16842105 20.3333333,7.8 C21.6666667,6.29473684 23.5333333,5.54210526 25.8666667,5.54210526 C28.2666667,5.54210526 30.0666667,6.29473684 31.4,7.86842105 L31.4,5.61052632 L33.3333333,5.61052632 L33.3333333,20.3894737 L31.4666667,20.3894737 L31.4666667,20.4578947 Z M30,8.96315789 C29,7.93684211 27.6,7.38947368 25.7333333,7.38947368 C24,7.38947368 22.6666667,7.93684211 21.6666667,9.1 C20.7333333,10.1947368 20.3333333,11.5631579 20.3333333,13.2052632 C20.3333333,14.9157895 20.8,16.2842105 21.6666667,17.3105263 C22.6,18.4052632 24,18.9526316 25.7333333,18.9526316 C27.4666667,18.9526316 28.8,18.4052632 29.8666667,17.3105263 C30.9333333,16.2157895 31.4,14.8473684 31.4,13.2052632 C31.4666667,11.4263158 31,9.98947368 30,8.96315789 L30,8.96315789 Z" id="Shape" fill="#3C3F40" sketch:type="MSShapeGroup"></path>
11
+ <path d="M42,9.64736842 C41.2,10.9473684 40.8,12.5894737 40.8,14.5736842 L40.8,20.4578947 L38.8666667,20.4578947 L38.8666667,5.95263158 L40.8,5.95263158 L40.8,7.93684211 C42.1333333,6.36315789 44.2,5.61052632 46.9333333,5.61052632 L46.9333333,7.38947368 C44.6,7.38947368 43,8.14210526 42,9.64736842" id="Shape" fill="#3C3F40" sketch:type="MSShapeGroup"></path>
12
+ <rect id="Rectangle-path" fill="#3C3F40" sketch:type="MSShapeGroup" x="51.3333333" y="0.684210526" width="1.93333333" height="20.1157895"></rect>
13
+ <path d="M64.4,25.7947368 C62.6666667,25.7947368 61.2,25.4526316 60.0666667,24.7684211 C58.6666667,23.8789474 57.9333333,22.3736842 57.8,20.2526316 L59.7333333,20.2526316 C59.8666667,21.5526316 60.2666667,22.5105263 61,23.1263158 C61.7333333,23.7421053 62.9333333,24.0157895 64.4666667,24.0157895 C67.9333333,24.0157895 69.6666667,22.5789474 69.6666667,19.7052632 L69.6666667,19.1578947 C68.4666667,20.4578947 66.8,21.0736842 64.6666667,21.0736842 C62.8,21.0736842 61.3333333,20.5947368 60.2,19.7052632 C59.0666667,18.6789474 58.4666667,17.3105263 58.4666667,15.5315789 L58.4666667,5.95263158 L60.4,5.95263158 L60.4,15.4631579 C60.4,17.9947368 61.8,19.2947368 64.6666667,19.2947368 C66.3333333,19.2947368 67.6,18.8157895 68.4,17.7894737 C69.2,16.9 69.6,15.6 69.6,13.9578947 L69.6,5.95263158 L71.5333333,5.95263158 L71.5333333,19.7052632 C71.5333333,23.7421053 69.1333333,25.7947368 64.4,25.7947368" id="Shape" fill="#3C3F40" sketch:type="MSShapeGroup"></path>
14
+ <path d="M85.6666667,20.6631579 C83.0666667,20.6631579 81.0666667,20.1842105 79.4666667,19.2947368 C77.4666667,18.1315789 76.5333333,16.3526316 76.5333333,13.8894737 L76.5333333,13 L78.4666667,13 L78.4666667,13.8210526 C78.4666667,17.2421053 80.8666667,18.9526316 85.7333333,18.9526316 C87.4,18.9526316 88.8,18.6789474 89.9333333,18.2 C91.3333333,17.5157895 92.0666667,16.5578947 92.0666667,15.2578947 C92.0666667,14.3684211 91.8,13.6842105 91.3333333,13.2052632 C90.9333333,12.7947368 90.2,12.4526316 89.1333333,12.1105263 C88.5333333,11.9052632 87.2,11.6315789 85,11.1526316 C82.5333333,10.6052632 80.8,10.1263158 79.9333333,9.64736842 C78.1333333,8.68947368 77.2,7.32105263 77.2,5.47368421 C77.2,1.98421053 79.8666667,0.205263158 85.1333333,0.205263158 C90.6666667,0.205263158 93.4666667,2.46315789 93.5333333,6.97894737 L91.6666667,6.97894737 C91.5333333,4.92631579 90.8666667,3.55789474 89.6666667,2.87368421 C88.6666667,2.32631579 87.1333333,2.05263158 85.1333333,2.05263158 C81.1333333,2.05263158 79.0666667,3.21578947 79.0666667,5.47368421 C79.0666667,6.56842105 79.6,7.45789474 80.6666667,8.00526316 C81.4,8.41578947 82.7333333,8.75789474 84.6,9.1 C88.1333333,9.78421053 90.5333333,10.4684211 91.7333333,11.1526316 C93.2,12.0421053 93.9333333,13.4105263 93.9333333,15.3263158 C93.9333333,17.2421053 92.9333333,18.6789474 91,19.6368421 C89.5333333,20.3210526 87.7333333,20.6631579 85.6666667,20.6631579" id="Shape" fill="#6BA651" sketch:type="MSShapeGroup"></path>
15
+ <path d="M110.266667,20.4578947 L110.266667,10.8105263 C110.266667,9.57894737 109.866667,8.62105263 109.133333,8.00526316 C108.4,7.38947368 107.333333,7.04736842 106,7.04736842 C104.466667,7.04736842 103.2,7.52631579 102.333333,8.41578947 C101.466667,9.37368421 101,10.6052632 101,12.1105263 L101,20.3894737 L99.0666667,20.3894737 L99.0666667,0.273684211 L101,0.273684211 L101,7.11578947 C102.2,5.88421053 103.866667,5.2 106,5.2 C107.733333,5.2 109.2,5.61052632 110.333333,6.5 C111.6,7.45789474 112.2,8.75789474 112.2,10.5368421 L112.2,20.3894737 L110.266667,20.3894737 L110.266667,20.4578947 Z" id="Shape" fill="#6BA651" sketch:type="MSShapeGroup"></path>
16
+ <path d="M140.333333,9.64736842 C139.533333,10.9473684 139.133333,12.5894737 139.133333,14.5736842 L139.133333,20.4578947 L137.2,20.4578947 L137.2,5.95263158 L139.133333,5.95263158 L139.133333,7.93684211 C140.466667,6.36315789 142.533333,5.61052632 145.266667,5.61052632 L145.266667,7.38947368 C142.933333,7.38947368 141.333333,8.14210526 140.333333,9.64736842" id="Shape" fill="#6BA651" sketch:type="MSShapeGroup"></path>
17
+ <path d="M150,13.9578947 C150.266667,17.3105263 152.133333,19.0210526 155.6,19.0210526 C158.266667,19.0210526 160.066667,17.8578947 160.933333,15.6 L162.933333,15.6 C162.266667,17.6526316 161.266667,19.0210526 159.866667,19.7736842 C158.6,20.4578947 157.2,20.8 155.533333,20.8 C153.066667,20.8 151.2,20.1157895 149.933333,18.6789474 C148.733333,17.3789474 148.133333,15.5315789 148.133333,13.2736842 C148.133333,11.0842105 148.8,9.23684211 150.133333,7.8 C151.466667,6.36315789 153.333333,5.61052632 155.666667,5.61052632 C157.933333,5.61052632 159.8,6.22631579 161.133333,7.52631579 C162.533333,8.82631579 163.2,10.5368421 163.2,12.7263158 L163.2,13.9578947 L150,13.9578947 L150,13.9578947 Z M159.733333,8.89473684 C158.733333,7.93684211 157.4,7.38947368 155.733333,7.38947368 C154.2,7.38947368 152.933333,7.8 151.933333,8.62105263 C150.933333,9.44210526 150.333333,10.6052632 150.133333,12.1789474 L161.2,12.1789474 C161,10.8105263 160.533333,9.71578947 159.733333,8.89473684 L159.733333,8.89473684 Z" id="Shape" fill="#6BA651" sketch:type="MSShapeGroup"></path>
18
+ <path d="M177.666667,20.0473684 C176.666667,20.5947368 175.333333,20.8684211 173.733333,20.8684211 C169.266667,20.8684211 167.066667,18.8157895 167.066667,14.6421053 L169.066667,14.6421053 C169.066667,16.2157895 169.466667,17.3105263 170.2,17.9947368 C170.933333,18.6789474 172.133333,19.0210526 173.8,19.0210526 C174.933333,19.0210526 175.866667,18.8157895 176.6,18.4736842 C177.466667,18.0631579 177.866667,17.3789474 177.866667,16.5578947 C177.866667,15.5315789 176.933333,14.7789474 175.133333,14.3684211 C175,14.3684211 174,14.2315789 172.266667,13.8894737 C169.266667,13.4105263 167.733333,12.1105263 167.733333,9.92105263 C167.733333,8.48421053 168.333333,7.38947368 169.533333,6.56842105 C170.6,5.88421053 171.8,5.54210526 173.266667,5.54210526 C177.533333,5.54210526 179.666667,7.38947368 179.733333,11.0842105 L177.733333,11.0842105 C177.733333,9.78421053 177.4,8.82631579 176.733333,8.21052632 C176.066667,7.66315789 174.933333,7.32105263 173.466667,7.32105263 C172.466667,7.32105263 171.6,7.52631579 170.866667,7.93684211 C170.066667,8.41578947 169.733333,9.03157895 169.733333,9.85263158 C169.733333,10.8789474 170.6,11.5631579 172.333333,11.8368421 C172.866667,11.9052632 173.866667,12.1105263 175.4,12.3842105 C178.333333,12.9315789 179.8,14.2315789 179.8,16.4210526 C179.733333,18.0631579 179.066667,19.2263158 177.666667,20.0473684" id="Shape" fill="#6BA651" sketch:type="MSShapeGroup"></path>
19
+ <path d="M128.8,20.3894737 L128.8,18.2684211 C127.466667,19.8421053 125.533333,20.6631579 123.133333,20.6631579 C120.866667,20.6631579 119,19.9105263 117.666667,18.4736842 C116.4,17.1052632 115.8,15.3263158 115.8,13.1368421 C115.8,10.9473684 116.4,9.1 117.666667,7.73157895 C119,6.22631579 120.866667,5.47368421 123.2,5.47368421 C125.6,5.47368421 127.4,6.22631579 128.733333,7.8 L128.733333,5.54210526 L130.666667,5.54210526 L130.666667,20.3210526 L128.8,20.3210526 L128.8,20.3894737 Z M127.333333,8.89473684 C126.333333,7.86842105 124.933333,7.32105263 123.066667,7.32105263 C121.333333,7.32105263 120,7.86842105 119,9.03157895 C118.066667,10.1263158 117.666667,11.4947368 117.666667,13.1368421 C117.666667,14.8473684 118.133333,16.2157895 119,17.2421053 C119.933333,18.3368421 121.333333,18.8842105 123.066667,18.8842105 C124.8,18.8842105 126.133333,18.3368421 127.2,17.2421053 C128.266667,16.1473684 128.733333,14.7789474 128.733333,13.1368421 C128.8,11.3578947 128.333333,9.92105263 127.333333,8.89473684 L127.333333,8.89473684 Z" id="Shape" fill="#6BA651" sketch:type="MSShapeGroup"></path>
20
+ </g>
21
+ </g>
22
+ </svg>
@@ -0,0 +1,54 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
3
+ <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
4
+ <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
5
+ width="627.062px" height="612px" viewBox="0 0 627.062 612" enable-background="new 0 0 627.062 612" xml:space="preserve">
6
+ <g>
7
+ <path d="M563.713,302.966c0,139.834-113.353,253.183-253.19,253.183c-139.837,0-253.19-113.349-253.19-253.183
8
+ c0-139.834,113.354-253.201,253.19-253.201C450.36,49.765,563.713,163.132,563.713,302.966"/>
9
+ <path fill="#FFFFFF" d="M310.522,69.572c-128.674,0-233.384,104.703-233.384,233.38c0,128.688,104.71,233.376,233.384,233.376
10
+ c128.691,0,233.376-104.688,233.376-233.376C543.898,174.275,439.214,69.572,310.522,69.572 M310.522,590.299
11
+ c-158.457,0-287.336-128.903-287.336-287.347c0-158.436,128.879-287.333,287.336-287.333s287.336,128.897,287.336,287.333
12
+ C597.858,461.396,468.979,590.299,310.522,590.299"/>
13
+ <path fill="#C1D82F" d="M310.522,14.185c-159.217,0-288.771,129.543-288.771,288.768c0,159.231,129.554,288.778,288.771,288.778
14
+ c159.228,0,288.789-129.547,288.789-288.778C599.312,143.728,469.75,14.185,310.522,14.185z M542.457,302.952
15
+ c0,127.893-104.042,231.944-231.935,231.944c-127.886,0-231.938-104.052-231.938-231.944
16
+ c0-127.889,104.052-231.934,231.938-231.934C438.415,71.018,542.457,175.063,542.457,302.952z M310.522,17.062v51.082
17
+ c-129.476,0-234.818,105.332-234.818,234.808H24.622C24.622,145.308,152.893,17.062,310.522,17.062z"/>
18
+ <path fill="#C1D82F" d="M187.809,232.519c-4.814,0-8.731,3.662-8.731,8.194l-0.06,36.076h24.112l0.039-12.285
19
+ c0-5.239,3.503-8.251,7.798-8.251l70.894-0.074l-92.888,181.206h28.785l93.164-185.182v-19.684H187.809z"/>
20
+ <path fill="#C1D82F" d="M413.941,232.625c0,0-59.977-0.042-65.402,0c-5.434,0.042-8.997-0.127-12.531,1.647
21
+ c-5.989,3.005-7.198,9.94-7.863,15.986c-0.809,7.332-8.392,84.803-7.738,85.118l11.857,5.903c0,0,17.644-10.237,38.31-10.237
22
+ c26.75,0,44.118,17.046,44.118,42.188c0,23.123-19.291,41.626-43.842,41.626c-28.126,0-42.693-22.405-42.693-22.405l-14.579,20.903
23
+ c0,0,19.234,27.227,58.636,27.227c40.559,0,70.621-30.055,70.621-68.503c0-36.418-27.019-64.741-67.301-64.741
24
+ c-18.318,0-27.578,6.37-27.578,6.37s5.112-50.206,5.112-50.237c0.368-3.761,3.515-6.685,7.184-6.685c0,0,36.563-0.007,39.618-0.007
25
+ c3.98,0,6.733,3.574,6.833,6.674c0.096,3.09,0,13.285,0,13.285h22.695l0.057-31.504c0-6.622-5.246-10.605-8.746-11.765
26
+ C418.499,232.721,416.204,232.59,413.941,232.625"/>
27
+ <polygon fill="#FFFFFF" points="188.699,166.494 222.912,166.494 221.039,176.371 199.5,176.371 197.382,186.146 217.659,186.146
28
+ 215.746,196.009 195.487,196.009 191.436,217.463 178.745,217.463 "/>
29
+ <path fill="#FFFFFF" d="M232.121,198.999h12.921l-2.888-19.549L232.121,198.999z M246.644,208.212h-19.185l-4.762,9.251h-12.695
30
+ l27.136-51.043h14.161l8.498,51.043h-11.789L246.644,208.212z"/>
31
+ <polygon fill="#FFFFFF" points="302.773,166.469 343.007,166.455 340.988,176.615 326.926,176.615 320.24,217.318 308.999,217.318
32
+ 315.617,176.615 301.172,176.619 "/>
33
+ <path fill="#FFFFFF" d="M409.081,189.772c2.867,0,5.056-0.714,6.529-2.131c1.492-1.432,2.234-3.524,2.234-6.282
34
+ c0-1.195-0.587-2.881-2.305-3.984c-1.599-1.021-4.179-1.015-8.159-1.015c-3.16,0-4.214,0.053-4.214,0.053l-1.901,13.359H409.081z
35
+ M400.184,199.098l-2.588,18.397l-11.963-0.042l7.883-50.892h20.532c5.401,0,9.495,1.071,12.267,3.224
36
+ c2.811,2.156,4.214,5.324,4.214,9.509c0,4.235-1.11,7.707-3.315,10.45c-2.185,2.733-5.176,4.292-8.923,4.702
37
+ c1.722,0.367,3.164,1.304,4.288,2.786c1.142,1.481,2.146,3.747,2.994,6.819l3.659,13.444h-12.617l-3.153-11.588
38
+ c-0.771-2.587-1.658-4.383-2.722-5.352c-1.071-0.969-2.612-1.457-4.646-1.457H400.184z"/>
39
+ <path fill="#FFFFFF" d="M284.809,166.494c-8.947,0-17.1,3.797-18.758,13.239c-0.007,0.042-3.58,21.041-3.609,21.31
40
+ c-0.205,2.139-0.145,4.179,0.039,6.441c0.178,1.796,1.086,3.669,2.153,5.115c1.075,1.372,2.364,2.454,3.906,3.228
41
+ c3.182,1.623,7.232,1.669,11.817,1.715c0.732,0,10.994,0,10.994,0l1.057-10.206c-0.66,0-16.187,0.131-16.879-0.042
42
+ c-1.055-0.261-1.69-1.025-2.051-1.919c-0.389-0.873-0.1-2.287,0.061-3.245c0.018-0.032,4.195-23.342,4.195-23.342
43
+ c0.283-1.704,1.541-2.178,3.143-2.167c3.16,0.06,15.982,0.018,15.982,0.018l1.835-10.125
44
+ C298.694,166.512,287.092,166.494,284.809,166.494"/>
45
+ <path fill="#FFFFFF" d="M372.779,203.796c-0.438,2.17-1.63,3.581-3.609,3.574c-0.676,0-3.786,0.032-7.611,0.032
46
+ c-4.15,0-7.819-0.032-8.509-0.032c-1.934,0.007-2.804-1.576-2.472-3.574c0.262-1.63,1.651-10.832,2.157-14.144
47
+ c0.626-3.761,1.347-8.148,1.583-9.329c0.39-2.266,1.57-3.715,3.454-3.793c0.039,0,3.8-0.05,8.177-0.05
48
+ c4.369-0.007,8.088,0.042,8.088,0.042c1.984,0,2.801,1.379,2.489,3.535c0,0-0.891,6.498-1.796,12.896
49
+ C373.832,199.342,372.779,203.796,372.779,203.796 M360.018,217.644c4.879-0.05,11.613-0.474,15.992-3.153
50
+ c4.091-2.521,6.354-6.356,7.251-12.394l3.221-20.345c0.799-6.059-0.039-9.859-3.358-12.373c-3.766-2.885-11.064-3.167-16.004-3.167
51
+ l-0.01,0.018c-4.89,0.046-11.603,0.488-15.982,3.15c-4.107,2.535-6.335,6.359-7.25,12.39l-3.211,20.327
52
+ c-1.008,6.038,0.008,9.874,3.303,12.394c3.538,2.679,10.152,3.104,15.01,3.153"/>
53
+ </g>
54
+ </svg>
@@ -0,0 +1,64 @@
1
+ module AbstractFeatureBranch
2
+ class Configuration
3
+ def application_root
4
+ @application_root ||= initialize_application_root
5
+ end
6
+ def application_root=(path)
7
+ @application_root = path
8
+ end
9
+ def initialize_application_root
10
+ self.application_root = defined?(Rails) ? Rails.root : '.'
11
+ end
12
+ def application_environment
13
+ @application_environment ||= initialize_application_environment
14
+ end
15
+ def application_environment=(environment)
16
+ @application_environment = environment
17
+ end
18
+ def initialize_application_environment
19
+ self.application_environment = defined?(Rails) ? Rails.env.to_s : ENV['APP_ENV'] || 'development'
20
+ end
21
+ def logger
22
+ @logger ||= initialize_logger
23
+ end
24
+ def logger=(logger)
25
+ @logger = logger
26
+ end
27
+ def initialize_logger
28
+ self.logger = defined?(Rails) && Rails.logger ? Rails.logger : Logger.new(STDOUT)
29
+ end
30
+ def cacheable
31
+ @cacheable ||= initialize_cacheable
32
+ end
33
+ def cacheable=(cacheable)
34
+ @cacheable = cacheable
35
+ end
36
+ def initialize_cacheable
37
+ self.cacheable = {
38
+ :development => false,
39
+ :test => true,
40
+ :staging => true,
41
+ :production => true
42
+ }
43
+ end
44
+
45
+ def feature_store
46
+ @feature_store ||= initialize_feature_store
47
+ end
48
+ alias user_features_storage feature_store
49
+
50
+ def feature_store=(feature_store)
51
+ @feature_store = feature_store
52
+ end
53
+ alias user_features_storage= feature_store=
54
+
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
63
+ end
64
+ end
@@ -11,92 +11,58 @@ rescue Bundler::BundlerError => e
11
11
  end
12
12
  require 'logger' unless defined?(Rails) && Rails.logger
13
13
  require 'deep_merge' unless {}.respond_to?(:deep_merge!)
14
+ require 'forwardable'
15
+
16
+ require File.join(File.dirname(__FILE__), 'abstract_feature_branch', 'configuration')
14
17
 
15
18
  module AbstractFeatureBranch
16
19
  ENV_FEATURE_PREFIX = "abstract_feature_branch_"
20
+ REDIS_HKEY = "abstract_feature_branch"
17
21
 
18
22
  class << self
19
- def application_root
20
- @application_root ||= initialize_application_root
21
- end
22
- def application_root=(path)
23
- @application_root = path
24
- end
25
- def initialize_application_root
26
- self.application_root = defined?(Rails) ? Rails.root : '.'
27
- end
28
- def application_environment
29
- @application_environment ||= initialize_application_environment
30
- end
31
- def application_environment=(environment)
32
- @application_environment = environment
33
- end
34
- def initialize_application_environment
35
- self.application_environment = defined?(Rails) ? Rails.env.to_s : ENV['APP_ENV'] || 'development'
36
- end
37
- def logger
38
- @logger ||= initialize_logger
39
- end
40
- def logger=(logger)
41
- @logger = logger
42
- end
43
- def initialize_logger
44
- self.logger = defined?(Rails) && Rails.logger ? Rails.logger : Logger.new(STDOUT)
45
- end
46
- def cacheable
47
- @cacheable ||= initialize_cacheable
48
- end
49
- def cacheable=(cacheable)
50
- @cacheable = cacheable
51
- end
52
- def initialize_cacheable
53
- self.cacheable = {
54
- :development => false,
55
- :test => true,
56
- :staging => true,
57
- :production => true
58
- }
59
- end
60
- def user_features_storage
61
- @user_features_storage ||= initialize_user_features_storage
62
- end
63
- def user_features_storage=(user_features_storage)
64
- @user_features_storage = user_features_storage
23
+ 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
25
+
26
+ def configuration
27
+ @configuration ||= Configuration.new
65
28
  end
66
- def initialize_user_features_storage
67
- require 'redis'
68
- self.user_features_storage = Redis.new
29
+
30
+ def redis_overrides
31
+ load_redis_overrides
32
+ end
33
+ def load_redis_overrides
34
+ return {} if feature_store.nil?
35
+
36
+ redis_feature_hash = get_store_features.inject({}) do |output, feature|
37
+ output.merge(feature => get_store_feature(feature))
38
+ end
39
+
40
+ downcase_keys(redis_feature_hash)
69
41
  end
42
+
70
43
  def environment_variable_overrides
71
44
  @environment_variable_overrides ||= load_environment_variable_overrides
72
45
  end
73
46
  def load_environment_variable_overrides
74
- @environment_variable_overrides = featureize_keys(select_feature_keys(booleanize_values(downcase_keys(ENV))))
47
+ @environment_variable_overrides = featureize_keys(downcase_keys(booleanize_values(select_feature_keys(ENV))))
75
48
  end
49
+
76
50
  def local_features
77
51
  @local_features ||= load_local_features
78
52
  end
79
53
  def load_local_features
80
54
  @local_features = {}
81
- Dir.glob(File.join(application_root, 'config', 'features', '**', '*.local.yml')).each do |feature_configuration_file|
82
- @local_features.deep_merge!(downcase_feature_hash_keys(YAML.load_file(feature_configuration_file)))
83
- end
84
- main_local_features_file = File.join(application_root, 'config', 'features.local.yml')
85
- @local_features.deep_merge!(downcase_feature_hash_keys(YAML.load_file(main_local_features_file))) if File.exists?(main_local_features_file)
86
- @local_features
55
+ load_specific_features(@local_features, '.local.yml')
87
56
  end
57
+
88
58
  def features
89
59
  @features ||= load_features
90
60
  end
91
61
  def load_features
92
62
  @features = {}
93
- Dir.glob(File.join(application_root, 'config', 'features', '**', '*.yml')).each do |feature_configuration_file|
94
- @features.deep_merge!(downcase_feature_hash_keys(YAML.load_file(feature_configuration_file)))
95
- end
96
- main_features_file = File.join(application_root, 'config', 'features.yml')
97
- @features.deep_merge!(downcase_feature_hash_keys(YAML.load_file(main_features_file))) if File.exists?(main_features_file)
98
- @features
63
+ load_specific_features(@features, '.yml')
99
64
  end
65
+
100
66
  # performance optimization via caching of feature values resolved through environment variable overrides and local features
101
67
  def environment_features(environment)
102
68
  @environment_features ||= {}
@@ -106,7 +72,9 @@ module AbstractFeatureBranch
106
72
  @environment_features ||= {}
107
73
  features[environment] ||= {}
108
74
  local_features[environment] ||= {}
109
- @environment_features[environment] = features[environment].merge(local_features[environment]).merge(environment_variable_overrides)
75
+ @environment_features[environment] = features[environment].
76
+ merge(local_features[environment]).
77
+ merge(environment_variable_overrides)
110
78
  end
111
79
  def application_features
112
80
  unload_application_features unless cacheable?
@@ -129,24 +97,79 @@ module AbstractFeatureBranch
129
97
  value = (application_environment != 'development') if value.nil?
130
98
  value
131
99
  end
100
+
101
+ # Sets feature value (true or false) in storage (e.g. Redis client)
102
+ def set_store_feature(feature, value)
103
+ raise 'Feature storage (e.g. Redis) is not setup!' if feature_store.nil?
104
+ feature = feature.to_s
105
+ return delete_store_feature(feature) if value.nil?
106
+ value = 'true' if value == true
107
+ value = 'false' if value == false
108
+ feature_store.hset(REDIS_HKEY, feature, value)
109
+ end
110
+
111
+ # Gets feature value (true or false) from storage (e.g. Redis client)
112
+ def get_store_feature(feature)
113
+ raise 'Feature storage (e.g. Redis) is not setup!' if feature_store.nil?
114
+ feature = feature.to_s
115
+ value = feature_store.hget(REDIS_HKEY, feature)
116
+ if value.nil?
117
+ matching_feature = get_store_features.find { |store_feature| store_feature.downcase == feature.downcase }
118
+ value = feature_store.hget(REDIS_HKEY, matching_feature) if matching_feature
119
+ end
120
+ return nil if value.nil?
121
+ return 'per_user' if value.to_s.downcase == 'per_user'
122
+ value.to_s.downcase == 'true'
123
+ end
124
+
125
+ # Gets feature value (true or false) from storage (e.g. Redis client)
126
+ def delete_store_feature(feature)
127
+ raise 'Feature storage (e.g. Redis) is not setup!' if feature_store.nil?
128
+ feature = feature.to_s
129
+ feature_store.hdel(REDIS_HKEY, feature)
130
+ end
131
+
132
+ # Gets features array (all features) from storage (e.g. Redis client)
133
+ def get_store_features
134
+ raise 'Feature storage (e.g. Redis) is not setup!' if feature_store.nil?
135
+ feature_store.hkeys(REDIS_HKEY)
136
+ end
137
+
138
+ # Gets features array (all features) from storage (e.g. Redis client)
139
+ def clear_store_features
140
+ raise 'Feature storage (e.g. Redis) is not setup!' if feature_store.nil?
141
+ feature_store.hkeys(REDIS_HKEY).each do |feature|
142
+ feature_store.hdel(REDIS_HKEY, feature)
143
+ end
144
+ end
145
+
132
146
  def toggle_features_for_user(user_id, features)
133
147
  features.each do |name, value|
134
148
  if value
135
- user_features_storage.sadd("#{ENV_FEATURE_PREFIX}#{name.to_s.downcase}", user_id)
149
+ feature_store.sadd("#{ENV_FEATURE_PREFIX}#{name.to_s.downcase}", user_id)
136
150
  else
137
- user_features_storage.srem("#{ENV_FEATURE_PREFIX}#{name.to_s.downcase}", user_id)
151
+ feature_store.srem("#{ENV_FEATURE_PREFIX}#{name.to_s.downcase}", user_id)
138
152
  end
139
153
  end
140
154
  end
141
155
 
142
156
  private
143
157
 
158
+ def load_specific_features(features_hash, extension)
159
+ Dir.glob(File.join(application_root, 'config', 'features', '**', "*#{extension}")).each do |feature_configuration_file|
160
+ features_hash.deep_merge!(downcase_feature_hash_keys(YAML.load_file(feature_configuration_file)))
161
+ end
162
+ main_local_features_file = File.join(application_root, 'config', "features#{extension}")
163
+ features_hash.deep_merge!(downcase_feature_hash_keys(YAML.load_file(main_local_features_file))) if File.exists?(main_local_features_file)
164
+ features_hash
165
+ end
166
+
144
167
  def featureize_keys(hash)
145
168
  Hash[hash.map {|k, v| [k.sub(ENV_FEATURE_PREFIX, ''), v]}]
146
169
  end
147
170
 
148
171
  def select_feature_keys(hash)
149
- hash.reject {|k, v| !k.start_with?(ENV_FEATURE_PREFIX)} # using reject for Ruby 1.8 compatibility as select returns an array in it
172
+ hash.reject {|k, v| !k.downcase.start_with?(ENV_FEATURE_PREFIX)} # using reject for Ruby 1.8 compatibility as select returns an array in it
150
173
  end
151
174
 
152
175
  def booleanize_values(hash)
@@ -10,9 +10,10 @@ 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
- value = AbstractFeatureBranch.application_features[normalized_feature_name]
13
+ redis_override_value = AbstractFeatureBranch.get_store_feature(normalized_feature_name) rescue nil
14
+ value = !redis_override_value.nil? ? redis_override_value : AbstractFeatureBranch.application_features[normalized_feature_name]
14
15
  if value == 'per_user'
15
- value = AbstractFeatureBranch.user_features_storage.sismember("#{AbstractFeatureBranch::ENV_FEATURE_PREFIX}#{normalized_feature_name}", user_id)
16
+ value = !user_id.nil? && AbstractFeatureBranch.user_features_storage.sismember("#{AbstractFeatureBranch::ENV_FEATURE_PREFIX}#{normalized_feature_name}", user_id)
16
17
  end
17
18
  value
18
19
  end
@@ -26,4 +27,4 @@ class Object
26
27
  def feature_enabled?(feature_name, user_id = nil)
27
28
  Object.feature_enabled?(feature_name.to_s, user_id)
28
29
  end
29
- end
30
+ end
@@ -1,9 +1,8 @@
1
- require 'redis'
1
+ # Storage system for features (other than YAML/Env-Vars). Right now, only Redis is supported.
2
+ # AbstractFeatureBranch.feature_store = Redis.new
2
3
 
3
- # Storage for user features, customizable over here. Right now, only a Redis client is supported.
4
4
  # The following example line works with Heroku Redis To Go while still operating on local Redis for local development
5
- # AbstractFeatureBranch.user_features_storage = Redis.new(:url => ENV['REDISTOGO_URL'])
6
- AbstractFeatureBranch.user_features_storage = Redis.new
5
+ # AbstractFeatureBranch.feature_store = Redis.new(:url => ENV['REDISTOGO_URL'])
7
6
 
8
7
  # Application root where config/features.yml or config/features/ is found
9
8
  AbstractFeatureBranch.application_root = Rails.root
@@ -24,4 +23,4 @@ AbstractFeatureBranch.cacheable = {
24
23
  }
25
24
 
26
25
  # Pre-load application features to improve performance of first web-page hit
27
- AbstractFeatureBranch.load_application_features unless Rails.env.development?
26
+ AbstractFeatureBranch.load_application_features unless Rails.env.development?
data/ruby187.Gemfile CHANGED
@@ -1,12 +1,13 @@
1
1
  source 'http://rubygems.org'
2
2
 
3
- gem 'deep_merge', '1.0.0', :require => false #avoid loading into memory to use deep_merge only if Rails is unavailable
3
+ gem 'deep_merge', '1.0.0', :require => false #avoid loading to use only if Rails is unavailable
4
4
  gem 'redis', '~> 3.0.0', :require => false
5
5
 
6
6
  group :development do
7
7
  gem 'jeweler', '1.8.8'
8
- end
9
-
10
- group :test do
11
8
  gem 'rspec', '2.14.1'
12
- end
9
+
10
+ #Ruby 1.8.7 compatible versions
11
+ gem "nokogiri", "~> 1.5.0"
12
+ gem "highline", "~> 1.6.21"
13
+ end
@@ -25,16 +25,22 @@ describe 'feature_branch object extensions' do
25
25
  rescue => e
26
26
  #noop
27
27
  end
28
+ AbstractFeatureBranch.user_features_storage.keys.each do |key|
29
+ AbstractFeatureBranch.user_features_storage.del(key)
30
+ end
28
31
  end
29
32
  describe '#feature_branch' do
30
33
  context 'per user' do
31
34
  it 'feature branches correctly after storing feature configuration per user in a separate process (ensuring persistence)' do
32
35
  user_id = 'email1@example.com'
33
- Process.fork do
36
+ ruby_code = <<-RUBY_CODE
37
+ $:.unshift('.')
38
+ require 'redis'
39
+ require 'lib/abstract_feature_branch'
34
40
  AbstractFeatureBranch.initialize_user_features_storage
35
- AbstractFeatureBranch.toggle_features_for_user(user_id, :feature1 => false, :feature3 => true, :feature6 => true, :feature7 => false)
36
- end
37
- Process.wait
41
+ AbstractFeatureBranch.toggle_features_for_user('#{user_id}', :feature1 => false, :feature3 => true, :feature6 => true, :feature7 => false)
42
+ RUBY_CODE
43
+ system "ruby -e \"#{ruby_code}\""
38
44
  features_enabled = []
39
45
  feature_branch :feature1, user_id do
40
46
  features_enabled << :feature1
@@ -63,12 +69,15 @@ describe 'feature_branch object extensions' do
63
69
  end
64
70
  it 'update feature branching (disabling some features) after having stored feature configuration per user in a separate process (ensuring persistence)' do
65
71
  user_id = 'email1@example.com'
66
- Process.fork do
72
+ ruby_code = <<-RUBY_CODE
73
+ $:.unshift('.')
74
+ require 'redis'
75
+ require 'lib/abstract_feature_branch'
67
76
  AbstractFeatureBranch.initialize_user_features_storage
68
- AbstractFeatureBranch.toggle_features_for_user(user_id, :feature6 => true, :feature7 => false)
69
- AbstractFeatureBranch.toggle_features_for_user(user_id, :feature6 => false, :feature7 => true)
70
- end
71
- Process.wait
77
+ AbstractFeatureBranch.toggle_features_for_user('#{user_id}', :feature6 => true, :feature7 => false)
78
+ AbstractFeatureBranch.toggle_features_for_user('#{user_id}', :feature6 => false, :feature7 => true)
79
+ RUBY_CODE
80
+ system "ruby -e \"#{ruby_code}\""
72
81
  features_enabled = []
73
82
  feature_branch :feature6, user_id do
74
83
  features_enabled << :feature6
@@ -15,6 +15,9 @@ describe 'feature_branch object extensions' do
15
15
  AbstractFeatureBranch.application_root = @app_root_backup
16
16
  AbstractFeatureBranch.application_environment = @app_env_backup
17
17
  AbstractFeatureBranch.unload_application_features
18
+ AbstractFeatureBranch.user_features_storage.keys.each do |key|
19
+ AbstractFeatureBranch.user_features_storage.del(key)
20
+ end
18
21
  end
19
22
  describe '#feature_branch' do
20
23
  context 'class level behavior (case-insensitive string or symbol feature names)' do
@@ -63,6 +66,26 @@ describe 'feature_branch object extensions' do
63
66
  features_enabled.should_not include(:feature2)
64
67
  features_enabled.should include(:feature3)
65
68
  end
69
+ it 'allows redis variables (case-insensitive booleans) to override configuration file' do
70
+ AbstractFeatureBranch.unload_application_features
71
+ AbstractFeatureBranch.user_features_storage.hset('abstract_feature_branch', 'FEATURE1', 'FALSE')
72
+ AbstractFeatureBranch.user_features_storage.hset('abstract_feature_branch', 'Feature2', 'False')
73
+ AbstractFeatureBranch.user_features_storage.hset('abstract_feature_branch', 'feature3', 'true')
74
+ AbstractFeatureBranch.load_application_features
75
+ features_enabled = []
76
+ feature_branch :feature1 do
77
+ features_enabled << :feature1
78
+ end
79
+ feature_branch :feature2 do
80
+ features_enabled << :feature2
81
+ end
82
+ feature_branch :feature3 do
83
+ features_enabled << :feature3
84
+ end
85
+ features_enabled.should_not include(:feature1)
86
+ features_enabled.should_not include(:feature2)
87
+ features_enabled.should include(:feature3)
88
+ end
66
89
  it 'allows local configuration file to override main configuration file' do
67
90
  features_enabled = []
68
91
  feature_branch :feature4 do
@@ -15,6 +15,9 @@ describe 'feature_branch object extensions' do
15
15
  AbstractFeatureBranch.application_root = @app_root_backup
16
16
  AbstractFeatureBranch.application_environment = @app_env_backup
17
17
  AbstractFeatureBranch.unload_application_features
18
+ AbstractFeatureBranch.user_features_storage.keys.each do |key|
19
+ AbstractFeatureBranch.user_features_storage.del(key)
20
+ end
18
21
  end
19
22
  describe '#feature_enabled?' do
20
23
  it 'determines whether a feature is enabled or not in features configuration (case-insensitive string or symbol feature names)' do
@@ -35,6 +38,17 @@ describe 'feature_branch object extensions' do
35
38
  feature_enabled?(:feature3).should == true
36
39
  feature_enabled?(:feature4a).should == true #not overridden
37
40
  end
41
+ it 'allows redis variables (case-insensitive booleans) to override configuration file' do
42
+ AbstractFeatureBranch.unload_application_features
43
+ AbstractFeatureBranch.user_features_storage.hset('abstract_feature_branch', 'FEATURE1', 'FALSE')
44
+ AbstractFeatureBranch.user_features_storage.hset('abstract_feature_branch', 'Feature2', 'False')
45
+ AbstractFeatureBranch.user_features_storage.hset('abstract_feature_branch', 'feature3', 'true')
46
+ AbstractFeatureBranch.load_application_features
47
+ feature_enabled?(:feature1).should == false
48
+ feature_enabled?(:feature2).should == false
49
+ feature_enabled?(:feature3).should == true
50
+ feature_enabled?(:feature4a).should == true #not overridden
51
+ end
38
52
  it 'allows local configuration file to override main configuration file in test environment' do
39
53
  feature_enabled?(:feature4).should == false
40
54
  feature_enabled?(:feature5).should == true
metadata CHANGED
@@ -1,63 +1,104 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: abstract_feature_branch
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.1
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Annas "Andy" Maleh
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-01-23 00:00:00.000000000 Z
11
+ date: 2022-12-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: deep_merge
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '='
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
19
  version: 1.0.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '='
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: 1.0.0
27
27
  - !ruby/object:Gem::Dependency
28
- name: redis
28
+ name: jeweler
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ~>
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 3.0.0
34
- type: :runtime
33
+ version: 2.3.9
34
+ type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ~>
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 3.0.0
40
+ version: 2.3.9
41
41
  - !ruby/object:Gem::Dependency
42
- name: jeweler
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 2.1.4
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 2.1.4
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '='
60
+ - !ruby/object:Gem::Version
61
+ version: 2.14.1
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '='
67
+ - !ruby/object:Gem::Version
68
+ version: 2.14.1
69
+ - !ruby/object:Gem::Dependency
70
+ name: rdoc
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '='
74
+ - !ruby/object:Gem::Version
75
+ version: 5.1.0
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '='
81
+ - !ruby/object:Gem::Version
82
+ version: 5.1.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: psych
43
85
  requirement: !ruby/object:Gem::Requirement
44
86
  requirements:
45
87
  - - '='
46
88
  - !ruby/object:Gem::Version
47
- version: 1.8.8
89
+ version: 3.3.4
48
90
  type: :development
49
91
  prerelease: false
50
92
  version_requirements: !ruby/object:Gem::Requirement
51
93
  requirements:
52
94
  - - '='
53
95
  - !ruby/object:Gem::Version
54
- version: 1.8.8
96
+ version: 3.3.4
55
97
  description: |
56
98
  abstract_feature_branch is a Rails gem that enables developers to easily branch by abstraction as per this pattern:
57
99
  http://paulhammant.com/blog/branch_by_abstraction.html
58
100
 
59
- It is a productivity and fault tolerance enhancing team practice that has been utilized by professional software development
60
- teams at large corporations, such as Sears and Groupon.
101
+ It is a productivity and fault tolerance enhancing team practice.
61
102
 
62
103
  It provides the ability to wrap blocks of code with an abstract feature branch name, and then
63
104
  specify in a configuration file which features to be switched on or off.
@@ -73,18 +114,21 @@ description: |
73
114
  abstract_feature_branch additionally supports DDD's pattern of
74
115
  Bounded Contexts by allowing developers to configure
75
116
  context-specific feature files if needed.
76
- email:
117
+ email:
77
118
  executables: []
78
119
  extensions: []
79
120
  extra_rdoc_files:
121
+ - CHANGELOG.md
80
122
  - LICENSE.txt
81
123
  - README.md
82
124
  files:
83
- - .coveralls.yml
84
- - .travis.yml
125
+ - ".coveralls.yml"
126
+ - ".travis.yml"
127
+ - CHANGELOG.md
85
128
  - LICENSE.txt
86
129
  - README.md
87
130
  - RELEASE_NOTES.md
131
+ - TODO.md
88
132
  - VERSION
89
133
  - abstract_feature_branch.gemspec
90
134
  - config/features/admin.local.yml
@@ -93,7 +137,11 @@ files:
93
137
  - config/features/internal/wiki.yml
94
138
  - config/features/public.local.yml
95
139
  - config/features/public.yml
140
+ - img/BigAstronaut-Logo.png
141
+ - img/EarlyShares-Logo.svg
142
+ - img/Factor75-Logo.svg
96
143
  - lib/abstract_feature_branch.rb
144
+ - lib/abstract_feature_branch/configuration.rb
97
145
  - lib/abstract_feature_branch/file_beautifier.rb
98
146
  - lib/ext/feature_branch.rb
99
147
  - lib/generators/abstract_feature_branch/context_generator.rb
@@ -104,7 +152,6 @@ files:
104
152
  - lib/generators/templates/config/initializers/abstract_feature_branch.rb
105
153
  - lib/generators/templates/lib/tasks/abstract_feature_branch.rake
106
154
  - ruby187.Gemfile
107
- - ruby187.Gemfile.lock
108
155
  - spec/abstract_feature_branch/file_beautifier_spec.rb
109
156
  - spec/ext/feature_branch__feature_branch_per_user_spec.rb
110
157
  - spec/ext/feature_branch__feature_branch_spec.rb
@@ -130,24 +177,33 @@ homepage: http://github.com/AndyObtiva/abstract_feature_branch
130
177
  licenses:
131
178
  - MIT
132
179
  metadata: {}
133
- post_install_message:
180
+ post_install_message: "\nRails-only post-install instructions:\n\n1) Run the following
181
+ command to generate the Rails initializer and basic feature files:\n\nrails g abstract_feature_branch:install\n\n2)
182
+ Optionally, you may run this command to generate feature files per context:\n\nrails
183
+ g abstract_feature_branch:context context_path\n \n3) Optionally, install Redis
184
+ server with [Homebrew](https://brew.sh/) by running:\n\nbrew install redis\n\n4)
185
+ Optionally, install redis client gem (required with Redis server) by adding the
186
+ following line to Gemfile above abstract_feature_branch:\n\ngem 'redis', '~> 5.0.5'\n\nAfterwards,
187
+ run:\n\nbundle\n\n5) Optionally, customize configuration in config/initializers/abstract_feature_branch.rb\n\n(can
188
+ 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"
134
191
  rdoc_options: []
135
192
  require_paths:
136
193
  - lib
137
194
  required_ruby_version: !ruby/object:Gem::Requirement
138
195
  requirements:
139
- - - '>='
196
+ - - ">="
140
197
  - !ruby/object:Gem::Version
141
198
  version: '0'
142
199
  required_rubygems_version: !ruby/object:Gem::Requirement
143
200
  requirements:
144
- - - '>='
201
+ - - ">="
145
202
  - !ruby/object:Gem::Version
146
203
  version: '0'
147
204
  requirements: []
148
- rubyforge_project:
149
- rubygems_version: 2.0.6
150
- signing_key:
205
+ rubygems_version: 3.3.6
206
+ signing_key:
151
207
  specification_version: 4
152
208
  summary: 'abstract_feature_branch is a Rails gem that enables developers to easily
153
209
  branch by abstraction as per this pattern: http://paulhammant.com/blog/branch_by_abstraction.html'
data/ruby187.Gemfile.lock DELETED
@@ -1,63 +0,0 @@
1
- GEM
2
- remote: http://rubygems.org/
3
- specs:
4
- addressable (2.3.5)
5
- builder (3.2.2)
6
- deep_merge (1.0.0)
7
- diff-lcs (1.2.5)
8
- faraday (0.8.9)
9
- multipart-post (~> 1.2.0)
10
- git (1.2.6)
11
- github_api (0.10.1)
12
- addressable
13
- faraday (~> 0.8.1)
14
- hashie (>= 1.2)
15
- multi_json (~> 1.4)
16
- nokogiri (~> 1.5.2)
17
- oauth2
18
- hashie (2.0.5)
19
- highline (1.6.20)
20
- httpauth (0.2.0)
21
- jeweler (1.8.8)
22
- builder
23
- bundler (~> 1.0)
24
- git (>= 1.2.5)
25
- github_api (= 0.10.1)
26
- highline (>= 1.6.15)
27
- nokogiri (= 1.5.10)
28
- rake
29
- rdoc
30
- json (1.8.1)
31
- jwt (0.1.10)
32
- multi_json (>= 1.5)
33
- multi_json (1.8.4)
34
- multi_xml (0.5.5)
35
- multipart-post (1.2.0)
36
- nokogiri (1.5.10)
37
- oauth2 (0.9.2)
38
- faraday (~> 0.8)
39
- httpauth (~> 0.2)
40
- jwt (~> 0.1.4)
41
- multi_json (~> 1.0)
42
- multi_xml (~> 0.5)
43
- rack (~> 1.2)
44
- rack (1.5.2)
45
- rake (10.1.1)
46
- rdoc (4.1.1)
47
- json (~> 1.4)
48
- rspec (2.14.1)
49
- rspec-core (~> 2.14.0)
50
- rspec-expectations (~> 2.14.0)
51
- rspec-mocks (~> 2.14.0)
52
- rspec-core (2.14.7)
53
- rspec-expectations (2.14.4)
54
- diff-lcs (>= 1.1.3, < 2.0)
55
- rspec-mocks (2.14.4)
56
-
57
- PLATFORMS
58
- ruby
59
-
60
- DEPENDENCIES
61
- deep_merge (= 1.0.0)
62
- jeweler (= 1.8.8)
63
- rspec (= 2.14.1)