flipper 0.11.0.beta6 → 0.11.0.beta7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Changelog.md +2 -0
- data/README.md +18 -10
- data/docs/Adapters.md +1 -0
- data/docs/Optimization.md +31 -0
- data/examples/basic.rb +21 -17
- data/examples/configuring_default.rb +23 -0
- data/examples/percentage_of_actors.rb +3 -4
- data/examples/percentage_of_time.rb +3 -3
- data/flipper-cache-store.gemspec +24 -0
- data/lib/flipper.rb +59 -9
- data/lib/flipper/configuration.rb +32 -0
- data/lib/flipper/dsl.rb +0 -1
- data/lib/flipper/errors.rb +9 -2
- data/lib/flipper/gate_values.rb +2 -2
- data/lib/flipper/gates/group.rb +2 -6
- data/lib/flipper/gates/percentage_of_actors.rb +3 -1
- data/lib/flipper/typecast.rb +24 -0
- data/lib/flipper/types/percentage.rb +1 -1
- data/lib/flipper/version.rb +1 -1
- data/spec/flipper/configuration_spec.rb +16 -0
- data/spec/flipper/dsl_spec.rb +18 -0
- data/spec/flipper/gates/percentage_of_actors_spec.rb +29 -7
- data/spec/flipper/gates/percentage_of_time_spec.rb +30 -0
- data/spec/flipper/typecast_spec.rb +55 -0
- data/spec/flipper_spec.rb +200 -30
- data/spec/helper.rb +1 -0
- data/spec/integration_spec.rb +68 -3
- metadata +7 -5
- data/lib/flipper/adapters/cache_store.rb +0 -104
- data/spec/flipper/adapters/cache_store_spec.rb +0 -50
data/spec/helper.rb
CHANGED
data/spec/integration_spec.rb
CHANGED
@@ -132,6 +132,29 @@ RSpec.describe Flipper do
|
|
132
132
|
end
|
133
133
|
end
|
134
134
|
|
135
|
+
context 'with a float percentage of actors' do
|
136
|
+
before do
|
137
|
+
@result = feature.enable_percentage_of_actors 5.1
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'returns true' do
|
141
|
+
expect(@result).to eq(true)
|
142
|
+
end
|
143
|
+
|
144
|
+
it 'enables feature for actor within percentage' do
|
145
|
+
enabled = (1..100).select do |i|
|
146
|
+
thing = Flipper::Actor.new(i)
|
147
|
+
feature.enabled?(thing)
|
148
|
+
end.size
|
149
|
+
|
150
|
+
expect(enabled).to be_within(2).of(5)
|
151
|
+
end
|
152
|
+
|
153
|
+
it 'adds feature to set of features' do
|
154
|
+
expect(flipper.features.map(&:name)).to include(:search)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
135
158
|
context 'with a percentage of time' do
|
136
159
|
before do
|
137
160
|
@gate = feature.gate(:percentage_of_time)
|
@@ -411,10 +434,27 @@ RSpec.describe Flipper do
|
|
411
434
|
end
|
412
435
|
end
|
413
436
|
|
414
|
-
context 'for
|
437
|
+
context 'for enabled float percentage of time' do
|
415
438
|
before do
|
416
|
-
# ensure percentage of time returns percentage that makes
|
417
|
-
# of time
|
439
|
+
# ensure percentage of time returns percentage that makes 4.1 percent
|
440
|
+
# of time true
|
441
|
+
@gate = feature.gate(:percentage_of_time)
|
442
|
+
allow(@gate).to receive_messages(rand: 0.04)
|
443
|
+
|
444
|
+
feature.enable_percentage_of_time 4.1
|
445
|
+
end
|
446
|
+
|
447
|
+
it 'returns true' do
|
448
|
+
expect(feature.enabled?).to eq(true)
|
449
|
+
expect(feature.enabled?(nil)).to eq(true)
|
450
|
+
expect(feature.enabled?(pitt)).to eq(true)
|
451
|
+
expect(feature.enabled?(admin_thing)).to eq(true)
|
452
|
+
end
|
453
|
+
end
|
454
|
+
|
455
|
+
context 'for NOT enabled integer percentage of time' do
|
456
|
+
before do
|
457
|
+
# ensure percentage of time returns percentage that makes enabled? false
|
418
458
|
@gate = feature.gate(:percentage_of_time)
|
419
459
|
allow(@gate).to receive_messages(rand: 0.10)
|
420
460
|
|
@@ -437,6 +477,31 @@ RSpec.describe Flipper do
|
|
437
477
|
end
|
438
478
|
end
|
439
479
|
|
480
|
+
context 'for NOT enabled float percentage of time' do
|
481
|
+
before do
|
482
|
+
# ensure percentage of time returns percentage that makes enabled? false
|
483
|
+
@gate = feature.gate(:percentage_of_time)
|
484
|
+
allow(@gate).to receive_messages(rand: 0.10)
|
485
|
+
|
486
|
+
feature.enable_percentage_of_time 9.9
|
487
|
+
end
|
488
|
+
|
489
|
+
it 'returns false' do
|
490
|
+
expect(feature.enabled?).to eq(false)
|
491
|
+
expect(feature.enabled?(nil)).to eq(false)
|
492
|
+
expect(feature.enabled?(pitt)).to eq(false)
|
493
|
+
expect(feature.enabled?(admin_thing)).to eq(false)
|
494
|
+
end
|
495
|
+
|
496
|
+
it 'returns true if boolean enabled' do
|
497
|
+
feature.enable
|
498
|
+
expect(feature.enabled?).to eq(true)
|
499
|
+
expect(feature.enabled?(nil)).to eq(true)
|
500
|
+
expect(feature.enabled?(pitt)).to eq(true)
|
501
|
+
expect(feature.enabled?(admin_thing)).to eq(true)
|
502
|
+
end
|
503
|
+
end
|
504
|
+
|
440
505
|
context 'for a non flipper thing' do
|
441
506
|
before do
|
442
507
|
feature.enable admin_group
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flipper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.11.0.
|
4
|
+
version: 0.11.0.beta7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Nunemaker
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-07-26 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Feature flipper is the act of enabling/disabling features in your application,
|
14
14
|
ideally without re-deploying or changing anything in your code base. Flipper makes
|
@@ -38,6 +38,7 @@ files:
|
|
38
38
|
- docs/http/README.md
|
39
39
|
- docs/read-only/README.md
|
40
40
|
- examples/basic.rb
|
41
|
+
- examples/configuring_default.rb
|
41
42
|
- examples/dsl.rb
|
42
43
|
- examples/enabled_for_actor.rb
|
43
44
|
- examples/example_setup.rb
|
@@ -51,11 +52,11 @@ files:
|
|
51
52
|
- examples/percentage_of_actors_enabled_check.rb
|
52
53
|
- examples/percentage_of_actors_group.rb
|
53
54
|
- examples/percentage_of_time.rb
|
55
|
+
- flipper-cache-store.gemspec
|
54
56
|
- flipper.gemspec
|
55
57
|
- lib/flipper.rb
|
56
58
|
- lib/flipper/actor.rb
|
57
59
|
- lib/flipper/adapter.rb
|
58
|
-
- lib/flipper/adapters/cache_store.rb
|
59
60
|
- lib/flipper/adapters/http.rb
|
60
61
|
- lib/flipper/adapters/http/client.rb
|
61
62
|
- lib/flipper/adapters/http/error.rb
|
@@ -65,6 +66,7 @@ files:
|
|
65
66
|
- lib/flipper/adapters/operation_logger.rb
|
66
67
|
- lib/flipper/adapters/pstore.rb
|
67
68
|
- lib/flipper/adapters/read_only.rb
|
69
|
+
- lib/flipper/configuration.rb
|
68
70
|
- lib/flipper/dsl.rb
|
69
71
|
- lib/flipper/errors.rb
|
70
72
|
- lib/flipper/feature.rb
|
@@ -101,7 +103,6 @@ files:
|
|
101
103
|
- spec/fixtures/feature.json
|
102
104
|
- spec/flipper/actor_spec.rb
|
103
105
|
- spec/flipper/adapter_spec.rb
|
104
|
-
- spec/flipper/adapters/cache_store_spec.rb
|
105
106
|
- spec/flipper/adapters/http_spec.rb
|
106
107
|
- spec/flipper/adapters/instrumented_spec.rb
|
107
108
|
- spec/flipper/adapters/memoizable_spec.rb
|
@@ -109,6 +110,7 @@ files:
|
|
109
110
|
- spec/flipper/adapters/operation_logger_spec.rb
|
110
111
|
- spec/flipper/adapters/pstore_spec.rb
|
111
112
|
- spec/flipper/adapters/read_only_spec.rb
|
113
|
+
- spec/flipper/configuration_spec.rb
|
112
114
|
- spec/flipper/dsl_spec.rb
|
113
115
|
- spec/flipper/feature_check_context_spec.rb
|
114
116
|
- spec/flipper/feature_spec.rb
|
@@ -171,7 +173,6 @@ test_files:
|
|
171
173
|
- spec/fixtures/feature.json
|
172
174
|
- spec/flipper/actor_spec.rb
|
173
175
|
- spec/flipper/adapter_spec.rb
|
174
|
-
- spec/flipper/adapters/cache_store_spec.rb
|
175
176
|
- spec/flipper/adapters/http_spec.rb
|
176
177
|
- spec/flipper/adapters/instrumented_spec.rb
|
177
178
|
- spec/flipper/adapters/memoizable_spec.rb
|
@@ -179,6 +180,7 @@ test_files:
|
|
179
180
|
- spec/flipper/adapters/operation_logger_spec.rb
|
180
181
|
- spec/flipper/adapters/pstore_spec.rb
|
181
182
|
- spec/flipper/adapters/read_only_spec.rb
|
183
|
+
- spec/flipper/configuration_spec.rb
|
182
184
|
- spec/flipper/dsl_spec.rb
|
183
185
|
- spec/flipper/feature_check_context_spec.rb
|
184
186
|
- spec/flipper/feature_spec.rb
|
@@ -1,104 +0,0 @@
|
|
1
|
-
module Flipper
|
2
|
-
module Adapters
|
3
|
-
# Public: Adapter that wraps another adapter with the ability to cache
|
4
|
-
# adapter calls in ActiveSupport::CacheStore caches.
|
5
|
-
#
|
6
|
-
class CacheStore
|
7
|
-
include ::Flipper::Adapter
|
8
|
-
|
9
|
-
Version = 'v1'.freeze
|
10
|
-
Namespace = "flipper/#{Version}".freeze
|
11
|
-
FeaturesKey = "#{Namespace}/features".freeze
|
12
|
-
|
13
|
-
# Private
|
14
|
-
def self.key_for(key)
|
15
|
-
"#{Namespace}/feature/#{key}"
|
16
|
-
end
|
17
|
-
|
18
|
-
# Internal
|
19
|
-
attr_reader :cache
|
20
|
-
|
21
|
-
# Public: The name of the adapter.
|
22
|
-
attr_reader :name
|
23
|
-
|
24
|
-
# Public
|
25
|
-
def initialize(adapter, cache, expires_in: nil)
|
26
|
-
@adapter = adapter
|
27
|
-
@name = :cache_store
|
28
|
-
@cache = cache
|
29
|
-
@write_options = {}
|
30
|
-
@write_options.merge!(expires_in: expires_in) if expires_in
|
31
|
-
end
|
32
|
-
|
33
|
-
# Public
|
34
|
-
def features
|
35
|
-
@cache.fetch(FeaturesKey, @write_options) do
|
36
|
-
@adapter.features
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
# Public
|
41
|
-
def add(feature)
|
42
|
-
result = @adapter.add(feature)
|
43
|
-
@cache.delete(FeaturesKey)
|
44
|
-
result
|
45
|
-
end
|
46
|
-
|
47
|
-
## Public
|
48
|
-
def remove(feature)
|
49
|
-
result = @adapter.remove(feature)
|
50
|
-
@cache.delete(FeaturesKey)
|
51
|
-
@cache.delete(key_for(feature.key))
|
52
|
-
result
|
53
|
-
end
|
54
|
-
|
55
|
-
## Public
|
56
|
-
def clear(feature)
|
57
|
-
result = @adapter.clear(feature)
|
58
|
-
@cache.delete(key_for(feature.key))
|
59
|
-
result
|
60
|
-
end
|
61
|
-
|
62
|
-
## Public
|
63
|
-
def get(feature)
|
64
|
-
@cache.fetch(key_for(feature.key), @write_options) do
|
65
|
-
@adapter.get(feature)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
def get_multi(features)
|
70
|
-
keys = features.map { |feature| key_for(feature.key) }
|
71
|
-
result = @cache.read_multi(keys)
|
72
|
-
uncached_features = features.reject { |feature| result[feature.key] }
|
73
|
-
if uncached_features.any?
|
74
|
-
response = @adapter.get_multi(uncached_features)
|
75
|
-
response.each do |key, value|
|
76
|
-
@cache.write(key_for(key), value, @write_options)
|
77
|
-
result[key] = value
|
78
|
-
end
|
79
|
-
end
|
80
|
-
result
|
81
|
-
end
|
82
|
-
|
83
|
-
## Public
|
84
|
-
def enable(feature, gate, thing)
|
85
|
-
result = @adapter.enable(feature, gate, thing)
|
86
|
-
@cache.delete(key_for(feature.key))
|
87
|
-
result
|
88
|
-
end
|
89
|
-
|
90
|
-
## Public
|
91
|
-
def disable(feature, gate, thing)
|
92
|
-
result = @adapter.disable(feature, gate, thing)
|
93
|
-
@cache.delete(key_for(feature.key))
|
94
|
-
result
|
95
|
-
end
|
96
|
-
|
97
|
-
private
|
98
|
-
|
99
|
-
def key_for(key)
|
100
|
-
self.class.key_for(key)
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
@@ -1,50 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
require 'active_support/cache'
|
3
|
-
require 'flipper/adapters/memory'
|
4
|
-
require 'flipper/adapters/cache_store'
|
5
|
-
require 'flipper/spec/shared_adapter_specs'
|
6
|
-
|
7
|
-
RSpec.describe Flipper::Adapters::CacheStore do
|
8
|
-
let(:memory_adapter) { Flipper::Adapters::Memory.new }
|
9
|
-
let(:cache) { ActiveSupport::Cache::MemoryStore.new }
|
10
|
-
let(:adapter) { described_class.new(memory_adapter, cache) }
|
11
|
-
let(:flipper) { Flipper.new(adapter) }
|
12
|
-
|
13
|
-
subject { adapter }
|
14
|
-
|
15
|
-
it_should_behave_like 'a flipper adapter'
|
16
|
-
|
17
|
-
describe '#remove' do
|
18
|
-
it 'expires feature' do
|
19
|
-
feature = flipper[:stats]
|
20
|
-
adapter.get(feature)
|
21
|
-
adapter.remove(feature)
|
22
|
-
expect(cache.read(described_class.key_for(feature))).to be(nil)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
describe '#get_multi' do
|
27
|
-
it 'warms uncached features' do
|
28
|
-
stats = flipper[:stats]
|
29
|
-
search = flipper[:search]
|
30
|
-
other = flipper[:other]
|
31
|
-
stats.enable
|
32
|
-
search.enable
|
33
|
-
|
34
|
-
adapter.get(stats)
|
35
|
-
expect(cache.read(described_class.key_for(search))).to be(nil)
|
36
|
-
expect(cache.read(described_class.key_for(other))).to be(nil)
|
37
|
-
|
38
|
-
adapter.get_multi([stats, search, other])
|
39
|
-
|
40
|
-
expect(cache.read(described_class.key_for(search))[:boolean]).to eq('true')
|
41
|
-
expect(cache.read(described_class.key_for(other))[:boolean]).to be(nil)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
describe '#name' do
|
46
|
-
it 'is cache_store' do
|
47
|
-
expect(subject.name).to be(:cache_store)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|