class ABSplit::Functions::WeightedSplit

Weighted split based on hash value.

Non persistent - No collisions are possible

Based on memory position

Constants

MAX_POSITIONS

Public Class Methods

value_for(value, *params) click to toggle source
# File lib/a_b_split/functions/weighted_split.rb, line 14
def value_for(value, *params)
  given_weights = validate(params)

  experiments = split_weights(params, params.size, given_weights)

  select_experiment_for(value, experiments)
end

Protected Class Methods

select_experiment_for(value, experiments) click to toggle source
# File lib/a_b_split/functions/weighted_split.rb, line 53
def select_experiment_for(value, experiments)
  x_position = value.hash

  markers(experiments).each_with_index do |limit, i|
    return experiments[i]['name'] if x_position <= limit
  end

  experiments.last['name']
end
split_weights(experiments, parts, given_percentage) click to toggle source
# File lib/a_b_split/functions/weighted_split.rb, line 36
def split_weights(experiments, parts, given_percentage)
  return experiments if given_percentage.size >= parts

  missing_weights = parts - given_percentage.size
  missing_percentage = 100 - given_percentage.reduce(0, &:+)

  experiments.map do |experiment|
    experiment['weight'] = if experiment['weight']
                             experiment['weight'].to_f
                           else
                             missing_percentage.to_f / missing_weights
                           end

    experiment
  end
end
validate(experiments) click to toggle source
# File lib/a_b_split/functions/weighted_split.rb, line 24
def validate(experiments)
  given_weights = experiments.each_with_object([]) do |param, memo|
    memo << param['weight'] if param.key?('weight')
  end

  unless experiments.any? && experiments.size > 1 && given_weights.reduce(0, &:+) <= 100
    raise ABSplit::NoValidExperiment
  end

  given_weights
end

Private Class Methods

markers(experiments) click to toggle source
# File lib/a_b_split/functions/weighted_split.rb, line 65
def markers(experiments)
  experiments.map do |experiment|
    (self::MAX_POSITIONS * (experiment['weight'] / 100)) - (self::MAX_POSITIONS / 2)
  end
end