Module: TalkToYourApp::Plugins::Flipper
- Defined in:
- lib/talk_to_your_app/plugins/flipper/plugin.rb,
lib/talk_to_your_app/plugins/flipper/tools/read_flag.rb,
lib/talk_to_your_app/plugins/flipper/tools/list_flags.rb,
lib/talk_to_your_app/plugins/flipper/tools/enable_flag.rb,
lib/talk_to_your_app/plugins/flipper/tools/disable_flag.rb,
lib/talk_to_your_app/plugins/flipper/tools/enabled_flags.rb
Overview
The Flipper plugin: list flags, read a flag’s state (globally or for an actor), and enable/disable flags globally or per actor. All operations run through the writer-capable :flipper_writer connection — deliberately separate from the DB plugin’s read-only one.
Defined Under Namespace
Modules: Tools Classes: Actor, Plugin
Class Method Summary collapse
-
.active?(gates) ⇒ Boolean
A flag is “enabled” if any gate is active.
-
.actor_for(actor_class, actor_id) ⇒ Object
Builds an actor from a class name + id, or nil when none was supplied.
-
.apply(operation, name, gate) ⇒ Object
Applies :enable or :disable across the resolved gate.
-
.gate_conflict?(args) ⇒ Boolean
True when a call names more than one gate dimension (actor, group, percentage).
-
.gate_from(args) ⇒ Object
Resolves which Flipper gate a tool call targets from its arguments.
-
.gate_values(name) ⇒ Object
The full per-gate configuration of a flag, for read_flag.
-
.preload_timestamps(names) ⇒ Object
Last-change timestamps for many flags in a single query, keyed by flag name, read from the flipper_features table when the ActiveRecord adapter is in use.
-
.state(name, actor) ⇒ Object
Reads a flag’s effective state, globally or for an actor.
Class Method Details
.active?(gates) ⇒ Boolean
A flag is “enabled” if any gate is active.
99 100 101 102 103 104 105 |
# File 'lib/talk_to_your_app/plugins/flipper/plugin.rb', line 99 def active?(gates) gates[:boolean] || gates[:actors].any? || gates[:groups].any? || gates[:percentage_of_actors].to_i.positive? || gates[:percentage_of_time].to_i.positive? end |
.actor_for(actor_class, actor_id) ⇒ Object
Builds an actor from a class name + id, or nil when none was supplied.
26 27 28 29 30 |
# File 'lib/talk_to_your_app/plugins/flipper/plugin.rb', line 26 def actor_for(actor_class, actor_id) return nil if actor_class.nil? || actor_id.nil? Actor.new("#{actor_class};#{actor_id}") end |
.apply(operation, name, gate) ⇒ Object
Applies :enable or :disable across the resolved gate. Every branch is an explicit named call so the dispatch is statically obvious and an unknown gate type fails fast rather than silently toggling the boolean gate.
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/talk_to_your_app/plugins/flipper/plugin.rb', line 62 def apply(operation, name, gate) enabling = operation == :enable case gate[:type] when :boolean enabling ? ::Flipper.enable(name) : ::Flipper.disable(name) when :actor enabling ? ::Flipper.enable(name, gate[:actor]) : ::Flipper.disable(name, gate[:actor]) when :group enabling ? ::Flipper.enable_group(name, gate[:group]) : ::Flipper.disable_group(name, gate[:group]) when :percentage_of_actors enabling ? ::Flipper.enable_percentage_of_actors(name, gate[:percentage]) : ::Flipper.disable_percentage_of_actors(name) when :percentage_of_time enabling ? ::Flipper.enable_percentage_of_time(name, gate[:percentage]) : ::Flipper.disable_percentage_of_time(name) else raise ArgumentError, "unknown Flipper gate type: #{gate[:type].inspect}" end end |
.gate_conflict?(args) ⇒ Boolean
True when a call names more than one gate dimension (actor, group, percentage). gate_from would silently pick one by precedence and drop the rest, so the tools reject the call instead.
35 36 37 38 39 40 41 |
# File 'lib/talk_to_your_app/plugins/flipper/plugin.rb', line 35 def gate_conflict?(args) selectors = [] selectors << :actor if args[:actor_class] && args[:actor_id] selectors << :group if args[:group] selectors << :percentage unless args[:percentage].nil? selectors.size > 1 end |
.gate_from(args) ⇒ Object
Resolves which Flipper gate a tool call targets from its arguments. In precedence order: a specific actor, a named group, a percentage, else the global boolean gate.
46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/talk_to_your_app/plugins/flipper/plugin.rb', line 46 def gate_from(args) if (actor = actor_for(args[:actor_class], args[:actor_id])) { type: :actor, actor: actor } elsif args[:group] { type: :group, group: args[:group].to_sym } elsif !args[:percentage].nil? type = args[:percentage_type] == "time" ? :percentage_of_time : :percentage_of_actors { type: type, percentage: args[:percentage].to_i } else { type: :boolean } end end |
.gate_values(name) ⇒ Object
The full per-gate configuration of a flag, for read_flag.
87 88 89 90 91 92 93 94 95 96 |
# File 'lib/talk_to_your_app/plugins/flipper/plugin.rb', line 87 def gate_values(name) values = ::Flipper[name].gate_values { boolean: values.boolean, actors: values.actors.to_a, groups: values.groups.to_a, percentage_of_actors: values.percentage_of_actors, percentage_of_time: values.percentage_of_time, } end |
.preload_timestamps(names) ⇒ Object
Last-change timestamps for many flags in a single query, keyed by flag name, read from the flipper_features table when the ActiveRecord adapter is in use. Flipper records no enable/disable history, so updated_at is the last time the feature row changed. Returns an empty hash (callers fall back to nil timestamps) for non-ActiveRecord adapters. Batched to avoid an N+1 across all flags.
113 114 115 116 117 118 119 120 121 |
# File 'lib/talk_to_your_app/plugins/flipper/plugin.rb', line 113 def (names) return {} unless defined?(::Flipper::Adapters::ActiveRecord::Feature) ::Flipper::Adapters::ActiveRecord::Feature.where(key: names.map(&:to_s)).each_with_object({}) do |row, acc| acc[row.key] = { created_at: row.created_at&.utc&.iso8601, updated_at: row.updated_at&.utc&.iso8601 } end rescue StandardError {} end |
.state(name, actor) ⇒ Object
Reads a flag’s effective state, globally or for an actor. Unknown flags read false.
82 83 84 |
# File 'lib/talk_to_your_app/plugins/flipper/plugin.rb', line 82 def state(name, actor) actor ? ::Flipper.enabled?(name, actor) : ::Flipper.enabled?(name) end |