fabes 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/fabes.gemspec +3 -2
- data/lib/fabes.rb +2 -7
- data/lib/fabes/admin/public/application.css +77 -11
- data/lib/fabes/admin/views/index.haml +12 -10
- data/lib/fabes/admin/views/layout.haml +3 -2
- data/lib/fabes/configuration.rb +11 -8
- data/lib/fabes/connection_adapters/abstract_adapter.rb +20 -6
- data/lib/fabes/connection_adapters/redis_adapter.rb +2 -2
- data/lib/fabes/experiment.rb +1 -1
- data/lib/fabes/railtie.rb +7 -0
- data/test/test_abstract_adapter.rb +4 -6
- data/test/test_configuration.rb +25 -10
- data/test/test_redis_adapter.rb +1 -0
- metadata +4 -3
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.2
|
data/fabes.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "fabes"
|
8
|
-
s.version = "0.0.
|
8
|
+
s.version = "0.0.2"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Alejandro Andres"]
|
12
|
-
s.date = "2012-07-
|
12
|
+
s.date = "2012-07-25"
|
13
13
|
s.description = "Fabes is an A/B testing system for your ruby projects"
|
14
14
|
s.email = "fuzzy.alej@gmail.com"
|
15
15
|
s.extra_rdoc_files = [
|
@@ -39,6 +39,7 @@ Gem::Specification.new do |s|
|
|
39
39
|
"lib/fabes/connection_handling.rb",
|
40
40
|
"lib/fabes/experiment.rb",
|
41
41
|
"lib/fabes/helper.rb",
|
42
|
+
"lib/fabes/railtie.rb",
|
42
43
|
"lib/fabes/utils.rb",
|
43
44
|
"test/helper.rb",
|
44
45
|
"test/test_abstract_adapter.rb",
|
data/lib/fabes.rb
CHANGED
@@ -17,15 +17,10 @@ module Fabes
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def db
|
20
|
-
@db ||= ConnectionHandling.establish_connection Fabes.configuration.
|
20
|
+
@db ||= ConnectionHandling.establish_connection Fabes.configuration.database
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
24
|
Fabes.configure
|
25
25
|
|
26
|
-
if defined? Rails
|
27
|
-
ActionController::Base.send :include, Fabes::Helper
|
28
|
-
ActionController::Base.helper Fabes::Helper
|
29
|
-
#TODO: Autoadd route to admin panel
|
30
|
-
#TODO: Railtie???
|
31
|
-
end
|
26
|
+
require 'fabes/railtie' if defined? Rails
|
@@ -1,7 +1,8 @@
|
|
1
1
|
body {
|
2
|
-
font:
|
3
|
-
|
4
|
-
|
2
|
+
font-family: 'trebuchet MS', 'Lucida sans', Arial, sans-serif;
|
3
|
+
font-size: 14px;
|
4
|
+
color: #3b3b3b;
|
5
|
+
background-image: url('http://subtlepatterns.com/patterns/fabric_plaid.png');
|
5
6
|
}
|
6
7
|
|
7
8
|
a {
|
@@ -18,38 +19,103 @@ h2.span {
|
|
18
19
|
font-size: 16px;
|
19
20
|
}
|
20
21
|
|
22
|
+
#logo {
|
23
|
+
margin-bottom: 25px;
|
24
|
+
}
|
25
|
+
|
26
|
+
#logo h1 {
|
27
|
+
font-family: Arial, sans-serif;
|
28
|
+
font-size: 75px;
|
29
|
+
margin: 25px 0 0 0;
|
30
|
+
color: #504f4f;
|
31
|
+
text-shadow: 0px 2px 1px #bbbaba;
|
32
|
+
}
|
33
|
+
|
34
|
+
#logo span {
|
35
|
+
text-shadow: 0px 1px 1px #bbbaba;
|
36
|
+
}
|
37
|
+
|
21
38
|
table {
|
22
39
|
width: 700px;
|
23
40
|
padding: 0px;
|
24
41
|
margin: 0px;
|
42
|
+
border: solid 1px #999;
|
43
|
+
*border-collapse: collapse;
|
44
|
+
border-spacing: 0;
|
45
|
+
border-radius: 6px;
|
46
|
+
-moz-border-radius: 6px;
|
47
|
+
-wekit-border-radius: 6px;
|
48
|
+
box-shadow: 0 1px 1px #999;
|
49
|
+
-webkit-box-shadow: 0 1px 1px #999;
|
50
|
+
-moz-box-shadow: 0 1px 1px #999;
|
25
51
|
}
|
26
52
|
|
27
53
|
th {
|
28
|
-
border-right: 1px solid #A64C2E;
|
29
|
-
border-bottom: 1px solid #A64C2E;
|
30
|
-
border-top: 1px solid #D53500;
|
31
|
-
border-left: 1px solid #D53500;
|
32
54
|
letter-spacing: 2px;
|
33
55
|
text-transform: uppercase;
|
34
56
|
text-align: center;
|
35
57
|
font-size: 13px;
|
36
58
|
padding: 10px;
|
37
|
-
background: #C63D0F;
|
38
59
|
color: #FFFFFF;
|
60
|
+
background-color: #C63D0F;
|
61
|
+
background-image: linear-gradient(top, #c63d0f, #6f1b00);
|
62
|
+
background-image: -webkit-linear-gradient(top, #c63d0f, #6f1b00);
|
63
|
+
background-image: -moz-linear-gradient(top, #c63d0f, #6f1b00);
|
39
64
|
text-shadow: 1px 1px 1px black;
|
65
|
+
box-shadow: 0 1px 0 rgba(255, 200, 200, .8) inset;
|
66
|
+
-moz-box-shadow: 0 1px 0 rgba(255, 200, 200, .8) inset;
|
67
|
+
-webkit-box-shadow: 0 1px 0 rgba(255, 200, 200, .8) inset;
|
68
|
+
}
|
69
|
+
|
70
|
+
th:first-child {
|
71
|
+
background-color: #C63D0F;
|
72
|
+
background-image: linear-gradient(top, #c63d0f, #6f1b00)
|
73
|
+
background-image: -webkit-linear-gradient(top, #c63d0f, #6f1b00);
|
74
|
+
background-image: -moz-linear-gradient(top, #c63d0f, #6f1b00);
|
75
|
+
-moz-border-radius: 6px 0 0 0;
|
76
|
+
-webkit-border-radius: 6px 0 0 0;
|
77
|
+
border-radius: 6px 0 0 0;
|
78
|
+
}
|
79
|
+
|
80
|
+
th:last-child {
|
81
|
+
-moz-border-radius: 0 6px 0 0;
|
82
|
+
-webkit-border-radius: 0 6px 0 0;
|
83
|
+
border-radius: 0 6px 0 0;
|
40
84
|
}
|
41
85
|
|
42
86
|
td {
|
43
87
|
border-right: 1px solid #C1DAD7;
|
44
88
|
border-bottom: 1px solid #C1DAD7;
|
45
|
-
background: #FDF3E7;
|
46
89
|
padding: 6px;
|
47
90
|
color: #3B3738;
|
48
|
-
|
91
|
+
}
|
92
|
+
|
93
|
+
td:first-child {
|
94
|
+
font-weight: bold;
|
95
|
+
}
|
96
|
+
|
97
|
+
tr {
|
98
|
+
background: white;
|
99
|
+
}
|
100
|
+
|
101
|
+
tr:last-child td:first-child {
|
102
|
+
border-radius: 0 0 0 6px;
|
103
|
+
-moz-border-radius: 0 0 0 6px;
|
104
|
+
-webkit-border-radius: 0 0 0 6px;
|
105
|
+
}
|
106
|
+
|
107
|
+
tr:last-child td:last-child {
|
108
|
+
border-radius: 0 0 6px 0;
|
109
|
+
-moz-border-radius: 0 0 6px 0;
|
110
|
+
-webkit-border-radius: 0 0 6px 0;
|
111
|
+
}
|
112
|
+
|
113
|
+
tr:hover {
|
114
|
+
background: #FBF8E9;
|
49
115
|
}
|
50
116
|
|
51
117
|
#container {
|
52
|
-
margin:
|
118
|
+
margin: 0 auto;
|
53
119
|
text-align: center;
|
54
120
|
overflow: hidden;
|
55
121
|
}
|
@@ -4,14 +4,16 @@
|
|
4
4
|
.experiment
|
5
5
|
%h2= "Experiment: #{name.capitalize}"
|
6
6
|
%table{id: name.first, cellspacing: 0, summary: "Data for experiment '#{name}'"}
|
7
|
-
%
|
8
|
-
%th{scope: 'col'} Alternative
|
9
|
-
%th{scope: 'col'} Participants
|
10
|
-
%th{scope: 'col'} Hits
|
11
|
-
%th{scope: 'col'} Weight
|
12
|
-
- experiment.alternatives.each do |alternative|
|
7
|
+
%thead
|
13
8
|
%tr
|
14
|
-
%
|
15
|
-
%
|
16
|
-
%
|
17
|
-
%
|
9
|
+
%th{scope: 'col'} Alternative
|
10
|
+
%th{scope: 'col'} Participants
|
11
|
+
%th{scope: 'col'} Hits
|
12
|
+
%th{scope: 'col'} Weight
|
13
|
+
%tbody
|
14
|
+
- experiment.alternatives.each do |alternative|
|
15
|
+
%tr
|
16
|
+
%td{title: alternative.id}= alternative.payload
|
17
|
+
%td= alternative.participants
|
18
|
+
%td= alternative.hits
|
19
|
+
%td= alternative.weight
|
data/lib/fabes/configuration.rb
CHANGED
@@ -1,17 +1,20 @@
|
|
1
1
|
module Fabes
|
2
2
|
class Configuration
|
3
|
-
attr_accessor :
|
3
|
+
attr_accessor :database, :factor
|
4
4
|
|
5
5
|
def initialize
|
6
|
-
@
|
7
|
-
@
|
6
|
+
@database = ENV['FABES_DB_URL'] || ENV['REDISTOGO_URL']
|
7
|
+
@factor = 0.1
|
8
8
|
end
|
9
9
|
|
10
|
-
def use(
|
11
|
-
@
|
12
|
-
|
13
|
-
|
14
|
-
|
10
|
+
def use(options)
|
11
|
+
@database = options[:database] || options [:db]
|
12
|
+
rescue
|
13
|
+
@database = nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def bandit_factor(percentage)
|
17
|
+
@factor = percentage
|
15
18
|
end
|
16
19
|
end
|
17
20
|
end
|
@@ -1,17 +1,31 @@
|
|
1
1
|
module Fabes
|
2
2
|
module ConnectionHandling
|
3
|
+
require 'ostruct'
|
3
4
|
extend self
|
4
5
|
|
5
|
-
def establish_connection(db
|
6
|
-
|
7
|
-
|
6
|
+
def establish_connection(db)
|
7
|
+
database = connection_url_to_hash(db)
|
8
|
+
adapter = database.delete :adapter
|
8
9
|
adapter_method = "#{adapter}_connection"
|
9
|
-
send adapter_method,
|
10
|
-
rescue
|
10
|
+
send adapter_method, database
|
11
|
+
rescue
|
11
12
|
raise "Could not find #{adapter} adapter!"
|
12
13
|
end
|
13
14
|
|
14
|
-
|
15
|
+
#from https://github.com/rails/rails/blob/master/activerecord/lib/active_record/connection_adapters/connection_specification.rb#L65
|
16
|
+
def connection_url_to_hash(url)
|
17
|
+
url ||= ''
|
18
|
+
uri = URI.parse url
|
19
|
+
spec = {
|
20
|
+
host: uri.host,
|
21
|
+
port: uri.port,
|
22
|
+
adapter: uri.scheme,
|
23
|
+
username: uri.user,
|
24
|
+
password: uri.password,
|
25
|
+
database: uri.path.sub(%r{^/}, '')
|
26
|
+
}
|
27
|
+
spec.reject! {|_, value| !value}
|
28
|
+
{adapter: 'redis'}.merge spec
|
15
29
|
end
|
16
30
|
end
|
17
31
|
|
data/lib/fabes/experiment.rb
CHANGED
@@ -4,17 +4,15 @@ class TestAbstractAdapter < Test::Unit::TestCase
|
|
4
4
|
context 'establish_connection' do
|
5
5
|
should 'raise if no suitable adapter' do
|
6
6
|
assert_raise RuntimeError do
|
7
|
-
|
8
|
-
db
|
9
|
-
Fabes::ConnectionHandling.establish_connection(db, adapter)
|
7
|
+
db = 'http://uno:dos@tres.com:123/'
|
8
|
+
Fabes::ConnectionHandling.establish_connection(db)
|
10
9
|
end
|
11
10
|
end
|
12
11
|
|
13
12
|
should 'work if suitable adapter (redis)' do
|
14
|
-
|
15
|
-
db = ''
|
13
|
+
db = 'redis://uno:dos@tres.com:123/'
|
16
14
|
Fabes::ConnectionHandling.expects :redis_connection
|
17
|
-
Fabes::ConnectionHandling.establish_connection(db
|
15
|
+
Fabes::ConnectionHandling.establish_connection(db)
|
18
16
|
end
|
19
17
|
end
|
20
18
|
end
|
data/test/test_configuration.rb
CHANGED
@@ -2,9 +2,14 @@ require 'helper'
|
|
2
2
|
|
3
3
|
class TestConfiguration < Test::Unit::TestCase
|
4
4
|
context 'initialization' do
|
5
|
-
should 'have
|
5
|
+
should 'have a database' do
|
6
6
|
configuration = Fabes::Configuration.new
|
7
|
-
assert configuration.respond_to? :
|
7
|
+
assert configuration.respond_to? :database
|
8
|
+
end
|
9
|
+
|
10
|
+
should 'have a factor' do
|
11
|
+
configuration = Fabes::Configuration.new
|
12
|
+
assert configuration.respond_to? :factor
|
8
13
|
end
|
9
14
|
end
|
10
15
|
|
@@ -14,20 +19,30 @@ class TestConfiguration < Test::Unit::TestCase
|
|
14
19
|
assert configuration.respond_to? :use
|
15
20
|
end
|
16
21
|
|
17
|
-
should '
|
22
|
+
should 'have a factor command' do
|
23
|
+
configuration = Fabes::Configuration.new
|
24
|
+
assert configuration.respond_to? :factor
|
25
|
+
end
|
26
|
+
|
27
|
+
should 'set the database' do
|
28
|
+
configuration = Fabes.configure do |c|
|
29
|
+
c.use database: 'redis://user:pwd@host.com:123/'
|
30
|
+
end
|
31
|
+
assert_not_nil configuration.instance_variable_get :@database
|
32
|
+
end
|
33
|
+
|
34
|
+
should 'nilify the db with bad configuration' do
|
18
35
|
configuration = Fabes.configure do |c|
|
19
|
-
c.use
|
36
|
+
c.use fail: 'redis://user:pwd@host.com:123/'
|
20
37
|
end
|
21
|
-
|
22
|
-
assert_equal configuration.instance_variable_get(:@adapter), 'redis'
|
38
|
+
assert_nil configuration.instance_variable_get :@database
|
23
39
|
end
|
24
40
|
|
25
|
-
should 'set the
|
41
|
+
should 'set the factor' do
|
26
42
|
configuration = Fabes.configure do |c|
|
27
|
-
c.
|
43
|
+
c.bandit_factor 0.25
|
28
44
|
end
|
29
|
-
|
30
|
-
assert_equal configuration.instance_variable_get(:@db), 'abc'
|
45
|
+
assert_equal configuration.factor, 0.25
|
31
46
|
end
|
32
47
|
end
|
33
48
|
end
|
data/test/test_redis_adapter.rb
CHANGED
@@ -15,6 +15,7 @@ class TestRedisAdapter < Test::Unit::TestCase
|
|
15
15
|
setup do
|
16
16
|
@db = Redis.new
|
17
17
|
@adapter = Fabes::ConnectionAdapters::RedisAdapter.new(@db)
|
18
|
+
Fabes.stubs(:db).returns(@adapter)
|
18
19
|
@experiment = Fabes::Experiment.new 'test', 'a', 'b', 'c'
|
19
20
|
@adapter.save_experiment(@experiment)
|
20
21
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fabes
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-07-
|
12
|
+
date: 2012-07-25 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: redis
|
@@ -185,6 +185,7 @@ files:
|
|
185
185
|
- lib/fabes/connection_handling.rb
|
186
186
|
- lib/fabes/experiment.rb
|
187
187
|
- lib/fabes/helper.rb
|
188
|
+
- lib/fabes/railtie.rb
|
188
189
|
- lib/fabes/utils.rb
|
189
190
|
- test/helper.rb
|
190
191
|
- test/test_abstract_adapter.rb
|
@@ -208,7 +209,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
208
209
|
version: '0'
|
209
210
|
segments:
|
210
211
|
- 0
|
211
|
-
hash:
|
212
|
+
hash: 3698846090476597919
|
212
213
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
213
214
|
none: false
|
214
215
|
requirements:
|