vignette 0.0.13 → 0.0.14
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +10 -10
- data/lib/vignette/object_extensions.rb +21 -13
- data/lib/vignette/version.rb +1 -1
- data/lib/vignette.rb +46 -46
- data/spec/lib/vignette/filter_spec.rb +3 -3
- data/spec/lib/vignette/object_extensions_spec.rb +42 -1
- data/spec/lib/vignette_spec.rb +80 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f45e9d2eb38a89e35ec4bf6d0cf62d80f77b92ad
|
4
|
+
data.tar.gz: 8ab414f006635373e0a88eaae142b85f4a205c1c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0f5b19dea4363391a52e2f7758e03007c0a616d29e15f59f285942d4b15ea3918ff7281160cee2427341bafd0139f7e7c658c97acd97fd13c565a75421c2d183
|
7
|
+
data.tar.gz: a98445107d11417e51eef0e16566a5cdc1559995ed061a8cc53b01930e02641ba68ccb96ef088620a10984ed14e60594a9c9e5a65946243975f009f5f38e6823
|
data/README.md
CHANGED
@@ -64,16 +64,6 @@ The choices for these tests are exposed through the `Vignette.test` method:
|
|
64
64
|
|
65
65
|
You may store these values as properties in your analytics system.
|
66
66
|
|
67
|
-
## Caveats
|
68
|
-
|
69
|
-
Tests are stored in your store object based on the original input. If you change the input of the test (regardless of the name), a new test will be created. Thus [1,2,3].vignette(:numbers) and [2,3,4].vignette(:numbers) will always be considered unique tests. New tests will overwrite old tests with the same name in `Vignette.tests`. This is by design so that you can update the test, have new results, but keep the same test name in your analytics system.
|
70
|
-
|
71
|
-
Note, you must use arrays that will not change between runs. Thus, `[Date.today, 1.days.ago].vignette` will end up creating separate tests every time this code is run. We use a `Zlib.crc32` check to check for uniqueness of an array. Instead, this should be `[0,1].vignette.days.ago`.
|
72
|
-
|
73
|
-
If you choose to store your `tests` in `cookies`, then the chosen result will be stored in a cookie sent to the user's browser. Thus, be careful not to store any secret information in a test.
|
74
|
-
|
75
|
-
For unnamed tests, the system will try to determine the name from the line in the file (e.g. `(app/models/user.rb:50)`). When it does this, it will keep the name the same so long as the underlying array has the same crc32 code. That is, even if that vignette moves off of line 50, the test will keep the same "name" until the choices of the test change. This is a trade-off to allow un-named vignettes to be easily understood in an analytics system without having to name each one unless you would like to.
|
76
|
-
|
77
67
|
## Naming Tests
|
78
68
|
|
79
69
|
Vignette tests can also be specifically named, e.g:
|
@@ -92,6 +82,16 @@ This will lead to `Vignette.tests` to include: `{ "cat_names" => "Chairman Meow"
|
|
92
82
|
|
93
83
|
Without a name, Vignettes will try to name themselves based on the name of the falling calling them, e.g. `(app/models/user.rb:25)` or `(app/views/users/new.html.haml:22)`
|
94
84
|
|
85
|
+
## Caveats
|
86
|
+
|
87
|
+
Tests are stored in your store object based on the original input. If you change the input of the test (regardless of the name), a new test will be created. Thus [1,2,3].vignette(:numbers) and [2,3,4].vignette(:numbers) will always be considered unique tests. New tests will overwrite old tests with the same name in `Vignette.tests`. This is by design so that you can update the test, have new results, but keep the same test name in your analytics system.
|
88
|
+
|
89
|
+
Note, you must use arrays that will not change between runs. Thus, `[Date.today, 1.days.ago].vignette` will end up creating separate tests every time this code is run. We use a `Zlib.crc32` check to check for uniqueness of an array. Instead, this should be `[0,1].vignette.days.ago`.
|
90
|
+
|
91
|
+
If you choose to store your `tests` in `cookies`, then the chosen result will be stored in a cookie sent to the user's browser. Thus, be careful not to store any secret information in a test.
|
92
|
+
|
93
|
+
For unnamed tests, the system will try to determine the name from the line in the file (e.g. `(app/models/user.rb:50)`). When it does this, it will keep the name the same so long as the underlying array has the same crc32 code. That is, even if that vignette moves off of line 50, the test will keep the same "name" until the choices of the test change. This is a trade-off to allow un-named vignettes to be easily understood in an analytics system without having to name each one unless you would like to.
|
94
|
+
|
95
95
|
## Contributing
|
96
96
|
|
97
97
|
1. Fork it
|
@@ -20,13 +20,12 @@ module ObjectExtensions
|
|
20
20
|
key = "vignette_#{vignette_crc}"
|
21
21
|
test_name = nil
|
22
22
|
|
23
|
-
|
24
|
-
v = store[:v] ? JSON(store[:v]) : {}
|
23
|
+
vig = Vignette.vig
|
25
24
|
|
26
25
|
test_name = if expect_consistent_name && name.present?
|
27
26
|
name
|
28
|
-
elsif
|
29
|
-
|
27
|
+
elsif vig[vignette_crc]
|
28
|
+
vig[vignette_crc]['n']
|
30
29
|
elsif name.present? # this logic looks weird, but this is if we don't expect consistent names *and* we don't have a name in v[]
|
31
30
|
name
|
32
31
|
else
|
@@ -34,13 +33,13 @@ module ObjectExtensions
|
|
34
33
|
"(#{Vignette::strip_path(loc.absolute_path)}:#{loc.lineno})"
|
35
34
|
end
|
36
35
|
|
37
|
-
result = if
|
38
|
-
|
36
|
+
result = if vig.has_key?(vignette_crc)
|
37
|
+
vig[vignette_crc]['v']
|
39
38
|
else
|
40
39
|
# Store key into storage if not available
|
41
40
|
new_value = self[Kernel.rand(length)]
|
42
41
|
|
43
|
-
|
42
|
+
Vignette.set_vig( vig.merge(vignette_crc => { n: test_name, v: new_value, t: Time.now.to_i }) )
|
44
43
|
|
45
44
|
new_value
|
46
45
|
end
|
@@ -53,16 +52,25 @@ module ObjectExtensions
|
|
53
52
|
module ActionControllerExtensions
|
54
53
|
|
55
54
|
def self.included(controller)
|
56
|
-
controller.around_filter(:
|
55
|
+
controller.around_filter(:with_vignettes)
|
57
56
|
end
|
58
57
|
|
59
58
|
private
|
60
59
|
|
61
|
-
def
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
60
|
+
def with_vignettes
|
61
|
+
# set repo based on what type of store we want
|
62
|
+
repo = case Vignette.store
|
63
|
+
when :session
|
64
|
+
session
|
65
|
+
when :cookies
|
66
|
+
cookies
|
67
|
+
when nil, :random
|
68
|
+
Hash.new
|
69
|
+
end
|
70
|
+
|
71
|
+
Vignette.with_repo(repo) do
|
72
|
+
yield
|
73
|
+
end
|
66
74
|
end
|
67
75
|
|
68
76
|
end
|
data/lib/vignette/version.rb
CHANGED
data/lib/vignette.rb
CHANGED
@@ -13,10 +13,9 @@ module Vignette
|
|
13
13
|
class TemplateRequiresNameError < VignetteStandardError; end
|
14
14
|
end
|
15
15
|
|
16
|
-
#
|
16
|
+
# Module Attributes, please set via `init()`
|
17
17
|
mattr_accessor :logging
|
18
18
|
mattr_accessor :store
|
19
|
-
mattr_accessor :request, :session, :cookies
|
20
19
|
|
21
20
|
# Initialization Code
|
22
21
|
|
@@ -30,66 +29,67 @@ module Vignette
|
|
30
29
|
|
31
30
|
# Member Functions
|
32
31
|
|
32
|
+
# Set any initializers
|
33
33
|
def self.init(opts={})
|
34
|
-
opts
|
35
|
-
|
36
|
-
|
37
|
-
|
34
|
+
opts.each do |k,v|
|
35
|
+
Vignette.send("#{k}=", v)
|
36
|
+
end
|
37
|
+
end
|
38
38
|
|
39
|
-
|
39
|
+
# Sets the current repo to be used to get and store tests for this thread
|
40
|
+
def self.set_repo(repo)
|
41
|
+
Thread.current[:vignette_repo] = repo
|
40
42
|
end
|
41
|
-
|
42
|
-
#
|
43
|
-
def self.
|
44
|
-
|
45
|
-
Vignette.session = session
|
46
|
-
Vignette.cookies = cookies
|
43
|
+
|
44
|
+
# Clears the current repo on this thread
|
45
|
+
def self.clear_repo
|
46
|
+
set_repo(nil)
|
47
47
|
end
|
48
48
|
|
49
|
-
|
49
|
+
# Performs block with repo set to `repo` for this thread
|
50
|
+
def self.with_repo(repo)
|
50
51
|
begin
|
51
|
-
Vignette.
|
52
|
+
Vignette.set_repo(repo)
|
52
53
|
|
53
54
|
yield
|
54
55
|
ensure
|
55
|
-
Vignette.
|
56
|
+
Vignette.clear_repo
|
56
57
|
end
|
57
58
|
end
|
58
|
-
|
59
|
-
|
60
|
-
|
59
|
+
|
60
|
+
# Is Vignette active for this thread (i.e. do we have a repo?)
|
61
|
+
def self.active?
|
62
|
+
!Thread.current[:vignette_repo].nil?
|
61
63
|
end
|
62
|
-
|
63
|
-
def self.tests(session=Vignette.session, cookies=Vignette.cookies)
|
64
|
-
store = get_store(session, cookies)
|
65
|
-
store && store[:v].present? ? JSON(store[:v]) : {}
|
66
|
-
if store && store[:v].present?
|
67
|
-
v = JSON(store[:v])
|
68
64
|
|
69
|
-
|
65
|
+
# Get the repo for this thread
|
66
|
+
def self.repo
|
67
|
+
raise Errors::ConfigError.new("Repo not active, please call Vignette.set_repo before using Vignette (or use around_filter in Rails)") if !active?
|
70
68
|
|
71
|
-
|
69
|
+
Thread.current[:vignette_repo]
|
70
|
+
end
|
72
71
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
72
|
+
# From the repo (default whatever is set for the thread), grab Vignettes' repo and unpack
|
73
|
+
def self.vig(repo=nil)
|
74
|
+
repo ||= Vignette.repo # allow using existing
|
75
|
+
|
76
|
+
repo && repo[:v].present? ? JSON(repo[:v]) : {}
|
77
77
|
end
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
78
|
+
|
79
|
+
# For this repo, store an update Vig
|
80
|
+
def self.set_vig(vig)
|
81
|
+
repo[:v] = vig.to_json
|
82
|
+
end
|
83
|
+
|
84
|
+
# Pull all the tests for this current repo
|
85
|
+
def self.tests(vig=nil)
|
86
|
+
vig ||= Vignette.vig
|
87
|
+
|
88
|
+
name_values = vig.values.map { |v| [ v['n'], [ v['t'], v['v'] ] ] }.group_by { |el| el[0] }
|
89
|
+
|
90
|
+
arr = name_values.map { |k,v| [ k.to_sym, v.sort { |a,b| b[1][0] <=> a[1][0] }.first[1][1] ] }
|
91
|
+
|
92
|
+
Hash[arr]
|
93
93
|
end
|
94
94
|
|
95
95
|
private
|
@@ -17,7 +17,7 @@ describe Haml::Filters::Vignette do
|
|
17
17
|
" }
|
18
18
|
|
19
19
|
it "should raise error" do
|
20
|
-
Vignette.
|
20
|
+
Vignette.with_repo(session) do
|
21
21
|
html = Haml::Engine.new(template).render
|
22
22
|
|
23
23
|
expect(html).to match(/\<p\>\s+three\s+\<\/p\>\n/)
|
@@ -38,7 +38,7 @@ describe Haml::Filters::Vignette do
|
|
38
38
|
" }
|
39
39
|
|
40
40
|
it "should correctly call vignette from render" do
|
41
|
-
Vignette.
|
41
|
+
Vignette.with_repo(session) do
|
42
42
|
html = Haml::Engine.new(template).render
|
43
43
|
|
44
44
|
expect(html).to eq("<p>\n three\n</p>\n")
|
@@ -53,7 +53,7 @@ describe Haml::Filters::Vignette do
|
|
53
53
|
before(:each) { expect(Kernel).to receive(:rand).and_return(2, 1) }
|
54
54
|
|
55
55
|
it "should correctly call vignette from render" do
|
56
|
-
Vignette.
|
56
|
+
Vignette.with_repo(session) do
|
57
57
|
template = File.read(template_file)
|
58
58
|
|
59
59
|
html = Haml::Engine.new(template, filename: template_file).render
|
@@ -2,6 +2,47 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe ObjectExtensions do
|
4
4
|
|
5
|
-
|
5
|
+
context "with a test controller" do
|
6
|
+
class TestController
|
7
|
+
@@filters = []
|
6
8
|
|
9
|
+
def self.filters
|
10
|
+
@@filters
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.around_filter(filter)
|
14
|
+
@@filters << filter
|
15
|
+
end
|
16
|
+
|
17
|
+
include ObjectExtensions::ActionControllerExtensions
|
18
|
+
|
19
|
+
def session
|
20
|
+
{ session_id: "whatever" }
|
21
|
+
end
|
22
|
+
|
23
|
+
def run(&block)
|
24
|
+
filter = @@filters.first # just make this easy
|
25
|
+
|
26
|
+
self.send(filter, &block)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should register an around_filter" do
|
31
|
+
expect(TestController.filters.count).to eq(1)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should correctly run around_filter" do
|
35
|
+
expect(Kernel).to receive(:rand).and_return(2)
|
36
|
+
expect(Vignette.active?).to be(false)
|
37
|
+
|
38
|
+
tc = TestController.new
|
39
|
+
|
40
|
+
tc.run do
|
41
|
+
expect(Vignette.repo).to eq(tc.session)
|
42
|
+
expect(Vignette.active?).to be(true)
|
43
|
+
expect([1,2,3].vignette(:number)).to eq(3)
|
44
|
+
expect(Vignette.tests).to eq(number: 3)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
7
48
|
end
|
data/spec/lib/vignette_spec.rb
CHANGED
@@ -5,7 +5,7 @@ describe Vignette do
|
|
5
5
|
context 'with simple session store' do
|
6
6
|
let!(:session) { Hash.new }
|
7
7
|
let(:array) { %w{a b c} }
|
8
|
-
before { Vignette.session
|
8
|
+
before { Vignette.set_repo(session) }
|
9
9
|
|
10
10
|
it 'should have correct crc' do
|
11
11
|
expect(array.crc).to eq(891568578)
|
@@ -98,4 +98,83 @@ describe Vignette do
|
|
98
98
|
end
|
99
99
|
end
|
100
100
|
|
101
|
+
context 'when threading' do
|
102
|
+
before(:each) { expect(Kernel).to receive(:rand).and_return(1, 2) }
|
103
|
+
|
104
|
+
context 'serially' do
|
105
|
+
it 'should work like normal' do
|
106
|
+
|
107
|
+
Thread.new do
|
108
|
+
Vignette.with_repo(Hash.new) do
|
109
|
+
expect(%w{a b c}.vignette(:name)).to eq('b')
|
110
|
+
expect(Vignette.tests).to eq(name: 'b')
|
111
|
+
end
|
112
|
+
end.join
|
113
|
+
|
114
|
+
Thread.new do
|
115
|
+
Vignette.with_repo(Hash.new) do
|
116
|
+
expect(%w{a b c}.vignette(:name)).to eq('c')
|
117
|
+
expect(Vignette.tests).to eq(name: 'c')
|
118
|
+
end
|
119
|
+
end.join
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
context 'with no delays' do
|
125
|
+
it 'should work like normal' do
|
126
|
+
threads = []
|
127
|
+
|
128
|
+
threads << Thread.new do
|
129
|
+
Vignette.with_repo(Hash.new) do
|
130
|
+
expect(%w{a b c}.vignette(:name)).to eq('b')
|
131
|
+
expect(Vignette.tests).to eq(name: 'b')
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
threads << Thread.new do
|
136
|
+
Vignette.with_repo(Hash.new) do
|
137
|
+
expect(%w{a b c}.vignette(:name)).to eq('c')
|
138
|
+
expect(Vignette.tests).to eq(name: 'c')
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
threads.each(&:join)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
context 'with a one second delay' do
|
147
|
+
it 'should work like normal' do
|
148
|
+
threads = []
|
149
|
+
|
150
|
+
threads << Thread.new do
|
151
|
+
Vignette.with_repo(Hash.new) do
|
152
|
+
sleep 0.1 # this is to cause a race condition
|
153
|
+
expect(%w{a b c}.vignette(:name)).to eq('c')
|
154
|
+
expect(Vignette.tests).to eq(name: 'c')
|
155
|
+
|
156
|
+
sleep 0.2
|
157
|
+
expect(%w{a b c}.vignette(:name)).to eq('c')
|
158
|
+
expect(Vignette.tests).to eq(name: 'c')
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
threads << Thread.new do
|
163
|
+
Vignette.with_repo(Hash.new) do
|
164
|
+
expect(%w{a b c}.vignette(:name)).to eq('b')
|
165
|
+
expect(Vignette.tests).to eq(name: 'b')
|
166
|
+
|
167
|
+
sleep 0.2
|
168
|
+
|
169
|
+
expect(%w{a b c}.vignette(:name)).to eq('b')
|
170
|
+
expect(Vignette.tests).to eq(name: 'b')
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
threads.each(&:join)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
end
|
179
|
+
|
101
180
|
end
|