Class: TrailGuide::Experiments::Config

Inherits:
Canfig::Config
  • Object
show all
Defined in:
lib/trail_guide/experiments/config.rb

Direct Known Subclasses

CombinedConfig

Constant Summary collapse

DEFAULT_KEYS =
[
  :name, :summary, :preview_url, :algorithm, :metric, :variants, :goals,
  :start_manually, :reset_manually, :store_override, :track_override,
  :combined, :allow_multiple_conversions, :allow_multiple_goals,
  :track_winner_conversions, :skip_request_filter, :target_sample_size,
  :can_resume
].freeze
CALLBACK_KEYS =
[
  :on_start, :on_stop, :on_pause, :on_resume, :on_winner, :on_reset,
  :on_delete, :on_choose, :on_use, :on_convert, :on_redis_failover,
  :allow_participation, :allow_conversion, :rollout_winner
].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(experiment, *args, **opts, &block) ⇒ Config

Returns a new instance of Config.



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/trail_guide/experiments/config.rb', line 36

def initialize(experiment, *args, **opts, &block)
  @experiment = experiment
  opts = opts.merge(default_config)
  ancestor = opts.delete(:inherit)
  if ancestor.present?
    keys = opts.keys.dup.concat(args).concat(DEFAULT_KEYS).concat(CALLBACK_KEYS).uniq
    opts = opts.merge(ancestor.to_h.slice(*keys))
    opts[:name] = nil
    opts[:goals] = ancestor.goals.dup
    opts[:combined] = ancestor.combined.dup
    opts[:variants] = ancestor.variants.map { |var| var.dup(experiment) }
    opts = opts.merge(ancestor.callbacks.map { |k,v| [k,[v].flatten.compact] }.to_h)
  end
  super(*args, **opts, &block)
end

Instance Attribute Details

#experimentObject (readonly)

Returns the value of attribute experiment.



34
35
36
# File 'lib/trail_guide/experiments/config.rb', line 34

def experiment
  @experiment
end

Instance Method Details

#algorithmObject



88
89
90
# File 'lib/trail_guide/experiments/config.rb', line 88

def algorithm
  @algorithm ||= TrailGuide::Algorithms.algorithm(self[:algorithm])
end

#allow_conversion(meth = nil, &block) ⇒ Object



202
203
204
205
# File 'lib/trail_guide/experiments/config.rb', line 202

def allow_conversion(meth=nil, &block)
  self[:allow_conversion] ||= []
  self[:allow_conversion] << (meth || block)
end

#allow_multiple_conversions?Boolean

Returns:

  • (Boolean)


60
61
62
# File 'lib/trail_guide/experiments/config.rb', line 60

def allow_multiple_conversions?
  !!allow_multiple_conversions
end

#allow_multiple_goals?Boolean

Returns:

  • (Boolean)


64
65
66
# File 'lib/trail_guide/experiments/config.rb', line 64

def allow_multiple_goals?
  !!allow_multiple_goals
end

#allow_participation(meth = nil, &block) ⇒ Object



197
198
199
200
# File 'lib/trail_guide/experiments/config.rb', line 197

def allow_participation(meth=nil, &block)
  self[:allow_participation] ||= []
  self[:allow_participation] << (meth || block)
end

#callback_configObject



28
29
30
31
32
# File 'lib/trail_guide/experiments/config.rb', line 28

def callback_config
  CALLBACK_KEYS.map do |key|
    [key, []]
  end.to_h
end

#callbacksObject



138
139
140
# File 'lib/trail_guide/experiments/config.rb', line 138

def callbacks
  to_h.slice(*CALLBACK_KEYS).map { |k,v| [k, [v].flatten.compact] }.to_h
end

#can_resume?Boolean

Returns:

  • (Boolean)


76
77
78
# File 'lib/trail_guide/experiments/config.rb', line 76

def can_resume?
  !!can_resume
end

#combined?Boolean

Returns:

  • (Boolean)


130
131
132
# File 'lib/trail_guide/experiments/config.rb', line 130

def combined?
  !combined.empty?
end

#controlObject



101
102
103
# File 'lib/trail_guide/experiments/config.rb', line 101

def control
  return variants.find { |var| var.control? } || variants.first
end

#control=(name) ⇒ Object



105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/trail_guide/experiments/config.rb', line 105

def control=(name)
  variants.each(&:variant!)
  var_idx = variants.index { |var| var == name }

  if var_idx.nil?
    variant = Variant.new(experiment, name, control: true)
    variants.push(variant)
  else
    variant = variants[var_idx]
    variant.control!
  end

  variant
end

#default_configObject



18
19
20
21
22
23
24
25
26
# File 'lib/trail_guide/experiments/config.rb', line 18

def default_config
  DEFAULT_KEYS.map do |key|
    [key, nil]
  end.to_h.merge({
    variants: [],
    goals: [],
    combined: []
  }).merge(callback_config)
end

#goal(name) ⇒ Object Also known as: funnel



120
121
122
# File 'lib/trail_guide/experiments/config.rb', line 120

def goal(name)
  goals << name.to_s.underscore.to_sym
end

#goalsObject Also known as: funnels



125
126
127
# File 'lib/trail_guide/experiments/config.rb', line 125

def goals
  self[:goals]
end

#metricObject



84
85
86
# File 'lib/trail_guide/experiments/config.rb', line 84

def metric
  @metric ||= (self[:metric] || name).try(:to_s).try(:underscore).try(:to_sym)
end

#nameObject



80
81
82
# File 'lib/trail_guide/experiments/config.rb', line 80

def name
  @name ||= (self[:name] || experiment.name).try(:to_s).try(:underscore).try(:to_sym)
end

#on_choose(meth = nil, &block) ⇒ Object



142
143
144
145
# File 'lib/trail_guide/experiments/config.rb', line 142

def on_choose(meth=nil, &block)
  self[:on_choose] ||= []
  self[:on_choose] << (meth || block)
end

#on_convert(meth = nil, &block) ⇒ Object



152
153
154
155
# File 'lib/trail_guide/experiments/config.rb', line 152

def on_convert(meth=nil, &block)
  self[:on_convert] ||= []
  self[:on_convert] << (meth || block)
end

#on_delete(meth = nil, &block) ⇒ Object



187
188
189
190
# File 'lib/trail_guide/experiments/config.rb', line 187

def on_delete(meth=nil, &block)
  self[:on_delete] ||= []
  self[:on_delete] << (meth || block)
end

#on_pause(meth = nil, &block) ⇒ Object



167
168
169
170
# File 'lib/trail_guide/experiments/config.rb', line 167

def on_pause(meth=nil, &block)
  self[:on_pause] ||= []
  self[:on_pause] << (meth || block)
end

#on_redis_failover(meth = nil, &block) ⇒ Object



192
193
194
195
# File 'lib/trail_guide/experiments/config.rb', line 192

def on_redis_failover(meth=nil, &block)
  self[:on_redis_failover] ||= []
  self[:on_redis_failover] << (meth || block)
end

#on_reset(meth = nil, &block) ⇒ Object



182
183
184
185
# File 'lib/trail_guide/experiments/config.rb', line 182

def on_reset(meth=nil, &block)
  self[:on_reset] ||= []
  self[:on_reset] << (meth || block)
end

#on_resume(meth = nil, &block) ⇒ Object



172
173
174
175
# File 'lib/trail_guide/experiments/config.rb', line 172

def on_resume(meth=nil, &block)
  self[:on_resume] ||= []
  self[:on_resume] << (meth || block)
end

#on_start(meth = nil, &block) ⇒ Object



157
158
159
160
# File 'lib/trail_guide/experiments/config.rb', line 157

def on_start(meth=nil, &block)
  self[:on_start] ||= []
  self[:on_start] << (meth || block)
end

#on_stop(meth = nil, &block) ⇒ Object



162
163
164
165
# File 'lib/trail_guide/experiments/config.rb', line 162

def on_stop(meth=nil, &block)
  self[:on_stop] ||= []
  self[:on_stop] << (meth || block)
end

#on_use(meth = nil, &block) ⇒ Object



147
148
149
150
# File 'lib/trail_guide/experiments/config.rb', line 147

def on_use(meth=nil, &block)
  self[:on_use] ||= []
  self[:on_use] << (meth || block)
end

#on_winner(meth = nil, &block) ⇒ Object



177
178
179
180
# File 'lib/trail_guide/experiments/config.rb', line 177

def on_winner(meth=nil, &block)
  self[:on_winner] ||= []
  self[:on_winner] << (meth || block)
end

#preview_url?Boolean

Returns:

  • (Boolean)


134
135
136
# File 'lib/trail_guide/experiments/config.rb', line 134

def preview_url?
  !!preview_url
end

#reset_manually?Boolean

Returns:

  • (Boolean)


56
57
58
# File 'lib/trail_guide/experiments/config.rb', line 56

def reset_manually?
  !!reset_manually
end

#rollout_winner(meth = nil, &block) ⇒ Object



207
208
209
210
# File 'lib/trail_guide/experiments/config.rb', line 207

def rollout_winner(meth=nil, &block)
  self[:rollout_winner] ||= []
  self[:rollout_winner] << (meth || block)
end

#skip_request_filter?Boolean

Returns:

  • (Boolean)


72
73
74
# File 'lib/trail_guide/experiments/config.rb', line 72

def skip_request_filter?
  !!skip_request_filter
end

#start_manually?Boolean

Returns:

  • (Boolean)


52
53
54
# File 'lib/trail_guide/experiments/config.rb', line 52

def start_manually?
  !!start_manually
end

#track_winner_conversions?Boolean

Returns:

  • (Boolean)


68
69
70
# File 'lib/trail_guide/experiments/config.rb', line 68

def track_winner_conversions?
  !!track_winner_conversions
end

#variant(varname, metadata: {}, weight: 1, control: false) ⇒ Object

Raises:

  • (ArgumentError)


92
93
94
95
96
97
98
99
# File 'lib/trail_guide/experiments/config.rb', line 92

def variant(varname, metadata: {}, weight: 1, control: false)
  raise ArgumentError, "The variant `#{varname}` already exists in the experiment `#{name}`" if variants.any? { |var| var == varname }
  control = true if variants.empty?
  variants.each(&:variant!) if control
  variant = Variant.new(experiment, varname, metadata: , weight: weight, control: control)
  variants << variant
  variant
end