Class: Flipper::Feature

Inherits:
Object
  • Object
show all
Defined in:
lib/flipper/feature.rb

Constant Summary collapse

InstrumentationName =

Private: The name of feature instrumentation events.

"feature_operation.#{InstrumentationNamespace}".freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, adapter, options = {}) ⇒ Feature

Internal: Initializes a new feature instance.

name - The Symbol or String name of the feature. adapter - The adapter that will be used to store details about this feature.

options - The Hash of options.

:instrumenter - What to use to instrument all the things.


32
33
34
35
36
37
# File 'lib/flipper/feature.rb', line 32

def initialize(name, adapter, options = {})
  @name = name
  @key = name.to_s
  @instrumenter = options.fetch(:instrumenter, Instrumenters::Noop)
  @adapter = adapter
end

Instance Attribute Details

#adapterObject (readonly)

Private: The adapter this feature should use.



19
20
21
# File 'lib/flipper/feature.rb', line 19

def adapter
  @adapter
end

#instrumenterObject (readonly)

Private: What is being used to instrument all the things.



22
23
24
# File 'lib/flipper/feature.rb', line 22

def instrumenter
  @instrumenter
end

#keyObject (readonly)

Public: Name converted to value safe for adapter.



16
17
18
# File 'lib/flipper/feature.rb', line 16

def key
  @key
end

#nameObject (readonly)

Public: The name of the feature.



13
14
15
# File 'lib/flipper/feature.rb', line 13

def name
  @name
end

Instance Method Details

#actors_valueObject

Public: Get the adapter value for the actors gate.

Returns Set of String flipper_id’s.



319
320
321
# File 'lib/flipper/feature.rb', line 319

def actors_value
  gate_values.actors
end

#addObject

Public: Adds this feature.

Returns the result of Adapter#add.



74
75
76
# File 'lib/flipper/feature.rb', line 74

def add
  instrument(:add) { adapter.add(self) }
end

#add_expression(expression_to_add) ⇒ Object

Public: Add an expression for a feature.

expression_to_add - an expression or Hash that can be converted to an expression.

Returns result of enable.



137
138
139
140
141
142
143
# File 'lib/flipper/feature.rb', line 137

def add_expression(expression_to_add)
  if (current_expression = expression)
    enable current_expression.add(expression_to_add)
  else
    enable expression_to_add
  end
end

#boolean_valueObject

Public: Get the adapter value for the boolean gate.

Returns true or false.



326
327
328
# File 'lib/flipper/feature.rb', line 326

def boolean_value
  gate_values.boolean
end

#clearObject

Public: Clears all gate values for this feature.

Returns the result of Adapter#clear.



95
96
97
# File 'lib/flipper/feature.rb', line 95

def clear
  instrument(:clear) { adapter.clear(self) }
end

#conditional?Boolean

Public: Is the feature conditionally enabled for a given actor, group, percentage of actors or percentage of the time.

Returns:

  • (Boolean)


273
274
275
# File 'lib/flipper/feature.rb', line 273

def conditional?
  state == :conditional
end

#disable(thing = false) ⇒ Object

Public: Disable this feature for something.

Returns the result of Adapter#disable.



58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/flipper/feature.rb', line 58

def disable(thing = false)
  instrument(:disable) do |payload|
    adapter.add self

    gate = gate_for(thing)
    wrapped_thing = gate.wrap(thing)
    payload[:gate_name] = gate.name
    payload[:thing] = wrapped_thing

    adapter.disable self, gate, wrapped_thing
  end
end

#disable_actor(actor) ⇒ Object

Public: Disables a feature for an actor.

actor - a Flipper::Types::Actor instance or an object that responds

to flipper_id.

Returns result of disable.



212
213
214
# File 'lib/flipper/feature.rb', line 212

def disable_actor(actor)
  disable Types::Actor.wrap(actor)
end

#disable_expressionObject

Public: Disables an expression for a feature.

expression - an expression or Hash that can be converted to an expression.

Returns result of disable.



190
191
192
# File 'lib/flipper/feature.rb', line 190

def disable_expression
  disable Flipper.all # just need an expression to clear
end

#disable_group(group) ⇒ Object

Public: Disables a feature for a group.

group - a Flipper::Types::Group instance or a String or Symbol name of a

registered group.

Returns result of disable.



222
223
224
# File 'lib/flipper/feature.rb', line 222

def disable_group(group)
  disable Types::Group.wrap(group)
end

#disable_percentage_of_actorsObject

Public: Disables a feature for a percentage of actors.

percentage - a Flipper::Types::PercentageOfTime instance or an object that

responds to to_i.

Returns result of disable.



242
243
244
# File 'lib/flipper/feature.rb', line 242

def disable_percentage_of_actors
  disable Types::PercentageOfActors.new(0)
end

#disable_percentage_of_timeObject

Public: Disables a feature a percentage of time.

percentage - a Flipper::Types::PercentageOfTime instance or an object that

responds to to_i.

Returns result of disable.



232
233
234
# File 'lib/flipper/feature.rb', line 232

def disable_percentage_of_time
  disable Types::PercentageOfTime.new(0)
end

#disabled_gate_namesObject

Public: Get the names of the disabled gates.

Returns an Array of gate names.



369
370
371
# File 'lib/flipper/feature.rb', line 369

def disabled_gate_names
  disabled_gates.map(&:name)
end

#disabled_gatesObject

Public: Get the gates that have not been enabled for the feature.

Returns an Array of Flipper::Gate instances.



362
363
364
# File 'lib/flipper/feature.rb', line 362

def disabled_gates
  gates - enabled_gates
end

#disabled_groupsObject

Public: Get groups not enabled for this feature.

Returns Set of Flipper::Types::Group instances.



294
295
296
# File 'lib/flipper/feature.rb', line 294

def disabled_groups
  Flipper.groups - enabled_groups
end

#enable(thing = true) ⇒ Object

Public: Enable this feature for something.

Returns the result of Adapter#enable.



42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/flipper/feature.rb', line 42

def enable(thing = true)
  instrument(:enable) do |payload|
    adapter.add self

    gate = gate_for(thing)
    wrapped_thing = gate.wrap(thing)
    payload[:gate_name] = gate.name
    payload[:thing] = wrapped_thing

    adapter.enable self, gate, wrapped_thing
  end
end

#enable_actor(actor) ⇒ Object

Public: Enables a feature for an actor.

actor - a Flipper::Types::Actor instance or an object that responds

to flipper_id.

Returns result of enable.



151
152
153
# File 'lib/flipper/feature.rb', line 151

def enable_actor(actor)
  enable Types::Actor.wrap(actor)
end

#enable_expression(expression) ⇒ Object

Public: Enables an expression_to_add for a feature.

expression - an Expression or Hash that can be converted to an expression.

Returns result of enable.



128
129
130
# File 'lib/flipper/feature.rb', line 128

def enable_expression(expression)
  enable Expression.build(expression)
end

#enable_group(group) ⇒ Object

Public: Enables a feature for a group.

group - a Flipper::Types::Group instance or a String or Symbol name of a

registered group.

Returns result of enable.



161
162
163
# File 'lib/flipper/feature.rb', line 161

def enable_group(group)
  enable Types::Group.wrap(group)
end

#enable_percentage_of_actors(percentage) ⇒ Object

Public: Enables a feature for a percentage of actors.

percentage - a Flipper::Types::PercentageOfTime instance or an object that

responds to to_i.

Returns result of enable.



181
182
183
# File 'lib/flipper/feature.rb', line 181

def enable_percentage_of_actors(percentage)
  enable Types::PercentageOfActors.wrap(percentage)
end

#enable_percentage_of_time(percentage) ⇒ Object

Public: Enables a feature a percentage of time.

percentage - a Flipper::Types::PercentageOfTime instance or an object that

responds to to_i.

Returns result of enable.



171
172
173
# File 'lib/flipper/feature.rb', line 171

def enable_percentage_of_time(percentage)
  enable Types::PercentageOfTime.wrap(percentage)
end

#enabled?(*actors) ⇒ Boolean

Public: Check if a feature is enabled for zero or more actors.

Returns true if enabled, false if not.

Returns:

  • (Boolean)


102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/flipper/feature.rb', line 102

def enabled?(*actors)
  actors = actors.flatten.compact.map { |actor| Types::Actor.wrap(actor) }
  actors = nil if actors.empty?

  # thing is left for backwards compatibility
  instrument(:enabled?, thing: actors&.first, actors: actors) do |payload|
    context = FeatureCheckContext.new(
      feature_name: @name,
      values: gate_values,
      actors: actors
    )

    if open_gate = gates.detect { |gate| gate.open?(context) }
      payload[:gate_name] = open_gate.name
      true
    else
      false
    end
  end
end

#enabled_gate_namesObject

Public: Get the names of the enabled gates.

Returns an Array of gate names.



355
356
357
# File 'lib/flipper/feature.rb', line 355

def enabled_gate_names
  enabled_gates.map(&:name)
end

#enabled_gatesObject

Public: Get the gates that have been enabled for the feature.

Returns an Array of Flipper::Gate instances.



347
348
349
350
# File 'lib/flipper/feature.rb', line 347

def enabled_gates
  values = gate_values
  gates.select { |gate| gate.enabled?(values.send(gate.key)) }
end

#enabled_groupsObject Also known as: groups

Public: Get groups enabled for this feature.

Returns Set of Flipper::Types::Group instances.



286
287
288
# File 'lib/flipper/feature.rb', line 286

def enabled_groups
  groups_value.map { |name| Flipper.group(name) }.to_set
end

#exist?Boolean

Public: Does this feature exist in the adapter.

Returns true if exists in adapter else false.

Returns:

  • (Boolean)


81
82
83
# File 'lib/flipper/feature.rb', line 81

def exist?
  instrument(:exist?) { adapter.features.include?(key) }
end

#expressionObject



298
299
300
# File 'lib/flipper/feature.rb', line 298

def expression
  Flipper::Expression.build(expression_value) if expression_value
end

#expression_valueObject

Public: Get the adapter value for the expression gate.

Returns expression.



312
313
314
# File 'lib/flipper/feature.rb', line 312

def expression_value
  gate_values.expression
end

#gate(name) ⇒ Object

Public: Find a gate by name.

Returns a Flipper::Gate if found, nil if not.



415
416
417
# File 'lib/flipper/feature.rb', line 415

def gate(name)
  gates_hash[name.to_sym]
end

#gate_for(actor) ⇒ Object

Public: Find the gate that protects an actor.

actor - The object for which you would like to find a gate

Returns a Flipper::Gate. Raises Flipper::GateNotFound if no gate found for actor



425
426
427
# File 'lib/flipper/feature.rb', line 425

def gate_for(actor)
  gates.detect { |gate| gate.protects?(actor) } || raise(GateNotFound, actor)
end

#gate_valuesObject

Public: Returns the raw gate values stored by the adapter.



278
279
280
281
# File 'lib/flipper/feature.rb', line 278

def gate_values
  adapter_values = adapter.get(self)
  GateValues.new(adapter_values)
end

#gatesObject

Public: Get all the gates used to determine enabled/disabled for the feature.

Returns an array of gates



397
398
399
# File 'lib/flipper/feature.rb', line 397

def gates
  @gates ||= gates_hash.values.freeze
end

#gates_hashObject



401
402
403
404
405
406
407
408
409
410
# File 'lib/flipper/feature.rb', line 401

def gates_hash
  @gates_hash ||= {
    boolean: Gates::Boolean.new,
    expression: Gates::Expression.new,
    actor: Gates::Actor.new,
    percentage_of_actors: Gates::PercentageOfActors.new,
    percentage_of_time: Gates::PercentageOfTime.new,
    group: Gates::Group.new,
  }.freeze
end

#groups_valueObject

Public: Get the adapter value for the groups gate.

Returns Set of String group names.



305
306
307
# File 'lib/flipper/feature.rb', line 305

def groups_value
  gate_values.groups
end

#inspectObject

Public: Pretty string version for debugging.



384
385
386
387
388
389
390
391
392
# File 'lib/flipper/feature.rb', line 384

def inspect
  attributes = [
    "name=#{name.inspect}",
    "state=#{state.inspect}",
    "enabled_gate_names=#{enabled_gate_names.inspect}",
    "adapter=#{adapter.name.inspect}",
  ]
  "#<#{self.class.name}:#{object_id} #{attributes.join(', ')}>"
end

#off?Boolean

Public: Is the feature fully disabled.

Returns:

  • (Boolean)


267
268
269
# File 'lib/flipper/feature.rb', line 267

def off?
  state == :off
end

#on?Boolean

Public: Is the feature fully enabled.

Returns:

  • (Boolean)


262
263
264
# File 'lib/flipper/feature.rb', line 262

def on?
  state == :on
end

#percentage_of_actors_valueObject

Public: Get the adapter value for the percentage of actors gate.

Returns Integer greater than or equal to 0 and less than or equal to 100.



333
334
335
# File 'lib/flipper/feature.rb', line 333

def percentage_of_actors_value
  gate_values.percentage_of_actors
end

#percentage_of_time_valueObject

Public: Get the adapter value for the percentage of time gate.

Returns Integer greater than or equal to 0 and less than or equal to 100.



340
341
342
# File 'lib/flipper/feature.rb', line 340

def percentage_of_time_value
  gate_values.percentage_of_time
end

#removeObject

Public: Removes this feature.

Returns the result of Adapter#remove.



88
89
90
# File 'lib/flipper/feature.rb', line 88

def remove
  instrument(:remove) { adapter.remove(self) }
end

#remove_expression(expression_to_remove) ⇒ Object

Public: Remove an expression from a feature. Does nothing if no expression is currently enabled.

expression - an Expression or Hash that can be converted to an expression.

Returns result of enable or nil (if no expression enabled).



200
201
202
203
204
# File 'lib/flipper/feature.rb', line 200

def remove_expression(expression_to_remove)
  if (current_expression = expression)
    enable current_expression.remove(expression_to_remove)
  end
end

#stateObject

Public: Returns state for feature (:on, :off, or :conditional).



247
248
249
250
251
252
253
254
255
256
257
258
259
# File 'lib/flipper/feature.rb', line 247

def state
  values = gate_values
  boolean = gate(:boolean)
  non_boolean_gates = gates - [boolean]

  if values.boolean || values.percentage_of_time == 100
    :on
  elsif non_boolean_gates.detect { |gate| gate.enabled?(values.send(gate.key)) }
    :conditional
  else
    :off
  end
end

#to_paramObject

Public: Identifier to be used in the url (a rails-ism).



379
380
381
# File 'lib/flipper/feature.rb', line 379

def to_param
  to_s
end

#to_sObject

Public: Returns the string representation of the feature.



374
375
376
# File 'lib/flipper/feature.rb', line 374

def to_s
  name.to_s
end