togl 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 21a490d4260342d1ab7ddcce025f11fdad6464d7
4
+ data.tar.gz: d6ca68b24b89b364b0ff534af5207ced033b145e
5
+ SHA512:
6
+ metadata.gz: a926954cd466dabb04212907cabf84a2411b74047fcdcca1a1d30d56a69364ddd3bf7822c3e262b8a39499972aca09c56d1fe3da5f7c2a95a006acc96794166d
7
+ data.tar.gz: bb9014d73d3bded301bb02825fbd4a6b271016de9882e12a0724cb8fcbf1110d919de1e745ba88333ec0f0f4b224a6f1d04b1db4cf5f2baa5a220058aacc806a
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ -rspec_helper
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+ gem "pry"
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Arne Brasseur
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.
@@ -0,0 +1,30 @@
1
+ # Togl
2
+
3
+
4
+ ## Installation
5
+
6
+ Add this line to your application's Gemfile:
7
+
8
+ ```ruby
9
+ gem 'togl'
10
+ ```
11
+
12
+ And then execute:
13
+
14
+ $ gem install -g
15
+
16
+
17
+ Or install it directly:
18
+
19
+ $ gem install togl
20
+
21
+ ## Usage
22
+
23
+
24
+ ## Contributing
25
+
26
+ 1. Fork it ( https://github.com/plexus/togl/fork )
27
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
28
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
29
+ 4. Push to the branch (`git push origin my-new-feature`)
30
+ 5. Create a new Pull Request
@@ -0,0 +1,31 @@
1
+ require 'rubygems/package_task'
2
+
3
+ spec = Gem::Specification.load(File.expand_path('../togl.gemspec', __FILE__))
4
+ gem = Gem::PackageTask.new(spec)
5
+ gem.define
6
+
7
+ desc "Push gem to rubygems.org"
8
+ task :push => :gem do
9
+ sh "git tag v#{Togl::VERSION}"
10
+ sh "git push --tags"
11
+ sh "gem push pkg/togl-#{Togl::VERSION}.gem"
12
+ end
13
+
14
+ require 'mutant'
15
+ task :default => :mutant
16
+
17
+ desc "run mutant"
18
+ task :mutant do
19
+ pattern = ENV.fetch('PATTERN', 'Togl*')
20
+ opts = ENV.fetch('MUTANT_OPTS', '').split(' ')
21
+ result = Mutant::CLI.run(%w[-Ilib -rtogl --use rspec --score 100] + opts + [pattern])
22
+ fail unless result == Mutant::CLI::EXIT_SUCCESS
23
+ end
24
+
25
+ require 'rspec/core/rake_task'
26
+
27
+ desc "run rspec"
28
+ RSpec::Core::RakeTask.new(:rspec) do |t, task_args|
29
+ t.rspec_opts = "-Ispec"
30
+ t.pattern = "spec"
31
+ end
@@ -0,0 +1,30 @@
1
+ require "attribs"
2
+ require "togl/version"
3
+ require "rack/utils"
4
+
5
+ module Togl
6
+ def self.config
7
+ @config ||= Config.new
8
+ end
9
+
10
+ def self.configure(&block)
11
+ Config::Builder.new(config, &block)
12
+ config
13
+ end
14
+
15
+ def on?(feature)
16
+ config.on?(feature)
17
+ end
18
+
19
+ def off?(feature)
20
+ config.on?(feature)
21
+ end
22
+ end
23
+
24
+ require "togl/feature"
25
+ require "togl/util"
26
+ require "togl/adapter"
27
+ require "togl/adapter/rack_session"
28
+ require "togl/config"
29
+ require "togl/config/builder"
30
+ require "togl/rack/middleware"
@@ -0,0 +1,11 @@
1
+ module Togl
2
+ class Adapter
3
+ def self.all
4
+ @all ||= {}
5
+ end
6
+
7
+ def self.register(name, callable)
8
+ Adapter.all[name] = callable
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Togl
2
+ class Adapter
3
+ class RackSession < self
4
+ register :rack_session, self
5
+
6
+ def self.call(name)
7
+ Thread.current[:togl_session_features][name.to_s]
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,51 @@
1
+ module Togl
2
+ class Config
3
+ include Attribs.new(:features, :adapters, :default_adapters)
4
+ attr_writer :default_adapters
5
+
6
+ def initialize(args = {}, &block)
7
+ super({features: [], adapters: Adapter.all, default_adapters: []}.merge(args))
8
+ Builder.new(self, &block) if block_given?
9
+ end
10
+
11
+ def add_feature(name, opts = {})
12
+ name = name.to_sym
13
+ opts = {
14
+ name: name,
15
+ config: self,
16
+ adapters: default_adapters
17
+ }.merge(opts)
18
+ features.push(Feature.new(opts))
19
+ self
20
+ end
21
+
22
+ def add_adapter(name, callable)
23
+ name = name.to_sym
24
+ adapters.merge!(name => callable)
25
+ self
26
+ end
27
+
28
+ def fetch(name)
29
+ name = name.to_sym
30
+ features.detect do |feature|
31
+ feature.name.equal?(name)
32
+ end
33
+ end
34
+
35
+ def fetch_adapter(name)
36
+ adapters.fetch(name.to_sym)
37
+ end
38
+
39
+ def on?(name)
40
+ fetch(name).on?
41
+ end
42
+
43
+ def off?(name)
44
+ !on?(name)
45
+ end
46
+
47
+ def rack_middleware
48
+ Rack::Middleware
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,22 @@
1
+ module Togl
2
+ class Config
3
+ class Builder
4
+ def initialize(config, &block)
5
+ @config = config
6
+ instance_eval(&block)
7
+ end
8
+
9
+ def feature(name, opts = {})
10
+ @config.add_feature(name, opts)
11
+ end
12
+
13
+ def adapter(name, callable)
14
+ @config.add_adapter(name, callable)
15
+ end
16
+
17
+ def adapters(*adapters)
18
+ @config.default_adapters = adapters
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,24 @@
1
+ module Togl
2
+ class Feature
3
+ include Attribs.new(:name, :config, default: :off, adapters: [])
4
+
5
+ def on?
6
+ on = adapters.reduce(nil) do |memo, adapter|
7
+ if [true, false].include?(memo)
8
+ memo
9
+ else
10
+ adapter_on?(adapter)
11
+ end
12
+ end
13
+ if on.nil?
14
+ default.equal?(:on)
15
+ else
16
+ on
17
+ end
18
+ end
19
+
20
+ def adapter_on?(adapter)
21
+ config.fetch_adapter(adapter).call(name)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,35 @@
1
+ module Togl
2
+ module Rack
3
+ class Middleware
4
+ def initialize(app)
5
+ @app = app
6
+ end
7
+
8
+ def call(env)
9
+ Thread.current[:togl_session_features] = detect_feature_params(env)
10
+ @app.call(env)
11
+ Thread.current[:togl_session_features] = nil
12
+ end
13
+
14
+ def detect_feature_params(env)
15
+ params = ::Rack::Utils.parse_query(env["QUERY_STRING"])
16
+ session = env["rack.session"]
17
+ session_features = session["features"] || {}
18
+ { ["enable_feature", "enable_features"] => true,
19
+ ["disable_feature", "disable_features"] => false,
20
+ ["reset_feature", "reset_features"] => nil }.each do |keys, flag|
21
+ keys.each do |key|
22
+ feature_names(params, key).each do |feature|
23
+ session_features[feature] = flag
24
+ end
25
+ end
26
+ end
27
+ session_features
28
+ end
29
+
30
+ def feature_names(params, key)
31
+ params.fetch(key, "").split(",").map(&:strip)
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,10 @@
1
+ module Togl
2
+ module Util
3
+ module_function
4
+
5
+ def camelize(str)
6
+ str.gsub(/\/(.?)/) { "::#{ $1.upcase }" }
7
+ .gsub!(/(?:^|_)(.)/) { $1.upcase }
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,3 @@
1
+ module Togl
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,30 @@
1
+ RSpec.describe "high level usage examples" do
2
+ let(:togl) do
3
+ Togl::Config.new do
4
+ adapters :rack_session
5
+
6
+ feature :hero
7
+ feature :frontend
8
+ end
9
+ end
10
+
11
+ specify do
12
+ called = false
13
+
14
+ app = ->(env) do
15
+ called = true
16
+
17
+ expect(togl.on? :hero).to be true
18
+ expect(togl.on? :frontend).to be false
19
+ end
20
+
21
+ app = togl.rack_middleware.new(app)
22
+ env = {
23
+ "rack.session" => {},
24
+ "QUERY_STRING" => "enable_feature=hero"
25
+ }
26
+ app.call(env)
27
+
28
+ expect(called).to be true
29
+ end
30
+ end
@@ -0,0 +1,16 @@
1
+ require 'bogus/rspec'
2
+ require 'timeout'
3
+ require 'togl'
4
+
5
+ RSpec.configure do |rspec|
6
+ rspec.backtrace_exclusion_patterns = [] if ENV['FULLSTACK']
7
+ rspec.disable_monkey_patching!
8
+ rspec.raise_errors_for_deprecations!
9
+ # rspec.around(:each) do |example|
10
+ # Timeout.timeout(1, &example)
11
+ # end
12
+ end
13
+
14
+ Bogus.configure do |bogus|
15
+ bogus.search_modules << Togl
16
+ end
@@ -0,0 +1,23 @@
1
+ RSpec.describe Togl::Config::Builder do
2
+ let(:config) { Togl::Config.new }
3
+ let!(:builder) {
4
+ Togl::Config::Builder.new(config) do
5
+ feature :foo, default: :on
6
+ feature :bar
7
+ adapters :rack_session
8
+ end
9
+ }
10
+
11
+ describe "#initialize" do
12
+ it "takes a Togl config and a configuration block" do
13
+ expect(config.fetch(:foo)).to eql Togl::Feature.new(name: :foo, default: :on, config: config)
14
+ end
15
+ end
16
+
17
+ describe "#feature" do
18
+ it "works with only a name" do
19
+ expect(config.fetch(:bar)).to eql Togl::Feature.new(name: :bar, config: config)
20
+
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,93 @@
1
+ RSpec.describe Togl::Config do
2
+ let(:config) do
3
+ described_class.new
4
+ .add_feature("foo")
5
+ .add_adapter("foo", ->(n){ :result })
6
+ .add_adapter("bar", ->(n){ :rasilt })
7
+ end
8
+
9
+ describe "#initialize" do
10
+ it "should take a block for building the config" do
11
+ config = described_class.new do
12
+ feature :foo
13
+ end
14
+
15
+ expect(config.features.map(&:name)).to eql [:foo]
16
+ end
17
+
18
+ it "should take arguments to override the defaults" do
19
+ config = described_class.new(default_adapters: [:rack, :session])
20
+ expect(config.default_adapters).to eql [:rack, :session]
21
+ end
22
+
23
+ it "should have defaults for its attributes" do
24
+ config = described_class.new
25
+ expect(config.features).to eql []
26
+ expect(config.adapters).to eql Togl::Adapter.all
27
+ expect(config.default_adapters).to eql []
28
+ end
29
+ end
30
+
31
+ describe "#add_feature" do
32
+ it "should append a feature to the list" do
33
+ expect(config.features).to eql [Togl::Feature.new(name: :foo, config: config)]
34
+ end
35
+
36
+ it "takes options" do
37
+ config.add_feature(:wammie, adapters: [:redis, :rack])
38
+ expect(config.fetch(:wammie))
39
+ .to eql Togl::Feature.new(name: :wammie, config: config, adapters: [:redis, :rack])
40
+ end
41
+
42
+ it "should use default adapters if none given" do
43
+ config.default_adapters.push(:rack)
44
+ config.add_feature(:lisa)
45
+ expect(config.fetch(:lisa)).to eql Togl::Feature.new(name: :lisa, config: config, adapters: [:rack])
46
+ end
47
+ end
48
+
49
+ describe '#fetch' do
50
+ let(:config) do
51
+ described_class.new
52
+ .add_feature(:foo)
53
+ .add_feature("bar")
54
+ .add_feature(:baz)
55
+ end
56
+
57
+ it "should find a feature object by name" do
58
+ expect(config.fetch("bar")).to eql Togl::Feature.new(name: :bar, config: config)
59
+ end
60
+ end
61
+
62
+ describe "#on?" do
63
+ fake(:feature, name: :disrupt)
64
+ it "should delegate to the feature" do
65
+ config = self.config.append_to(:features, feature)
66
+
67
+ config.on?("disrupt")
68
+ expect(feature).to have_received.on?
69
+ end
70
+ end
71
+
72
+ describe "#add_adapter" do
73
+
74
+ it "should store the adapter" do
75
+ expect(config.adapters[:foo].call(:bar)).to equal :result
76
+ end
77
+ end
78
+
79
+ describe "#fetch_adapter" do
80
+ it "should return the adapter by name" do
81
+ expect(config.fetch_adapter("bar").call(1)).to equal :rasilt
82
+ end
83
+ end
84
+
85
+ describe "rack_middleware" do
86
+ it "should return a rack middleware builder" do
87
+ Togl::Config::Builder.new(config) do
88
+ adapters :rack_session
89
+ end
90
+ expect(config.rack_middleware.new(->(env){})).to be_a Togl::Rack::Middleware
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,63 @@
1
+ RSpec.describe Togl::Feature do
2
+ subject(:feature) do
3
+ described_class.new(
4
+ name: name,
5
+ config: config,
6
+ default: default,
7
+ adapters: adapters
8
+ )
9
+ end
10
+
11
+ let(:name) { :eric }
12
+ let(:config) { Togl::Config.new }
13
+ let(:default) { :off }
14
+ let(:adapters) { [] }
15
+
16
+ describe "#on?" do
17
+ it "should be disabled by default" do
18
+ expect(feature.on?).to be false
19
+ end
20
+
21
+ context "when on by default" do
22
+ let(:adapters) { [:s1, :s2] }
23
+ let(:default) { :on }
24
+
25
+ it "should be on if all strategues return nil" do
26
+ config
27
+ .add_adapter(:s1, ->(name){ nil })
28
+ .add_adapter(:s2, ->(name){ nil })
29
+ expect(feature.on?).to be true
30
+ end
31
+ end
32
+
33
+ context "with adapters" do
34
+ let(:adapters) { [:s1, :s2] }
35
+
36
+ it "should be on if the adapter returns true - skipping nils" do
37
+ config
38
+ .add_adapter(:s1, ->(name){ nil })
39
+ .add_adapter(:s2, ->(name){ name == :eric })
40
+ expect(feature.on?).to be true
41
+ end
42
+
43
+ it "should be off if the adapter returns false - skipping nils" do
44
+ config
45
+ .add_adapter(:s1, ->(name){ nil })
46
+ .add_adapter(:s2, ->(name){ name != :eric })
47
+ expect(feature.on?).to be false
48
+ end
49
+
50
+ it "should be on if the adapter returns true" do
51
+ config
52
+ .add_adapter(:s1, ->(name){ name == :eric })
53
+ expect(feature.on?).to be true
54
+ end
55
+
56
+ it "should be off if the adapter returns false" do
57
+ config
58
+ .add_adapter(:s1, ->(name){ name != :eric })
59
+ expect(feature.on?).to be false
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,11 @@
1
+ RSpec.describe Togl do
2
+ describe ".config" do
3
+ it "should return a Togl::Config" do
4
+ expect(Togl.config).to be_a Togl::Config
5
+ end
6
+
7
+ it "should memoize" do
8
+ expect(Togl.config).to equal Togl.config
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+
3
+ require File.expand_path("../lib/togl/version", __FILE__)
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "togl"
7
+ spec.version = Togl::VERSION
8
+ spec.authors = ["Arne Brasseur"]
9
+ spec.email = ["arne@arnebrasseur.net"]
10
+ spec.summary = %q{Perfect Features Toggles}
11
+ spec.description = %q{Multi-strategy feature flags.}
12
+ spec.homepage = "https://github.com/plexus/togl"
13
+ spec.license = "MIT"
14
+
15
+ spec.require_paths = ["lib"]
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^spec/})
19
+ spec.extra_rdoc_files = %w[README.md]
20
+
21
+ spec.add_runtime_dependency "rack"
22
+ spec.add_runtime_dependency "attribs", "~> 1.0"
23
+
24
+ spec.add_development_dependency "rake"
25
+ spec.add_development_dependency "rspec", "~> 3.1"
26
+ spec.add_development_dependency "mutant-rspec"
27
+ spec.add_development_dependency "bogus"
28
+ end
metadata ADDED
@@ -0,0 +1,157 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: togl
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Arne Brasseur
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-04-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rack
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: attribs
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '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: '3.1'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.1'
69
+ - !ruby/object:Gem::Dependency
70
+ name: mutant-rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: bogus
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: Multi-strategy feature flags.
98
+ email:
99
+ - arne@arnebrasseur.net
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files:
103
+ - README.md
104
+ files:
105
+ - ".gitignore"
106
+ - ".rspec"
107
+ - Gemfile
108
+ - LICENSE.txt
109
+ - README.md
110
+ - Rakefile
111
+ - lib/togl.rb
112
+ - lib/togl/adapter.rb
113
+ - lib/togl/adapter/rack_session.rb
114
+ - lib/togl/config.rb
115
+ - lib/togl/config/builder.rb
116
+ - lib/togl/feature.rb
117
+ - lib/togl/rack/middleware.rb
118
+ - lib/togl/util.rb
119
+ - lib/togl/version.rb
120
+ - spec/integration_spec.rb
121
+ - spec/spec_helper.rb
122
+ - spec/togl/config/builder_spec.rb
123
+ - spec/togl/config_spec.rb
124
+ - spec/togl/feature_spec.rb
125
+ - spec/togl_spec.rb
126
+ - togl.gemspec
127
+ homepage: https://github.com/plexus/togl
128
+ licenses:
129
+ - MIT
130
+ metadata: {}
131
+ post_install_message:
132
+ rdoc_options: []
133
+ require_paths:
134
+ - lib
135
+ required_ruby_version: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
140
+ required_rubygems_version: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: '0'
145
+ requirements: []
146
+ rubyforge_project:
147
+ rubygems_version: 2.2.2
148
+ signing_key:
149
+ specification_version: 4
150
+ summary: Perfect Features Toggles
151
+ test_files:
152
+ - spec/integration_spec.rb
153
+ - spec/spec_helper.rb
154
+ - spec/togl/config/builder_spec.rb
155
+ - spec/togl/config_spec.rb
156
+ - spec/togl/feature_spec.rb
157
+ - spec/togl_spec.rb