1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
|
# frozen_string_literal: true
module Gitlab
class Experiment
class Context
include Cookies
DNT_REGEXP = /^(true|t|yes|y|1|on)$/i.freeze
attr_reader :request
def initialize(experiment, **initial_value)
@experiment = experiment
@value = {}
@migrations = { merged: [], unmerged: [] }
value(initial_value)
end
def reinitialize(request)
@signature = nil # clear memoization
@request = request if request.respond_to?(:headers) && request.respond_to?(:cookie_jar)
end
def value(value = nil)
return @value if value.nil?
value = value.dup # dup so we don't mutate
reinitialize(value.delete(:request))
key(value.delete(:sticky_to))
@value.merge!(process_migrations(value))
end
def key(key = nil)
return @key || @experiment.key_for(value) if key.nil?
@key = @experiment.key_for(key)
end
def trackable?
!(@request && @request.headers['DNT'].to_s.match?(DNT_REGEXP))
end
def freeze
signature # finalize before freezing
super
end
def signature
@signature ||= { key: key, migration_keys: migration_keys }.compact
end
def method_missing(method_name, *)
@value.include?(method_name.to_sym) ? @value[method_name.to_sym] : super
end
def respond_to_missing?(method_name, *)
@value.include?(method_name.to_sym) ? true : super
end
private
def process_migrations(value)
add_unmerged_migration(value.delete(:migrated_from))
add_merged_migration(value.delete(:migrated_with))
migrate_cookie(value, @experiment.instance_exec(@experiment, &Configuration.cookie_name))
end
def add_unmerged_migration(value = {})
@migrations[:unmerged] << value if value.is_a?(Hash)
end
def add_merged_migration(value = {})
@migrations[:merged] << value if value.is_a?(Hash)
end
def migration_keys
return nil if @migrations[:unmerged].empty? && @migrations[:merged].empty?
@migrations[:unmerged].map { |m| @experiment.key_for(m) } +
@migrations[:merged].map { |m| @experiment.key_for(@value.merge(m)) }
end
end
end
end
|