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 CHANGED
@@ -1 +1 @@
1
- 0.0.1
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.1"
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-23"
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.db, Fabes.configuration.adapter
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: normal 12px auto Verdana, Arial, Helvetica, sans-serif;
3
- color: #FDF3E7;
4
- background: #3B3738;
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
- font-size: 13px;
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: 50px auto;
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
- %tr
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
- %td{title: alternative.id}= alternative.payload
15
- %td= alternative.participants
16
- %td= alternative.hits
17
- %td= alternative.weight
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
@@ -5,7 +5,8 @@
5
5
  %link{href: request.env['SCRIPT_NAME'] + '/application.css', media: 'all', rel: 'stylesheet', type: 'text/css'}
6
6
  %body
7
7
  #container
8
- #header
9
- .logo
8
+ #logo
9
+ %h1 Fabes
10
+ %span Fabulous A/B Experimentation System
10
11
  #content
11
12
  =yield
@@ -1,17 +1,20 @@
1
1
  module Fabes
2
2
  class Configuration
3
- attr_accessor :adapter, :db
3
+ attr_accessor :database, :factor
4
4
 
5
5
  def initialize
6
- @adapter = 'redis'
7
- @db = nil
6
+ @database = ENV['FABES_DB_URL'] || ENV['REDISTOGO_URL']
7
+ @factor = 0.1
8
8
  end
9
9
 
10
- def use(db_config)
11
- @adapter = db_config[:adapter].to_s
12
- @db = db_config[:db] || ENV['FABES_DB_URL'] || ENV['REDISTOGO_URL']
13
- rescue => e
14
- raise "Bad 'use' config: #{e.message}"
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, adapter)
6
- #TODO: automagically parse db a la rails
7
- #REF: https://github.com/rails/rails/blob/master/activerecord/lib/active_record/connection_handling.rb
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, db
10
- rescue => e
10
+ send adapter_method, database
11
+ rescue
11
12
  raise "Could not find #{adapter} adapter!"
12
13
  end
13
14
 
14
- def parse_connection_url(url)
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
 
@@ -2,8 +2,8 @@ module Fabes
2
2
  module ConnectionHandling
3
3
  def self.redis_connection(db)
4
4
  require 'redis'
5
- db ||= ::Redis.new
6
- ConnectionAdapters::RedisAdapter.new(db)
5
+ redis = ::Redis.new db
6
+ ConnectionAdapters::RedisAdapter.new redis
7
7
  end
8
8
  end
9
9
 
@@ -52,7 +52,7 @@ module Fabes
52
52
  private
53
53
 
54
54
  def exploration?
55
- rand() < 0.2 # 20% of times
55
+ rand() < Fabes.configuration.factor.to_f
56
56
  end
57
57
 
58
58
  def random_alternative
@@ -0,0 +1,7 @@
1
+ module Fabes
2
+ class FabesRailtie < ::Rails::Railtie
3
+ ActionController::Base.send :include, Fabes::Helper
4
+ ActionController::Base.helper Fabes::Helper
5
+ #TODO: auto-inject route in rails?
6
+ end
7
+ end
@@ -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
- adapter = 'caca'
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
- adapter = 'redis'
15
- db = ''
13
+ db = 'redis://uno:dos@tres.com:123/'
16
14
  Fabes::ConnectionHandling.expects :redis_connection
17
- Fabes::ConnectionHandling.establish_connection(db, adapter)
15
+ Fabes::ConnectionHandling.establish_connection(db)
18
16
  end
19
17
  end
20
18
  end
@@ -2,9 +2,14 @@ require 'helper'
2
2
 
3
3
  class TestConfiguration < Test::Unit::TestCase
4
4
  context 'initialization' do
5
- should 'have an adapter' do
5
+ should 'have a database' do
6
6
  configuration = Fabes::Configuration.new
7
- assert configuration.respond_to? :adapter
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 'set the adapter' do
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 db: 'abc', adapter: :redis
36
+ c.use fail: 'redis://user:pwd@host.com:123/'
20
37
  end
21
- assert_not_nil configuration.instance_variable_get :@adapter
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 db' do
41
+ should 'set the factor' do
26
42
  configuration = Fabes.configure do |c|
27
- c.use db: 'abc', adapter: :redis
43
+ c.bandit_factor 0.25
28
44
  end
29
- assert_not_nil configuration.instance_variable_get(:@db)
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
@@ -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.1
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-23 00:00:00.000000000 Z
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: 4128537144808349217
212
+ hash: 3698846090476597919
212
213
  required_rubygems_version: !ruby/object:Gem::Requirement
213
214
  none: false
214
215
  requirements: