conductor 0.8.3 → 0.9.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/{LICENSE → MIT-LICENSE} +1 -1
- data/README.rdoc +7 -0
- data/Rakefile +25 -45
- data/app/assets/javascripts/conductor/application.js +15 -0
- data/app/assets/javascripts/conductor/dashboard.js +2 -0
- data/app/assets/stylesheets/conductor/application.css +13 -0
- data/{generators/conductor/templates/conductor.css → app/assets/stylesheets/conductor/dashboard.css} +0 -0
- data/app/controllers/conductor/application_controller.rb +4 -0
- data/app/controllers/conductor/dashboard_controller.rb +11 -0
- data/app/helpers/conductor/application_helper.rb +4 -0
- data/{lib/conductor/rails/helpers → app/helpers/conductor}/dashboard_helper.rb +3 -1
- data/app/models/conductor/experiment/daily.rb +47 -0
- data/app/models/conductor/experiment/history.rb +9 -0
- data/app/models/conductor/experiment/raw.rb +20 -0
- data/app/models/conductor/experiment/weight.rb +11 -0
- data/{lib/conductor/rails/views → app/views/conductor}/dashboard/_current_weights.html.haml +0 -0
- data/{lib/conductor/rails/views → app/views/conductor}/dashboard/_daily_stats.html.haml +0 -0
- data/{lib/conductor/rails/views → app/views/conductor}/dashboard/_group_stats.html.haml +0 -0
- data/{lib/conductor/rails/views → app/views/conductor}/dashboard/_top_nav.html.haml +0 -0
- data/{lib/conductor/rails/views → app/views/conductor}/dashboard/_weight_history.html.haml +0 -0
- data/app/views/conductor/dashboard/index.html.haml +12 -0
- data/app/views/layouts/conductor/application.html.erb +14 -0
- data/config/routes.rb +4 -0
- data/db/migrate/20121010131323_create_conductor_daily_experiments.rb +16 -0
- data/db/migrate/20121010173406_create_conductor_experiment_weights.rb +13 -0
- data/db/migrate/20121010174835_create_conductor_raw_experiments.rb +13 -0
- data/db/migrate/20121010174950_create_conductor_weight_histories.rb +14 -0
- data/lib/conductor.rb +33 -57
- data/lib/conductor/core_ext.rb +18 -0
- data/lib/conductor/engine.rb +5 -0
- data/lib/conductor/experiment.rb +61 -60
- data/lib/conductor/roll_up.rb +2 -2
- data/lib/conductor/version.rb +3 -0
- data/lib/conductor/weights.rb +9 -8
- data/lib/tasks/conductor_tasks.rake +9 -0
- data/test/core_ext_test.rb +13 -0
- data/test/fixtures/conductor/conductor_daily_experiments.yml +17 -0
- data/test/functional/conductor/dashboard_controller_test.rb +11 -0
- data/test/integration/conductor/dashboard_test.rb +7 -0
- data/test/integration/navigation_test.rb +10 -0
- data/test/test_helper.rb +9 -23
- data/test/unit/conductor/conductor_daily_experiment_test.rb +9 -0
- data/test/unit/helpers/conductor/dashboard_helper_test.rb +6 -0
- metadata +240 -91
- data/VERSION +0 -1
- data/generators/conductor/conductor_generator.rb +0 -27
- data/generators/conductor/templates/conductor.rake +0 -6
- data/generators/conductor/templates/migration.rb +0 -54
- data/init.rb +0 -2
- data/lib/conductor/rails/controllers/dashboard.rb +0 -16
- data/lib/conductor/rails/models/daily.rb +0 -53
- data/lib/conductor/rails/models/history.rb +0 -14
- data/lib/conductor/rails/models/raw.rb +0 -27
- data/lib/conductor/rails/models/weight.rb +0 -18
- data/lib/conductor/rails/views/dashboard/index.html.haml +0 -29
- data/rails/init.rb +0 -7
- data/test/db/schema.rb +0 -43
- data/test/test_conductor.rb +0 -346
@@ -0,0 +1,18 @@
|
|
1
|
+
Array.class_eval do
|
2
|
+
def sum_it(attribute)
|
3
|
+
self.map {|x| x.send(attribute) }.compact.sum
|
4
|
+
end
|
5
|
+
|
6
|
+
def weighted_mean_of_attribute(attribute)
|
7
|
+
self.map {|x| x.send(attribute) }.compact.weighted_mean
|
8
|
+
end
|
9
|
+
|
10
|
+
def weighted_mean
|
11
|
+
w_sum = sum(self)
|
12
|
+
return 0.00 if w_sum == 0.00
|
13
|
+
|
14
|
+
w_prod = 0
|
15
|
+
self.each_index {|i| w_prod += (i+1) * self[i].to_f}
|
16
|
+
w_prod.to_f / w_sum.to_f
|
17
|
+
end
|
18
|
+
end
|
data/lib/conductor/experiment.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
module Conductor
|
2
2
|
class Experiment
|
3
3
|
class << self
|
4
4
|
# Selects the best alternative for a given group
|
@@ -24,7 +24,7 @@ class Conductor
|
|
24
24
|
# check for previous selection
|
25
25
|
selection = Conductor.cache.read("Conductor::#{Conductor.identity}::Experience::#{group_name}")
|
26
26
|
|
27
|
-
|
27
|
+
if selection.blank?
|
28
28
|
selection = select_alternative_for_group(group_name, alternatives)
|
29
29
|
Conductor::Experiment::Raw.create!({:identity_id => Conductor.identity.to_s, :group_name => group_name, :alternative => selection}.merge!(options))
|
30
30
|
Conductor.cache.write("Conductor::#{Conductor.identity}::Experience::#{group_name}", selection)
|
@@ -69,77 +69,78 @@ class Conductor
|
|
69
69
|
#
|
70
70
|
def track!(options={})
|
71
71
|
value = (options.delete(:value) || 1) # => pull the conversion value and remove from hash or set value to 1
|
72
|
-
experiments = Conductor::Experiment::Raw.
|
72
|
+
experiments = Conductor::Experiment::Raw.where({:identity_id => Conductor.identity.to_s}.merge!(options))
|
73
73
|
experiments.each {|x| x.update_attributes(:conversion_value => value)} if experiments
|
74
74
|
end
|
75
75
|
|
76
76
|
private
|
77
77
|
|
78
|
-
|
79
|
-
# create weighting table
|
80
|
-
weighting_table = generate_weighting_table(group_name, alternatives)
|
78
|
+
def select_alternative_for_group(group_name, alternatives)
|
81
79
|
|
82
|
-
|
83
|
-
|
84
|
-
end
|
80
|
+
# create weighting table
|
81
|
+
weighting_table = generate_weighting_table(group_name, alternatives)
|
85
82
|
|
86
|
-
#
|
87
|
-
|
88
|
-
|
89
|
-
# Note: We create sql where statement that includes the list of
|
90
|
-
# alternatives to select from in case an existing group
|
91
|
-
# has an alternative you no longer want to include in the result set
|
92
|
-
#
|
93
|
-
# TODO: store all weights for a group in cache and then weed out
|
94
|
-
# those not in the alternatives list
|
95
|
-
#
|
96
|
-
def generate_weighting_table(group_name, alternatives)
|
97
|
-
weights = Conductor::Weights.find_or_create(group_name, alternatives)
|
98
|
-
|
99
|
-
# create selection hash
|
100
|
-
weighting_table = weights.inject({}) {|res, x| res.merge!({x.alternative => x.weight})}
|
101
|
-
|
102
|
-
# is anything missing?
|
103
|
-
alternative_names = weights.map(&:alternative)
|
104
|
-
missing = alternatives - alternative_names
|
105
|
-
|
106
|
-
# if anything is missing, add it to the weighted list
|
107
|
-
unless missing.empty?
|
108
|
-
max_weight = weights.empty? ? 1 : weights.max {|a,b| a.weight <=> b.weight}.weight
|
109
|
-
missing.each do |name|
|
110
|
-
weighting_table.merge!({name => max_weight * MAX_WEIGHTING_FACTOR})
|
111
|
-
end
|
112
|
-
end
|
83
|
+
# make a selection from weighted hash
|
84
|
+
return choose_weighted(weighting_table)
|
85
|
+
end
|
113
86
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
87
|
+
# Returns a hash of alternatives with weights based on conversion
|
88
|
+
# e.g. {:option_a => .25, :option_b => .25, :option_c => .50}
|
89
|
+
#
|
90
|
+
# Note: We create sql where statement that includes the list of
|
91
|
+
# alternatives to select from in case an existing group
|
92
|
+
# has an alternative you no longer want to include in the result set
|
93
|
+
#
|
94
|
+
# TODO: store all weights for a group in cache and then weed out
|
95
|
+
# those not in the alternatives list
|
96
|
+
#
|
97
|
+
def generate_weighting_table(group_name, alternatives)
|
98
|
+
weights = Conductor::Weights.find_or_create(group_name, alternatives)
|
122
99
|
|
123
|
-
#
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
100
|
+
# create selection hash
|
101
|
+
weighting_table = weights.inject({}) {|res, x| res.merge!({x.alternative => x.weight})}
|
102
|
+
|
103
|
+
# is anything missing?
|
104
|
+
alternative_names = weights.map(&:alternative)
|
105
|
+
missing = alternatives - alternative_names
|
106
|
+
|
107
|
+
# if anything is missing, add it to the weighted list
|
108
|
+
unless missing.empty?
|
109
|
+
max_weight = weights.empty? ? 1 : weights.max {|a,b| a.weight <=> b.weight}.weight
|
110
|
+
missing.each do |name|
|
111
|
+
weighting_table.merge!({name => max_weight * MAX_WEIGHTING_FACTOR})
|
133
112
|
end
|
134
113
|
end
|
135
114
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
115
|
+
return weighting_table
|
116
|
+
end
|
117
|
+
|
118
|
+
# selects a random float
|
119
|
+
def float_rand(start_num, end_num=0)
|
120
|
+
width = end_num-start_num
|
121
|
+
return (rand*width)+start_num
|
122
|
+
end
|
123
|
+
|
124
|
+
# choose a random alternative based on weights
|
125
|
+
# from recipe 5.11 in ruby cookbook
|
126
|
+
def choose_weighted(weighted)
|
127
|
+
sum = weighted.inject(0) do |sum, item_and_weight|
|
128
|
+
sum += item_and_weight[1]
|
142
129
|
end
|
130
|
+
target = float_rand(sum)
|
131
|
+
weighted.each do |item, weight|
|
132
|
+
return item if target <= weight
|
133
|
+
target -= weight
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def normalize!(weighted)
|
138
|
+
sum = weighted.inject(0) do |sum, item_and_weight|
|
139
|
+
sum += item_and_weight[1]
|
140
|
+
end
|
141
|
+
sum = sum.to_f
|
142
|
+
weighted.each { |item, weight| weighted[item] = weight/sum }
|
143
|
+
end
|
143
144
|
end
|
144
145
|
end
|
145
146
|
end
|
data/lib/conductor/roll_up.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
module Conductor
|
2
2
|
class RollUp
|
3
3
|
def self.process
|
4
4
|
Conductor::Experiment::Raw.since(14.days.ago).group_by(&:created_date).each do |day, daily_rows|
|
@@ -20,7 +20,7 @@ class Conductor
|
|
20
20
|
end
|
21
21
|
|
22
22
|
# delete the cache for this group so it can be recreated with the new values
|
23
|
-
Conductor.cache.delete("Conductor::Experiment::#{
|
23
|
+
Conductor.cache.delete("Conductor::Experiment::#{group_name}::Alternatives")
|
24
24
|
end
|
25
25
|
end
|
26
26
|
end
|
data/lib/conductor/weights.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
|
2
|
-
class Weights
|
1
|
+
module Conductor
|
2
|
+
class Weights
|
3
3
|
class << self
|
4
4
|
|
5
5
|
# Returns all the weights for a given group. In the event that the alternatives specified for the
|
@@ -13,7 +13,7 @@ class Conductor
|
|
13
13
|
Conductor.log('alternatives equal to cache')
|
14
14
|
return weights_for_group
|
15
15
|
else
|
16
|
-
|
16
|
+
Conductor.log('alternatives NOT equal to cache. Need to recompute')
|
17
17
|
compute(group_name, alternatives)
|
18
18
|
|
19
19
|
# get the new weights
|
@@ -42,7 +42,7 @@ class Conductor
|
|
42
42
|
max_weight = 0
|
43
43
|
unless post_equalization_data.empty?
|
44
44
|
total = post_equalization_data.sum_it(Conductor.attribute_for_weighting)
|
45
|
-
data = (total
|
45
|
+
data = (total > 0) ? compute_weights(post_equalization_data, total, max_weight) : assign_equal_weights(post_equalization_data)
|
46
46
|
end
|
47
47
|
|
48
48
|
# add weights for recently launched
|
@@ -70,10 +70,10 @@ class Conductor
|
|
70
70
|
def weight_recently_launched(data, max_weight, equalization_period_data)
|
71
71
|
max_weight = 1 if data.empty?
|
72
72
|
equalization_period_data.each do |x|
|
73
|
-
days_ago = (Date.today - x.activity_date)
|
74
|
-
handicap = (days_ago.to_f / Conductor.equalization_period)
|
75
|
-
launch_window = (Conductor.equalization_period - days_ago)
|
76
|
-
|
73
|
+
days_ago = (Date.today - x.activity_date).to_f
|
74
|
+
handicap = (days_ago.to_f / Conductor.equalization_period).to_f
|
75
|
+
launch_window = (Conductor.equalization_period - days_ago).to_f
|
76
|
+
|
77
77
|
Conductor.log("Handicap for #{x.alternative} is #{handicap} (#{days_ago} days ago)")
|
78
78
|
data << {:name => x.alternative, :weight => max_weight * MAX_WEIGHTING_FACTOR * (1 - handicap), :launch_window => launch_window}
|
79
79
|
end
|
@@ -92,6 +92,7 @@ class Conductor
|
|
92
92
|
|
93
93
|
# creates new records in weights table and adds weights to weight history for reporting
|
94
94
|
def update_weights_in_db(group_name, data)
|
95
|
+
Conductor.log('update_weights_in_db')
|
95
96
|
data.each { |alternative|
|
96
97
|
Conductor::Experiment::Weight.create!(:group_name => group_name, :alternative => alternative[:name], :weight => alternative[:weight])
|
97
98
|
Conductor::Experiment::History.create!(:group_name => group_name, :alternative => alternative[:name], :weight => alternative[:weight], :launch_window => alternative[:launch_window], :computed_at => Time.now)
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# yaffle/test/core_ext_test.rb
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
class CoreExtTest < Test::Unit::TestCase
|
6
|
+
def test_calculation_of_waited_mean_exists
|
7
|
+
assert [1,2,3,4,5].weighted_mean
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_calculation_of_weighted_mean_is_correct
|
11
|
+
assert_equal [1,2,3,4,5].weighted_mean, 3.6666666666666665
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html
|
2
|
+
|
3
|
+
one:
|
4
|
+
activity_date: 2012-10-10
|
5
|
+
group_name: MyString
|
6
|
+
option_name: MyString
|
7
|
+
conversion_value: 9.99
|
8
|
+
views: 1
|
9
|
+
conversions: 1
|
10
|
+
|
11
|
+
two:
|
12
|
+
activity_date: 2012-10-10
|
13
|
+
group_name: MyString
|
14
|
+
option_name: MyString
|
15
|
+
conversion_value: 9.99
|
16
|
+
views: 1
|
17
|
+
conversions: 1
|
data/test/test_helper.rb
CHANGED
@@ -1,29 +1,15 @@
|
|
1
|
+
# Configure Rails Environment
|
1
2
|
ENV["RAILS_ENV"] = "test"
|
2
|
-
$:.unshift(File.dirname(__FILE__) + '/../lib')
|
3
3
|
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require 'active_record/version'
|
7
|
-
require 'active_record/fixtures'
|
8
|
-
require 'action_controller'
|
9
|
-
require 'action_controller/test_process'
|
10
|
-
require 'action_view'
|
11
|
-
require 'active_support'
|
12
|
-
require 'test/unit'
|
13
|
-
require 'conductor'
|
14
|
-
require 'shoulda'
|
4
|
+
require File.expand_path("../../spec/dummy/config/environment.rb", __FILE__)
|
5
|
+
require "rails/test_help"
|
15
6
|
|
16
|
-
|
7
|
+
Rails.backtrace_cleaner.remove_silencers!
|
17
8
|
|
9
|
+
# Load support files
|
10
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
|
18
11
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
ActiveRecord::Migration.verbose = false
|
23
|
-
load(File.dirname(__FILE__) + "/db/schema.rb")
|
24
|
-
|
25
|
-
@@cache = ActiveSupport::Cache::MemoryStore.new
|
26
|
-
|
27
|
-
class Test::Unit::TestCase
|
28
|
-
|
12
|
+
# Load fixtures from the engine
|
13
|
+
if ActiveSupport::TestCase.method_defined?(:fixture_path=)
|
14
|
+
ActiveSupport::TestCase.fixture_path = File.expand_path("../fixtures", __FILE__)
|
29
15
|
end
|
metadata
CHANGED
@@ -1,120 +1,269 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: conductor
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
|
6
|
-
- 0
|
7
|
-
- 8
|
8
|
-
- 3
|
9
|
-
version: 0.8.3
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.9.3
|
5
|
+
prerelease:
|
10
6
|
platform: ruby
|
11
|
-
authors:
|
7
|
+
authors:
|
12
8
|
- Noctivity
|
13
9
|
autorequire:
|
14
10
|
bindir: bin
|
15
11
|
cert_chain: []
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
12
|
+
date: 2012-10-10 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rails
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 3.2.8
|
22
|
+
type: :runtime
|
22
23
|
prerelease: false
|
23
|
-
|
24
|
-
none: false
|
25
|
-
requirements:
|
26
|
-
- -
|
27
|
-
- !ruby/object:Gem::Version
|
28
|
-
|
29
|
-
|
30
|
-
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 3.2.8
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: googlecharts
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
31
38
|
type: :runtime
|
32
|
-
version_requirements: *id001
|
33
|
-
- !ruby/object:Gem::Dependency
|
34
|
-
name: haml
|
35
39
|
prerelease: false
|
36
|
-
|
37
|
-
none: false
|
38
|
-
requirements:
|
39
|
-
- -
|
40
|
-
- !ruby/object:Gem::Version
|
41
|
-
|
42
|
-
|
43
|
-
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: haml
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
44
54
|
type: :runtime
|
45
|
-
|
46
|
-
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: sqlite3
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: rspec-rails
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: capybara
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: guard-rspec
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ! '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: guard-spork
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ! '>='
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0'
|
134
|
+
type: :development
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ! '>='
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '0'
|
142
|
+
- !ruby/object:Gem::Dependency
|
143
|
+
name: rb-fsevent
|
144
|
+
requirement: !ruby/object:Gem::Requirement
|
145
|
+
none: false
|
146
|
+
requirements:
|
147
|
+
- - ~>
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: 0.9.1
|
150
|
+
type: :development
|
151
|
+
prerelease: false
|
152
|
+
version_requirements: !ruby/object:Gem::Requirement
|
153
|
+
none: false
|
154
|
+
requirements:
|
155
|
+
- - ~>
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: 0.9.1
|
158
|
+
- !ruby/object:Gem::Dependency
|
159
|
+
name: debugger
|
160
|
+
requirement: !ruby/object:Gem::Requirement
|
161
|
+
none: false
|
162
|
+
requirements:
|
163
|
+
- - ! '>='
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: '0'
|
166
|
+
type: :development
|
167
|
+
prerelease: false
|
168
|
+
version_requirements: !ruby/object:Gem::Requirement
|
169
|
+
none: false
|
170
|
+
requirements:
|
171
|
+
- - ! '>='
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
description: Conductor is the bastard child of a/b testing and personalization. It
|
175
|
+
throws everything you know about creating a web site our the window and lets you
|
176
|
+
just "try stuff" without ever having to worry about not maximing your site's "purpose." Have
|
177
|
+
a new landing page? Just throw it to the conductor. Want to try different price
|
178
|
+
points - conductor. Different form designs? Conductor. Conductor will rotate
|
179
|
+
all alternatives through the mix and eventually settle on the top performing of
|
180
|
+
all, without you having to do anything other than just creating. Think intelligent
|
181
|
+
A/B testing on steriods.
|
47
182
|
email: jlippiner@noctivity.com
|
48
183
|
executables: []
|
49
|
-
|
50
184
|
extensions: []
|
51
|
-
|
52
|
-
|
53
|
-
-
|
54
|
-
-
|
55
|
-
|
56
|
-
-
|
57
|
-
-
|
58
|
-
-
|
59
|
-
-
|
60
|
-
-
|
61
|
-
-
|
62
|
-
-
|
63
|
-
-
|
64
|
-
-
|
65
|
-
-
|
185
|
+
extra_rdoc_files: []
|
186
|
+
files:
|
187
|
+
- app/assets/javascripts/conductor/application.js
|
188
|
+
- app/assets/javascripts/conductor/dashboard.js
|
189
|
+
- app/assets/stylesheets/conductor/application.css
|
190
|
+
- app/assets/stylesheets/conductor/dashboard.css
|
191
|
+
- app/controllers/conductor/application_controller.rb
|
192
|
+
- app/controllers/conductor/dashboard_controller.rb
|
193
|
+
- app/helpers/conductor/application_helper.rb
|
194
|
+
- app/helpers/conductor/dashboard_helper.rb
|
195
|
+
- app/models/conductor/experiment/daily.rb
|
196
|
+
- app/models/conductor/experiment/history.rb
|
197
|
+
- app/models/conductor/experiment/raw.rb
|
198
|
+
- app/models/conductor/experiment/weight.rb
|
199
|
+
- app/views/conductor/dashboard/_current_weights.html.haml
|
200
|
+
- app/views/conductor/dashboard/_daily_stats.html.haml
|
201
|
+
- app/views/conductor/dashboard/_group_stats.html.haml
|
202
|
+
- app/views/conductor/dashboard/_top_nav.html.haml
|
203
|
+
- app/views/conductor/dashboard/_weight_history.html.haml
|
204
|
+
- app/views/conductor/dashboard/index.html.haml
|
205
|
+
- app/views/layouts/conductor/application.html.erb
|
206
|
+
- config/routes.rb
|
207
|
+
- db/migrate/20121010131323_create_conductor_daily_experiments.rb
|
208
|
+
- db/migrate/20121010173406_create_conductor_experiment_weights.rb
|
209
|
+
- db/migrate/20121010174835_create_conductor_raw_experiments.rb
|
210
|
+
- db/migrate/20121010174950_create_conductor_weight_histories.rb
|
211
|
+
- lib/conductor/core_ext.rb
|
212
|
+
- lib/conductor/engine.rb
|
66
213
|
- lib/conductor/experiment.rb
|
67
|
-
- lib/conductor/rails/controllers/dashboard.rb
|
68
|
-
- lib/conductor/rails/helpers/dashboard_helper.rb
|
69
|
-
- lib/conductor/rails/models/daily.rb
|
70
|
-
- lib/conductor/rails/models/history.rb
|
71
|
-
- lib/conductor/rails/models/raw.rb
|
72
|
-
- lib/conductor/rails/models/weight.rb
|
73
|
-
- lib/conductor/rails/views/dashboard/_current_weights.html.haml
|
74
|
-
- lib/conductor/rails/views/dashboard/_daily_stats.html.haml
|
75
|
-
- lib/conductor/rails/views/dashboard/_group_stats.html.haml
|
76
|
-
- lib/conductor/rails/views/dashboard/_top_nav.html.haml
|
77
|
-
- lib/conductor/rails/views/dashboard/_weight_history.html.haml
|
78
|
-
- lib/conductor/rails/views/dashboard/index.html.haml
|
79
214
|
- lib/conductor/roll_up.rb
|
215
|
+
- lib/conductor/version.rb
|
80
216
|
- lib/conductor/weights.rb
|
81
|
-
-
|
82
|
-
-
|
83
|
-
-
|
217
|
+
- lib/conductor.rb
|
218
|
+
- lib/tasks/conductor_tasks.rake
|
219
|
+
- MIT-LICENSE
|
220
|
+
- Rakefile
|
221
|
+
- README.rdoc
|
222
|
+
- test/core_ext_test.rb
|
223
|
+
- test/fixtures/conductor/conductor_daily_experiments.yml
|
224
|
+
- test/functional/conductor/dashboard_controller_test.rb
|
225
|
+
- test/integration/conductor/dashboard_test.rb
|
226
|
+
- test/integration/navigation_test.rb
|
84
227
|
- test/test_helper.rb
|
85
|
-
|
86
|
-
|
228
|
+
- test/unit/conductor/conductor_daily_experiment_test.rb
|
229
|
+
- test/unit/helpers/conductor/dashboard_helper_test.rb
|
230
|
+
homepage:
|
87
231
|
licenses: []
|
88
|
-
|
89
232
|
post_install_message:
|
90
|
-
rdoc_options:
|
91
|
-
|
92
|
-
require_paths:
|
233
|
+
rdoc_options: []
|
234
|
+
require_paths:
|
93
235
|
- lib
|
94
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
236
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
95
237
|
none: false
|
96
|
-
requirements:
|
97
|
-
- -
|
98
|
-
- !ruby/object:Gem::Version
|
99
|
-
|
238
|
+
requirements:
|
239
|
+
- - ! '>='
|
240
|
+
- !ruby/object:Gem::Version
|
241
|
+
version: '0'
|
242
|
+
segments:
|
100
243
|
- 0
|
101
|
-
|
102
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
244
|
+
hash: -3930624046851759134
|
245
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
103
246
|
none: false
|
104
|
-
requirements:
|
105
|
-
- -
|
106
|
-
- !ruby/object:Gem::Version
|
107
|
-
|
247
|
+
requirements:
|
248
|
+
- - ! '>='
|
249
|
+
- !ruby/object:Gem::Version
|
250
|
+
version: '0'
|
251
|
+
segments:
|
108
252
|
- 0
|
109
|
-
|
253
|
+
hash: -3930624046851759134
|
110
254
|
requirements: []
|
111
|
-
|
112
255
|
rubyforge_project: conductor
|
113
|
-
rubygems_version: 1.
|
256
|
+
rubygems_version: 1.8.24
|
114
257
|
signing_key:
|
115
258
|
specification_version: 3
|
116
|
-
summary: lets you just try things while always maximizing towards a goal (e.g. purchase,
|
117
|
-
|
118
|
-
|
119
|
-
- test/
|
259
|
+
summary: lets you just try things while always maximizing towards a goal (e.g. purchase,
|
260
|
+
signups, etc)
|
261
|
+
test_files:
|
262
|
+
- test/core_ext_test.rb
|
263
|
+
- test/fixtures/conductor/conductor_daily_experiments.yml
|
264
|
+
- test/functional/conductor/dashboard_controller_test.rb
|
265
|
+
- test/integration/conductor/dashboard_test.rb
|
266
|
+
- test/integration/navigation_test.rb
|
120
267
|
- test/test_helper.rb
|
268
|
+
- test/unit/conductor/conductor_daily_experiment_test.rb
|
269
|
+
- test/unit/helpers/conductor/dashboard_helper_test.rb
|