Module: BrainzLab::Cortex

Defined in:
lib/brainzlab/cortex.rb,
lib/brainzlab/cortex/cache.rb,
lib/brainzlab/cortex/client.rb,
lib/brainzlab/cortex/provisioner.rb

Defined Under Namespace

Classes: Cache, Client, Provisioner

Class Method Summary collapse

Class Method Details

.all(**context) ⇒ Hash

Get all flags for a context

Examples:

flags = BrainzLab::Cortex.all(user: current_user)
flags[:new_checkout]  # => true
flags[:rate_limit]    # => 200

Parameters:

  • context (Hash)

    Evaluation context

Returns:

  • (Hash)

    All flag values



93
94
95
96
97
98
99
100
101
# File 'lib/brainzlab/cortex.rb', line 93

def all(**context)
  return {} unless module_enabled?

  ensure_provisioned!
  return {} unless BrainzLab.configuration.cortex_valid?

  merged_context = merge_context(context)
  client.evaluate_all(context: merged_context)
end

.cacheObject



171
172
173
# File 'lib/brainzlab/cortex.rb', line 171

def cache
  @cache ||= Cache.new(BrainzLab.configuration.cortex_cache_ttl)
end

.clear_cache!Object

Clear the flag cache



127
128
129
# File 'lib/brainzlab/cortex.rb', line 127

def clear_cache!
  cache.clear!
end

.clear_context!Object

Clear the current context



140
141
142
# File 'lib/brainzlab/cortex.rb', line 140

def clear_context!
  Thread.current[:cortex_context] = nil
end

.clientObject



167
168
169
# File 'lib/brainzlab/cortex.rb', line 167

def client
  @client ||= Client.new(BrainzLab.configuration)
end

.disabled?(flag_name, **context) ⇒ Boolean

Check if a feature flag is disabled

Parameters:

  • flag_name (String, Symbol)

    The flag name

  • context (Hash)

    Evaluation context

Returns:

  • (Boolean)

    True if the flag is disabled



29
30
31
# File 'lib/brainzlab/cortex.rb', line 29

def disabled?(flag_name, **context)
  !enabled?(flag_name, **context)
end

.enabled?(flag_name, **context) ⇒ Boolean

Check if a feature flag is enabled

Examples:

if BrainzLab::Cortex.enabled?(:new_checkout, user: current_user)
  render_new_checkout
end

Parameters:

  • flag_name (String, Symbol)

    The flag name

  • context (Hash)

    Evaluation context (user, attributes, etc.)

Returns:

  • (Boolean)

    True if the flag is enabled



20
21
22
23
# File 'lib/brainzlab/cortex.rb', line 20

def enabled?(flag_name, **context)
  result = get(flag_name, **context)
  [true, 'true'].include?(result)
end

.ensure_provisioned!Object

INTERNAL ===



156
157
158
159
160
161
# File 'lib/brainzlab/cortex.rb', line 156

def ensure_provisioned!
  return if @provisioned

  @provisioned = true
  provisioner.ensure_project!
end

.flag_config(flag_name) ⇒ Hash?

Get a flag’s configuration

Parameters:

  • flag_name (String, Symbol)

    The flag name

Returns:

  • (Hash, nil)

    Flag configuration



117
118
119
120
121
122
123
124
# File 'lib/brainzlab/cortex.rb', line 117

def flag_config(flag_name)
  return nil unless module_enabled?

  ensure_provisioned!
  return nil unless BrainzLab.configuration.cortex_valid?

  client.get_flag(flag_name.to_s)
end

.get(flag_name, default: nil, **context) ⇒ Object

Get the value of a feature flag

Examples:

limit = BrainzLab::Cortex.get(:rate_limit, user: current_user, default: 100)

Parameters:

  • flag_name (String, Symbol)

    The flag name

  • context (Hash)

    Evaluation context

  • default (Object) (defaults to: nil)

    Default value if flag not found

Returns:

  • (Object)

    The flag value



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/brainzlab/cortex.rb', line 42

def get(flag_name, default: nil, **context)
  return default unless module_enabled?

  ensure_provisioned!
  return default unless BrainzLab.configuration.cortex_valid?

  flag_key = flag_name.to_s
  merged_context = merge_context(context)
  cache_key = build_cache_key(flag_key, merged_context)

  # Check cache first
  return cache.get(cache_key) if BrainzLab.configuration.cortex_cache_enabled && cache.has?(cache_key)

  result = client.evaluate(flag_key, context: merged_context)

  if result.nil?
    default
  else
    cache.set(cache_key, result) if BrainzLab.configuration.cortex_cache_enabled
    result
  end
end

.list_flagsArray<Hash>

List all flag definitions

Returns:

  • (Array<Hash>)

    List of flag metadata



105
106
107
108
109
110
111
112
# File 'lib/brainzlab/cortex.rb', line 105

def list_flags
  return [] unless module_enabled?

  ensure_provisioned!
  return [] unless BrainzLab.configuration.cortex_valid?

  client.list
end

.provisionerObject



163
164
165
# File 'lib/brainzlab/cortex.rb', line 163

def provisioner
  @provisioner ||= Provisioner.new(BrainzLab.configuration)
end

.reset!Object



175
176
177
178
179
180
181
# File 'lib/brainzlab/cortex.rb', line 175

def reset!
  @client = nil
  @provisioner = nil
  @cache = nil
  @provisioned = false
  Thread.current[:cortex_context] = nil
end

.set_context(**context) ⇒ Object

Set default context for all evaluations in current request

Parameters:

  • context (Hash)

    Context to merge



135
136
137
# File 'lib/brainzlab/cortex.rb', line 135

def set_context(**context)
  Thread.current[:cortex_context] = (Thread.current[:cortex_context] || {}).merge(context)
end

.variant(flag_name, default: nil, **context) ⇒ String?

Get the variant for an A/B test flag

Examples:

variant = BrainzLab::Cortex.variant(:checkout_experiment, user: current_user)
case variant
when "control" then render_control
when "treatment_a" then render_treatment_a
when "treatment_b" then render_treatment_b
end

Parameters:

  • flag_name (String, Symbol)

    The flag name

  • context (Hash)

    Evaluation context

  • default (String) (defaults to: nil)

    Default variant if flag not found

Returns:

  • (String, nil)

    The variant name



79
80
81
82
# File 'lib/brainzlab/cortex.rb', line 79

def variant(flag_name, default: nil, **context)
  result = get(flag_name, **context)
  result.is_a?(String) ? result : default
end

.with_context(**context) ⇒ Object

Evaluate flags with a temporary context

Parameters:

  • context (Hash)

    Temporary context



146
147
148
149
150
151
152
# File 'lib/brainzlab/cortex.rb', line 146

def with_context(**context)
  previous = Thread.current[:cortex_context]
  Thread.current[:cortex_context] = (previous || {}).merge(context)
  yield
ensure
  Thread.current[:cortex_context] = previous
end