class Gitlab::Experiment

Constants

Error
InvalidRolloutRules
VERSION
Variant

Public Class Methods

default_rollout(rollout = nil, options = {}) click to toggle source
# File lib/gitlab/experiment.rb, line 33
def default_rollout(rollout = nil, options = {})
  return @rollout ||= Configuration.default_rollout if rollout.blank?

  @rollout = Rollout.resolve(rollout).new(options)
end
exclude(*filter_list, **options, &block) click to toggle source
# File lib/gitlab/experiment.rb, line 39
def exclude(*filter_list, **options, &block)
  build_callback(:exclusion_check, filter_list.unshift(block), **options) do |target, callback|
    throw(:abort) if target.instance_variable_get(:@excluded) || callback.call(target, nil) == true
  end
end
model_name() click to toggle source

used for generating routes

# File lib/gitlab/experiment/engine.rb, line 10
def self.model_name
  ActiveModel::Name.new(self, Gitlab)
end
published_experiments() click to toggle source
# File lib/gitlab/experiment.rb, line 51
def published_experiments
  RequestStore.store[:published_gitlab_experiments] || {}
end
segment(*filter_list, variant:, **options, &block) click to toggle source
# File lib/gitlab/experiment.rb, line 45
def segment(*filter_list, variant:, **options, &block)
  build_callback(:segmentation_check, filter_list.unshift(block), **options) do |target, callback|
    target.variant(variant) if target.instance_variable_get(:@variant_name).nil? && callback.call(target, nil)
  end
end

Public Instance Methods

candidate(name = nil, &block) click to toggle source
# File lib/gitlab/experiment.rb, line 65
def candidate(name = nil, &block)
  name = (name || :candidate).to_s
  behaviors[name] = block
end
Also aliased as: try
context(value = nil) click to toggle source
# File lib/gitlab/experiment.rb, line 71
def context(value = nil)
  return @context if value.blank?

  @context.value(value)
  @context
end
control(&block) click to toggle source
# File lib/gitlab/experiment.rb, line 60
def control(&block)
  candidate(:control, &block)
end
Also aliased as: use
enabled?() click to toggle source
# File lib/gitlab/experiment.rb, line 130
def enabled?
  true
end
exclude!() click to toggle source
# File lib/gitlab/experiment.rb, line 101
def exclude!
  @excluded = true
end
excluded?() click to toggle source
# File lib/gitlab/experiment.rb, line 134
def excluded?
  return @excluded if defined?(@excluded)

  @excluded = !run_callbacks(:exclusion_check) { :not_excluded }
end
experiment_group?() click to toggle source
# File lib/gitlab/experiment.rb, line 140
def experiment_group?
  instance_exec(@variant_name, &Configuration.inclusion_resolver)
end
key_for(source, seed = name) click to toggle source
# File lib/gitlab/experiment.rb, line 152
def key_for(source, seed = name)
  # TODO: Added deprecation in release 0.6.0
  if (block = Configuration.instance_variable_get(:@__context_hash_strategy))
    return instance_exec(source, seed, &block)
  end

  source = source.keys + source.values if source.is_a?(Hash)

  ingredients = Array(source).map { |v| identify(v) }
  ingredients.unshift(seed).unshift(Configuration.context_key_secret)

  Digest::SHA2.new(Configuration.context_key_bit_length).hexdigest(ingredients.join('|'))
end
name() click to toggle source
# File lib/gitlab/experiment.rb, line 56
def name
  [Configuration.name_prefix, @name].compact.join('_')
end
process_redirect_url(url) click to toggle source
# File lib/gitlab/experiment.rb, line 123
def process_redirect_url(url)
  return unless Configuration.redirect_url_validator&.call(url)

  track('visited', url: url)
  url # return the url, which allows for mutation
end
publish(result) click to toggle source
# File lib/gitlab/experiment.rb, line 111
def publish(result)
  instance_exec(result, &Configuration.publishing_behavior)

  (RequestStore.store[:published_gitlab_experiments] ||= {})[name] = signature.merge(excluded: excluded?)
end
rollout(rollout = nil, options = {}) click to toggle source
# File lib/gitlab/experiment.rb, line 95
def rollout(rollout = nil, options = {})
  return @rollout ||= self.class.default_rollout(nil, options) if rollout.blank?

  @rollout = Rollout.resolve(rollout).new(options)
end
run(variant_name = nil) click to toggle source
Calls superclass method
# File lib/gitlab/experiment.rb, line 105
def run(variant_name = nil)
  @result ||= super(variant(variant_name).name)
rescue Scientist::BehaviorMissing => e
  raise Error, e
end
should_track?() click to toggle source
# File lib/gitlab/experiment.rb, line 144
def should_track?
  enabled? && @context.trackable? && !excluded?
end
signature() click to toggle source
# File lib/gitlab/experiment.rb, line 148
def signature
  { variant: variant.name, experiment: name }.merge(context.signature)
end
track(action, **event_args) click to toggle source
# File lib/gitlab/experiment.rb, line 117
def track(action, **event_args)
  return unless should_track?

  instance_exec(action, event_args, &Configuration.tracking_behavior)
end
try(name = nil, &block)
Alias for: candidate
use(&block)
Alias for: control
variant(value = nil) click to toggle source
# File lib/gitlab/experiment.rb, line 78
def variant(value = nil)
  @variant_name = cache_variant(value) if value.present?
  return Variant.new(name: (@variant_name || :unresolved).to_s) if @variant_name || @resolving_variant

  if enabled?
    @resolving_variant = true
    @variant_name = cached_variant_resolver(@variant_name)
  end

  run_callbacks(segmentation_callback_chain) do
    @variant_name ||= :control
    Variant.new(name: @variant_name.to_s)
  end
ensure
  @resolving_variant = false
end

Protected Instance Methods

identify(object) click to toggle source
# File lib/gitlab/experiment.rb, line 168
def identify(object)
  (object.respond_to?(:to_global_id) ? object.to_global_id : object).to_s
end
resolve_variant_name() click to toggle source
# File lib/gitlab/experiment.rb, line 178
def resolve_variant_name
  rollout.rollout_for(self) if experiment_group?
end
segmentation_callback_chain() click to toggle source
# File lib/gitlab/experiment.rb, line 172
def segmentation_callback_chain
  return :segmentation_check if @variant_name.nil? && enabled? && !excluded?

  :unsegmented
end