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.
Files changed (58) hide show
  1. data/{LICENSE → MIT-LICENSE} +1 -1
  2. data/README.rdoc +7 -0
  3. data/Rakefile +25 -45
  4. data/app/assets/javascripts/conductor/application.js +15 -0
  5. data/app/assets/javascripts/conductor/dashboard.js +2 -0
  6. data/app/assets/stylesheets/conductor/application.css +13 -0
  7. data/{generators/conductor/templates/conductor.css → app/assets/stylesheets/conductor/dashboard.css} +0 -0
  8. data/app/controllers/conductor/application_controller.rb +4 -0
  9. data/app/controllers/conductor/dashboard_controller.rb +11 -0
  10. data/app/helpers/conductor/application_helper.rb +4 -0
  11. data/{lib/conductor/rails/helpers → app/helpers/conductor}/dashboard_helper.rb +3 -1
  12. data/app/models/conductor/experiment/daily.rb +47 -0
  13. data/app/models/conductor/experiment/history.rb +9 -0
  14. data/app/models/conductor/experiment/raw.rb +20 -0
  15. data/app/models/conductor/experiment/weight.rb +11 -0
  16. data/{lib/conductor/rails/views → app/views/conductor}/dashboard/_current_weights.html.haml +0 -0
  17. data/{lib/conductor/rails/views → app/views/conductor}/dashboard/_daily_stats.html.haml +0 -0
  18. data/{lib/conductor/rails/views → app/views/conductor}/dashboard/_group_stats.html.haml +0 -0
  19. data/{lib/conductor/rails/views → app/views/conductor}/dashboard/_top_nav.html.haml +0 -0
  20. data/{lib/conductor/rails/views → app/views/conductor}/dashboard/_weight_history.html.haml +0 -0
  21. data/app/views/conductor/dashboard/index.html.haml +12 -0
  22. data/app/views/layouts/conductor/application.html.erb +14 -0
  23. data/config/routes.rb +4 -0
  24. data/db/migrate/20121010131323_create_conductor_daily_experiments.rb +16 -0
  25. data/db/migrate/20121010173406_create_conductor_experiment_weights.rb +13 -0
  26. data/db/migrate/20121010174835_create_conductor_raw_experiments.rb +13 -0
  27. data/db/migrate/20121010174950_create_conductor_weight_histories.rb +14 -0
  28. data/lib/conductor.rb +33 -57
  29. data/lib/conductor/core_ext.rb +18 -0
  30. data/lib/conductor/engine.rb +5 -0
  31. data/lib/conductor/experiment.rb +61 -60
  32. data/lib/conductor/roll_up.rb +2 -2
  33. data/lib/conductor/version.rb +3 -0
  34. data/lib/conductor/weights.rb +9 -8
  35. data/lib/tasks/conductor_tasks.rake +9 -0
  36. data/test/core_ext_test.rb +13 -0
  37. data/test/fixtures/conductor/conductor_daily_experiments.yml +17 -0
  38. data/test/functional/conductor/dashboard_controller_test.rb +11 -0
  39. data/test/integration/conductor/dashboard_test.rb +7 -0
  40. data/test/integration/navigation_test.rb +10 -0
  41. data/test/test_helper.rb +9 -23
  42. data/test/unit/conductor/conductor_daily_experiment_test.rb +9 -0
  43. data/test/unit/helpers/conductor/dashboard_helper_test.rb +6 -0
  44. metadata +240 -91
  45. data/VERSION +0 -1
  46. data/generators/conductor/conductor_generator.rb +0 -27
  47. data/generators/conductor/templates/conductor.rake +0 -6
  48. data/generators/conductor/templates/migration.rb +0 -54
  49. data/init.rb +0 -2
  50. data/lib/conductor/rails/controllers/dashboard.rb +0 -16
  51. data/lib/conductor/rails/models/daily.rb +0 -53
  52. data/lib/conductor/rails/models/history.rb +0 -14
  53. data/lib/conductor/rails/models/raw.rb +0 -27
  54. data/lib/conductor/rails/models/weight.rb +0 -18
  55. data/lib/conductor/rails/views/dashboard/index.html.haml +0 -29
  56. data/rails/init.rb +0 -7
  57. data/test/db/schema.rb +0 -43
  58. 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
@@ -0,0 +1,5 @@
1
+ module Conductor
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace Conductor
4
+ end
5
+ end
@@ -1,4 +1,4 @@
1
- class Conductor
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
- unless selection
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.find(:all, :conditions => {:identity_id => Conductor.identity.to_s}.merge!(options))
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
- def select_alternative_for_group(group_name, alternatives)
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
- # make a selection from weighted hash
83
- return choose_weighted(weighting_table)
84
- end
80
+ # create weighting table
81
+ weighting_table = generate_weighting_table(group_name, alternatives)
85
82
 
86
- # Returns a hash of alternatives with weights based on conversion
87
- # e.g. {:option_a => .25, :option_b => .25, :option_c => .50}
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
- return weighting_table
115
- end
116
-
117
- # selects a random float
118
- def float_rand(start_num, end_num=0)
119
- width = end_num-start_num
120
- return (rand*width)+start_num
121
- end
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
- # choose a random alternative based on weights
124
- # from recipe 5.11 in ruby cookbook
125
- def choose_weighted(weighted)
126
- sum = weighted.inject(0) do |sum, item_and_weight|
127
- sum += item_and_weight[1]
128
- end
129
- target = float_rand(sum)
130
- weighted.each do |item, weight|
131
- return item if target <= weight
132
- target -= weight
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
- def normalize!(weighted)
137
- sum = weighted.inject(0) do |sum, item_and_weight|
138
- sum += item_and_weight[1]
139
- end
140
- sum = sum.to_f
141
- weighted.each { |item, weight| weighted[item] = weight/sum }
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
@@ -1,4 +1,4 @@
1
- class Conductor
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::#{Conductor.attribute_for_weighting}::#{group_name}::Alternatives")
23
+ Conductor.cache.delete("Conductor::Experiment::#{group_name}::Alternatives")
24
24
  end
25
25
  end
26
26
  end
@@ -0,0 +1,3 @@
1
+ module Conductor
2
+ VERSION = "0.9.3"
3
+ end
@@ -1,5 +1,5 @@
1
- class Conductor
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
- # Conductor.log('alternatives NOT equal to cache. Need to recompute')
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 >= Conductor.minimum_conversions_per_group) ? compute_weights(post_equalization_data, total, max_weight) : assign_equal_weights(post_equalization_data)
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,9 @@
1
+ namespace :conductor do
2
+ desc "Rollup raw data for daily processing and reporting"
3
+ task :rollup => :environment do
4
+ p "(conductor) #{Time.now} >> Conductor::RollUp.process"
5
+ Conductor::RollUp.process
6
+ end
7
+ end
8
+
9
+
@@ -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
@@ -0,0 +1,11 @@
1
+ require 'test_helper'
2
+
3
+ module Conductor
4
+ class DashboardControllerTest < ActionController::TestCase
5
+ test "should get index" do
6
+ get :index
7
+ assert_response :success
8
+ end
9
+
10
+ end
11
+ end
@@ -0,0 +1,7 @@
1
+ require 'test_helper'
2
+
3
+ class DashboardTest < ActionDispatch::IntegrationTest
4
+ # test "the truth" do
5
+ # assert true
6
+ # end
7
+ end
@@ -0,0 +1,10 @@
1
+ require 'test_helper'
2
+
3
+ class NavigationTest < ActionDispatch::IntegrationTest
4
+ fixtures :all
5
+
6
+ # test "the truth" do
7
+ # assert true
8
+ # end
9
+ end
10
+
@@ -1,29 +1,15 @@
1
+ # Configure Rails Environment
1
2
  ENV["RAILS_ENV"] = "test"
2
- $:.unshift(File.dirname(__FILE__) + '/../lib')
3
3
 
4
- require 'rubygems'
5
- require 'active_record'
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
- require File.dirname(__FILE__) + '/../init.rb'
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
- config = YAML::load(IO.read(File.dirname(__FILE__) + '/db/database.yml'))
20
- # ActiveRecord::Base.logger = Logger.new(STDOUT) # Logger.new(File.dirname(__FILE__) + "/debug.log")
21
- ActiveRecord::Base.establish_connection(config[ENV['DB'] || 'postgresql'])
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
@@ -0,0 +1,9 @@
1
+ require 'test_helper'
2
+
3
+ module Conductor
4
+ class ConductorDailyExperimentTest < ActiveSupport::TestCase
5
+ # test "the truth" do
6
+ # assert true
7
+ # end
8
+ end
9
+ end
@@ -0,0 +1,6 @@
1
+ require 'test_helper'
2
+
3
+ module Conductor
4
+ class DashboardHelperTest < ActionView::TestCase
5
+ end
6
+ 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
- prerelease: false
5
- segments:
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
- date: 2010-10-04 00:00:00 -04:00
18
- default_executable:
19
- dependencies:
20
- - !ruby/object:Gem::Dependency
21
- name: googlecharts
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
- requirement: &id001 !ruby/object:Gem::Requirement
24
- none: false
25
- requirements:
26
- - - ">="
27
- - !ruby/object:Gem::Version
28
- segments:
29
- - 0
30
- version: "0"
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
- requirement: &id002 !ruby/object:Gem::Requirement
37
- none: false
38
- requirements:
39
- - - ">="
40
- - !ruby/object:Gem::Version
41
- segments:
42
- - 0
43
- version: "0"
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
- version_requirements: *id002
46
- description: Conductor is the bastard child of a/b testing and personalization. It throws everything you know about creating a web site our the window and lets you just "try stuff" without ever having to worry about not maximing your site's "purpose." Have a new landing page? Just throw it to the conductor. Want to try different price points - conductor. Different form designs? Conductor. Conductor will rotate all alternatives through the mix and eventually settle on the top performing of all, without you having to do anything other than just creating. Think "intelligent A/B testing" on steriods.
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
- extra_rdoc_files:
53
- - LICENSE
54
- - README.rdoc
55
- files:
56
- - LICENSE
57
- - README.rdoc
58
- - Rakefile
59
- - VERSION
60
- - generators/conductor/conductor_generator.rb
61
- - generators/conductor/templates/conductor.css
62
- - generators/conductor/templates/conductor.rake
63
- - generators/conductor/templates/migration.rb
64
- - init.rb
65
- - lib/conductor.rb
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
- - rails/init.rb
82
- - test/db/schema.rb
83
- - test/test_conductor.rb
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
- has_rdoc: true
86
- homepage: http://github.com/noctivityinc/conductor
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
- - --charset=UTF-8
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
- segments:
238
+ requirements:
239
+ - - ! '>='
240
+ - !ruby/object:Gem::Version
241
+ version: '0'
242
+ segments:
100
243
  - 0
101
- version: "0"
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
- segments:
247
+ requirements:
248
+ - - ! '>='
249
+ - !ruby/object:Gem::Version
250
+ version: '0'
251
+ segments:
108
252
  - 0
109
- version: "0"
253
+ hash: -3930624046851759134
110
254
  requirements: []
111
-
112
255
  rubyforge_project: conductor
113
- rubygems_version: 1.3.7
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, signups, etc)
117
- test_files:
118
- - test/db/schema.rb
119
- - test/test_conductor.rb
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