offs 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/.rspec +2 -0
- data/.travis.yml +3 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +90 -0
- data/Rakefile +7 -0
- data/lib/offs/version.rb +3 -0
- data/lib/offs.rb +64 -0
- data/offs.gemspec +29 -0
- data/spec/offs_spec.rb +63 -0
- data/spec/spec_helper.rb +2 -0
- metadata +118 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f7f44fb139c3f2a88d2510ee22559e18037d9a32
|
4
|
+
data.tar.gz: 0b224e3575e8f241ffec5e5f2a370b2d402ba565
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fcea828f9ec2c1819e231f8964083575d8f1d83277ee3371826d62c1b4057d6487e6a5f6da178b9c3621dd7c0616d04539ab2c8534d22205ef042238559b9ee0
|
7
|
+
data.tar.gz: 19b9c2ccbb99a95b397421a2c17731408cf73a6502098d7bb3ab1a2acf6412d8c22200b609759e0b1f11db1744107ddff8be2c583fa69ed964c4fcb7f9a837cc
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 John Wilger
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
# OFFS Feature Flagging System
|
2
|
+
|
3
|
+
OFFS allows new features-in-progress to be constantly integrated with
|
4
|
+
a project's master or production code branch by allowing the code to
|
5
|
+
take different branches depending on how the feature flags are
|
6
|
+
configured.
|
7
|
+
|
8
|
+
## Installation
|
9
|
+
|
10
|
+
Add this line to your application's Gemfile:
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
gem 'offs'
|
14
|
+
```
|
15
|
+
|
16
|
+
And then execute:
|
17
|
+
|
18
|
+
$ bundle
|
19
|
+
|
20
|
+
Or install it yourself as:
|
21
|
+
|
22
|
+
$ gem install offs
|
23
|
+
|
24
|
+
## Usage
|
25
|
+
|
26
|
+
Let's say you are working on an application and are going to add a hot
|
27
|
+
new feature that is virtually guaranteed to make you millions of
|
28
|
+
dollars. You want to continuously integrate the new code into the master
|
29
|
+
branch of the repository to avoid merging-headaches down the line (there
|
30
|
+
are other developers working on other features at the same time), but
|
31
|
+
you need to keep the master branch in a deployable state. OFFS allows
|
32
|
+
you to do just that.
|
33
|
+
|
34
|
+
First, you need to decide on the name for your feature flag and tell
|
35
|
+
OFFS about it when your application loads. For instance, in a Rails app,
|
36
|
+
you could put the following in `config/initializers/offs_flags.rb`:
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
require 'offs'
|
40
|
+
|
41
|
+
OFFS.flag :use_my_million_dollar_idea, false
|
42
|
+
OFFS.flag :use_this_mostly_done_feature, true
|
43
|
+
```
|
44
|
+
|
45
|
+
You've now defined the flags that your app will use, and you've given
|
46
|
+
each flag a default value where `true` means you will use the new
|
47
|
+
feature and `false` means you will use the old code instead.
|
48
|
+
|
49
|
+
When running your application, you can override the default flag setting
|
50
|
+
by setting environment variables. For instance, to reverse both of the
|
51
|
+
flags above when running `rake` on your application code, you would do
|
52
|
+
this:
|
53
|
+
|
54
|
+
```sh
|
55
|
+
USE_MY_MILLION_DOLLAR_IDEA=1 USE_THIS_MOSTLY_DONE_FEATURE=0 rake
|
56
|
+
```
|
57
|
+
|
58
|
+
In your code, simply do the following in each place where you have new
|
59
|
+
and/or existing code that should be run or not run depending on the
|
60
|
+
feature flag setting:
|
61
|
+
|
62
|
+
```ruby
|
63
|
+
class Foo
|
64
|
+
def do_something
|
65
|
+
OFFS.so_you_want_to(:use_my_million_dollar_idea) do |you|
|
66
|
+
you.would_like_to do
|
67
|
+
# this is where you put the new code that will run when the flag
|
68
|
+
# is *on*.
|
69
|
+
end
|
70
|
+
|
71
|
+
you.may_still_need_to do
|
72
|
+
# this is where you put the old code that will run when the flag
|
73
|
+
# is *off*
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
```
|
79
|
+
|
80
|
+
Note that you are not required to have *both* the `would_like_to` and
|
81
|
+
`may_still_need_to` blocks present; they simply become a noop if not
|
82
|
+
present.
|
83
|
+
|
84
|
+
## Contributing
|
85
|
+
|
86
|
+
1. Fork it ( https://github.com/jwilger/offs/fork )
|
87
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
88
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
89
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
90
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/lib/offs/version.rb
ADDED
data/lib/offs.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
require "offs/version"
|
2
|
+
require 'injectable_dependencies'
|
3
|
+
|
4
|
+
class OFFS
|
5
|
+
include InjectableDependencies
|
6
|
+
|
7
|
+
UndefinedFlagError = Class.new(StandardError)
|
8
|
+
|
9
|
+
class << self
|
10
|
+
def so_you_want_to(flag, &block)
|
11
|
+
new(flag).so_you_want_to(&block)
|
12
|
+
end
|
13
|
+
|
14
|
+
def flag(name, default)
|
15
|
+
env_var_name = name.to_s.upcase
|
16
|
+
feature_flags[name] = if ENV.has_key?(env_var_name)
|
17
|
+
ENV[env_var_name].strip == '1'
|
18
|
+
else
|
19
|
+
default
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def feature_flags
|
24
|
+
@feature_flags ||= {}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
dependency(:feature_flags) { OFFS.feature_flags }
|
29
|
+
|
30
|
+
def initialize(flag, options={})
|
31
|
+
initialize_dependencies options[:dependencies]
|
32
|
+
self.flag = flag
|
33
|
+
end
|
34
|
+
|
35
|
+
def so_you_want_to(&block)
|
36
|
+
block.call(self)
|
37
|
+
end
|
38
|
+
|
39
|
+
def would_like_to(&block)
|
40
|
+
return unless flag_is_on?
|
41
|
+
block.call
|
42
|
+
end
|
43
|
+
|
44
|
+
def may_still_need_to(&block)
|
45
|
+
return if flag_is_on?
|
46
|
+
block.call
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
attr_reader :flag
|
52
|
+
|
53
|
+
def flag_is_on?
|
54
|
+
!!feature_flags[flag]
|
55
|
+
end
|
56
|
+
|
57
|
+
def flag=(new_flag)
|
58
|
+
if feature_flags.has_key?(new_flag)
|
59
|
+
@flag = new_flag
|
60
|
+
else
|
61
|
+
raise UndefinedFlagError, "The #{new_flag} flag has not been defined."
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/offs.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'offs/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "offs"
|
8
|
+
spec.version = OFFS::VERSION
|
9
|
+
spec.authors = ["John Wilger"]
|
10
|
+
spec.email = ["johnwilger@gmail.com"]
|
11
|
+
spec.summary = %q{OFFS Feature Flagging System}
|
12
|
+
spec.description = %q{OFFS provides a means to demarcate code that is
|
13
|
+
related to new features as well as the old code path
|
14
|
+
and switch between the two depending on
|
15
|
+
configuration.}
|
16
|
+
spec.homepage = ""
|
17
|
+
spec.license = "MIT"
|
18
|
+
|
19
|
+
spec.files = `git ls-files -z`.split("\x0")
|
20
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
21
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
22
|
+
spec.require_paths = ["lib"]
|
23
|
+
|
24
|
+
spec.add_dependency "injectable_dependencies"
|
25
|
+
|
26
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
27
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
28
|
+
spec.add_development_dependency "rspec"
|
29
|
+
end
|
data/spec/offs_spec.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe OFFS do
|
4
|
+
it 'has a version number' do
|
5
|
+
expect(described_class::VERSION).not_to be nil
|
6
|
+
end
|
7
|
+
|
8
|
+
subject { described_class.new(flag, dependencies: dependencies) }
|
9
|
+
|
10
|
+
let(:flag) { :my_cool_new_feature }
|
11
|
+
|
12
|
+
let(:dependencies) {{
|
13
|
+
feature_flags: feature_flags
|
14
|
+
}}
|
15
|
+
|
16
|
+
let(:feature_flags) {{
|
17
|
+
:my_cool_new_feature => feature_status
|
18
|
+
}}
|
19
|
+
|
20
|
+
let(:feature_status) { true }
|
21
|
+
|
22
|
+
context 'when the specified feature flag is not defined' do
|
23
|
+
let(:feature_flags) {{}}
|
24
|
+
|
25
|
+
it 'raises an error' do
|
26
|
+
expect{ subject.so_you_want_to {} }.to \
|
27
|
+
raise_error(OFFS::UndefinedFlagError,
|
28
|
+
"The #{flag} flag has not been defined.")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context "when the specified feature flag is defined" do
|
33
|
+
let(:would_like_to_blk) { ->{} }
|
34
|
+
let(:may_still_need_to_blk) { ->{} }
|
35
|
+
|
36
|
+
after(:each) do
|
37
|
+
subject.so_you_want_to do |you|
|
38
|
+
you.would_like_to(&would_like_to_blk)
|
39
|
+
you.may_still_need_to(&may_still_need_to_blk)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context "and the feature is turned on by default" do
|
44
|
+
it 'executes the would_like_to block' do
|
45
|
+
expect(would_like_to_blk).to receive(:call)
|
46
|
+
end
|
47
|
+
it 'does not execute the may_still_need_to block' do
|
48
|
+
expect(may_still_need_to_blk).to_not receive(:call)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context "and the feature is turned off by default" do
|
53
|
+
let(:feature_status) { false }
|
54
|
+
|
55
|
+
it "executes the may_still_need_to block" do
|
56
|
+
expect(may_still_need_to_blk).to receive(:call)
|
57
|
+
end
|
58
|
+
it 'does not execute the would_like_to block' do
|
59
|
+
expect(would_like_to_blk).to_not receive(:call)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: offs
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- John Wilger
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-08-21 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: injectable_dependencies
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.7'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.7'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '10.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '10.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description: |-
|
70
|
+
OFFS provides a means to demarcate code that is
|
71
|
+
related to new features as well as the old code path
|
72
|
+
and switch between the two depending on
|
73
|
+
configuration.
|
74
|
+
email:
|
75
|
+
- johnwilger@gmail.com
|
76
|
+
executables: []
|
77
|
+
extensions: []
|
78
|
+
extra_rdoc_files: []
|
79
|
+
files:
|
80
|
+
- ".gitignore"
|
81
|
+
- ".rspec"
|
82
|
+
- ".travis.yml"
|
83
|
+
- Gemfile
|
84
|
+
- LICENSE.txt
|
85
|
+
- README.md
|
86
|
+
- Rakefile
|
87
|
+
- lib/offs.rb
|
88
|
+
- lib/offs/version.rb
|
89
|
+
- offs.gemspec
|
90
|
+
- spec/offs_spec.rb
|
91
|
+
- spec/spec_helper.rb
|
92
|
+
homepage: ''
|
93
|
+
licenses:
|
94
|
+
- MIT
|
95
|
+
metadata: {}
|
96
|
+
post_install_message:
|
97
|
+
rdoc_options: []
|
98
|
+
require_paths:
|
99
|
+
- lib
|
100
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
requirements: []
|
111
|
+
rubyforge_project:
|
112
|
+
rubygems_version: 2.2.2
|
113
|
+
signing_key:
|
114
|
+
specification_version: 4
|
115
|
+
summary: OFFS Feature Flagging System
|
116
|
+
test_files:
|
117
|
+
- spec/offs_spec.rb
|
118
|
+
- spec/spec_helper.rb
|