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/lib/flipper/gate_values.rb
CHANGED
@@ -22,8 +22,8 @@ module Flipper
|
|
22
22
|
@boolean = Typecast.to_boolean(adapter_values[:boolean])
|
23
23
|
@actors = Typecast.to_set(adapter_values[:actors])
|
24
24
|
@groups = Typecast.to_set(adapter_values[:groups])
|
25
|
-
@percentage_of_actors = Typecast.
|
26
|
-
@percentage_of_time = Typecast.
|
25
|
+
@percentage_of_actors = Typecast.to_percentage(adapter_values[:percentage_of_actors])
|
26
|
+
@percentage_of_time = Typecast.to_percentage(adapter_values[:percentage_of_time])
|
27
27
|
end
|
28
28
|
|
29
29
|
def [](key)
|
data/lib/flipper/gates/group.rb
CHANGED
@@ -28,12 +28,8 @@ module Flipper
|
|
28
28
|
false
|
29
29
|
else
|
30
30
|
value.any? do |name|
|
31
|
-
|
32
|
-
|
33
|
-
group.match?(context.thing, context)
|
34
|
-
rescue GroupNotRegistered
|
35
|
-
false
|
36
|
-
end
|
31
|
+
group = Flipper.group(name)
|
32
|
+
group.match?(context.thing, context)
|
37
33
|
end
|
38
34
|
end
|
39
35
|
end
|
@@ -30,7 +30,9 @@ module Flipper
|
|
30
30
|
if Types::Actor.wrappable?(context.thing)
|
31
31
|
actor = Types::Actor.wrap(context.thing)
|
32
32
|
id = "#{context.feature_name}#{actor.value}"
|
33
|
-
|
33
|
+
# this is to support up to 3 decimal places in percentages
|
34
|
+
scaling_factor = 1_000
|
35
|
+
Zlib.crc32(id) % (100 * scaling_factor) < percentage * scaling_factor
|
34
36
|
else
|
35
37
|
false
|
36
38
|
end
|
data/lib/flipper/typecast.rb
CHANGED
@@ -26,6 +26,30 @@ module Flipper
|
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
+
# Internal: Convert value to a float.
|
30
|
+
#
|
31
|
+
# Returns a Float representation of the value.
|
32
|
+
# Raises ArgumentError if conversion is not possible.
|
33
|
+
def self.to_float(value)
|
34
|
+
if value.respond_to?(:to_f)
|
35
|
+
value.to_f
|
36
|
+
else
|
37
|
+
raise ArgumentError, "#{value.inspect} cannot be converted to a float"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Internal: Convert value to a percentage.
|
42
|
+
#
|
43
|
+
# Returns a Integer or Float representation of the value.
|
44
|
+
# Raises ArgumentError if conversion is not possible.
|
45
|
+
def self.to_percentage(value)
|
46
|
+
if value.to_s.include?('.'.freeze)
|
47
|
+
to_float(value)
|
48
|
+
else
|
49
|
+
to_integer(value)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
29
53
|
# Internal: Convert value to a set.
|
30
54
|
#
|
31
55
|
# Returns a Set representation of the value.
|
data/lib/flipper/version.rb
CHANGED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'flipper/configuration'
|
3
|
+
|
4
|
+
RSpec.describe Flipper::Configuration do
|
5
|
+
describe '#default' do
|
6
|
+
it 'raises if default not configured' do
|
7
|
+
expect { subject.default }.to raise_error(Flipper::DefaultNotSet)
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'can be set default' do
|
11
|
+
instance = Flipper.new(Flipper::Adapters::Memory.new)
|
12
|
+
subject.default { instance }
|
13
|
+
expect(subject.default).to be(instance)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/spec/flipper/dsl_spec.rb
CHANGED
@@ -274,6 +274,15 @@ RSpec.describe Flipper::DSL do
|
|
274
274
|
subject.disable_percentage_of_time(:stats)
|
275
275
|
expect(subject[:stats].percentage_of_time_value).to be(0)
|
276
276
|
end
|
277
|
+
|
278
|
+
it 'can enable/disable float values' do
|
279
|
+
expect(subject[:stats].percentage_of_time_value).to be(0)
|
280
|
+
subject.enable_percentage_of_time(:stats, 0.01)
|
281
|
+
expect(subject[:stats].percentage_of_time_value).to be(0.01)
|
282
|
+
|
283
|
+
subject.disable_percentage_of_time(:stats)
|
284
|
+
expect(subject[:stats].percentage_of_time_value).to be(0)
|
285
|
+
end
|
277
286
|
end
|
278
287
|
|
279
288
|
describe '#enable_percentage_of_actors/disable_percentage_of_actors' do
|
@@ -285,6 +294,15 @@ RSpec.describe Flipper::DSL do
|
|
285
294
|
subject.disable_percentage_of_actors(:stats)
|
286
295
|
expect(subject[:stats].percentage_of_actors_value).to be(0)
|
287
296
|
end
|
297
|
+
|
298
|
+
it 'can enable/disable float values' do
|
299
|
+
expect(subject[:stats].percentage_of_actors_value).to be(0)
|
300
|
+
subject.enable_percentage_of_actors(:stats, 0.01)
|
301
|
+
expect(subject[:stats].percentage_of_actors_value).to be(0.01)
|
302
|
+
|
303
|
+
subject.disable_percentage_of_actors(:stats)
|
304
|
+
expect(subject[:stats].percentage_of_actors_value).to be(0)
|
305
|
+
end
|
288
306
|
end
|
289
307
|
|
290
308
|
describe '#add' do
|
@@ -7,10 +7,10 @@ RSpec.describe Flipper::Gates::PercentageOfActors do
|
|
7
7
|
described_class.new
|
8
8
|
end
|
9
9
|
|
10
|
-
def context(
|
10
|
+
def context(percentage_of_actors_value, feature = feature_name, thing = nil)
|
11
11
|
Flipper::FeatureCheckContext.new(
|
12
12
|
feature_name: feature,
|
13
|
-
values: Flipper::GateValues.new(percentage_of_actors:
|
13
|
+
values: Flipper::GateValues.new(percentage_of_actors: percentage_of_actors_value),
|
14
14
|
thing: thing || Flipper::Types::Actor.new(Flipper::Actor.new(1))
|
15
15
|
)
|
16
16
|
end
|
@@ -19,20 +19,18 @@ RSpec.describe Flipper::Gates::PercentageOfActors do
|
|
19
19
|
context 'when compared against two features' do
|
20
20
|
let(:percentage) { 0.05 }
|
21
21
|
let(:percentage_as_integer) { percentage * 100 }
|
22
|
-
let(:number_of_actors) {
|
22
|
+
let(:number_of_actors) { 10_000 }
|
23
23
|
|
24
24
|
let(:actors) do
|
25
25
|
(1..number_of_actors).map { |n| Flipper::Actor.new(n) }
|
26
26
|
end
|
27
27
|
|
28
28
|
let(:feature_one_enabled_actors) do
|
29
|
-
|
30
|
-
actors.select { |actor| gate.open? context(percentage_as_integer, :name_one, actor) }
|
29
|
+
actors.select { |actor| subject.open? context(percentage_as_integer, :name_one, actor) }
|
31
30
|
end
|
32
31
|
|
33
32
|
let(:feature_two_enabled_actors) do
|
34
|
-
|
35
|
-
actors.select { |actor| gate.open? context(percentage_as_integer, :name_two, actor) }
|
33
|
+
actors.select { |actor| subject.open? context(percentage_as_integer, :name_two, actor) }
|
36
34
|
end
|
37
35
|
|
38
36
|
it 'does not enable both features for same set of actors' do
|
@@ -51,5 +49,29 @@ RSpec.describe Flipper::Gates::PercentageOfActors do
|
|
51
49
|
end
|
52
50
|
end
|
53
51
|
end
|
52
|
+
|
53
|
+
context 'for fractional percentage' do
|
54
|
+
let(:decimal) { 0.001 }
|
55
|
+
let(:percentage) { decimal * 100 }
|
56
|
+
let(:number_of_actors) { 10_000 }
|
57
|
+
|
58
|
+
let(:actors) do
|
59
|
+
(1..number_of_actors).map { |n| Flipper::Actor.new(n) }
|
60
|
+
end
|
61
|
+
|
62
|
+
subject { described_class.new }
|
63
|
+
|
64
|
+
it 'enables feature for accurate number of actors' do
|
65
|
+
margin_of_error = 0.02 * number_of_actors
|
66
|
+
expected_open_count = number_of_actors * decimal
|
67
|
+
|
68
|
+
open_count = actors.select do |actor|
|
69
|
+
context = context(percentage, :feature, actor)
|
70
|
+
subject.open?(context)
|
71
|
+
end.size
|
72
|
+
|
73
|
+
expect(open_count).to be_within(margin_of_error).of(expected_open_count)
|
74
|
+
end
|
75
|
+
end
|
54
76
|
end
|
55
77
|
end
|
@@ -6,4 +6,34 @@ RSpec.describe Flipper::Gates::PercentageOfTime do
|
|
6
6
|
subject do
|
7
7
|
described_class.new
|
8
8
|
end
|
9
|
+
|
10
|
+
def context(percentage_of_time_value, feature = feature_name, thing = nil)
|
11
|
+
Flipper::FeatureCheckContext.new(
|
12
|
+
feature_name: feature,
|
13
|
+
values: Flipper::GateValues.new(percentage_of_time: percentage_of_time_value),
|
14
|
+
thing: thing || Flipper::Types::Actor.new(Flipper::Actor.new(1))
|
15
|
+
)
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '#open?' do
|
19
|
+
context 'for fractional percentage' do
|
20
|
+
let(:decimal) { 0.001 }
|
21
|
+
let(:percentage) { decimal * 100 }
|
22
|
+
let(:number_of_invocations) { 10_000 }
|
23
|
+
|
24
|
+
subject { described_class.new }
|
25
|
+
|
26
|
+
it 'enables feature for accurate percentage of time' do
|
27
|
+
margin_of_error = 0.02 * number_of_invocations
|
28
|
+
expected_open_count = number_of_invocations * decimal
|
29
|
+
|
30
|
+
open_count = (1..number_of_invocations).select do |_actor|
|
31
|
+
context = context(percentage, :feature, Flipper::Actor.new("1"))
|
32
|
+
subject.open?(context)
|
33
|
+
end.size
|
34
|
+
|
35
|
+
expect(open_count).to be_within(margin_of_error).of(expected_open_count)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
9
39
|
end
|
@@ -36,6 +36,43 @@ RSpec.describe Flipper::Typecast do
|
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
|
+
{
|
40
|
+
nil => 0.0,
|
41
|
+
'' => 0.0,
|
42
|
+
0 => 0.0,
|
43
|
+
1 => 1.0,
|
44
|
+
1.1 => 1.1,
|
45
|
+
'0.01' => 0.01,
|
46
|
+
'1' => 1.0,
|
47
|
+
'99' => 99.0,
|
48
|
+
}.each do |value, expected|
|
49
|
+
context "#to_float for #{value.inspect}" do
|
50
|
+
it "returns #{expected}" do
|
51
|
+
expect(described_class.to_float(value)).to be(expected)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
{
|
57
|
+
nil => 0,
|
58
|
+
'' => 0,
|
59
|
+
0 => 0,
|
60
|
+
0.0 => 0.0,
|
61
|
+
1 => 1,
|
62
|
+
1.1 => 1.1,
|
63
|
+
'0.01' => 0.01,
|
64
|
+
'1' => 1,
|
65
|
+
'1.1' => 1.1,
|
66
|
+
'99' => 99,
|
67
|
+
'99.9' => 99.9,
|
68
|
+
}.each do |value, expected|
|
69
|
+
context "#to_percentage for #{value.inspect}" do
|
70
|
+
it "returns #{expected}" do
|
71
|
+
expect(described_class.to_percentage(value)).to be(expected)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
39
76
|
{
|
40
77
|
nil => Set.new,
|
41
78
|
'' => Set.new,
|
@@ -55,6 +92,24 @@ RSpec.describe Flipper::Typecast do
|
|
55
92
|
end.to raise_error(ArgumentError, %(["asdf"] cannot be converted to an integer))
|
56
93
|
end
|
57
94
|
|
95
|
+
it 'raises argument error for float value that cannot be converted to an float' do
|
96
|
+
expect do
|
97
|
+
described_class.to_float(['asdf'])
|
98
|
+
end.to raise_error(ArgumentError, %(["asdf"] cannot be converted to a float))
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'raises argument error for bad integer percentage' do
|
102
|
+
expect do
|
103
|
+
described_class.to_percentage(['asdf'])
|
104
|
+
end.to raise_error(ArgumentError, %(["asdf"] cannot be converted to an integer))
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'raises argument error for bad float percentage' do
|
108
|
+
expect do
|
109
|
+
described_class.to_percentage(['asdf.0'])
|
110
|
+
end.to raise_error(ArgumentError, %(["asdf.0"] cannot be converted to a float))
|
111
|
+
end
|
112
|
+
|
58
113
|
it 'raises argument error for set value that cannot be converted to a set' do
|
59
114
|
expect do
|
60
115
|
described_class.to_set('asdf')
|
data/spec/flipper_spec.rb
CHANGED
@@ -8,28 +8,173 @@ RSpec.describe Flipper do
|
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
|
-
describe '.
|
12
|
-
it '
|
13
|
-
|
14
|
-
|
11
|
+
describe '.configure' do
|
12
|
+
it 'yield configuration instance' do
|
13
|
+
described_class.configure do |config|
|
14
|
+
expect(config).to be_instance_of(Flipper::Configuration)
|
15
|
+
end
|
15
16
|
end
|
17
|
+
end
|
16
18
|
|
17
|
-
|
18
|
-
|
19
|
+
describe '.configuration' do
|
20
|
+
it 'returns configuration instance' do
|
21
|
+
expect(described_class.configuration).to be_instance_of(Flipper::Configuration)
|
19
22
|
end
|
20
23
|
end
|
21
24
|
|
22
|
-
describe '.
|
23
|
-
it
|
24
|
-
|
25
|
+
describe '.configuration=' do
|
26
|
+
it "sets configuration instance" do
|
27
|
+
configuration = Flipper::Configuration.new
|
28
|
+
described_class.configuration = configuration
|
29
|
+
expect(described_class.configuration).to be(configuration)
|
25
30
|
end
|
26
31
|
end
|
27
32
|
|
28
|
-
describe '.
|
29
|
-
it '
|
30
|
-
|
31
|
-
described_class.
|
32
|
-
|
33
|
+
describe '.instance' do
|
34
|
+
it 'returns DSL instance using result of default invocation' do
|
35
|
+
instance = described_class.new(Flipper::Adapters::Memory.new)
|
36
|
+
described_class.configure do |config|
|
37
|
+
config.default { instance }
|
38
|
+
end
|
39
|
+
expect(described_class.instance).to be(instance)
|
40
|
+
expect(described_class.instance).to be(described_class.instance) # memoized
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "delegation to instance" do
|
45
|
+
let(:group) { Flipper::Types::Group.new(:admins) }
|
46
|
+
let(:actor) { Flipper::Actor.new("1") }
|
47
|
+
|
48
|
+
before do
|
49
|
+
described_class.configure do |config|
|
50
|
+
config.default { described_class.new(Flipper::Adapters::Memory.new) }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'delegates enabled? to instance' do
|
55
|
+
expect(described_class.enabled?(:search)).to eq(described_class.instance.enabled?(:search))
|
56
|
+
described_class.instance.enable(:search)
|
57
|
+
expect(described_class.enabled?(:search)).to eq(described_class.instance.enabled?(:search))
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'delegates enable to instance' do
|
61
|
+
described_class.enable(:search)
|
62
|
+
expect(described_class.instance.enabled?(:search)).to be(true)
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'delegates disable to instance' do
|
66
|
+
described_class.disable(:search)
|
67
|
+
expect(described_class.instance.enabled?(:search)).to be(false)
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'delegates bool to instance' do
|
71
|
+
expect(described_class.bool).to eq(described_class.instance.bool)
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'delegates boolean to instance' do
|
75
|
+
expect(described_class.boolean).to eq(described_class.instance.boolean)
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'delegates enable_actor to instance' do
|
79
|
+
described_class.enable_actor(:search, actor)
|
80
|
+
expect(described_class.instance.enabled?(:search, actor)).to be(true)
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'delegates disable_actor to instance' do
|
84
|
+
described_class.disable_actor(:search, actor)
|
85
|
+
expect(described_class.instance.enabled?(:search, actor)).to be(false)
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'delegates actor to instance' do
|
89
|
+
expect(described_class.actor(actor)).to eq(described_class.instance.actor(actor))
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'delegates enable_group to instance' do
|
93
|
+
described_class.enable_group(:search, group)
|
94
|
+
expect(described_class.instance[:search].enabled_groups).to include(group)
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'delegates disable_group to instance' do
|
98
|
+
described_class.disable_group(:search, group)
|
99
|
+
expect(described_class.instance[:search].enabled_groups).not_to include(group)
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'delegates enable_percentage_of_actors to instance' do
|
103
|
+
described_class.enable_percentage_of_actors(:search, 5)
|
104
|
+
expect(described_class.instance[:search].percentage_of_actors_value).to be(5)
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'delegates disable_percentage_of_actors to instance' do
|
108
|
+
described_class.disable_percentage_of_actors(:search)
|
109
|
+
expect(described_class.instance[:search].percentage_of_actors_value).to be(0)
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'delegates actors to instance' do
|
113
|
+
expect(described_class.actors(5)).to eq(described_class.instance.actors(5))
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'delegates percentage_of_actors to instance' do
|
117
|
+
expected = described_class.instance.percentage_of_actors(5)
|
118
|
+
expect(described_class.percentage_of_actors(5)).to eq(expected)
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'delegates enable_percentage_of_time to instance' do
|
122
|
+
described_class.enable_percentage_of_time(:search, 5)
|
123
|
+
expect(described_class.instance[:search].percentage_of_time_value).to be(5)
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'delegates disable_percentage_of_time to instance' do
|
127
|
+
described_class.disable_percentage_of_time(:search)
|
128
|
+
expect(described_class.instance[:search].percentage_of_time_value).to be(0)
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'delegates time to instance' do
|
132
|
+
expect(described_class.time(56)).to eq(described_class.instance.time(56))
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'delegates percentage_of_time to instance' do
|
136
|
+
expected = described_class.instance.percentage_of_time(56)
|
137
|
+
expect(described_class.percentage_of_time(56)).to eq(expected)
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'delegates features to instance' do
|
141
|
+
described_class.instance.add(:search)
|
142
|
+
expect(described_class.features).to eq(described_class.instance.features)
|
143
|
+
expect(described_class.features).to include(described_class.instance[:search])
|
144
|
+
end
|
145
|
+
|
146
|
+
it 'delegates feature to instance' do
|
147
|
+
expect(described_class.feature(:search)).to eq(described_class.instance.feature(:search))
|
148
|
+
end
|
149
|
+
|
150
|
+
it 'delegates [] to instance' do
|
151
|
+
expect(described_class[:search]).to eq(described_class.instance[:search])
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'delegates preload to instance' do
|
155
|
+
described_class.instance.enable(:search)
|
156
|
+
expect(described_class.preload([:search])).to eq(described_class.instance.preload([:search]))
|
157
|
+
end
|
158
|
+
|
159
|
+
it 'delegates preload_all to instance' do
|
160
|
+
described_class.instance.enable(:search)
|
161
|
+
described_class.instance.enable(:stats)
|
162
|
+
expect(described_class.preload_all).to eq(described_class.instance.preload_all)
|
163
|
+
end
|
164
|
+
|
165
|
+
it 'delegates add to instance' do
|
166
|
+
expect(described_class.add(:search)).to eq(described_class.instance.add(:search))
|
167
|
+
end
|
168
|
+
|
169
|
+
it 'delegates remove to instance' do
|
170
|
+
expect(described_class.remove(:search)).to eq(described_class.instance.remove(:search))
|
171
|
+
end
|
172
|
+
|
173
|
+
it 'delegates import to instance' do
|
174
|
+
other = described_class.new(Flipper::Adapters::Memory.new)
|
175
|
+
other.enable(:search)
|
176
|
+
described_class.import(other)
|
177
|
+
expect(described_class.enabled?(:search)).to be(true)
|
33
178
|
end
|
34
179
|
end
|
35
180
|
|
@@ -57,6 +202,28 @@ RSpec.describe Flipper do
|
|
57
202
|
end
|
58
203
|
end
|
59
204
|
|
205
|
+
describe '.groups' do
|
206
|
+
it 'returns array of group instances' do
|
207
|
+
admins = described_class.register(:admins, &:admin?)
|
208
|
+
preview_features = described_class.register(:preview_features, &:preview_features?)
|
209
|
+
expect(described_class.groups).to eq(Set[
|
210
|
+
admins,
|
211
|
+
preview_features,
|
212
|
+
])
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
describe '.group_names' do
|
217
|
+
it 'returns array of group names' do
|
218
|
+
described_class.register(:admins, &:admin?)
|
219
|
+
described_class.register(:preview_features, &:preview_features?)
|
220
|
+
expect(described_class.group_names).to eq(Set[
|
221
|
+
:admins,
|
222
|
+
:preview_features,
|
223
|
+
])
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
60
227
|
describe '.unregister_groups' do
|
61
228
|
it 'clear group registry' do
|
62
229
|
expect(described_class.groups_registry).to receive(:clear)
|
@@ -64,6 +231,17 @@ RSpec.describe Flipper do
|
|
64
231
|
end
|
65
232
|
end
|
66
233
|
|
234
|
+
describe '.group_exists' do
|
235
|
+
it 'returns true if the group is already created' do
|
236
|
+
group = described_class.register('admins', &:admin?)
|
237
|
+
expect(described_class.group_exists?(:admins)).to eq(true)
|
238
|
+
end
|
239
|
+
|
240
|
+
it 'returns false when the group is not yet registered' do
|
241
|
+
expect(described_class.group_exists?(:non_existing)).to eq(false)
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
67
245
|
describe '.group' do
|
68
246
|
context 'for registered group' do
|
69
247
|
before do
|
@@ -95,25 +273,17 @@ RSpec.describe Flipper do
|
|
95
273
|
end
|
96
274
|
end
|
97
275
|
|
98
|
-
describe '.
|
99
|
-
it 'returns
|
100
|
-
|
101
|
-
preview_features = described_class.register(:preview_features, &:preview_features?)
|
102
|
-
expect(described_class.groups).to eq(Set[
|
103
|
-
admins,
|
104
|
-
preview_features,
|
105
|
-
])
|
276
|
+
describe '.groups_registry' do
|
277
|
+
it 'returns a registry instance' do
|
278
|
+
expect(described_class.groups_registry).to be_instance_of(Flipper::Registry)
|
106
279
|
end
|
107
280
|
end
|
108
281
|
|
109
|
-
describe '.
|
110
|
-
it '
|
111
|
-
|
112
|
-
described_class.
|
113
|
-
expect(described_class.
|
114
|
-
:admins,
|
115
|
-
:preview_features,
|
116
|
-
])
|
282
|
+
describe '.groups_registry=' do
|
283
|
+
it 'sets groups_registry registry' do
|
284
|
+
registry = Flipper::Registry.new
|
285
|
+
described_class.groups_registry = registry
|
286
|
+
expect(described_class.instance_variable_get('@groups_registry')).to eq(registry)
|
117
287
|
end
|
118
288
|
end
|
119
289
|
end
|