flipper 0.7.0.beta2 → 0.7.0.beta3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fcc306a0110366af90921368bda9c8aeffa353ca
4
- data.tar.gz: a1b1808be6c648f99f14e9e033dd945a4152744a
3
+ metadata.gz: b952f92d9398ba28267085a3084fbc659e571f6f
4
+ data.tar.gz: 4e535ba61ef3e38e24f419489c305c17cbdf58e1
5
5
  SHA512:
6
- metadata.gz: 16397be35aa9c521e74c15046bd2efacb8537d9460f0e4dc9ef3ca212e46d320791d0a22fd1dbacd058776feab6ea7cd91e6af7855b7c9e297bcca75342ea641
7
- data.tar.gz: e70319c0460a878e2f861a637715cc749f76992d08f3ee6d17a149b05ea847a49fb665d2a77a604981dac8366e09fc3740c08a59ba35cdba027952b4fb220a7e
6
+ metadata.gz: 5457f2328718155eef1ff0014346179f5bec08cd594a9c6f31ccd3e02977a91089477bffee66d53438bf849c04d66b9ca73dc56e06653f8a4dbb6168e69e56c8
7
+ data.tar.gz: 9c7da626025b191605e70beb3b6cdefd190d124c429354b54451472e7d3ea3fb48b90218356da8843fd30955529981769b320404e2c07e7ffef92da2cf787e40
data/README.md CHANGED
@@ -250,6 +250,35 @@ A good place to start when creating your own adapter is to copy one of the adapt
250
250
 
251
251
  I would also recommend setting `fail_fast = true` in your RSpec configuration as that will just give you one failure at a time to work through. It is also handy to have the shared adapter spec file open.
252
252
 
253
+ ## Instrumentation
254
+
255
+ Flipper comes with automatic instrumentation. By default these work with ActiveSupport::Notifications, but only require the pieces of ActiveSupport that are needed and only do so if you actually attempt to require the instrumentation files listed below.
256
+
257
+ To use the log subscriber:
258
+
259
+ ```ruby
260
+ # Gemfile
261
+ gem "activesupport"
262
+
263
+ # config/initializers/flipper.rb (or wherever you want it)
264
+ require "flipper/instrumentation/log_subscriber"
265
+ ```
266
+
267
+ To use the statsd instrumentation:
268
+
269
+ ```ruby
270
+ # Gemfile
271
+ gem "activesupport"
272
+ gem "statsd-ruby"
273
+
274
+ # config/initializers/flipper.rb (or wherever you want it)
275
+ require "flipper/instrumentation/statsd"
276
+ Flipper::Instrumentation::StatsdSubscriber.client = Statsd.new # or whatever your statsd instance is
277
+ ```
278
+
279
+ You can also do whatever you want with the instrumented events. Check out [this example](https://github.com/jnunemaker/flipper/blob/master/examples/instrumentation.rb) for more.
280
+
281
+
253
282
  ## Optimization
254
283
 
255
284
  One optimization that flipper provides is a memoizing middleware. The memoizing middleware ensures that you only make one adapter call per feature per request.
data/flipper.gemspec CHANGED
@@ -4,7 +4,6 @@ require File.expand_path('../lib/flipper/version', __FILE__)
4
4
  Gem::Specification.new do |gem|
5
5
  gem.authors = ["John Nunemaker"]
6
6
  gem.email = ["nunemaker@gmail.com"]
7
- gem.description = %q{Feature flipper for any adapter}
8
7
  gem.summary = %q{Feature flipper for any adapter}
9
8
  gem.homepage = "http://jnunemaker.github.com/flipper"
10
9
 
@@ -14,4 +13,5 @@ Gem::Specification.new do |gem|
14
13
  gem.name = "flipper"
15
14
  gem.require_paths = ["lib"]
16
15
  gem.version = Flipper::VERSION
16
+ gem.license = "MIT"
17
17
  end
@@ -3,7 +3,7 @@ require 'flipper/decorator'
3
3
  module Flipper
4
4
  module Adapters
5
5
  class Decorator < ::Flipper::Decorator
6
- include Flipper::Adapter
6
+ include Adapter
7
7
  end
8
8
  end
9
9
  end
@@ -20,7 +20,7 @@ module Flipper
20
20
  def initialize(adapter, options = {})
21
21
  super(adapter)
22
22
  @name = :instrumented
23
- @instrumenter = options.fetch(:instrumenter, Flipper::Instrumenters::Noop)
23
+ @instrumenter = options.fetch(:instrumenter, Instrumenters::Noop)
24
24
  end
25
25
 
26
26
  # Public
@@ -3,7 +3,7 @@ require 'set'
3
3
  module Flipper
4
4
  module Adapters
5
5
  class Memory
6
- include Flipper::Adapter
6
+ include Adapter
7
7
 
8
8
  FeaturesKey = :flipper_features
9
9
 
@@ -0,0 +1,166 @@
1
+ require "pstore"
2
+ require "set"
3
+
4
+ module Flipper
5
+ module Adapters
6
+ class PStore
7
+ include Adapter
8
+
9
+ FeaturesKey = :flipper_features
10
+
11
+ # Public: The name of the adapter.
12
+ attr_reader :name
13
+
14
+ # Public: The path to where the file is stored.
15
+ attr_reader :path
16
+
17
+ # Public
18
+ def initialize(path = "flipper.pstore")
19
+ @path = path
20
+ @store = ::PStore.new(path)
21
+ @name = :pstore
22
+ end
23
+
24
+ # Public: The set of known features.
25
+ def features
26
+ set_members FeaturesKey
27
+ end
28
+
29
+ # Public: Adds a feature to the set of known features.
30
+ def add(feature)
31
+ set_add FeaturesKey, feature.key
32
+ true
33
+ end
34
+
35
+ # Public: Removes a feature from the set of known features and clears
36
+ # all the values for the feature.
37
+ def remove(feature)
38
+ set_delete FeaturesKey, feature.key
39
+ clear(feature)
40
+ true
41
+ end
42
+
43
+ # Public: Clears all the gate values for a feature.
44
+ def clear(feature)
45
+ feature.gates.each do |gate|
46
+ delete key(feature, gate)
47
+ end
48
+ true
49
+ end
50
+
51
+ # Public
52
+ def get(feature)
53
+ result = {}
54
+
55
+ feature.gates.each do |gate|
56
+ result[gate.key] = case gate.data_type
57
+ when :boolean, :integer
58
+ read key(feature, gate)
59
+ when :set
60
+ set_members key(feature, gate)
61
+ else
62
+ raise "#{gate} is not supported by this adapter yet"
63
+ end
64
+ end
65
+
66
+ result
67
+ end
68
+
69
+ # Public
70
+ def enable(feature, gate, thing)
71
+ case gate.data_type
72
+ when :boolean, :integer
73
+ write key(feature, gate), thing.value.to_s
74
+ when :set
75
+ set_add key(feature, gate), thing.value.to_s
76
+ else
77
+ raise "#{gate} is not supported by this adapter yet"
78
+ end
79
+
80
+ true
81
+ end
82
+
83
+ # Public
84
+ def disable(feature, gate, thing)
85
+ case gate.data_type
86
+ when :boolean
87
+ clear(feature)
88
+ when :integer
89
+ write key(feature, gate), thing.value.to_s
90
+ when :set
91
+ set_delete key(feature, gate), thing.value.to_s
92
+ else
93
+ raise "#{gate} is not supported by this adapter yet"
94
+ end
95
+
96
+ true
97
+ end
98
+
99
+ # Public
100
+ def inspect
101
+ attributes = [
102
+ "name=#{@name.inspect}",
103
+ "path=#{@path.inspect}",
104
+ "store=#{@store}",
105
+ ]
106
+ "#<#{self.class.name}:#{object_id} #{attributes.join(', ')}>"
107
+ end
108
+
109
+ private
110
+
111
+ # Private
112
+ def key(feature, gate)
113
+ "#{feature.key}/#{gate.key}"
114
+ end
115
+
116
+ # Private
117
+ def read(key)
118
+ @store.transaction do
119
+ @store[key.to_s]
120
+ end
121
+ end
122
+
123
+ # Private
124
+ def write(key, value)
125
+ @store.transaction do
126
+ @store[key.to_s] = value.to_s
127
+ end
128
+ end
129
+
130
+ # Private
131
+ def delete(key)
132
+ @store.transaction do
133
+ @store.delete(key.to_s)
134
+ end
135
+ end
136
+
137
+ # Private
138
+ def set_add(key, value)
139
+ set_members(key) do |members|
140
+ members.add(value.to_s)
141
+ end
142
+ end
143
+
144
+ # Private
145
+ def set_delete(key, value)
146
+ set_members(key) do |members|
147
+ members.delete(value.to_s)
148
+ end
149
+ end
150
+
151
+ # Private
152
+ def set_members(key)
153
+ key = key.to_s
154
+ @store.transaction do
155
+ @store[key] ||= Set.new
156
+
157
+ if block_given?
158
+ yield @store[key]
159
+ else
160
+ @store[key]
161
+ end
162
+ end
163
+ end
164
+ end
165
+ end
166
+ end
data/lib/flipper/dsl.rb CHANGED
@@ -16,12 +16,12 @@ module Flipper
16
16
  # options - The Hash of options.
17
17
  # :instrumenter - What should be used to instrument all the things.
18
18
  def initialize(adapter, options = {})
19
- @instrumenter = options.fetch(:instrumenter, Flipper::Instrumenters::Noop)
19
+ @instrumenter = options.fetch(:instrumenter, Instrumenters::Noop)
20
20
 
21
- instrumented = Flipper::Adapters::Instrumented.new(adapter, {
21
+ instrumented = Adapters::Instrumented.new(adapter, {
22
22
  :instrumenter => @instrumenter,
23
23
  })
24
- memoized = Flipper::Adapters::Memoizable.new(instrumented)
24
+ memoized = Adapters::Memoizable.new(instrumented)
25
25
  @adapter = memoized
26
26
 
27
27
  @memoized_features = {}
@@ -35,14 +35,14 @@ module Flipper
35
35
  def initialize(name, adapter, options = {})
36
36
  @name = name
37
37
  @key = name.to_s
38
- @instrumenter = options.fetch(:instrumenter, Flipper::Instrumenters::Noop)
38
+ @instrumenter = options.fetch(:instrumenter, Instrumenters::Noop)
39
39
  @adapter = adapter
40
40
  end
41
41
 
42
42
  # Public: Enable this feature for something.
43
43
  #
44
44
  # Returns the result of Adapter#enable.
45
- def enable(thing = Types::Boolean.new(true))
45
+ def enable(thing = true)
46
46
  instrument(:enable, thing) { |payload|
47
47
  adapter.add self
48
48
 
@@ -56,7 +56,7 @@ module Flipper
56
56
  # Public: Disable this feature for something.
57
57
  #
58
58
  # Returns the result of Adapter#disable.
59
- def disable(thing = Types::Boolean.new(false))
59
+ def disable(thing = false)
60
60
  instrument(:disable, thing) { |payload|
61
61
  adapter.add self
62
62
 
@@ -110,7 +110,7 @@ module Flipper
110
110
  #
111
111
  # Returns result of enable.
112
112
  def enable_group(group)
113
- enable Flipper::Types::Group.wrap(group)
113
+ enable Types::Group.wrap(group)
114
114
  end
115
115
 
116
116
  # Public: Enables a feature a percentage of time.
@@ -150,7 +150,7 @@ module Flipper
150
150
  #
151
151
  # Returns result of disable.
152
152
  def disable_group(group)
153
- disable Flipper::Types::Group.wrap(group)
153
+ disable Types::Group.wrap(group)
154
154
  end
155
155
 
156
156
  # Public: Disables a feature a percentage of time.
@@ -176,10 +176,12 @@ module Flipper
176
176
  # Public: Returns state for feature (:on, :off, or :conditional).
177
177
  def state
178
178
  values = gate_values
179
+ boolean = gate(:boolean)
180
+ non_boolean_gates = gates - [boolean]
179
181
 
180
- if boolean_gate.enabled?(values.boolean)
182
+ if values.boolean || values.percentage_of_actors == 100 || values.percentage_of_time == 100
181
183
  :on
182
- elsif conditional_gates(values).any?
184
+ elsif non_boolean_gates.detect { |gate| gate.enabled?(values[gate.key]) }
183
185
  :conditional
184
186
  else
185
187
  :off
@@ -202,23 +204,6 @@ module Flipper
202
204
  state == :conditional
203
205
  end
204
206
 
205
- # Public: Human readable description of the enabled-ness of the feature.
206
- def description
207
- values = gate_values
208
- conditional_gates = conditional_gates(values)
209
-
210
- if boolean_gate.enabled?(values.boolean) || !conditional_gates.any?
211
- boolean_gate.description(values.boolean).capitalize
212
- else
213
- fragments = conditional_gates.map { |gate|
214
- value = values[gate.key]
215
- gate.description(value)
216
- }
217
-
218
- "Enabled for #{fragments.join(', ')}"
219
- end
220
- end
221
-
222
207
  # Public: Returns the raw gate values stored by the adapter.
223
208
  def gate_values
224
209
  GateValues.new(adapter.get(self))
@@ -274,6 +259,35 @@ module Flipper
274
259
  gate_values.percentage_of_time
275
260
  end
276
261
 
262
+ # Public: Get the gates that have been enabled for the feature.
263
+ #
264
+ # Returns an Array of Flipper::Gate instances.
265
+ def enabled_gates
266
+ values = gate_values
267
+ gates.select { |gate| gate.enabled?(values[gate.key]) }
268
+ end
269
+
270
+ # Public: Get the names of the enabled gates.
271
+ #
272
+ # Returns an Array of gate names.
273
+ def enabled_gate_names
274
+ enabled_gates.map(&:name)
275
+ end
276
+
277
+ # Public: Get the gates that have not been enabled for the feature.
278
+ #
279
+ # Returns an Array of Flipper::Gate instances.
280
+ def disabled_gates
281
+ gates - enabled_gates
282
+ end
283
+
284
+ # Public: Get the names of the disabled gates.
285
+ #
286
+ # Returns an Array of gate names.
287
+ def disabled_gate_names
288
+ disabled_gates.map(&:name)
289
+ end
290
+
277
291
  # Public: Returns the string representation of the feature.
278
292
  def to_s
279
293
  name.to_s
@@ -289,7 +303,7 @@ module Flipper
289
303
  attributes = [
290
304
  "name=#{name.inspect}",
291
305
  "state=#{state.inspect}",
292
- "description=#{description.inspect}",
306
+ "enabled_gate_names=#{enabled_gate_names.inspect}",
293
307
  "adapter=#{adapter.name.inspect}",
294
308
  ]
295
309
  "#<#{self.class.name}:#{object_id} #{attributes.join(', ')}>"
@@ -328,24 +342,6 @@ module Flipper
328
342
 
329
343
  private
330
344
 
331
- # Private: Get the boolean gate.
332
- def boolean_gate
333
- @boolean_gate ||= gate(:boolean)
334
- end
335
-
336
- # Private: Get all gates except the boolean gate.
337
- def non_boolean_gates
338
- @non_boolean_gates ||= gates - [boolean_gate]
339
- end
340
-
341
- # Private: Get all non boolean gates that are enabled in some way.
342
- def conditional_gates(gate_values)
343
- non_boolean_gates.select { |gate|
344
- value = gate_values[gate.key]
345
- gate.enabled?(value)
346
- }
347
- end
348
-
349
345
  # Private: Instrument a feature operation.
350
346
  def instrument(operation, thing)
351
347
  payload = {
data/lib/flipper/gate.rb CHANGED
@@ -26,10 +26,6 @@ module Flipper
26
26
  raise 'Not implemented'
27
27
  end
28
28
 
29
- def description(value)
30
- raise 'Not implemented'
31
- end
32
-
33
29
  # Internal: Check if a gate is open for a thing. Implemented in subclass.
34
30
  #
35
31
  # Returns true if gate open for thing, false if not.
@@ -15,15 +15,6 @@ module Flipper
15
15
  :set
16
16
  end
17
17
 
18
- def description(value)
19
- if enabled?(value)
20
- actor_ids = value.to_a.sort.map { |id| id.inspect }
21
- "actors (#{actor_ids.join(', ')})"
22
- else
23
- 'disabled'
24
- end
25
- end
26
-
27
18
  def enabled?(value)
28
19
  !Typecast.to_set(value).empty?
29
20
  end
@@ -15,14 +15,6 @@ module Flipper
15
15
  :boolean
16
16
  end
17
17
 
18
- def description(value)
19
- if enabled?(value)
20
- 'Enabled'
21
- else
22
- 'Disabled'
23
- end
24
- end
25
-
26
18
  def enabled?(value)
27
19
  Typecast.to_boolean(value)
28
20
  end
@@ -35,8 +27,17 @@ module Flipper
35
27
  value
36
28
  end
37
29
 
30
+ def wrap(thing)
31
+ Types::Boolean.wrap(thing)
32
+ end
33
+
38
34
  def protects?(thing)
39
- thing.is_a?(Flipper::Types::Boolean)
35
+ case thing
36
+ when Types::Boolean, TrueClass, FalseClass
37
+ true
38
+ else
39
+ false
40
+ end
40
41
  end
41
42
  end
42
43
  end
@@ -15,15 +15,6 @@ module Flipper
15
15
  :set
16
16
  end
17
17
 
18
- def description(value)
19
- if enabled?(value)
20
- group_names = value.to_a.sort.map { |name| name.to_sym.inspect }
21
- "groups (#{group_names.join(', ')})"
22
- else
23
- 'disabled'
24
- end
25
- end
26
-
27
18
  def enabled?(value)
28
19
  !Typecast.to_set(value).empty?
29
20
  end
@@ -47,7 +38,7 @@ module Flipper
47
38
  end
48
39
 
49
40
  def protects?(thing)
50
- thing.is_a?(Flipper::Types::Group)
41
+ thing.is_a?(Types::Group)
51
42
  end
52
43
  end
53
44
  end
@@ -17,14 +17,6 @@ module Flipper
17
17
  :integer
18
18
  end
19
19
 
20
- def description(value)
21
- if enabled?(value)
22
- "#{value}% of actors"
23
- else
24
- 'disabled'
25
- end
26
- end
27
-
28
20
  def enabled?(value)
29
21
  Typecast.to_integer(value) > 0
30
22
  end
@@ -46,7 +38,7 @@ module Flipper
46
38
  end
47
39
 
48
40
  def protects?(thing)
49
- thing.is_a?(Flipper::Types::PercentageOfActors)
41
+ thing.is_a?(Types::PercentageOfActors)
50
42
  end
51
43
  end
52
44
  end
@@ -15,14 +15,6 @@ module Flipper
15
15
  :integer
16
16
  end
17
17
 
18
- def description(value)
19
- if enabled?(value)
20
- "#{value}% of the time"
21
- else
22
- 'disabled'
23
- end
24
- end
25
-
26
18
  def enabled?(value)
27
19
  Typecast.to_integer(value) > 0
28
20
  end
data/lib/flipper/type.rb CHANGED
@@ -1,6 +1,11 @@
1
1
  module Flipper
2
2
  # Internal: Root class for all flipper types. You should never need to use this.
3
3
  class Type
4
+ def self.wrap(value_or_instance)
5
+ return value_or_instance if value_or_instance.is_a?(self)
6
+ new(value_or_instance)
7
+ end
8
+
4
9
  def value
5
10
  raise 'Not implemented'
6
11
  end
@@ -1,3 +1,3 @@
1
1
  module Flipper
2
- VERSION = "0.7.0.beta2"
2
+ VERSION = "0.7.0.beta3"
3
3
  end
data/lib/flipper.rb CHANGED
@@ -68,7 +68,7 @@ module Flipper
68
68
  # Raises Flipper::GroupNotRegistered if group is not registered.
69
69
  def self.group(name)
70
70
  groups_registry.get(name)
71
- rescue Flipper::Registry::KeyNotFound => e
71
+ rescue Registry::KeyNotFound => e
72
72
  raise GroupNotRegistered, "Group #{e.key.inspect} has not been registered"
73
73
  end
74
74
 
@@ -0,0 +1,13 @@
1
+ require 'helper'
2
+ require 'flipper/adapters/pstore'
3
+ require 'flipper/spec/shared_adapter_specs'
4
+
5
+ describe Flipper::Adapters::PStore do
6
+ subject { described_class.new(FlipperRoot.join("tmp", "flipper.pstore")) }
7
+
8
+ it_should_behave_like 'a flipper adapter'
9
+
10
+ it "defaults path to flipper.pstore" do
11
+ described_class.new.path.should eq("flipper.pstore")
12
+ end
13
+ end
@@ -97,8 +97,13 @@ describe Flipper::Feature do
97
97
  string.should include('Flipper::Feature')
98
98
  string.should include('name=:search')
99
99
  string.should include('state=:off')
100
- string.should include('description="Disabled"')
100
+ string.should include('enabled_gate_names=[]')
101
101
  string.should include("adapter=#{subject.adapter.name.inspect}")
102
+
103
+ subject.enable
104
+ string = subject.inspect
105
+ string.should include('state=:on')
106
+ string.should include('enabled_gate_names=[:boolean]')
102
107
  end
103
108
  end
104
109
 
@@ -178,21 +183,21 @@ describe Flipper::Feature do
178
183
  end
179
184
  end
180
185
 
181
- context "fully off" do
186
+ context "percentage of time set to 100" do
182
187
  before do
183
- subject.disable
188
+ subject.enable_percentage_of_time 100
184
189
  end
185
190
 
186
- it "returns :off" do
187
- subject.state.should be(:off)
191
+ it "returns :on" do
192
+ subject.state.should be(:on)
188
193
  end
189
194
 
190
- it "returns false for on?" do
191
- subject.on?.should be(false)
195
+ it "returns true for on?" do
196
+ subject.on?.should be(true)
192
197
  end
193
198
 
194
- it "returns true for off?" do
195
- subject.off?.should be(true)
199
+ it "returns false for off?" do
200
+ subject.off?.should be(false)
196
201
  end
197
202
 
198
203
  it "returns false for conditional?" do
@@ -200,59 +205,69 @@ describe Flipper::Feature do
200
205
  end
201
206
  end
202
207
 
203
- context "partially on" do
208
+ context "percentage of actors set to 100" do
204
209
  before do
205
- subject.enable Flipper::Types::PercentageOfTime.new(5)
210
+ subject.enable_percentage_of_actors 100
206
211
  end
207
212
 
208
- it "returns :conditional" do
209
- subject.state.should be(:conditional)
213
+ it "returns :on" do
214
+ subject.state.should be(:on)
210
215
  end
211
216
 
212
- it "returns false for on?" do
213
- subject.on?.should be(false)
217
+ it "returns true for on?" do
218
+ subject.on?.should be(true)
214
219
  end
215
220
 
216
221
  it "returns false for off?" do
217
222
  subject.off?.should be(false)
218
223
  end
219
224
 
220
- it "returns true for conditional?" do
221
- subject.conditional?.should be(true)
225
+ it "returns false for conditional?" do
226
+ subject.conditional?.should be(false)
222
227
  end
223
228
  end
224
- end
225
229
 
226
- describe "#description" do
227
- context "fully on" do
230
+ context "fully off" do
228
231
  before do
229
- subject.enable
232
+ subject.disable
230
233
  end
231
234
 
232
- it "returns enabled" do
233
- subject.description.should eq('Enabled')
235
+ it "returns :off" do
236
+ subject.state.should be(:off)
234
237
  end
235
- end
236
238
 
237
- context "fully off" do
238
- before do
239
- subject.disable
239
+ it "returns false for on?" do
240
+ subject.on?.should be(false)
241
+ end
242
+
243
+ it "returns true for off?" do
244
+ subject.off?.should be(true)
240
245
  end
241
246
 
242
- it "returns disabled" do
243
- subject.description.should eq('Disabled')
247
+ it "returns false for conditional?" do
248
+ subject.conditional?.should be(false)
244
249
  end
245
250
  end
246
251
 
247
252
  context "partially on" do
248
253
  before do
249
- actor = Struct.new(:flipper_id).new(5)
250
254
  subject.enable Flipper::Types::PercentageOfTime.new(5)
251
- subject.enable actor
252
255
  end
253
256
 
254
- it "returns text" do
255
- subject.description.should eq('Enabled for actors ("5"), 5% of the time')
257
+ it "returns :conditional" do
258
+ subject.state.should be(:conditional)
259
+ end
260
+
261
+ it "returns false for on?" do
262
+ subject.on?.should be(false)
263
+ end
264
+
265
+ it "returns false for off?" do
266
+ subject.off?.should be(false)
267
+ end
268
+
269
+ it "returns true for conditional?" do
270
+ subject.conditional?.should be(true)
256
271
  end
257
272
  end
258
273
  end
@@ -623,4 +638,37 @@ describe Flipper::Feature do
623
638
  end
624
639
  end
625
640
  end
641
+
642
+ describe "#enabled/disabled_gates" do
643
+ before do
644
+ subject.enable_percentage_of_time 5
645
+ subject.enable_percentage_of_actors 5
646
+ end
647
+
648
+ it "can return enabled gates" do
649
+ subject.enabled_gates.map(&:name).to_set.should eq(Set[
650
+ :percentage_of_actors,
651
+ :percentage_of_time,
652
+ ])
653
+
654
+ subject.enabled_gate_names.to_set.should eq(Set[
655
+ :percentage_of_actors,
656
+ :percentage_of_time,
657
+ ])
658
+ end
659
+
660
+ it "can return disabled gates" do
661
+ subject.disabled_gates.map(&:name).to_set.should eq(Set[
662
+ :actor,
663
+ :boolean,
664
+ :group,
665
+ ])
666
+
667
+ subject.disabled_gate_names.to_set.should eq(Set[
668
+ :actor,
669
+ :boolean,
670
+ :group,
671
+ ])
672
+ end
673
+ end
626
674
  end
@@ -6,19 +6,4 @@ describe Flipper::Gates::Actor do
6
6
  subject {
7
7
  described_class.new
8
8
  }
9
-
10
- describe "#description" do
11
- context "with actors in set" do
12
- it "returns text" do
13
- values = Set['bacon', 'ham']
14
- subject.description(values).should eq('actors ("bacon", "ham")')
15
- end
16
- end
17
-
18
- context "with no actors in set" do
19
- it "returns disabled" do
20
- subject.description(Set.new).should eq('disabled')
21
- end
22
- end
23
- end
24
9
  end
@@ -7,20 +7,6 @@ describe Flipper::Gates::Boolean do
7
7
  described_class.new
8
8
  }
9
9
 
10
- describe "#description" do
11
- context "for enabled" do
12
- it "returns Enabled" do
13
- subject.description(true).should eq('Enabled')
14
- end
15
- end
16
-
17
- context "for disabled" do
18
- it "returns Disabled" do
19
- subject.description(false).should eq('Disabled')
20
- end
21
- end
22
- end
23
-
24
10
  describe "#enabled?" do
25
11
  context "for true value" do
26
12
  it "returns true" do
@@ -48,4 +34,34 @@ describe Flipper::Gates::Boolean do
48
34
  end
49
35
  end
50
36
  end
37
+
38
+ describe "#protects?" do
39
+ it "returns true for boolean type" do
40
+ subject.protects?(Flipper::Types::Boolean.new(true)).should be(true)
41
+ end
42
+
43
+ it "returns true for true" do
44
+ subject.protects?(true).should be(true)
45
+ end
46
+
47
+ it "returns true for false" do
48
+ subject.protects?(false).should be(true)
49
+ end
50
+ end
51
+
52
+ describe "#wrap" do
53
+ it "returns boolean type for boolean type" do
54
+ subject.wrap(Flipper::Types::Boolean.new(true)).should be_instance_of(Flipper::Types::Boolean)
55
+ end
56
+
57
+ it "returns boolean type for true" do
58
+ subject.wrap(true).should be_instance_of(Flipper::Types::Boolean)
59
+ subject.wrap(true).value.should be(true)
60
+ end
61
+
62
+ it "returns boolean type for true" do
63
+ subject.wrap(false).should be_instance_of(Flipper::Types::Boolean)
64
+ subject.wrap(false).value.should be(false)
65
+ end
66
+ end
51
67
  end
@@ -7,21 +7,6 @@ describe Flipper::Gates::Group do
7
7
  described_class.new
8
8
  }
9
9
 
10
- describe "#description" do
11
- context "with groups in set" do
12
- it "returns text" do
13
- values = Set['bacon', 'ham']
14
- subject.description(values).should eq('groups (:bacon, :ham)')
15
- end
16
- end
17
-
18
- context "with no groups in set" do
19
- it "returns disabled" do
20
- subject.description(Set.new).should eq('disabled')
21
- end
22
- end
23
- end
24
-
25
10
  describe "#open?" do
26
11
  context "with a group in adapter, but not registered" do
27
12
  before do
@@ -7,20 +7,6 @@ describe Flipper::Gates::PercentageOfActors do
7
7
  described_class.new
8
8
  }
9
9
 
10
- describe "#description" do
11
- context "when enabled" do
12
- it "returns text" do
13
- subject.description(22).should eq('22% of actors')
14
- end
15
- end
16
-
17
- context "when disabled" do
18
- it "returns disabled" do
19
- subject.description(0).should eq('disabled')
20
- end
21
- end
22
- end
23
-
24
10
  describe "#open?" do
25
11
  context "when compared against two features" do
26
12
  let(:percentage) { 0.05 }
@@ -6,18 +6,4 @@ describe Flipper::Gates::PercentageOfTime do
6
6
  subject {
7
7
  described_class.new
8
8
  }
9
-
10
- describe "#description" do
11
- context "when enabled" do
12
- it "returns text" do
13
- subject.description(22).should eq('22% of the time')
14
- end
15
- end
16
-
17
- context "when disabled" do
18
- it "returns disabled" do
19
- subject.description(0).should eq('disabled')
20
- end
21
- end
22
- end
23
9
  end
data/spec/helper.rb CHANGED
@@ -3,9 +3,9 @@ $:.unshift(File.expand_path('../../lib', __FILE__))
3
3
  require 'pathname'
4
4
  require 'logger'
5
5
 
6
- root_path = Pathname(__FILE__).dirname.join('..').expand_path
7
- lib_path = root_path.join('lib')
8
- log_path = root_path.join('log')
6
+ FlipperRoot = Pathname(__FILE__).dirname.join('..').expand_path
7
+ lib_path = FlipperRoot.join('lib')
8
+ log_path = FlipperRoot.join('log')
9
9
  log_path.mkpath
10
10
 
11
11
  require 'rubygems'
@@ -15,14 +15,9 @@ Bundler.setup(:default)
15
15
 
16
16
  require 'flipper'
17
17
 
18
- Dir[root_path.join("spec/support/**/*.rb")].each { |f| require f }
18
+ Dir[FlipperRoot.join("spec/support/**/*.rb")].each { |f| require f }
19
19
 
20
20
  RSpec.configure do |config|
21
- config.filter_run :focus => true
22
- config.alias_example_to :fit, :focused => true
23
- config.alias_example_to :xit, :pending => true
24
- config.run_all_when_everything_filtered = true
25
-
26
21
  config.before(:each) do
27
22
  Flipper.unregister_groups
28
23
  end
metadata CHANGED
@@ -1,16 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flipper
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0.beta2
4
+ version: 0.7.0.beta3
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Nunemaker
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-04-16 00:00:00.000000000 Z
11
+ date: 2015-04-24 00:00:00.000000000 Z
12
12
  dependencies: []
13
- description: Feature flipper for any adapter
13
+ description:
14
14
  email:
15
15
  - nunemaker@gmail.com
16
16
  executables: []
@@ -42,6 +42,7 @@ files:
42
42
  - lib/flipper/adapters/memoizable.rb
43
43
  - lib/flipper/adapters/memory.rb
44
44
  - lib/flipper/adapters/operation_logger.rb
45
+ - lib/flipper/adapters/pstore.rb
45
46
  - lib/flipper/decorator.rb
46
47
  - lib/flipper/dsl.rb
47
48
  - lib/flipper/errors.rb
@@ -81,6 +82,7 @@ files:
81
82
  - spec/flipper/adapters/memoizable_spec.rb
82
83
  - spec/flipper/adapters/memory_spec.rb
83
84
  - spec/flipper/adapters/operation_logger_spec.rb
85
+ - spec/flipper/adapters/pstore_spec.rb
84
86
  - spec/flipper/dsl_spec.rb
85
87
  - spec/flipper/feature_spec.rb
86
88
  - spec/flipper/gate_spec.rb
@@ -109,7 +111,8 @@ files:
109
111
  - spec/integration_spec.rb
110
112
  - spec/support/fake_udp_socket.rb
111
113
  homepage: http://jnunemaker.github.com/flipper
112
- licenses: []
114
+ licenses:
115
+ - MIT
113
116
  metadata: {}
114
117
  post_install_message:
115
118
  rdoc_options: []
@@ -136,6 +139,7 @@ test_files:
136
139
  - spec/flipper/adapters/memoizable_spec.rb
137
140
  - spec/flipper/adapters/memory_spec.rb
138
141
  - spec/flipper/adapters/operation_logger_spec.rb
142
+ - spec/flipper/adapters/pstore_spec.rb
139
143
  - spec/flipper/dsl_spec.rb
140
144
  - spec/flipper/feature_spec.rb
141
145
  - spec/flipper/gate_spec.rb