chanko_ab 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b97fbd1349d68e6c318736e7fd0ad0ec0f86cfe8a731cb875ade20d6c785c72b
4
- data.tar.gz: 92029f92c969fb816749987326dbb7be33d2e8813434193ebb3b611712eef6ce
3
+ metadata.gz: a967e68060d36eb785d8fd8759e8222e82c9e484e731e837064568ed12e62371
4
+ data.tar.gz: 23454bd8fe55e33eb8cf75ae6c9ca755f36eae4aef583c8970363b934251b477
5
5
  SHA512:
6
- metadata.gz: 82b5a4eb5b35d016c6e0af2a0c13fff7f10a7c4dad52fb1379179e24113604b2c5d17d30701ab5b9f55b3008ed6f61551d82283c034d3b7a3e59f71433766938
7
- data.tar.gz: a3615454afd6e4262931acf47f2ad08c33cced96f36293f27b8b03cf473e1d4732de30a8ad17df3f7adbc887afa155897109dd0f7a031af11ae45812f5ddcc07
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
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env sh
2
+ . "$(dirname -- "$0")/_/husky.sh"
3
+
4
+ npx lint-staged
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
@@ -0,0 +1,6 @@
1
+ # Change Log
2
+
3
+ ## [0.2.0] (2022-09-07)
4
+ ### Added
5
+ - Selectable logic to use identifier.
6
+ - Add HexIdentifier logic to use identifier composed by hex numbers.
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.log_tesmplate('show' ,'my_split_test.[name]')
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,15 @@
1
+ require "chanko_ab/version"
2
+
3
+ module ChankoAb
4
+ module Logic
5
+ class HexIdentifier < Base
6
+ def just_pattern_sizes
7
+ [1, 2, 4, 8, 16]
8
+ end
9
+
10
+ def assigned_number
11
+ @identifier.slice(-(@using_index + 1)).to_i(16)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ require "chanko_ab/version"
2
+
3
+ module ChankoAb
4
+ module Logic
5
+ class NumberIdentifier < Base
6
+ def just_pattern_sizes
7
+ [1, 2, 5, 10]
8
+ end
9
+
10
+ def assigned_number
11
+ @identifier.slice(-(@using_index + 1)).to_i
12
+ end
13
+ end
14
+ end
15
+ 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
@@ -1,3 +1,3 @@
1
1
  module ChankoAb
2
- VERSION = "0.1.1"
2
+ VERSION = "0.2.0"
3
3
  end
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.log(caller_scope, name, options)
17
- raise NotImplementedError unless @logging_proc
18
- caller_scope.instance_exec(name, options, &@logging_proc)
30
+ def self.default_logic
31
+ @default_logic
19
32
  end
20
33
 
21
- module Process
22
- class Base
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
- class SplitTest
119
- def initialize(unit)
120
- @unit = unit
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
@@ -0,0 +1,13 @@
1
+ {
2
+ "husky": {
3
+ "hooks": {
4
+ "pre-commit": "lint-staged"
5
+ }
6
+ },
7
+
8
+ "lint-staged": {
9
+ "*.{rb,rake}": [
10
+ "rubocop -a"
11
+ ]
12
+ }
13
+ }
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.1.1
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: {}