Class: Abingo::Experiment

Inherits:
ActiveRecord::Base
  • Object
show all
Includes:
ConversionRate, Statistics
Defined in:
lib/abingo/experiment.rb

Constant Summary

Constants included from Statistics

Statistics::DESCRIPTION_IN_WORDS, Statistics::HANDY_Z_SCORE_CHEATSHEET, Statistics::PERCENTAGES

Class Method Summary collapse

Instance Method Summary collapse

Methods included from ConversionRate

#conversion_rate, #pretty_conversion_rate

Methods included from Statistics

#describe_result_in_words, #is_statistically_significant?, #p_value, #pretty_conversion_rate, #zscore

Class Method Details

.alternatives_for_test(test_name) ⇒ Object



45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/abingo/experiment.rb', line 45

def self.alternatives_for_test(test_name)
  cache_key = "Abingo::#{test_name}::alternatives".gsub(" ","_")
  Abingo.cache.fetch(cache_key) do
    experiment = Abingo::Experiment.find_by_test_name(test_name)
    alternatives_array = Abingo.cache.fetch(cache_key) do
      tmp_array = experiment.alternatives.map do |alt|
        [alt.content, alt.weight]
      end
      tmp_hash = tmp_array.inject({}) {|hash, couplet| hash[couplet[0]] = couplet[1]; hash}
      Abingo.parse_alternatives(tmp_hash)
    end
    alternatives_array
  end
end

.exists?(test_name) ⇒ Boolean

Returns:

  • (Boolean)


36
37
38
39
40
41
42
43
# File 'lib/abingo/experiment.rb', line 36

def self.exists?(test_name)
  cache_key = "Abingo::Experiment::exists(#{test_name})".gsub(" ", "_")
  ret = Abingo.cache.fetch(cache_key) do
    count = Abingo::Experiment.count(:conditions => {:test_name => test_name})
    count > 0 ? count : nil
  end
  (!ret.nil?)
end

.start_experiment!(test_name, alternatives_array, conversion_name = nil) ⇒ Object



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
# File 'lib/abingo/experiment.rb', line 60

def self.start_experiment!(test_name, alternatives_array, conversion_name = nil)
  conversion_name ||= test_name
  conversion_name.gsub!(" ", "_")
  cloned_alternatives_array = alternatives_array.clone
  ActiveRecord::Base.transaction do
    experiment = Abingo::Experiment.find_or_create_by_test_name(test_name)
    experiment.alternatives.destroy_all  #Blows away alternatives for pre-existing experiments.
    while (cloned_alternatives_array.size > 0)
      alt = cloned_alternatives_array[0]
      weight = cloned_alternatives_array.size - (cloned_alternatives_array - [alt]).size
      experiment.alternatives.build(:content => alt, :weight => weight,
        :lookup => Abingo::Alternative.calculate_lookup(test_name, alt))
      cloned_alternatives_array -= [alt]
    end
    experiment.status = "Live"
    experiment.save(false)  #Calling the validation here causes problems b/c of transaction.
    Abingo.cache.write("Abingo::Experiment::exists(#{test_name})".gsub(" ", "_"), 1)

    #This might have issues in very, very high concurrency environments...

    tests_listening_to_conversion = Abingo.cache.read("Abingo::tests_listening_to_conversion#{conversion_name}") || []
    tests_listening_to_conversion << test_name unless tests_listening_to_conversion.include? test_name
    Abingo.cache.write("Abingo::tests_listening_to_conversion#{conversion_name}", tests_listening_to_conversion)
    experiment
  end
end

Instance Method Details

#before_destroyObject



15
16
17
18
19
20
# File 'lib/abingo/experiment.rb', line 15

def before_destroy
  cache_keys.each do |key|
    Abingo.cache.delete key
  end
  true
end

#best_alternativeObject



30
31
32
33
34
# File 'lib/abingo/experiment.rb', line 30

def best_alternative
  alternatives.max do |a,b|
    a.conversion_rate <=> b.conversion_rate
  end
end

#cache_keysObject



8
9
10
11
12
13
# File 'lib/abingo/experiment.rb', line 8

def cache_keys
["Abingo::Experiment::exists(#{test_name})".gsub(" ", "_"),
  "Abingo::Experiment::#{test_name}::alternatives".gsub(" ","_"),
  "Abingo::Experiment::short_circuit(#{test_name})".gsub(" ", "_")
]
end

#conversionsObject



26
27
28
# File 'lib/abingo/experiment.rb', line 26

def conversions
  alternatives.sum("conversions")
end

#end_experiment!(final_alternative, conversion_name = nil) ⇒ Object



87
88
89
90
91
92
93
94
95
96
97
# File 'lib/abingo/experiment.rb', line 87

def end_experiment!(final_alternative, conversion_name = nil)
  conversion_name ||= test_name
  ActiveRecord::Base.transaction do
    alternatives.each do |alternative|
      alternative.lookup = "Experiment completed.  #{alternative.id}"
      alternative.save!
    end
    update_attribute(:status, "Finished")
    Abingo.cache.write("Abingo::Experiment::short_circuit(#{test_name})".gsub(" ", "_"), final_alternative)
  end
end

#participantsObject



22
23
24
# File 'lib/abingo/experiment.rb', line 22

def participants
  alternatives.sum("participants")
end