File: context.rb

package info (click to toggle)
ruby-gitlab-experiment 0.9.1-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 260 kB
  • sloc: ruby: 1,202; makefile: 7
file content (87 lines) | stat: -rw-r--r-- 2,306 bytes parent folder | download
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