Module: Split::Helper

Included in:
EncapsulatedHelper::ContextShim
Defined in:
lib/split/helper.rb

Constant Summary collapse

OVERRIDE_PARAM_NAME =
"ab_test"

Class Method Summary collapse

Class Method Details

.ab_active_experimentsObject



100
101
102
103
104
105
# File 'lib/split/helper.rb', line 100

def ab_active_experiments()
  ab_user.active_experiments
rescue => e
  raise unless Split.configuration.db_failover
  Split.configuration.db_failover_on_db_error.call(e)
end

.ab_finished(metric_descriptor, options = {:reset => true}) ⇒ Object



65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/split/helper.rb', line 65

def ab_finished(metric_descriptor, options = {:reset => true})
  return if exclude_visitor? || Split.configuration.disabled?
  metric_descriptor, goals = normalize_metric(metric_descriptor)
  experiments = Metric.possible_experiments(metric_descriptor)

  if experiments.any?
    experiments.each do |experiment|
      finish_experiment(experiment, options.merge(:goals => goals))
    end
  end
rescue => e
  raise unless Split.configuration.db_failover
  Split.configuration.db_failover_on_db_error.call(e)
end

.ab_record_extra_info(metric_descriptor, key, value = 1) ⇒ Object



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/split/helper.rb', line 80

def ab_record_extra_info(metric_descriptor, key, value = 1)
  return if exclude_visitor? || Split.configuration.disabled?
  metric_descriptor, goals = normalize_metric(metric_descriptor)
  experiments = Metric.possible_experiments(metric_descriptor)

  if experiments.any?
    experiments.each do |experiment|
      alternative_name = ab_user[experiment.key]

      if alternative_name
        alternative = experiment.alternatives.find{|alt| alt.name == alternative_name}
        alternative.record_extra_info(key, value) if alternative
      end
    end
  end
rescue => e
  raise unless Split.configuration.db_failover
  Split.configuration.db_failover_on_db_error.call(e)
end

.ab_test(metric_descriptor, control = nil, *alternatives) ⇒ Object



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
# File 'lib/split/helper.rb', line 8

def ab_test(metric_descriptor, control = nil, *alternatives)
  begin
    experiment = ExperimentCatalog.find_or_initialize(metric_descriptor, control, *alternatives)
    alternative = if Split.configuration.enabled && !exclude_visitor?
      experiment.save
      raise(Split::InvalidExperimentsFormatError) unless (Split.configuration.experiments || {}).fetch(experiment.name.to_sym, {})[:combined_experiments].nil?
      trial = Trial.new(:user => ab_user, :experiment => experiment,
          :override => override_alternative(experiment.name), :exclude => exclude_visitor?,
          :disabled => split_generically_disabled?)
      alt = trial.choose!(self)
      alt ? alt.name : nil
    else
      control_variable(experiment.control)
    end
  rescue Errno::ECONNREFUSED, Redis::BaseError, SocketError => e
    raise(e) unless Split.configuration.db_failover
    Split.configuration.db_failover_on_db_error.call(e)

    if Split.configuration.db_failover_allow_parameter_override
      alternative = override_alternative(experiment.name) if override_present?(experiment.name)
      alternative = control_variable(experiment.control) if split_generically_disabled?
    end
  ensure
    alternative ||= control_variable(experiment.control)
  end

  if block_given?
     = trial ? trial. : {}
    yield(alternative, )
  else
    alternative
  end
end

.ab_userObject



120
121
122
# File 'lib/split/helper.rb', line 120

def ab_user
  @ab_user ||= User.new(self)
end

.active_experimentsObject



145
146
147
# File 'lib/split/helper.rb', line 145

def active_experiments
  ab_user.active_experiments
end

.control_variable(control) ⇒ Object



160
161
162
# File 'lib/split/helper.rb', line 160

def control_variable(control)
  Hash === control ? control.keys.first.to_s : control.to_s
end

.exclude_visitor?Boolean

Returns:

  • (Boolean)


124
125
126
# File 'lib/split/helper.rb', line 124

def exclude_visitor?
  defined?(request) && (instance_exec(request, &Split.configuration.ignore_filter) || is_ignored_ip_address? || is_robot? || is_preview?)
end

.finish_experiment(experiment, options = {:reset => true}) ⇒ Object



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/split/helper.rb', line 46

def finish_experiment(experiment, options = {:reset => true})
  return true if experiment.has_winner?
  should_reset = experiment.resettable? && options[:reset]
  if ab_user[experiment.finished_key] && !should_reset
    return true
  else
    alternative_name = ab_user[experiment.key]
    trial = Trial.new(:user => ab_user, :experiment => experiment,
          :alternative => alternative_name)
    trial.complete!(options[:goals], self)

    if should_reset
      reset!(experiment)
    else
      ab_user[experiment.finished_key] = true
    end
  end
end

.is_ignored_ip_address?Boolean

Returns:

  • (Boolean)


136
137
138
139
140
141
142
143
# File 'lib/split/helper.rb', line 136

def is_ignored_ip_address?
  return false if Split.configuration.ignore_ip_addresses.empty?

  Split.configuration.ignore_ip_addresses.each do |ip|
    return true if defined?(request) && (request.ip == ip || (ip.class == Regexp && request.ip =~ ip))
  end
  false
end

.is_preview?Boolean

Returns:

  • (Boolean)


132
133
134
# File 'lib/split/helper.rb', line 132

def is_preview?
  defined?(request) && defined?(request.headers) && request.headers['x-purpose'] == 'preview'
end

.is_robot?Boolean

Returns:

  • (Boolean)


128
129
130
# File 'lib/split/helper.rb', line 128

def is_robot?
  defined?(request) && request.user_agent =~ Split.configuration.robot_regex
end

.normalize_metric(metric_descriptor) ⇒ Object



149
150
151
152
153
154
155
156
157
158
# File 'lib/split/helper.rb', line 149

def normalize_metric(metric_descriptor)
  if Hash === metric_descriptor
    experiment_name = metric_descriptor.keys.first
    goals = Array(metric_descriptor.values.first)
  else
    experiment_name = metric_descriptor
    goals = []
  end
  return experiment_name, goals
end

.override_alternative(experiment_name) ⇒ Object



112
113
114
# File 'lib/split/helper.rb', line 112

def override_alternative(experiment_name)
  defined?(params) && params[OVERRIDE_PARAM_NAME] && params[OVERRIDE_PARAM_NAME][experiment_name]
end

.override_present?(experiment_name) ⇒ Boolean

Returns:

  • (Boolean)


108
109
110
# File 'lib/split/helper.rb', line 108

def override_present?(experiment_name)
  override_alternative(experiment_name)
end

.reset!(experiment) ⇒ Object



42
43
44
# File 'lib/split/helper.rb', line 42

def reset!(experiment)
  ab_user.delete(experiment.key)
end

.split_generically_disabled?Boolean

Returns:

  • (Boolean)


116
117
118
# File 'lib/split/helper.rb', line 116

def split_generically_disabled?
  defined?(params) && params['SPLIT_DISABLE']
end