best_choice 0.0.1
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.
- checksums.yaml +7 -0
- data/README.rdoc +3 -0
- data/Rakefile +32 -0
- data/lib/best_choice.rb +26 -0
- data/lib/best_choice/algorithm.rb +65 -0
- data/lib/best_choice/algorithms/epsilon_greedy.rb +31 -0
- data/lib/best_choice/rails_util.rb +76 -0
- data/lib/best_choice/selector.rb +51 -0
- data/lib/best_choice/selectors/greedy_redis.rb +16 -0
- data/lib/best_choice/storage/redis_hash.rb +71 -0
- data/lib/best_choice/version.rb +5 -0
- data/test/algorithm_test.rb +40 -0
- data/test/algorithms/epsilon_greedy_test.rb +152 -0
- data/test/best_choice_test.rb +97 -0
- data/test/dummy/app/controllers/application_controller.rb +5 -0
- data/test/dummy/app/controllers/main_controller.rb +20 -0
- data/test/dummy/app/views/layouts/application.html.erb +11 -0
- data/test/dummy/app/views/main/landing.html.erb +22 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +12 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +29 -0
- data/test/dummy/config/environments/production.rb +80 -0
- data/test/dummy/config/environments/test.rb +36 -0
- data/test/dummy/config/initializers/secret_token.rb +12 -0
- data/test/dummy/config/initializers/session_store.rb +3 -0
- data/test/dummy/config/routes.rb +6 -0
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/dummy/log/test.log +5059 -0
- data/test/dummy/test/controllers/main_controller_test.rb +116 -0
- data/test/fixtures/dummy_algorithm.rb +6 -0
- data/test/fixtures/dummy_storage.rb +6 -0
- data/test/test_helper.rb +20 -0
- metadata +178 -0
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class MainControllerTest < ActionController::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
Redis.current.flushall
|
7
|
+
@s_name = :sign_up_button
|
8
|
+
end
|
9
|
+
|
10
|
+
test 'display the same option for the same visitor' do
|
11
|
+
|
12
|
+
get :landing
|
13
|
+
picked_option = session[:_best_choice_picks][@s_name]
|
14
|
+
css_selector = "#test-#{picked_option}"
|
15
|
+
assert_select css_selector
|
16
|
+
|
17
|
+
3.times {
|
18
|
+
get :landing
|
19
|
+
assert_select css_selector
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
test 'display better option if available' do
|
24
|
+
get :landing
|
25
|
+
first_picked_option = session[:_best_choice_picks][@s_name]
|
26
|
+
assert_has_html_for first_picked_option
|
27
|
+
|
28
|
+
new_visitor
|
29
|
+
get :landing
|
30
|
+
second_picked_option = session[:_best_choice_picks][@s_name]
|
31
|
+
assert_not_equal first_picked_option, second_picked_option
|
32
|
+
assert_has_html_for second_picked_option
|
33
|
+
|
34
|
+
new_visitor
|
35
|
+
get :landing
|
36
|
+
third_picked_option = session[:_best_choice_picks][@s_name]
|
37
|
+
assert_not_equal second_picked_option, third_picked_option
|
38
|
+
assert_has_html_for third_picked_option
|
39
|
+
end
|
40
|
+
|
41
|
+
test 'display the best option' do
|
42
|
+
# -------------------------------------------------
|
43
|
+
# 1. Get landing. The visitor does not choose to sign up.
|
44
|
+
#
|
45
|
+
get :landing
|
46
|
+
all_options = BestChoice.for(@s_name)
|
47
|
+
.instance_variable_get('@storage')
|
48
|
+
.options
|
49
|
+
first_picked_option = session[:_best_choice_picks][@s_name]
|
50
|
+
assert_has_html_for first_picked_option
|
51
|
+
# First option: success 0 / display 1.
|
52
|
+
|
53
|
+
# -------------------------------------------------
|
54
|
+
# 2. The second visitor sees another option and chooses to sign up.
|
55
|
+
#
|
56
|
+
new_visitor
|
57
|
+
get :landing
|
58
|
+
second_picked_option = session[:_best_choice_picks][@s_name]
|
59
|
+
assert_has_html_for second_picked_option
|
60
|
+
get :sign_up
|
61
|
+
# Second option: success 1 / display 1.
|
62
|
+
|
63
|
+
# -------------------------------------------------
|
64
|
+
# 3. The third visitor might either see the second option or the last
|
65
|
+
# available one with success 0 / display 0. He doesn't sign up.
|
66
|
+
#
|
67
|
+
new_visitor
|
68
|
+
get :landing
|
69
|
+
assert_not_equal first_picked_option,
|
70
|
+
session[:_best_choice_picks][@s_name]
|
71
|
+
|
72
|
+
# -------------------------------------------------
|
73
|
+
# 4. Force the fourth visitor to see the third option. He also doesn't
|
74
|
+
# sign up.
|
75
|
+
new_visitor
|
76
|
+
third_available_option =
|
77
|
+
(all_options - [first_picked_option, second_picked_option])[0]
|
78
|
+
session[:_best_choice_picks] = { @s_name => third_available_option }
|
79
|
+
get :landing
|
80
|
+
assert_has_html_for third_available_option
|
81
|
+
|
82
|
+
# -------------------------------------------------
|
83
|
+
# Success/display ratio:
|
84
|
+
# * First option -> 0%
|
85
|
+
# * Second option -> 50-100% (depending on the Step 3)
|
86
|
+
# * Third option -> 0%
|
87
|
+
#
|
88
|
+
# Thus the fifth user HAS to see the second option
|
89
|
+
# which is currently the best.
|
90
|
+
#
|
91
|
+
new_visitor
|
92
|
+
get :landing
|
93
|
+
assert_equal second_picked_option, session[:_best_choice_picks][@s_name]
|
94
|
+
assert_has_html_for second_picked_option
|
95
|
+
end
|
96
|
+
|
97
|
+
|
98
|
+
# -------------------------------------------------
|
99
|
+
# Utilities
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
# Deletes the picks from the session to avoid forcing the same option
|
104
|
+
# in consecutive requests (to mock different visitors).
|
105
|
+
#
|
106
|
+
def new_visitor
|
107
|
+
session.delete :_best_choice_picks
|
108
|
+
assigns(:_best_choice_selectors).clear
|
109
|
+
end
|
110
|
+
|
111
|
+
def assert_has_html_for picked_option
|
112
|
+
css_selector = "#test-#{picked_option}"
|
113
|
+
assert_select css_selector
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# Configure Rails Environment
|
2
|
+
ENV["RAILS_ENV"] = "test"
|
3
|
+
|
4
|
+
require File.expand_path("../dummy/config/environment.rb", __FILE__)
|
5
|
+
require "rails/test_help"
|
6
|
+
|
7
|
+
require 'rr'
|
8
|
+
|
9
|
+
require 'fixtures/dummy_algorithm'
|
10
|
+
require 'fixtures/dummy_storage'
|
11
|
+
|
12
|
+
Rails.backtrace_cleaner.remove_silencers!
|
13
|
+
|
14
|
+
# Load support files
|
15
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
|
16
|
+
|
17
|
+
# Load fixtures from the engine
|
18
|
+
if ActiveSupport::TestCase.method_defined?(:fixture_path=)
|
19
|
+
ActiveSupport::TestCase.fixture_path = File.expand_path("../fixtures", __FILE__)
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,178 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: best_choice
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Mariusz Pruszyński
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-05-06 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: json
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: redis-objects
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rr
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rails
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '4'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '4'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: sqlite3
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description: Prepare a set of possible options and let your users determine which
|
84
|
+
is the best.
|
85
|
+
email:
|
86
|
+
- mpruszynski@gmail.com
|
87
|
+
executables: []
|
88
|
+
extensions: []
|
89
|
+
extra_rdoc_files: []
|
90
|
+
files:
|
91
|
+
- README.rdoc
|
92
|
+
- Rakefile
|
93
|
+
- lib/best_choice.rb
|
94
|
+
- lib/best_choice/algorithm.rb
|
95
|
+
- lib/best_choice/algorithms/epsilon_greedy.rb
|
96
|
+
- lib/best_choice/rails_util.rb
|
97
|
+
- lib/best_choice/selector.rb
|
98
|
+
- lib/best_choice/selectors/greedy_redis.rb
|
99
|
+
- lib/best_choice/storage/redis_hash.rb
|
100
|
+
- lib/best_choice/version.rb
|
101
|
+
- test/algorithm_test.rb
|
102
|
+
- test/algorithms/epsilon_greedy_test.rb
|
103
|
+
- test/best_choice_test.rb
|
104
|
+
- test/dummy/app/controllers/application_controller.rb
|
105
|
+
- test/dummy/app/controllers/main_controller.rb
|
106
|
+
- test/dummy/app/views/layouts/application.html.erb
|
107
|
+
- test/dummy/app/views/main/landing.html.erb
|
108
|
+
- test/dummy/bin/bundle
|
109
|
+
- test/dummy/bin/rails
|
110
|
+
- test/dummy/bin/rake
|
111
|
+
- test/dummy/config.ru
|
112
|
+
- test/dummy/config/application.rb
|
113
|
+
- test/dummy/config/boot.rb
|
114
|
+
- test/dummy/config/database.yml
|
115
|
+
- test/dummy/config/environment.rb
|
116
|
+
- test/dummy/config/environments/development.rb
|
117
|
+
- test/dummy/config/environments/production.rb
|
118
|
+
- test/dummy/config/environments/test.rb
|
119
|
+
- test/dummy/config/initializers/secret_token.rb
|
120
|
+
- test/dummy/config/initializers/session_store.rb
|
121
|
+
- test/dummy/config/routes.rb
|
122
|
+
- test/dummy/db/test.sqlite3
|
123
|
+
- test/dummy/log/test.log
|
124
|
+
- test/dummy/test/controllers/main_controller_test.rb
|
125
|
+
- test/fixtures/dummy_algorithm.rb
|
126
|
+
- test/fixtures/dummy_storage.rb
|
127
|
+
- test/test_helper.rb
|
128
|
+
homepage:
|
129
|
+
licenses: []
|
130
|
+
metadata: {}
|
131
|
+
post_install_message:
|
132
|
+
rdoc_options: []
|
133
|
+
require_paths:
|
134
|
+
- lib
|
135
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - ">="
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: '0'
|
140
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
141
|
+
requirements:
|
142
|
+
- - ">="
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: '0'
|
145
|
+
requirements: []
|
146
|
+
rubyforge_project:
|
147
|
+
rubygems_version: 2.4.4
|
148
|
+
signing_key:
|
149
|
+
specification_version: 4
|
150
|
+
summary: Auto A/B testing
|
151
|
+
test_files:
|
152
|
+
- test/algorithm_test.rb
|
153
|
+
- test/algorithms/epsilon_greedy_test.rb
|
154
|
+
- test/best_choice_test.rb
|
155
|
+
- test/dummy/app/controllers/application_controller.rb
|
156
|
+
- test/dummy/app/controllers/main_controller.rb
|
157
|
+
- test/dummy/app/views/layouts/application.html.erb
|
158
|
+
- test/dummy/app/views/main/landing.html.erb
|
159
|
+
- test/dummy/bin/bundle
|
160
|
+
- test/dummy/bin/rails
|
161
|
+
- test/dummy/bin/rake
|
162
|
+
- test/dummy/config/application.rb
|
163
|
+
- test/dummy/config/boot.rb
|
164
|
+
- test/dummy/config/database.yml
|
165
|
+
- test/dummy/config/environment.rb
|
166
|
+
- test/dummy/config/environments/development.rb
|
167
|
+
- test/dummy/config/environments/production.rb
|
168
|
+
- test/dummy/config/environments/test.rb
|
169
|
+
- test/dummy/config/initializers/secret_token.rb
|
170
|
+
- test/dummy/config/initializers/session_store.rb
|
171
|
+
- test/dummy/config/routes.rb
|
172
|
+
- test/dummy/config.ru
|
173
|
+
- test/dummy/db/test.sqlite3
|
174
|
+
- test/dummy/log/test.log
|
175
|
+
- test/dummy/test/controllers/main_controller_test.rb
|
176
|
+
- test/fixtures/dummy_algorithm.rb
|
177
|
+
- test/fixtures/dummy_storage.rb
|
178
|
+
- test/test_helper.rb
|