ruby_optimize 2.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 06219338afa9e9b6a5feb8b10e5accb8728a82c3
4
+ data.tar.gz: 35fc66284257c5c4327dc42dccfcec447352977c
5
+ SHA512:
6
+ metadata.gz: 99088d7643a95a1c1e6ca9907f38a2909b056dac8ec7ec9a2d3857d0ad8f2c7676d84ee48d8299ebe6581fb68a85c48dd5cf8b3cdc031fc19f8cffd6e7f76b9e
7
+ data.tar.gz: 1ecff56be0b92756e88dafe26c52ed9ae22a3fd4cd810c17f1d2d15d13bce43f42bbdf92ff5d6f21913368b3229dfbaa30fa76820afc169ee6d13aa83436c409
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ .DS_Store
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2017 Adriano di Lauro
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,90 @@
1
+ To know more about RubyOptimize look at the [full documentation](https://github.com/adrdilauro/ruby_optimize/wiki/Full-documentation).
2
+
3
+ # Features
4
+
5
+ 1. Set up an A/B test with a very **simple** and **descriptive code** (the gem consists of just three methods)
6
+ 2. A/B tests are valid across different pages, using cookies
7
+ 3. You can test **multiple versions** with changes as complicated as you need, while still keeping the code clean and understandable
8
+ 4. Effortlessly set up **multiple A/B tests** that don't clash with each other (remembering of course to ensure that results of the tests are kept separated)
9
+ 5. Very easy to select a special version for crawlers, so you don't affect your SEO while you are running the test
10
+ 6. The gem is safe and super tested (https://github.com/adrdilauro/ruby_optimize/blob/master/spec/ruby_optimize_spec.rb)
11
+
12
+ # Usage
13
+
14
+ Install it using bundler
15
+ ```ruby
16
+ gem 'ruby_optimize'
17
+ ```
18
+
19
+ #### (1) - Initialize the A/B test in the actions you need inside the controller
20
+ ```ruby
21
+ before_action :initialize_ab_test
22
+
23
+ def initialize_ab_test
24
+ ruby_optimize [ :v1, :v2, :v3 ] # Declare the names of all the versions you are going to test
25
+ end
26
+ ```
27
+
28
+ #### (2) - Render the script that reads / writes the cookie
29
+ ```html
30
+ <head>
31
+ <%= ruby_optimize_init %>
32
+ ...
33
+ </head>
34
+ ```
35
+
36
+ #### (3) - Wrap blocks of HTML that will be rendered depending on the version
37
+ ```html
38
+ <%= ruby_optimize_wrap(:v1) do %>
39
+ <div class="for-version-1">
40
+ ...
41
+ </div>
42
+ <% end %>
43
+
44
+ <%= ruby_optimize_wrap(:v2) do %>
45
+ <div class="for-version-2">
46
+ ...
47
+ </div>
48
+ <% end %>
49
+ ```
50
+
51
+ # How it works
52
+
53
+ When you call `ruby_optimize_init` in your `.erb` files, you will render a simple synchronous script that
54
+
55
+ - tries to read the cookie relative to your A/B test
56
+ - if the cookie is not present, extract a random version among the ones you defined, and store it in a cookie
57
+ - save the version in an internal javascript object that will be used across the page
58
+
59
+ When you wrap a block of HTML inside `ruby_optimize_wrap`, passing a specific version, the block will be wrapped inside a `<div>` with a generated random id, and after the block it will be appended a synchronous `<script>` tag that looks like this:
60
+
61
+ ```html
62
+ <script>
63
+ window.rubyOptimizerObject.keepOrRemoveHtmlBlock('[random id]', '[version]');
64
+ </script>
65
+ ```
66
+
67
+ If the version passed doesn't match with the version that has been stored on the top of the page, then the block is removed. This happens before the page is fully rendered, so there isn't any chance to get page flickering.
68
+
69
+ The synchronous scripts are really simple and don't slow down page rendering time.
70
+
71
+
72
+ # Why RubyOptimize is good for complex A/B tests
73
+
74
+ You can create several different versions of the same page, as complex and as big as you need, without filling your HTML with unnecessary code. This will make your A/B test less error prone, and also it will make it easier to remove the loser versions after the test, because the code is clear and descriptive.
75
+
76
+ You can easily span your tests across different pages reading the same cookie, with no additional code, RubyOptimize does all the work for you.
77
+
78
+ You can maintain as many different A/B tests you want without risking them to clash.
79
+
80
+ # Why RubyOptimize is good for small A/B tests as well
81
+
82
+ Usually, to set up a small A/B test (changing a color, removing or adding a div, etc) people use client side tools like Google Optimize.
83
+
84
+ This approach can potentially affect user experience, because Google Optimize has to change parts of the page depending on the specific version selected, and, if this happens while the user is already looking at the page, we have the effect called "page flickering". To prevent page flickering Google Optimize introduced a "hide-page tag", i.e. a script that hides the page until the external call to Google Optimize server has responded.
85
+
86
+ Now, usually Google Optimize tag loads fast, but you cannot always rely on external calls, especially in conditions of low network; in the worst scenario, if Google Optimize server doesn't respond, the hide-page tag gets unblocked after the threshold of 4 seconds.
87
+
88
+ This means that, even if your server has responded in 150 milliseconds, your user won't be able to see anything in the page until the 4 seconds have expired.
89
+
90
+ Are you sure you want to risk this? With RubyOptimize you can set up a simple A/B test easily and cleanly directly in the code, this means that you can get rid of the hide-page tag, and let Google Optimize focus only on data collection.
@@ -0,0 +1,17 @@
1
+ module RubyOptimize
2
+ end
3
+
4
+ begin
5
+ require 'rails'
6
+ rescue LoadError
7
+ end
8
+
9
+ require 'ruby_optimize/common_controllers_and_helpers'
10
+ require 'ruby_optimize/controllers/action_controller_extension'
11
+ require 'ruby_optimize/helpers/action_view_extension'
12
+ require 'ruby_optimize/models/ab_test_handler'
13
+ require 'ruby_optimize/hooks'
14
+
15
+ if defined? Rails
16
+ require 'ruby_optimize/railtie'
17
+ end
@@ -0,0 +1,10 @@
1
+ module RubyOptimize
2
+ module CommonControllersAndHelpers
3
+ def ruby_optimize(versions, **params)
4
+ @ruby_optimize = {} if @ruby_optimize.nil?
5
+ scope = params[:scope] || :default
6
+ raise "RubyOptimize - scope already defined: #{scope.inspect}" if @ruby_optimize.has_key?(scope)
7
+ @ruby_optimize[scope] = AbTestHandler.new(cookies, versions, scope, request.user_agent, params[:domain], params[:cookie_expiration], params[:version_for_crawler])
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,5 @@
1
+ module RubyOptimize
2
+ module ActionControllerExtension
3
+ include CommonControllersAndHelpers
4
+ end
5
+ end
@@ -0,0 +1,12 @@
1
+ module RubyOptimize
2
+ module ActionViewExtension
3
+ include CommonControllersAndHelpers
4
+
5
+ def ruby_optimize_wrap(*version_and_scope, **params, &block)
6
+ scope = version_and_scope[1] || :default
7
+ raise "RubyOptimize - A/B test not initialized" if @ruby_optimize.nil?
8
+ raise "RubyOptimize - scope not found: #{scope.inspect}" if !@ruby_optimize.has_key?(scope)
9
+ @ruby_optimize[scope].show?(version_and_scope[0], !!params[:version_for_crawler]) ? capture(&block).html_safe : ''
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,10 @@
1
+ module RubyOptimize
2
+ class Hooks
3
+ def self.init
4
+ ActiveSupport.on_load(:action_view) do
5
+ ::ActionView::Base.send :include, RubyOptimize::ActionViewExtension
6
+ ::ActionController::Base.send :include, RubyOptimize::ActionControllerExtension
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,68 @@
1
+ module RubyOptimize
2
+ class AbTestHandler
3
+ ALPHANUMERIC_STRING = /\A[a-zA-Z0-9]+\z/
4
+ CRAWLER = /#{[
5
+ 'bot', 'crawl', 'slurp', 'spider', 'Google favicon', 'Mediapartners-Google', 'java', 'wget', 'curl', 'Commons-HttpClient',
6
+ 'Python-urllib', 'libwww', 'httpunit', 'nutch', 'biglotron', 'teoma', 'convera', 'gigablast', 'ia_archiver', 'webmon',
7
+ 'httrack', 'grub.org', 'netresearchserver', 'speedy', 'fluffy', 'bibnum.bnf', 'findlink', 'panscient', 'IOI', 'ips-agent',
8
+ 'yanga', 'Voyager', 'CyberPatrol', 'postrank', 'page2rss', 'linkdex', 'ezooms', 'heritrix', 'findthatfile', 'europarchive.org',
9
+ 'Aboundex', 'summify', 'ec2linkfinder', 'facebookexternalhit', 'yeti', 'RetrevoPageAnalyzer', 'sogou', 'wotbox', 'ichiro',
10
+ 'drupact', 'coccoc', 'integromedb', 'siteexplorer.info', 'proximic', 'changedetection', 'WeSEE:SearchLipperhey SEO Service',
11
+ 'CC Metadata Scaper', 'g00g1e.net', 'binlar', 'A6-Indexer', 'ADmantX', 'MegaIndex', 'ltx71', 'BUbiNG', 'Qwantify', 'lipperhey',
12
+ 'y!j-asr', 'AddThis'
13
+ ].join('|')}/i
14
+
15
+ def initialize(cookies, some_versions, scope, agent, domain=nil, a_cookie_expiration=nil, a_version_for_crawler=nil)
16
+ @versions = some_versions
17
+ validate_versions
18
+ validate_scope(scope)
19
+ @cookie_name = "ruby-optimize-cookie-#{scope}"
20
+ @is_crawler = !CRAWLER.match(agent).nil?
21
+ @cookie_expiration = (a_cookie_expiration || 180.days).to_i
22
+ validate_cookie_expiration
23
+ @version_for_crawler = a_version_for_crawler
24
+ validate_version_for_crawler
25
+ return if is_crawler
26
+ if cookies.has_key?(cookie_name)
27
+ @version = cookies[cookie_name].to_sym
28
+ else
29
+ @version = versions.sample
30
+ cookies[cookie_name] = {
31
+ value: version,
32
+ expires: cookie_expiration.from_now,
33
+ domain: domain || :all,
34
+ }
35
+ end
36
+ end
37
+
38
+ def show?(a_version, for_crawler)
39
+ raise "RubyOptimize - for_crawler must be a boolean: #{for_crawler.inspect}" if for_crawler != !!for_crawler
40
+ return for_crawler || (!version_for_crawler.nil? && a_version == version_for_crawler) if is_crawler
41
+ raise "RubyOptimize - version must be one of the available versions: #{a_version.inspect}" if !a_version.nil? && !versions.include?(a_version)
42
+ a_version == version
43
+ end
44
+
45
+ private
46
+
47
+ def validate_versions
48
+ raise "RubyOptimize - you need to pass an array of at least two versions: #{versions.inspect}" if !versions.is_a?(Array) || versions.length < 2
49
+ raise "RubyOptimize - versions need to be alphanumeric symbols: #{versions.inspect}" if versions.any? do |version|
50
+ !version.is_a?(Symbol) || ALPHANUMERIC_STRING.match(version.to_s).nil?
51
+ end
52
+ end
53
+
54
+ def validate_scope(scope)
55
+ raise "RubyOptimize - scope needs to be an alphanumeric symbol: #{scope.inspect}" if !scope.is_a?(Symbol) || ALPHANUMERIC_STRING.match(scope.to_s).nil?
56
+ end
57
+
58
+ def validate_cookie_expiration
59
+ raise "RubyOptimize - cookie_expiration needs to be an integer greater than zero: #{cookie_expiration.inspect}" if cookie_expiration <= 0
60
+ end
61
+
62
+ def validate_version_for_crawler
63
+ raise "RubyOptimize - version_for_crawler must be one of the available versions: #{version_for_crawler.inspect}" if !version_for_crawler.nil? && !versions.include?(version_for_crawler)
64
+ end
65
+
66
+ attr_reader :cookie_expiration, :cookie_name, :version_for_crawler, :is_crawler, :version, :versions
67
+ end
68
+ end
@@ -0,0 +1,7 @@
1
+ module RubyOptimize
2
+ class Railtie < ::Rails::Railtie #:nodoc:
3
+ initializer 'ruby_optimize' do |_app|
4
+ RubyOptimize::Hooks.init
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,3 @@
1
+ module RubyOptimize
2
+ VERSION = '2.3'
3
+ end
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'ruby_optimize/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'ruby_optimize'
8
+ spec.version = RubyOptimize::VERSION
9
+ spec.authors = ['Adriano di Lauro']
10
+ spec.email = ['adr_dilauro@hotmail.it']
11
+ spec.summary = 'Tool to implement flexible A/B tests in Ruby on Rails'
12
+ spec.description = 'With ruby_optimize you can set up multiple A/B tests, consistent across session, in a clean way and without page flickering'
13
+ spec.homepage = 'https://github.com/adrdilauro/ruby_optimize'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.require_paths = ['lib']
19
+
20
+ spec.add_dependency 'activesupport', ['>= 3.0.0']
21
+ spec.add_dependency 'actionpack', ['>= 3.0.0']
22
+
23
+ spec.add_development_dependency 'bundler', '~> 1.7'
24
+ spec.add_development_dependency 'rake', '~> 10.0'
25
+ end
@@ -0,0 +1,546 @@
1
+ require 'rails_helper'
2
+
3
+ RSpec.describe AbTestHandler, type: :model do
4
+ def ruby_optimize(versions, **params)
5
+ @ruby_optimize = {} if @ruby_optimize.nil?
6
+ scope = params[:scope] || :default
7
+ raise "RubyOptimize - scope already defined: #{scope.inspect}" if @ruby_optimize.has_key?(scope)
8
+ @ruby_optimize[scope] = AbTestHandler.new({}, versions, scope, request.user_agent, params[:domain], params[:cookie_expiration], params[:version_for_crawler])
9
+ end
10
+
11
+ def ruby_optimize_wrap(*version_and_scope, **params, &block)
12
+ scope = version_and_scope[1] || :default
13
+ raise "RubyOptimize - A/B test not initialized" if @ruby_optimize.nil?
14
+ raise "RubyOptimize - scope not found: #{scope.inspect}" if !@ruby_optimize.has_key?(scope)
15
+ @ruby_optimize[scope].wrap(yield, version_and_scope[0], !!params[:version_for_crawler])
16
+ end
17
+
18
+ def fake_wrapped(version, random_div_id, js_object_id)
19
+ " <div id=\"#{random_div_id}\">\n hello\n </div>\n <script>\n window['#{js_object_id}'].handle('#{version}', '#{random_div_id}');\n </script>\n"
20
+ end
21
+
22
+ describe 'create' do
23
+ context 'not crawler' do
24
+ let(:request) do
25
+ OpenStruct.new(user_agent: 'safari')
26
+ end
27
+
28
+ it 'raises an error if "versions" is not an array' do
29
+ expect do
30
+ ruby_optimize 'hello'
31
+ end.to raise_error('RubyOptimize - you need to pass an array of at least two versions: "hello"')
32
+ end
33
+
34
+ it 'raises an error if there are less than two versions, 1' do
35
+ expect do
36
+ ruby_optimize [ 'helllo' ]
37
+ end.to raise_error('RubyOptimize - you need to pass an array of at least two versions: ["helllo"]')
38
+ end
39
+
40
+ it 'raises an error if there are less than two versions, 2' do
41
+ expect do
42
+ ruby_optimize []
43
+ end.to raise_error('RubyOptimize - you need to pass an array of at least two versions: []')
44
+ end
45
+
46
+ it 'raises an error if there versions are not alphanumeric, 1' do
47
+ expect do
48
+ ruby_optimize [ 'v1', :v2 ]
49
+ end.to raise_error('RubyOptimize - versions need to be alphanumeric symbols: ["v1", :v2]')
50
+ end
51
+
52
+ it 'raises an error if there versions are not alphanumeric, 2' do
53
+ expect do
54
+ ruby_optimize [ :v1, :v2, 3 ]
55
+ end.to raise_error('RubyOptimize - versions need to be alphanumeric symbols: [:v1, :v2, 3]')
56
+ end
57
+
58
+ it 'raises an error if there versions are not alphanumeric, 3' do
59
+ expect do
60
+ ruby_optimize [ :'v-1', :v2, :v3 ]
61
+ end.to raise_error('RubyOptimize - versions need to be alphanumeric symbols: [:"v-1", :v2, :v3]')
62
+ end
63
+
64
+ it 'raises an error if there versions are not alphanumeric, 4' do
65
+ expect do
66
+ ruby_optimize [ :'v1-', :v2, :v3 ]
67
+ end.to raise_error('RubyOptimize - versions need to be alphanumeric symbols: [:"v1-", :v2, :v3]')
68
+ end
69
+
70
+ it 'raises an error if scope is not alphanumeric, 1' do
71
+ expect do
72
+ ruby_optimize [ :v1, :v2, :v3 ], scope: 23
73
+ end.to raise_error('RubyOptimize - scope needs to be an alphanumeric symbol: 23')
74
+ end
75
+
76
+ it 'raises an error if scope is not alphanumeric, 2' do
77
+ expect do
78
+ ruby_optimize [ :v1, :v2, :v3 ], scope: 'ehi23'
79
+ end.to raise_error('RubyOptimize - scope needs to be an alphanumeric symbol: "ehi23"')
80
+ end
81
+
82
+ it 'raises an error if scope is not alphanumeric, 3' do
83
+ expect do
84
+ ruby_optimize [ :v1, :v2, :v3 ], scope: :'ehi-'
85
+ end.to raise_error('RubyOptimize - scope needs to be an alphanumeric symbol: :"ehi-"')
86
+ end
87
+
88
+ it 'raises an error if cookie_expiration is not a positive integer, 1' do
89
+ expect do
90
+ ruby_optimize [ :v1, :v2, :v3 ], cookie_expiration: 'ahi'
91
+ end.to raise_error('RubyOptimize - cookie_expiration needs to be an integer greater than zero: 0')
92
+ end
93
+
94
+ it 'raises an error if cookie_expiration is not a positive integer, 2' do
95
+ expect do
96
+ ruby_optimize [ :v1, :v2, :v3 ], cookie_expiration: -1
97
+ end.to raise_error('RubyOptimize - cookie_expiration needs to be an integer greater than zero: -1')
98
+ end
99
+
100
+ it 'raises an error if version_for_crawler is not one of the whitelisted versions' do
101
+ expect do
102
+ ruby_optimize [ :v1, :v2, :v3 ], version_for_crawler: 'ehi'
103
+ end.to raise_error('RubyOptimize - version_for_crawler must be one of the available versions: "ehi"')
104
+ end
105
+
106
+ it 'raises an error if version_for_crawler is not one of the whitelisted versions' do
107
+ expect do
108
+ ruby_optimize [ :v1, :v2, :v3 ], version_for_crawler: :v4
109
+ end.to raise_error('RubyOptimize - version_for_crawler must be one of the available versions: :v4')
110
+ end
111
+
112
+ it 'does not raise any error if cookie_expiration is explicitly nil' do
113
+ expect do
114
+ ruby_optimize [ :v1, :v2, :v3 ], cookie_expiration: nil
115
+ end.not_to raise_error
116
+ end
117
+
118
+ it 'does not raise any error if version_for_crawler is explicitly nil' do
119
+ expect do
120
+ ruby_optimize [ :v1, :v2, :v3 ], version_for_crawler: nil
121
+ end.not_to raise_error
122
+ end
123
+
124
+ it 'raises an error if you try to access the same scope twice' do
125
+ expect do
126
+ ruby_optimize [ :v1, :v2, :v3 ], scope: :myscope
127
+ ruby_optimize [ :v4, :v5 ], scope: :myscope
128
+ end.to raise_error('RubyOptimize - scope already defined: :myscope')
129
+ end
130
+
131
+ it 'raises an error if you try to access the same scope twice (default)' do
132
+ expect do
133
+ ruby_optimize [ :v1, :v2, :v3 ]
134
+ ruby_optimize [ :v4, :v5 ]
135
+ end.to raise_error('RubyOptimize - scope already defined: :default')
136
+ end
137
+
138
+ it 'raises an error if you try to access the same scope twice (default set explicitly 1)' do
139
+ expect do
140
+ ruby_optimize [ :v1, :v2, :v3 ], scope: :default
141
+ ruby_optimize [ :v4, :v5 ]
142
+ end.to raise_error('RubyOptimize - scope already defined: :default')
143
+ end
144
+
145
+ it 'raises an error if you try to access the same scope twice (default set explicitly 2)' do
146
+ expect do
147
+ ruby_optimize [ :v1, :v2, :v3 ]
148
+ ruby_optimize [ :v4, :v5 ], scope: :default
149
+ end.to raise_error('RubyOptimize - scope already defined: :default')
150
+ end
151
+
152
+ it 'raises an error if you try using the object without having initialized it previously' do
153
+ expect do
154
+ ruby_optimize_wrap(:v1) do
155
+ 'hello'
156
+ end
157
+ end.to raise_error('RubyOptimize - A/B test not initialized')
158
+ expect do
159
+ ruby_optimize_wrap(:v1, :somescope) do
160
+ 'hello'
161
+ end
162
+ end.to raise_error('RubyOptimize - A/B test not initialized')
163
+ end
164
+
165
+ it 'correctly sets up the object, init scripts, wrap' do
166
+ ruby_optimize [ :v1, :v2, :v3 ]
167
+ ruby_optimize [ :old, :new ], scope: :test
168
+ ruby_optimize [ :old, :new ], scope: :test2, cookie_expiration: nil, version_for_crawler: nil
169
+ ruby_optimize [ :v4, :v5 ], scope: :test3, cookie_expiration: 33
170
+ ruby_optimize [ :v4, :v5 ], scope: :test4, version_for_crawler: :v5
171
+ expect(@ruby_optimize.class.to_s).to eq('Hash')
172
+ expect(@ruby_optimize.keys.length).to eq(5)
173
+ expect(@ruby_optimize.keys.sort[0]).to eq(:default)
174
+ expect(@ruby_optimize.keys.sort[1]).to eq(:test)
175
+ expect(@ruby_optimize.keys.sort[2]).to eq(:test2)
176
+ expect(@ruby_optimize.keys.sort[3]).to eq(:test3)
177
+ expect(@ruby_optimize.keys.sort[4]).to eq(:test4)
178
+ # WRAP GENERIC
179
+ expect do
180
+ ruby_optimize_wrap(:v1, :anotherscope) do
181
+ 'hello'
182
+ end
183
+ end.to raise_error('RubyOptimize - scope not found: :anotherscope')
184
+ expect do
185
+ @ruby_optimize[:default].wrap('hello', :v1, 'true') do
186
+ 'hello'
187
+ end
188
+ end.to raise_error('RubyOptimize - for_crawler must be a boolean: "true"')
189
+ # DEFAULT SET UP
190
+ def (@ruby_optimize[:default]).set_version(a_version)
191
+ @version = a_version
192
+ end
193
+ def (@ruby_optimize[:default]).get_cookie_expiration
194
+ cookie_expiration
195
+ end
196
+ def (@ruby_optimize[:default]).get_cookie_name
197
+ cookie_name
198
+ end
199
+ def (@ruby_optimize[:default]).get_version_for_crawler
200
+ version_for_crawler
201
+ end
202
+ def (@ruby_optimize[:default]).get_is_crawler
203
+ is_crawler
204
+ end
205
+ def (@ruby_optimize[:default]).get_versions
206
+ versions
207
+ end
208
+ expect(@ruby_optimize[:default].get_cookie_expiration).to eq(15552000)
209
+ expect(@ruby_optimize[:default].get_cookie_name).to eq('ruby-optimize-cookie-default')
210
+ expect(@ruby_optimize[:default].get_version_for_crawler).to eq(nil)
211
+ expect(@ruby_optimize[:default].get_is_crawler).to eq(false)
212
+ expect(@ruby_optimize[:default].get_versions.sort).to eq([:v1, :v2, :v3])
213
+ # DEFAULT WRAP
214
+ expect do
215
+ ruby_optimize_wrap(:new) do
216
+ 'hello'
217
+ end
218
+ end.to raise_error('RubyOptimize - version must be one of the available versions: :new')
219
+ expect(ruby_optimize_wrap do
220
+ 'hello'
221
+ end).to eq('')
222
+ @ruby_optimize[:default].set_version(:v1)
223
+ expect(ruby_optimize_wrap(:v1) do
224
+ 'hello'
225
+ end).to eq('hello')
226
+ @ruby_optimize[:default].set_version(:other)
227
+ expect(ruby_optimize_wrap(:v1) do
228
+ 'hello'
229
+ end).to eq('')
230
+ @ruby_optimize[:default].set_version(:v2)
231
+ expect(ruby_optimize_wrap(:v2, :default) do
232
+ 'hello'
233
+ end).to eq('hello')
234
+ @ruby_optimize[:default].set_version(:other)
235
+ expect(ruby_optimize_wrap(:v2, :default) do
236
+ 'hello'
237
+ end).to eq('')
238
+ @ruby_optimize[:default].set_version(:v3)
239
+ expect(ruby_optimize_wrap(:v3, :default, version_for_crawler: true) do
240
+ 'hello'
241
+ end).to eq('hello')
242
+ @ruby_optimize[:default].set_version(:other)
243
+ expect(ruby_optimize_wrap(:v3, :default, version_for_crawler: true) do
244
+ 'hello'
245
+ end).to eq('')
246
+ @ruby_optimize[:default].set_version(:v1)
247
+ expect(ruby_optimize_wrap(:v1, version_for_crawler: true) do
248
+ 'hello'
249
+ end).to eq('hello')
250
+ @ruby_optimize[:default].set_version(:other)
251
+ expect(ruby_optimize_wrap(:v1, version_for_crawler: true) do
252
+ 'hello'
253
+ end).to eq('')
254
+ expect(ruby_optimize_wrap(version_for_crawler: true) do
255
+ 'hello'
256
+ end).to eq('')
257
+ # TEST SET UP
258
+ def (@ruby_optimize[:test]).set_version(a_version)
259
+ @version = a_version
260
+ end
261
+ def (@ruby_optimize[:test]).get_cookie_expiration
262
+ cookie_expiration
263
+ end
264
+ def (@ruby_optimize[:test]).get_cookie_name
265
+ cookie_name
266
+ end
267
+ def (@ruby_optimize[:test]).get_version_for_crawler
268
+ version_for_crawler
269
+ end
270
+ def (@ruby_optimize[:test]).get_is_crawler
271
+ is_crawler
272
+ end
273
+ def (@ruby_optimize[:test]).get_versions
274
+ versions
275
+ end
276
+ expect(@ruby_optimize[:test].get_cookie_expiration).to eq(15552000)
277
+ expect(@ruby_optimize[:test].get_cookie_name).to eq('ruby-optimize-cookie-test')
278
+ expect(@ruby_optimize[:test].get_version_for_crawler).to eq(nil)
279
+ expect(@ruby_optimize[:test].get_is_crawler).to eq(false)
280
+ expect(@ruby_optimize[:test].get_versions.sort).to eq([:new, :old])
281
+ # TEST WRAP
282
+ expect do
283
+ ruby_optimize_wrap(:v444, :test) do
284
+ 'hello'
285
+ end
286
+ end.to raise_error('RubyOptimize - version must be one of the available versions: :v444')
287
+ @ruby_optimize[:test].set_version(:old)
288
+ expect(ruby_optimize_wrap(:old, :test) do
289
+ 'hello'
290
+ end).to eq('hello')
291
+ @ruby_optimize[:test].set_version(:other)
292
+ expect(ruby_optimize_wrap(:old, :test) do
293
+ 'hello'
294
+ end).to eq('')
295
+ @ruby_optimize[:test].set_version(:new)
296
+ expect(ruby_optimize_wrap(:new, :test, version_for_crawler: true) do
297
+ 'hello'
298
+ end).to eq('hello')
299
+ @ruby_optimize[:test].set_version(:other)
300
+ expect(ruby_optimize_wrap(:new, :test, version_for_crawler: true) do
301
+ 'hello'
302
+ end).to eq('')
303
+ # TEST2 SET UP
304
+ def (@ruby_optimize[:test2]).set_version(a_version)
305
+ @version = a_version
306
+ end
307
+ def (@ruby_optimize[:test2]).get_cookie_expiration
308
+ cookie_expiration
309
+ end
310
+ def (@ruby_optimize[:test2]).get_cookie_name
311
+ cookie_name
312
+ end
313
+ def (@ruby_optimize[:test2]).get_version_for_crawler
314
+ version_for_crawler
315
+ end
316
+ def (@ruby_optimize[:test2]).get_is_crawler
317
+ is_crawler
318
+ end
319
+ def (@ruby_optimize[:test2]).get_versions
320
+ versions
321
+ end
322
+ expect(@ruby_optimize[:test2].get_cookie_expiration).to eq(15552000)
323
+ expect(@ruby_optimize[:test2].get_cookie_name).to eq('ruby-optimize-cookie-test2')
324
+ expect(@ruby_optimize[:test2].get_version_for_crawler).to eq(nil)
325
+ expect(@ruby_optimize[:test2].get_is_crawler).to eq(false)
326
+ expect(@ruby_optimize[:test2].get_versions.sort).to eq([:new, :old])
327
+ # TEST2 WRAP
328
+ expect do
329
+ ruby_optimize_wrap(:v444, :test2) do
330
+ 'hello'
331
+ end
332
+ end.to raise_error('RubyOptimize - version must be one of the available versions: :v444')
333
+ @ruby_optimize[:test2].set_version(:old)
334
+ expect(ruby_optimize_wrap(:old, :test2) do
335
+ 'hello'
336
+ end).to eq('hello')
337
+ @ruby_optimize[:test2].set_version(:other)
338
+ expect(ruby_optimize_wrap(:old, :test2) do
339
+ 'hello'
340
+ end).to eq('')
341
+ @ruby_optimize[:test2].set_version(:new)
342
+ expect(ruby_optimize_wrap(:new, :test2, version_for_crawler: true) do
343
+ 'hello'
344
+ end).to eq('hello')
345
+ @ruby_optimize[:test2].set_version(:other)
346
+ expect(ruby_optimize_wrap(:new, :test2, version_for_crawler: true) do
347
+ 'hello'
348
+ end).to eq('')
349
+ # TEST3 SET UP
350
+ def (@ruby_optimize[:test3]).set_version(a_version)
351
+ @version = a_version
352
+ end
353
+ def (@ruby_optimize[:test3]).get_cookie_expiration
354
+ cookie_expiration
355
+ end
356
+ def (@ruby_optimize[:test3]).get_cookie_name
357
+ cookie_name
358
+ end
359
+ def (@ruby_optimize[:test3]).get_version_for_crawler
360
+ version_for_crawler
361
+ end
362
+ def (@ruby_optimize[:test3]).get_is_crawler
363
+ is_crawler
364
+ end
365
+ def (@ruby_optimize[:test3]).get_versions
366
+ versions
367
+ end
368
+ expect(@ruby_optimize[:test3].get_cookie_expiration).to eq(33)
369
+ expect(@ruby_optimize[:test3].get_cookie_name).to eq('ruby-optimize-cookie-test3')
370
+ expect(@ruby_optimize[:test3].get_version_for_crawler).to eq(nil)
371
+ expect(@ruby_optimize[:test3].get_is_crawler).to eq(false)
372
+ expect(@ruby_optimize[:test3].get_versions.sort).to eq([:v4, :v5])
373
+ # TEST3 WRAP
374
+ expect do
375
+ ruby_optimize_wrap(:v444, :test3) do
376
+ 'hello'
377
+ end
378
+ end.to raise_error('RubyOptimize - version must be one of the available versions: :v444')
379
+ @ruby_optimize[:test3].set_version(:v4)
380
+ expect(ruby_optimize_wrap(:v4, :test3) do
381
+ 'hello'
382
+ end).to eq('hello')
383
+ @ruby_optimize[:test3].set_version(:other)
384
+ expect(ruby_optimize_wrap(:v4, :test3) do
385
+ 'hello'
386
+ end).to eq('')
387
+ @ruby_optimize[:test3].set_version(:v5)
388
+ expect(ruby_optimize_wrap(:v5, :test3, version_for_crawler: true) do
389
+ 'hello'
390
+ end).to eq('hello')
391
+ @ruby_optimize[:test3].set_version(:other)
392
+ expect(ruby_optimize_wrap(:v5, :test3, version_for_crawler: true) do
393
+ 'hello'
394
+ end).to eq('')
395
+ # TEST4 SET UP
396
+ def (@ruby_optimize[:test4]).set_version(a_version)
397
+ @version = a_version
398
+ end
399
+ def (@ruby_optimize[:test4]).get_cookie_expiration
400
+ cookie_expiration
401
+ end
402
+ def (@ruby_optimize[:test4]).get_cookie_name
403
+ cookie_name
404
+ end
405
+ def (@ruby_optimize[:test4]).get_version_for_crawler
406
+ version_for_crawler
407
+ end
408
+ def (@ruby_optimize[:test4]).get_is_crawler
409
+ is_crawler
410
+ end
411
+ def (@ruby_optimize[:test4]).get_versions
412
+ versions
413
+ end
414
+ expect(@ruby_optimize[:test4].get_cookie_expiration).to eq(15552000)
415
+ expect(@ruby_optimize[:test4].get_cookie_name).to eq('ruby-optimize-cookie-test4')
416
+ expect(@ruby_optimize[:test4].get_version_for_crawler).to eq(:v5)
417
+ expect(@ruby_optimize[:test4].get_is_crawler).to eq(false)
418
+ expect(@ruby_optimize[:test4].get_versions.sort).to eq([:v4, :v5])
419
+ # TEST4 WRAP
420
+ expect do
421
+ ruby_optimize_wrap(:v444, :test4) do
422
+ 'hello'
423
+ end
424
+ end.to raise_error('RubyOptimize - version must be one of the available versions: :v444')
425
+ @ruby_optimize[:test4].set_version(:v5)
426
+ expect(ruby_optimize_wrap(:v5, :test4) do
427
+ 'hello'
428
+ end).to eq('hello')
429
+ @ruby_optimize[:test4].set_version(:other)
430
+ expect(ruby_optimize_wrap(:v5, :test4) do
431
+ 'hello'
432
+ end).to eq('')
433
+ @ruby_optimize[:test4].set_version(:v4)
434
+ expect(ruby_optimize_wrap(:v4, :test4, version_for_crawler: true) do
435
+ 'hello'
436
+ end).to eq('hello')
437
+ @ruby_optimize[:test4].set_version(:other)
438
+ expect(ruby_optimize_wrap(:v4, :test4, version_for_crawler: true) do
439
+ 'hello'
440
+ end).to eq('')
441
+ end
442
+ end
443
+
444
+ context 'crawler' do
445
+ let(:request) do
446
+ OpenStruct.new(user_agent: 'summify')
447
+ end
448
+
449
+ it 'correctly sets up the object, empty init scripts, empty wrap' do
450
+ ruby_optimize [ :v1, :v2, :v3 ]
451
+ ruby_optimize [ :old, :new ], scope: :test, version_for_crawler: :old
452
+ # WRAP GENERIC
453
+ expect do
454
+ ruby_optimize_wrap(:v1, :anotherscope) do
455
+ 'hello'
456
+ end
457
+ end.to raise_error('RubyOptimize - scope not found: :anotherscope')
458
+ expect do
459
+ @ruby_optimize[:default].wrap('hello', :v1, 'true') do
460
+ 'hello'
461
+ end
462
+ end.to raise_error('RubyOptimize - for_crawler must be a boolean: "true"')
463
+ # DEFAULT SET UP
464
+ def (@ruby_optimize[:default]).get_cookie_expiration
465
+ cookie_expiration
466
+ end
467
+ def (@ruby_optimize[:default]).get_cookie_name
468
+ cookie_name
469
+ end
470
+ def (@ruby_optimize[:default]).get_version_for_crawler
471
+ version_for_crawler
472
+ end
473
+ def (@ruby_optimize[:default]).get_is_crawler
474
+ is_crawler
475
+ end
476
+ def (@ruby_optimize[:default]).get_versions
477
+ versions
478
+ end
479
+ expect(@ruby_optimize[:default].get_cookie_expiration).to eq(15552000)
480
+ expect(@ruby_optimize[:default].get_cookie_name).to eq('ruby-optimize-cookie-default')
481
+ expect(@ruby_optimize[:default].get_version_for_crawler).to eq(nil)
482
+ expect(@ruby_optimize[:default].get_is_crawler).to eq(true)
483
+ expect(@ruby_optimize[:default].get_versions.sort).to eq([:v1, :v2, :v3])
484
+ # DEFAULT WRAP
485
+ expect(ruby_optimize_wrap(:xxx) do
486
+ 'hello'
487
+ end).to eq('')
488
+ expect(ruby_optimize_wrap do
489
+ 'hello'
490
+ end).to eq('')
491
+ expect(ruby_optimize_wrap(:v1) do
492
+ 'hello'
493
+ end).to eq('')
494
+ expect(ruby_optimize_wrap(:v2, :default) do
495
+ 'hello'
496
+ end).to eq('')
497
+ expect(ruby_optimize_wrap(:v3, :default, version_for_crawler: true) do
498
+ 'hello'
499
+ end).to eq('hello')
500
+ expect(ruby_optimize_wrap(:v1, version_for_crawler: true) do
501
+ 'hello'
502
+ end).to eq('hello')
503
+ expect(ruby_optimize_wrap(version_for_crawler: true) do
504
+ 'hello'
505
+ end).to eq('hello')
506
+ # TEST SET UP
507
+ def (@ruby_optimize[:test]).get_cookie_expiration
508
+ cookie_expiration
509
+ end
510
+ def (@ruby_optimize[:test]).get_cookie_name
511
+ cookie_name
512
+ end
513
+ def (@ruby_optimize[:test]).get_version_for_crawler
514
+ version_for_crawler
515
+ end
516
+ def (@ruby_optimize[:test]).get_is_crawler
517
+ is_crawler
518
+ end
519
+ def (@ruby_optimize[:test]).get_versions
520
+ versions
521
+ end
522
+ expect(@ruby_optimize[:test].get_cookie_expiration).to eq(15552000)
523
+ expect(@ruby_optimize[:test].get_cookie_name).to eq('ruby-optimize-cookie-test')
524
+ expect(@ruby_optimize[:test].get_version_for_crawler).to eq(:old)
525
+ expect(@ruby_optimize[:test].get_is_crawler).to eq(true)
526
+ expect(@ruby_optimize[:test].get_versions.sort).to eq([:new, :old])
527
+ # TEST WRAP
528
+ expect(ruby_optimize_wrap(:xxx, :test) do
529
+ 'hello'
530
+ end).to eq('')
531
+ expect(ruby_optimize_wrap(:old, :test) do
532
+ 'hello'
533
+ end).to eq('hello')
534
+ expect(ruby_optimize_wrap(:new, :test) do
535
+ 'hello'
536
+ end).to eq('')
537
+ expect(ruby_optimize_wrap(:old, :test, version_for_crawler: true) do
538
+ 'hello'
539
+ end).to eq('hello')
540
+ expect(ruby_optimize_wrap(:new, :test, version_for_crawler: true) do
541
+ 'hello'
542
+ end).to eq('hello')
543
+ end
544
+ end
545
+ end
546
+ end
metadata ADDED
@@ -0,0 +1,116 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby_optimize
3
+ version: !ruby/object:Gem::Version
4
+ version: '2.3'
5
+ platform: ruby
6
+ authors:
7
+ - Adriano di Lauro
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-10-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 3.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 3.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: actionpack
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 3.0.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 3.0.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.7'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.7'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '10.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10.0'
69
+ description: With ruby_optimize you can set up multiple A/B tests, consistent across
70
+ session, in a clean way and without page flickering
71
+ email:
72
+ - adr_dilauro@hotmail.it
73
+ executables: []
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - ".gitignore"
78
+ - Gemfile
79
+ - MIT-LICENSE
80
+ - README.md
81
+ - lib/ruby_optimize.rb
82
+ - lib/ruby_optimize/common_controllers_and_helpers.rb
83
+ - lib/ruby_optimize/controllers/action_controller_extension.rb
84
+ - lib/ruby_optimize/helpers/action_view_extension.rb
85
+ - lib/ruby_optimize/hooks.rb
86
+ - lib/ruby_optimize/models/ab_test_handler.rb
87
+ - lib/ruby_optimize/railtie.rb
88
+ - lib/ruby_optimize/version.rb
89
+ - ruby_optimize.gemspec
90
+ - spec/ruby_optimize_spec.rb
91
+ homepage: https://github.com/adrdilauro/ruby_optimize
92
+ licenses:
93
+ - MIT
94
+ metadata: {}
95
+ post_install_message:
96
+ rdoc_options: []
97
+ require_paths:
98
+ - lib
99
+ required_ruby_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ required_rubygems_version: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ requirements: []
110
+ rubyforge_project:
111
+ rubygems_version: 2.2.2
112
+ signing_key:
113
+ specification_version: 4
114
+ summary: Tool to implement flexible A/B tests in Ruby on Rails
115
+ test_files: []
116
+ has_rdoc: