chanko_ab 0.1.1 → 0.2.0
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 +4 -4
- data/.gitignore +1 -0
- data/.husky/pre-commit +4 -0
- data/.rubocop.yml +16 -0
- data/CHANGELOG.md +6 -0
- data/README.md +10 -1
- data/lib/chanko_ab/logic/base.rb +95 -0
- data/lib/chanko_ab/logic/hex_identifier.rb +15 -0
- data/lib/chanko_ab/logic/number_identifier.rb +15 -0
- data/lib/chanko_ab/split_test.rb +94 -0
- data/lib/chanko_ab/test.rb +20 -0
- data/lib/chanko_ab/version.rb +1 -1
- data/lib/chanko_ab.rb +21 -214
- data/package.json +13 -0
- metadata +11 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a967e68060d36eb785d8fd8759e8222e82c9e484e731e837064568ed12e62371
|
4
|
+
data.tar.gz: 23454bd8fe55e33eb8cf75ae6c9ca755f36eae4aef583c8970363b934251b477
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e7c9cbdb8222de95783a790f7168918a7dbad6c43d683a7c9a4e483b838fec080a42bcf96023ad04fd113a1a878879aeba9668a941e397a2ba32567e63141a67
|
7
|
+
data.tar.gz: 77e2ddf77e4298023e7de46f892db281c094f32c2b776401f20bb4d584d6b41de2fd57f00e71c06a4dbe0df45f82d40dbd6942ad74b321d129f974d4a48a7c8c
|
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
.rubocop-https---raw-githubusercontent-com-cookpad-styleguide-master--rubocop-yml
|
data/.husky/pre-commit
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
inherit_from: https://raw.githubusercontent.com/cookpad/styleguide/master/.rubocop.yml
|
2
|
+
|
3
|
+
inherit_mode:
|
4
|
+
merge:
|
5
|
+
- Exclude
|
6
|
+
- Include
|
7
|
+
|
8
|
+
require:
|
9
|
+
- rubocop-rspec
|
10
|
+
|
11
|
+
Metrics/BlockLength:
|
12
|
+
Exclude:
|
13
|
+
- 'spec/**/*'
|
14
|
+
|
15
|
+
Layout/LineLength:
|
16
|
+
Enabled: false
|
data/CHANGELOG.md
ADDED
data/README.md
CHANGED
@@ -38,7 +38,7 @@ module MySplitTest
|
|
38
38
|
split_test.add(:default, {})
|
39
39
|
split_test.add(:pattern1, { partial: 'partial1'} )
|
40
40
|
|
41
|
-
split_test.
|
41
|
+
split_test.log_tenmplate('show' ,'my_split_test.[name]')
|
42
42
|
|
43
43
|
split_test.define(:new_text, scope: :view) do
|
44
44
|
ab.log('show')
|
@@ -53,6 +53,15 @@ module MySplitTest
|
|
53
53
|
end
|
54
54
|
```
|
55
55
|
|
56
|
+
### Use HexIdentifier if identifier is composed by hex.
|
57
|
+
```ruby
|
58
|
+
module HexMySplitTest
|
59
|
+
...
|
60
|
+
split_test.logic ChankoAb::Logic::HexIdentifier
|
61
|
+
...
|
62
|
+
end
|
63
|
+
```
|
64
|
+
|
56
65
|
## Contributing
|
57
66
|
|
58
67
|
Bug reports and pull requests are welcome on GitHub at https://github.com/eudoxa/chanko_ab.
|
@@ -0,0 +1,95 @@
|
|
1
|
+
module ChankoAb
|
2
|
+
module Logic
|
3
|
+
class Base
|
4
|
+
def initialize(split_test, caller_scope, request, identifier, using_index)
|
5
|
+
@split_test = split_test
|
6
|
+
@caller_scope = caller_scope
|
7
|
+
@request = request
|
8
|
+
@identifier = identifier
|
9
|
+
@using_index = using_index || 0
|
10
|
+
@data = {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def data(name, &block)
|
14
|
+
@data[name] ||= block.call
|
15
|
+
end
|
16
|
+
|
17
|
+
def just_pattern_sizes
|
18
|
+
raise NotImplementedError
|
19
|
+
end
|
20
|
+
|
21
|
+
def validate!
|
22
|
+
unless Rails.env.production?
|
23
|
+
raise "Argument should be a divisor of #{just_patterns_size.max}, but #{split_size} is given." if !just_patterns_size.member?(split_size)
|
24
|
+
raise "Identifier is blank" if @identifier.blank?
|
25
|
+
raise "Identifier is too short" if @identifier.size < (@using_index + 1)
|
26
|
+
raise 'Too large pattern size' if patterns.size >= just_pattern_sizes.max
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def ab_index
|
31
|
+
assigned_number % split_size
|
32
|
+
end
|
33
|
+
|
34
|
+
def should_run_default?
|
35
|
+
return true if !item
|
36
|
+
@identifier.blank?
|
37
|
+
end
|
38
|
+
|
39
|
+
def pattern_by_overwritten
|
40
|
+
overwritten_name = ChankoAb::Test.overwritten_name(@split_test.unit)
|
41
|
+
pattern = patterns.detect { |pt| pt[0] == overwritten_name }
|
42
|
+
pattern || raise("ChankoAb: specified no defined name '#{overwritten_name}'")
|
43
|
+
end
|
44
|
+
private :pattern_by_overwritten
|
45
|
+
|
46
|
+
def name
|
47
|
+
item[0]
|
48
|
+
end
|
49
|
+
|
50
|
+
def fetch(key)
|
51
|
+
item[1][key]
|
52
|
+
end
|
53
|
+
|
54
|
+
def log_key(template_name)
|
55
|
+
template = @split_test.fetch_template(template_name)
|
56
|
+
template.gsub('[name]', name)
|
57
|
+
end
|
58
|
+
|
59
|
+
def log(template_name)
|
60
|
+
ChankoAb.log(@caller_scope, log_key(template_name), request: @request, identifier: @identifier)
|
61
|
+
end
|
62
|
+
|
63
|
+
def item
|
64
|
+
if Rails.env.test? && ChankoAb::Test.overwritten?(@split_test.unit)
|
65
|
+
return pattern_by_overwritten
|
66
|
+
else
|
67
|
+
index = decide_pattern_index
|
68
|
+
return nil if index > patterns.size
|
69
|
+
return patterns[index]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def patterns
|
74
|
+
@split_test.patterns
|
75
|
+
end
|
76
|
+
private :patterns
|
77
|
+
|
78
|
+
def decide_pattern_index
|
79
|
+
return 0 if patterns.size == 0
|
80
|
+
ab_index
|
81
|
+
end
|
82
|
+
private :decide_pattern_index
|
83
|
+
|
84
|
+
def split_size
|
85
|
+
just_pattern_sizes.select { |_size| _size >= patterns.size }.min
|
86
|
+
end
|
87
|
+
private :split_size
|
88
|
+
|
89
|
+
def assigned_number
|
90
|
+
raise NotImplementedNumber
|
91
|
+
end
|
92
|
+
private :assigned_number
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module ChankoAb
|
2
|
+
class SplitTest
|
3
|
+
def initialize(unit)
|
4
|
+
@unit = unit
|
5
|
+
@patterns = []
|
6
|
+
@log_templates = {}
|
7
|
+
|
8
|
+
initialize_shared_methods
|
9
|
+
end
|
10
|
+
|
11
|
+
def process(caller_scope, request, identifier, &block)
|
12
|
+
process = logic_klass.new(self, caller_scope, request, identifier, @using_index)
|
13
|
+
|
14
|
+
processes.push(process)
|
15
|
+
begin
|
16
|
+
block.call(process)
|
17
|
+
ensure
|
18
|
+
processes.pop
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def unit
|
23
|
+
@unit
|
24
|
+
end
|
25
|
+
|
26
|
+
def logic(logic)
|
27
|
+
@logic = logic
|
28
|
+
end
|
29
|
+
|
30
|
+
def logic_klass
|
31
|
+
@logic || ChankoAb.default_logic || ChankoAb::Logic::NumberIdentifier
|
32
|
+
end
|
33
|
+
|
34
|
+
def add(name, attributes)
|
35
|
+
@patterns << [name, attributes]
|
36
|
+
end
|
37
|
+
|
38
|
+
def reset_patterns
|
39
|
+
@patterns = []
|
40
|
+
end
|
41
|
+
|
42
|
+
def log_template(name, template)
|
43
|
+
@log_templates[name] = template
|
44
|
+
end
|
45
|
+
|
46
|
+
def patterns
|
47
|
+
@patterns
|
48
|
+
end
|
49
|
+
|
50
|
+
def fetch_template(name)
|
51
|
+
@log_templates[name]
|
52
|
+
end
|
53
|
+
|
54
|
+
def processes
|
55
|
+
@processes ||= []
|
56
|
+
end
|
57
|
+
|
58
|
+
def using_index(index)
|
59
|
+
@using_index = index
|
60
|
+
end
|
61
|
+
|
62
|
+
def define(key, options = {}, &block)
|
63
|
+
__split_test__ = self
|
64
|
+
unit.class_eval do
|
65
|
+
scope(options[:scope] || :view) do
|
66
|
+
function(key) do
|
67
|
+
__split_test__.process(self, request, identifier) do |process|
|
68
|
+
next run_default if process.should_run_default?
|
69
|
+
self.instance_eval(&block)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def initialize_shared_methods
|
77
|
+
__split_test__ = self
|
78
|
+
@unit.class_eval do
|
79
|
+
shared(:unit_name) do
|
80
|
+
@units.last.name
|
81
|
+
end
|
82
|
+
|
83
|
+
shared(:ab) do
|
84
|
+
__split_test__.processes.last
|
85
|
+
end
|
86
|
+
|
87
|
+
shared(:identifier) do
|
88
|
+
self.instance_eval(&ChankoAb.identifier_proc)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
private :initialize_shared_methods
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module ChankoAb
|
2
|
+
module Test
|
3
|
+
def self.overwritten_name(klass)
|
4
|
+
@overwritten_names[klass]
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.overwrite(klass, name)
|
8
|
+
@overwritten_names ||= {}
|
9
|
+
@overwritten_names[klass] = name
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.overwritten?(klass)
|
13
|
+
!!@overwritten_names[klass]
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.reset!
|
17
|
+
@overwritten_names = {}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/chanko_ab/version.rb
CHANGED
data/lib/chanko_ab.rb
CHANGED
@@ -1,6 +1,20 @@
|
|
1
1
|
require "chanko_ab/version"
|
2
|
+
require "chanko_ab/split_test"
|
3
|
+
require "chanko_ab/logic/base"
|
4
|
+
require "chanko_ab/logic/number_identifier"
|
5
|
+
require "chanko_ab/logic/hex_identifier"
|
2
6
|
|
3
7
|
module ChankoAb
|
8
|
+
module ClassMethods
|
9
|
+
def split_test
|
10
|
+
@split_test ||= SplitTest.new(self)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.included(klass)
|
15
|
+
klass.extend(ClassMethods)
|
16
|
+
end
|
17
|
+
|
4
18
|
def self.set_logging(&block)
|
5
19
|
@logging_proc = block
|
6
20
|
end
|
@@ -13,223 +27,16 @@ module ChankoAb
|
|
13
27
|
@identifier_proc
|
14
28
|
end
|
15
29
|
|
16
|
-
def self.
|
17
|
-
|
18
|
-
caller_scope.instance_exec(name, options, &@logging_proc)
|
30
|
+
def self.default_logic
|
31
|
+
@default_logic
|
19
32
|
end
|
20
33
|
|
21
|
-
|
22
|
-
|
23
|
-
def initialize(split_test, caller_scope, request, identifier, using_index)
|
24
|
-
@split_test = split_test
|
25
|
-
@caller_scope = caller_scope
|
26
|
-
@request = request
|
27
|
-
@identifier = identifier
|
28
|
-
@using_index = using_index || 0
|
29
|
-
@data = {}
|
30
|
-
end
|
31
|
-
|
32
|
-
def data(name, &block)
|
33
|
-
@data[name] ||= block.call
|
34
|
-
end
|
35
|
-
|
36
|
-
def should_run_default?
|
37
|
-
raise NotImplementedError
|
38
|
-
end
|
39
|
-
private :should_run_default?
|
40
|
-
|
41
|
-
def pattern_by_overwritten
|
42
|
-
overwritten_name = ChankoAb::Test.overwritten_name(@split_test.unit)
|
43
|
-
pattern = patterns.detect { |pt| pt[0] == overwritten_name }
|
44
|
-
pattern || raise("ChankoAb: specified no defined name '#{overwritten_name}'")
|
45
|
-
end
|
46
|
-
private :pattern_by_overwritten
|
47
|
-
|
48
|
-
def name
|
49
|
-
item[0]
|
50
|
-
end
|
51
|
-
|
52
|
-
def fetch(key)
|
53
|
-
item[1][key]
|
54
|
-
end
|
55
|
-
|
56
|
-
def log_key(template_name)
|
57
|
-
template = @split_test.fetch_template(template_name)
|
58
|
-
template.gsub('[name]', name)
|
59
|
-
end
|
60
|
-
|
61
|
-
def log(template_name)
|
62
|
-
ChankoAb.log(@caller_scope, log_key(template_name), request: @request, identifier: @identifier)
|
63
|
-
end
|
64
|
-
|
65
|
-
def item
|
66
|
-
if Rails.env.test? && ChankoAb::Test.overwritten?(@split_test.unit)
|
67
|
-
return pattern_by_overwritten
|
68
|
-
else
|
69
|
-
index = decide_pattern_index
|
70
|
-
return nil if index > patterns.size
|
71
|
-
return patterns[index]
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
def patterns
|
76
|
-
@split_test.patterns
|
77
|
-
end
|
78
|
-
private :patterns
|
79
|
-
|
80
|
-
def decide_pattern_index
|
81
|
-
#e.g
|
82
|
-
raise NotImplementedError
|
83
|
-
end
|
84
|
-
private :decide_pattern_index
|
85
|
-
end
|
86
|
-
|
87
|
-
class NumberIdentifier < Base
|
88
|
-
DEFAULT_JUST_PATTERN_SIZES = [1, 2, 5, 10]
|
89
|
-
|
90
|
-
def just_pattern_sizes
|
91
|
-
DEFAULT_JUST_PATTERN_SIZES
|
92
|
-
end
|
93
|
-
|
94
|
-
def should_run_default?
|
95
|
-
return true if !item
|
96
|
-
@identifier.blank?
|
97
|
-
end
|
98
|
-
|
99
|
-
def ab_index(identifier, size, using_index)
|
100
|
-
unless Rails.env.production?
|
101
|
-
raise "argument should be a divisor of 10 but #{size}" if !just_pattern_sizes.member?(size)
|
102
|
-
raise "identifier is blank" if identifier.blank?
|
103
|
-
raise "using_index error" if identifier.size < (using_index + 1)
|
104
|
-
end
|
105
|
-
using_number = identifier.slice(-(using_index + 1)).to_i
|
106
|
-
using_number % size
|
107
|
-
end
|
108
|
-
|
109
|
-
def decide_pattern_index
|
110
|
-
return 0 if patterns.size == 0
|
111
|
-
raise 'too large size' if patterns.size >= just_pattern_sizes.max
|
112
|
-
size = just_pattern_sizes.select { |size| size >= patterns.size }.min
|
113
|
-
ab_index(@identifier, size, @using_index)
|
114
|
-
end
|
115
|
-
end
|
34
|
+
def self.set_default_logic(logic)
|
35
|
+
@default_logic = logic
|
116
36
|
end
|
117
37
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
@patterns = []
|
122
|
-
@log_templates = {}
|
123
|
-
|
124
|
-
initialize_shared_methods
|
125
|
-
end
|
126
|
-
|
127
|
-
def process(caller_scope, request, identifier, &block)
|
128
|
-
process = ChankoAb::Process::NumberIdentifier.new(self, caller_scope, request, identifier, @using_index)
|
129
|
-
|
130
|
-
processes.push(process)
|
131
|
-
begin
|
132
|
-
block.call(process)
|
133
|
-
ensure
|
134
|
-
processes.pop
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
def unit
|
139
|
-
@unit
|
140
|
-
end
|
141
|
-
|
142
|
-
def add(name, attributes)
|
143
|
-
@patterns << [name, attributes]
|
144
|
-
end
|
145
|
-
|
146
|
-
def log_template(name, template)
|
147
|
-
@log_templates[name] = template
|
148
|
-
end
|
149
|
-
|
150
|
-
def patterns
|
151
|
-
@patterns
|
152
|
-
end
|
153
|
-
|
154
|
-
def fetch_template(name)
|
155
|
-
@log_templates[name]
|
156
|
-
end
|
157
|
-
|
158
|
-
def processes
|
159
|
-
@processes ||= []
|
160
|
-
end
|
161
|
-
|
162
|
-
def using_index(index)
|
163
|
-
@using_index = index
|
164
|
-
end
|
165
|
-
|
166
|
-
def use_user_via(&user_proc)
|
167
|
-
@user_proc = user_proc
|
168
|
-
end
|
169
|
-
|
170
|
-
def user_ab?
|
171
|
-
!!@user_proc
|
172
|
-
end
|
173
|
-
|
174
|
-
def define(key, options = {}, &block)
|
175
|
-
__split_test__ = self
|
176
|
-
unit.class_eval do
|
177
|
-
scope(options[:scope] || :view) do
|
178
|
-
function(key) do
|
179
|
-
__split_test__.process(self, request, identifier) do |process|
|
180
|
-
next run_default if process.should_run_default?
|
181
|
-
self.instance_eval(&block)
|
182
|
-
end
|
183
|
-
end
|
184
|
-
end
|
185
|
-
end
|
186
|
-
end
|
187
|
-
|
188
|
-
def initialize_shared_methods
|
189
|
-
__split_test__ = self
|
190
|
-
@unit.class_eval do
|
191
|
-
shared(:unit_name) do
|
192
|
-
@units.last.name
|
193
|
-
end
|
194
|
-
|
195
|
-
shared(:ab) do
|
196
|
-
__split_test__.processes.last
|
197
|
-
end
|
198
|
-
|
199
|
-
shared(:identifier) do
|
200
|
-
self.instance_eval(&ChankoAb.identifier_proc)
|
201
|
-
end
|
202
|
-
end
|
203
|
-
end
|
204
|
-
private :initialize_shared_methods
|
205
|
-
end
|
206
|
-
|
207
|
-
module Test
|
208
|
-
def self.overwritten_name(klass)
|
209
|
-
@overwritten_names[klass]
|
210
|
-
end
|
211
|
-
|
212
|
-
def self.overwrite(klass, name)
|
213
|
-
@overwritten_names ||= {}
|
214
|
-
@overwritten_names[klass] = name
|
215
|
-
end
|
216
|
-
|
217
|
-
def self.overwritten?(klass)
|
218
|
-
!!@overwritten_names[klass]
|
219
|
-
end
|
220
|
-
|
221
|
-
def self.reset!
|
222
|
-
@overwritten_names = {}
|
223
|
-
end
|
224
|
-
end
|
225
|
-
|
226
|
-
module ClassMethods
|
227
|
-
def split_test
|
228
|
-
@split_test ||= SplitTest.new(self)
|
229
|
-
end
|
230
|
-
end
|
231
|
-
|
232
|
-
def self.included(klass)
|
233
|
-
klass.extend(ClassMethods)
|
38
|
+
def self.log(caller_scope, name, options)
|
39
|
+
raise 'Should implement logging proc via ChankoAb.set_logging {}' unless @logging_proc
|
40
|
+
caller_scope.instance_exec(name, options, &@logging_proc)
|
234
41
|
end
|
235
42
|
end
|
data/package.json
ADDED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: chanko_ab
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- morita shingo
|
@@ -45,6 +45,10 @@ executables: []
|
|
45
45
|
extensions: []
|
46
46
|
extra_rdoc_files: []
|
47
47
|
files:
|
48
|
+
- ".gitignore"
|
49
|
+
- ".husky/pre-commit"
|
50
|
+
- ".rubocop.yml"
|
51
|
+
- CHANGELOG.md
|
48
52
|
- Gemfile
|
49
53
|
- Gemfile.lock
|
50
54
|
- LICENSE
|
@@ -54,7 +58,13 @@ files:
|
|
54
58
|
- bin/setup
|
55
59
|
- chanko_ab.gemspec
|
56
60
|
- lib/chanko_ab.rb
|
61
|
+
- lib/chanko_ab/logic/base.rb
|
62
|
+
- lib/chanko_ab/logic/hex_identifier.rb
|
63
|
+
- lib/chanko_ab/logic/number_identifier.rb
|
64
|
+
- lib/chanko_ab/split_test.rb
|
65
|
+
- lib/chanko_ab/test.rb
|
57
66
|
- lib/chanko_ab/version.rb
|
67
|
+
- package.json
|
58
68
|
homepage:
|
59
69
|
licenses: []
|
60
70
|
metadata: {}
|