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 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: {}