prefab-cloud-ruby 0.20.0 → 0.22.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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.envrc.sample +3 -0
  3. data/.github/workflows/ruby.yml +5 -1
  4. data/.gitmodules +3 -0
  5. data/Gemfile +14 -12
  6. data/Gemfile.lock +24 -14
  7. data/README.md +12 -10
  8. data/Rakefile +13 -14
  9. data/VERSION +1 -1
  10. data/lib/prefab/auth_interceptor.rb +2 -1
  11. data/lib/prefab/cancellable_interceptor.rb +8 -7
  12. data/lib/prefab/client.rb +52 -27
  13. data/lib/prefab/config_client.rb +59 -70
  14. data/lib/prefab/config_loader.rb +7 -114
  15. data/lib/prefab/config_resolver.rb +27 -57
  16. data/lib/prefab/config_value_unwrapper.rb +23 -0
  17. data/lib/prefab/criteria_evaluator.rb +96 -0
  18. data/lib/prefab/errors/invalid_api_key_error.rb +1 -1
  19. data/lib/prefab/feature_flag_client.rb +13 -145
  20. data/lib/prefab/internal_logger.rb +7 -6
  21. data/lib/prefab/local_config_parser.rb +110 -0
  22. data/lib/prefab/log_path_collector.rb +98 -0
  23. data/lib/prefab/logger_client.rb +46 -44
  24. data/lib/prefab/murmer3.rb +3 -4
  25. data/lib/prefab/noop_cache.rb +5 -7
  26. data/lib/prefab/noop_stats.rb +2 -3
  27. data/lib/prefab/options.rb +32 -11
  28. data/lib/prefab/ratelimit_client.rb +11 -13
  29. data/lib/prefab/sse_logger.rb +3 -2
  30. data/lib/prefab/weighted_value_resolver.rb +42 -0
  31. data/lib/prefab/yaml_config_parser.rb +32 -0
  32. data/lib/prefab-cloud-ruby.rb +7 -2
  33. data/lib/prefab_pb.rb +70 -43
  34. data/lib/prefab_services_pb.rb +14 -1
  35. data/prefab-cloud-ruby.gemspec +33 -19
  36. data/test/.prefab.unit_tests.config.yaml +3 -2
  37. data/test/integration_test.rb +98 -0
  38. data/test/integration_test_helpers.rb +37 -0
  39. data/test/test_client.rb +56 -31
  40. data/test/test_config_client.rb +21 -20
  41. data/test/test_config_loader.rb +48 -37
  42. data/test/test_config_resolver.rb +312 -135
  43. data/test/test_config_value_unwrapper.rb +83 -0
  44. data/test/test_criteria_evaluator.rb +533 -0
  45. data/test/test_feature_flag_client.rb +35 -347
  46. data/test/test_helper.rb +18 -14
  47. data/test/test_integration.rb +33 -0
  48. data/test/test_local_config_parser.rb +78 -0
  49. data/test/test_log_path_collector.rb +56 -0
  50. data/test/test_logger.rb +52 -51
  51. data/test/test_options.rb +32 -0
  52. data/test/test_weighted_value_resolver.rb +65 -0
  53. metadata +30 -16
  54. data/lib/prefab/config_helper.rb +0 -31
  55. data/run_test_harness_server.sh +0 -8
  56. data/test/harness_server.rb +0 -64
@@ -1,176 +1,44 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Prefab
3
4
  class FeatureFlagClient
4
- include Prefab::ConfigHelper
5
- MAX_32_FLOAT = 4294967294.0
6
-
7
5
  def initialize(base_client)
8
6
  @base_client = base_client
9
7
  end
10
8
 
11
- def upsert(feature_name, feature_obj)
12
- @base_client.config_client.upsert(feature_name, Prefab::ConfigValue.new(feature_flag: feature_obj))
13
- end
14
-
15
9
  def feature_is_on?(feature_name)
16
10
  feature_is_on_for?(feature_name, nil)
17
11
  end
18
12
 
19
13
  def feature_is_on_for?(feature_name, lookup_key, attributes: {})
20
- @base_client.stats.increment("prefab.featureflag.on", tags: ["feature:#{feature_name}"])
14
+ @base_client.stats.increment('prefab.featureflag.on', tags: ["feature:#{feature_name}"])
21
15
 
22
- return is_on?(_get(feature_name, lookup_key, attributes, default: false))
23
- end
24
-
25
- def get(feature_name, lookup_key=nil, attributes={}, default: false)
26
- variant = _get(feature_name, lookup_key, attributes, default: default)
16
+ variant = @base_client.config_client.get(feature_name, false, attributes, lookup_key)
27
17
 
28
- value_of_variant_or_nil(variant, default)
18
+ is_on?(variant)
29
19
  end
30
20
 
31
- private
21
+ def get(feature_name, lookup_key = nil, attributes = {}, default: false)
22
+ value = _get(feature_name, lookup_key, attributes)
32
23
 
33
- def value_of_variant_or_nil(variant_maybe, default)
34
- if variant_maybe.nil?
35
- default != Prefab::Client::NO_DEFAULT_PROVIDED ? default : nil
36
- else
37
- value_of_variant(variant_maybe)
38
- end
24
+ value.nil? ? default : value
39
25
  end
40
26
 
41
- def _get(feature_name, lookup_key=nil, attributes={}, default:)
42
- feature_obj = @base_client.config_client.get(feature_name, default)
43
- config_obj = @base_client.config_client.get_config_obj(feature_name)
44
-
45
- return nil if feature_obj.nil? || config_obj.nil?
46
-
47
- if feature_obj == !!feature_obj
48
- return feature_obj
49
- end
27
+ private
50
28
 
51
- variants = config_obj.variants
52
- get_variant(feature_name, lookup_key, attributes, feature_obj, variants)
29
+ def _get(feature_name, lookup_key = nil, attributes = {})
30
+ @base_client.config_client.get(feature_name, nil, attributes, lookup_key)
53
31
  end
54
32
 
55
33
  def is_on?(variant)
56
- if variant.nil?
57
- return false
58
- end
34
+ return false if variant.nil?
59
35
 
60
- if variant == !!variant
61
- return variant
62
- end
36
+ return variant if variant == !!variant
63
37
 
64
38
  variant.bool
65
- rescue
39
+ rescue StandardError
66
40
  @base_client.log.info("is_on? methods only work for boolean feature flags variants. This feature flags variant is '#{variant}'. Returning false")
67
41
  false
68
42
  end
69
-
70
- def get_variant(feature_name, lookup_key, attributes, feature_obj, variants)
71
- if !feature_obj.active
72
- return get_variant_obj(variants, feature_obj.inactive_variant_idx)
73
- end
74
-
75
- #default to inactive
76
- variant_weights = [Prefab::VariantWeight.new(variant_idx: feature_obj.inactive_variant_idx, weight: 1)]
77
-
78
- # if rules.match
79
- feature_obj.rules.each do |rule|
80
- if criteria_match?(rule.criteria, lookup_key, attributes)
81
- variant_weights = rule.variant_weights
82
- break
83
- end
84
- end
85
-
86
- percent_through_distribution = rand()
87
- if lookup_key
88
- percent_through_distribution = get_user_pct(feature_name, lookup_key)
89
- end
90
-
91
- variant_idx = get_variant_idx_from_weights(variant_weights, percent_through_distribution, feature_name)
92
-
93
- return get_variant_obj(variants, variant_idx)
94
- end
95
-
96
- def get_variant_obj(variants, idx)
97
- # our array is 0 based, but the idx are 1 based so the protos are clearly set
98
- return variants[idx - 1] if variants.length >= idx
99
- nil
100
- end
101
-
102
- def get_variant_idx_from_weights(variant_weights, percent_through_distribution, feature_name)
103
- distrubution_space = variant_weights.inject(0) { |sum, v| sum + v.weight }
104
- bucket = distrubution_space * percent_through_distribution
105
- sum = 0
106
- variant_weights.each do |variant_weight|
107
- if bucket < sum + variant_weight.weight
108
- return variant_weight.variant_idx
109
- else
110
- sum += variant_weight.weight
111
- end
112
- end
113
- # variants didn't add up to 100%
114
- @base_client.log.info("Variants of #{feature_name} did not add to 100%")
115
- return variant_weights.last.variant_idx
116
- end
117
-
118
- def get_user_pct(feature, lookup_key)
119
- to_hash = "#{feature}#{lookup_key}"
120
- int_value = Murmur3.murmur3_32(to_hash)
121
- int_value / MAX_32_FLOAT
122
- end
123
-
124
- def criteria_match?(criteria, lookup_key, attributes)
125
- case criteria.operator
126
- when :ALWAYS_TRUE
127
- true
128
- when :LOOKUP_KEY_IN
129
- criteria.values.include?(lookup_key)
130
- when :LOOKUP_KEY_NOT_IN
131
- !criteria.values.include?(lookup_key)
132
- when :IN_SEG
133
- segment_matches?(criteria.values, lookup_key, attributes)
134
- when :NOT_IN_SEG
135
- !segment_matches?(criteria.values, lookup_key, attributes)
136
- when :PROP_IS_ONE_OF
137
- criteria.values.include?(attribute_value(attributes, criteria.property))
138
- when :PROP_IS_NOT_ONE_OF
139
- !criteria.values.include?(attribute_value(attributes, criteria.property))
140
- when :PROP_ENDS_WITH_ONE_OF
141
- criteria.values.any? { |value| attribute_value(attributes, criteria.property)&.end_with?(value) }
142
- when :PROP_DOES_NOT_END_WITH_ONE_OF
143
- criteria.values.none? { |value| attribute_value(attributes, criteria.property)&.end_with?(value) }
144
- else
145
- @base_client.log.info("Unknown Operator: #{criteria.operator}")
146
- false
147
- end
148
- end
149
-
150
- def attribute_value(attributes, property)
151
- attributes[property] || attributes[property.to_sym]
152
- end
153
-
154
- # evaluate each segment key and return whether any match
155
- # there should be an associated segment available as a standard config obj
156
- def segment_matches?(segment_keys, lookup_key, attributes)
157
- segment_keys.any? do |segment_key|
158
- segment = @base_client.config_client.get(segment_key)
159
- if segment.nil?
160
- @base_client.log.info("Missing Segment")
161
- false
162
- else
163
- segment_match?(segment, lookup_key, attributes)
164
- end
165
- end
166
- end
167
-
168
- # does a given segment match?
169
- def segment_match?(segment, lookup_key, attributes)
170
- segment.criterion.any? do |criteria|
171
- criteria_match?(criteria, lookup_key, attributes)
172
- end
173
- end
174
43
  end
175
44
  end
176
-
@@ -1,28 +1,29 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Prefab
3
- class InternalLogger < Logger
4
+ class InternalLogger < ::Logger
4
5
  def initialize(path, logger)
5
6
  @path = path
6
7
  @logger = logger
7
8
  end
8
9
 
9
- def debug(progname = nil, &block)
10
+ def debug(progname = nil)
10
11
  @logger.log_internal yield, @path, progname, DEBUG
11
12
  end
12
13
 
13
- def info(progname = nil, &block)
14
+ def info(progname = nil)
14
15
  @logger.log_internal yield, @path, progname, INFO
15
16
  end
16
17
 
17
- def warn(progname = nil, &block)
18
+ def warn(progname = nil)
18
19
  @logger.log_internal yield, @path, progname, WARN
19
20
  end
20
21
 
21
- def error(progname = nil, &block)
22
+ def error(progname = nil)
22
23
  @logger.log_internal yield, @path, progname, ERROR
23
24
  end
24
25
 
25
- def fatal(progname = nil, &block)
26
+ def fatal(progname = nil)
26
27
  @logger.log_internal yield, @path, progname, FATAL
27
28
  end
28
29
  end
@@ -0,0 +1,110 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Prefab
4
+ class LocalConfigParser
5
+ class << self
6
+ def parse(key, value, config, file)
7
+ if value.instance_of?(Hash)
8
+ if value['feature_flag']
9
+ config[key] = feature_flag_config(file, key, value)
10
+ else
11
+ value.each do |nest_key, nest_value|
12
+ nested_key = "#{key}.#{nest_key}"
13
+ nested_key = key if nest_key == '_'
14
+ parse(nested_key, nest_value, config, file)
15
+ end
16
+ end
17
+ else
18
+ config[key] = {
19
+ source: file,
20
+ match: 'default',
21
+ config: Prefab::Config.new(
22
+ config_type: :CONFIG,
23
+ key: key,
24
+ rows: [
25
+ Prefab::ConfigRow.new(values: [
26
+ Prefab::ConditionalValue.new(value: value_from(key, value))
27
+ ])
28
+ ]
29
+ )
30
+ }
31
+ end
32
+
33
+ config
34
+ end
35
+
36
+ def value_from(key, raw)
37
+ case raw
38
+ when String
39
+ if key.to_s.start_with? Prefab::LoggerClient::BASE_KEY
40
+ prefab_log_level_resolve = Prefab::LogLevel.resolve(raw.upcase.to_sym) || Prefab::LogLevel::NOT_SET_LOG_LEVEL
41
+ { log_level: prefab_log_level_resolve }
42
+ else
43
+ { string: raw }
44
+ end
45
+ when Integer
46
+ { int: raw }
47
+ when TrueClass, FalseClass
48
+ { bool: raw }
49
+ when Float
50
+ { double: raw }
51
+ end
52
+ end
53
+
54
+ def feature_flag_config(file, key, value)
55
+ criterion = (parse_criterion(value['criterion']) if value['criterion'])
56
+
57
+ variant = Prefab::ConfigValue.new(value_from(key, value['value']))
58
+
59
+ row = Prefab::ConfigRow.new(
60
+ values: [
61
+ Prefab::ConditionalValue.new(
62
+ criteria: [criterion].compact,
63
+ value: Prefab::ConfigValue.new(
64
+ weighted_values: Prefab::WeightedValues.new(weighted_values: [
65
+ Prefab::WeightedValue.new(
66
+ weight: 1000,
67
+ value: variant
68
+ )
69
+ ])
70
+ )
71
+ )
72
+ ]
73
+ )
74
+
75
+ raise Prefab::Error, "Feature flag config `#{key}` #{file} must have a `value`" unless value.key?('value')
76
+
77
+ {
78
+ source: file,
79
+ match: key,
80
+ config: Prefab::Config.new(
81
+ config_type: :FEATURE_FLAG,
82
+ key: key,
83
+ allowable_values: [variant],
84
+ rows: [row]
85
+ )
86
+ }
87
+ end
88
+
89
+ def parse_criterion(criterion)
90
+ Prefab::Criterion.new(operator: criterion['operator'],
91
+ property_name: parse_property(criterion),
92
+ value_to_match: parse_value_to_match(criterion['values']))
93
+ end
94
+
95
+ def parse_property(criterion)
96
+ if criterion['operator'] == 'LOOKUP_KEY_IN'
97
+ Prefab::CriteriaEvaluator::LOOKUP_KEY
98
+ else
99
+ criterion['property']
100
+ end
101
+ end
102
+
103
+ def parse_value_to_match(values)
104
+ raise "Can't handle #{values}" unless values.instance_of?(Array)
105
+
106
+ Prefab::ConfigValue.new(string_list: Prefab::StringList.new(values: values))
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Prefab
4
+ class LogPathCollector
5
+ INCREMENT = ->(count) { (count || 0) + 1 }
6
+
7
+ SEVERITY_KEY = {
8
+ ::Logger::DEBUG => 'debugs',
9
+ ::Logger::INFO => 'infos',
10
+ ::Logger::WARN => 'warns',
11
+ ::Logger::ERROR => 'errors',
12
+ ::Logger::FATAL => 'fatals'
13
+ }.freeze
14
+
15
+ def initialize(client:, max_paths:, sync_interval:)
16
+ @max_paths = max_paths
17
+ @sync_interval = sync_interval
18
+ @client = client
19
+ @start_at = now
20
+
21
+ @pool = Concurrent::ThreadPoolExecutor.new(
22
+ fallback_policy: :discard,
23
+ max_queue: 5,
24
+ max_threads: 4,
25
+ min_threads: 1,
26
+ name: 'prefab-log-paths'
27
+ )
28
+
29
+ @paths = Concurrent::Map.new
30
+
31
+ start_periodic_sync
32
+ end
33
+
34
+ def push(path, severity)
35
+ return unless @paths.size < @max_paths
36
+
37
+ @paths.compute([path, severity], &INCREMENT)
38
+ end
39
+
40
+ private
41
+
42
+ def sync
43
+ return if @paths.size.zero?
44
+
45
+ log_internal "Syncing #{@paths.size} paths"
46
+
47
+ flush
48
+ end
49
+
50
+ def flush
51
+ to_ship = @paths.dup
52
+ @paths.clear
53
+
54
+ start_at_was = @start_at
55
+ @start_at = now
56
+
57
+ @pool.post do
58
+ log_internal "Uploading stats for #{to_ship.size} paths"
59
+
60
+ aggregate = Hash.new { |h, k| h[k] = Prefab::Logger.new }
61
+
62
+ to_ship.each do |(path, severity), count|
63
+ aggregate[path][SEVERITY_KEY[severity]] = count
64
+ aggregate[path]['logger_name'] = path
65
+ end
66
+
67
+ loggers = Prefab::Loggers.new(
68
+ loggers: aggregate.values,
69
+ start_at: start_at_was,
70
+ end_at: now,
71
+ instance_hash: @client.instance_hash,
72
+ namespace: @client.namespace
73
+ )
74
+
75
+ @client.request Prefab::LoggerReportingService, :send, req_options: {}, params: loggers
76
+ end
77
+ end
78
+
79
+ def start_periodic_sync
80
+ Thread.new do
81
+ log_internal "Initialized log path collector instance_hash=#{@client.instance_hash} max_paths=#{@max_paths} sync_interval=#{@sync_interval}"
82
+
83
+ loop do
84
+ sleep @sync_interval
85
+ sync
86
+ end
87
+ end
88
+ end
89
+
90
+ def log_internal(message)
91
+ @client.log.log_internal message, 'log_path_collector', nil, ::Logger::INFO
92
+ end
93
+
94
+ def now
95
+ (Time.now.utc.to_f * 1000).to_i
96
+ end
97
+ end
98
+ end
@@ -1,52 +1,57 @@
1
1
  # frozen_string_literal: true
2
- module Prefab
3
- class LoggerClient < Logger
4
2
 
5
- SEP = "."
6
- BASE_KEY = "log-level"
7
- UNKNOWN_PATH = "unknown."
8
- INTERNAL_PREFIX = "cloud.prefab.client"
3
+ require 'prefab/log_path_collector'
4
+
5
+ module Prefab
6
+ class LoggerClient < ::Logger
7
+ SEP = '.'
8
+ BASE_KEY = 'log-level'
9
+ UNKNOWN_PATH = 'unknown.'
10
+ INTERNAL_PREFIX = 'cloud.prefab.client'
9
11
 
10
12
  LOG_LEVEL_LOOKUPS = {
11
- Prefab::LogLevel::NOT_SET_LOG_LEVEL => Logger::DEBUG,
12
- Prefab::LogLevel::TRACE => Logger::DEBUG,
13
- Prefab::LogLevel::DEBUG => Logger::DEBUG,
14
- Prefab::LogLevel::INFO => Logger::INFO,
15
- Prefab::LogLevel::WARN => Logger::WARN,
16
- Prefab::LogLevel::ERROR => Logger::ERROR,
17
- Prefab::LogLevel::FATAL => Logger::FATAL
13
+ Prefab::LogLevel::NOT_SET_LOG_LEVEL => ::Logger::DEBUG,
14
+ Prefab::LogLevel::TRACE => ::Logger::DEBUG,
15
+ Prefab::LogLevel::DEBUG => ::Logger::DEBUG,
16
+ Prefab::LogLevel::INFO => ::Logger::INFO,
17
+ Prefab::LogLevel::WARN => ::Logger::WARN,
18
+ Prefab::LogLevel::ERROR => ::Logger::ERROR,
19
+ Prefab::LogLevel::FATAL => ::Logger::FATAL
18
20
  }
19
21
 
20
- def initialize(logdev, formatter: nil, prefix: nil)
22
+ def initialize(logdev, log_path_collector: nil, formatter: nil, prefix: nil)
21
23
  super(logdev)
22
24
  self.formatter = formatter
23
25
  @config_client = BootstrappingConfigClient.new
24
26
  @silences = Concurrent::Map.new(initial_capacity: 2)
25
- @prefix = prefix
27
+ @prefix = "#{prefix}#{prefix && '.'}"
28
+
29
+ @log_path_collector = log_path_collector
26
30
  end
27
31
 
28
32
  def add(severity, message = nil, progname = nil, loc, &block)
29
- path = get_loc_path(loc)
30
- path = "#{@prefix}#{@prefix && '.'}#{path}"
33
+ path_loc = get_loc_path(loc)
34
+ path = @prefix + path_loc
35
+
36
+ @log_path_collector&.push(path_loc, severity)
31
37
 
32
38
  log(message, path, progname, severity, &block)
33
39
  end
34
40
 
35
41
  def log_internal(message, path = nil, progname, severity, &block)
36
- if path
37
- path = "#{INTERNAL_PREFIX}.#{path}"
38
- else
39
- path = INTERNAL_PREFIX
40
- end
42
+ path = if path
43
+ "#{INTERNAL_PREFIX}.#{path}"
44
+ else
45
+ INTERNAL_PREFIX
46
+ end
41
47
 
42
48
  log(message, path, progname, severity, &block)
43
49
  end
44
50
 
45
- def log(message, path, progname, severity, &block)
46
- severity ||= Logger::UNKNOWN
47
- if @logdev.nil? || severity < level_of(path) || @silences[local_log_id]
48
- return true
49
- end
51
+ def log(message, path, progname, severity)
52
+ severity ||= ::Logger::UNKNOWN
53
+
54
+ return true if @logdev.nil? || severity < level_of(path) || @silences[local_log_id]
50
55
 
51
56
  progname = "#{path}: #{progname || @progname}"
52
57
 
@@ -60,7 +65,8 @@ module Prefab
60
65
  end
61
66
 
62
67
  @logdev.write(
63
- format_message(format_severity(severity), Time.now, progname, message))
68
+ format_message(format_severity(severity), Time.now, progname, message)
69
+ )
64
70
  true
65
71
  end
66
72
 
@@ -85,23 +91,23 @@ module Prefab
85
91
  end
86
92
 
87
93
  def debug?
88
- true;
94
+ true
89
95
  end
90
96
 
91
97
  def info?
92
- true;
98
+ true
93
99
  end
94
100
 
95
101
  def warn?
96
- true;
102
+ true
97
103
  end
98
104
 
99
105
  def error?
100
- true;
106
+ true
101
107
  end
102
108
 
103
109
  def fatal?
104
- true;
110
+ true
105
111
  end
106
112
 
107
113
  def level
@@ -128,13 +134,10 @@ module Prefab
128
134
  # Find the closest match to 'log_level.path' in config
129
135
  def level_of(path)
130
136
  closest_log_level_match = @config_client.get(BASE_KEY, :WARN)
131
- path.split(SEP).inject([BASE_KEY]) do |memo, n|
137
+ path.split(SEP).each_with_object([BASE_KEY]) do |n, memo|
132
138
  memo << n
133
139
  val = @config_client.get(memo.join(SEP), nil)
134
- unless val.nil?
135
- closest_log_level_match = val
136
- end
137
- memo
140
+ closest_log_level_match = val unless val.nil?
138
141
  end
139
142
  closest_log_level_match_int = Prefab::LogLevel.resolve(closest_log_level_match)
140
143
  LOG_LEVEL_LOOKUPS[closest_log_level_match_int]
@@ -150,10 +153,10 @@ module Prefab
150
153
  def get_path(absolute_path, base_label)
151
154
  path = (absolute_path || UNKNOWN_PATH).dup
152
155
  path.slice! Dir.pwd
153
- path.gsub!(/(.*)?(?=\/lib)/im, "") # replace everything before first lib
156
+ path.gsub!(%r{(.*)?(?=/lib)}im, '') # replace everything before first lib
154
157
 
155
- path = path.gsub("/", SEP).gsub(/.rb.*/, "") + SEP + base_label
156
- path.slice! ".lib"
158
+ path = path.gsub('/', SEP).gsub(/.rb.*/, '') + SEP + base_label
159
+ path.slice! '.lib'
157
160
  path.slice! SEP
158
161
  path
159
162
  end
@@ -162,9 +165,8 @@ module Prefab
162
165
  # StubConfigClient to be used while config client initializes
163
166
  # since it may log
164
167
  class BootstrappingConfigClient
165
- def get(key, default = nil)
166
- ENV["PREFAB_LOG_CLIENT_BOOTSTRAP_LOG_LEVEL"] ? ENV["PREFAB_LOG_CLIENT_BOOTSTRAP_LOG_LEVEL"].upcase.to_sym : default
168
+ def get(_key, default = nil)
169
+ ENV['PREFAB_LOG_CLIENT_BOOTSTRAP_LOG_LEVEL'] ? ENV['PREFAB_LOG_CLIENT_BOOTSTRAP_LOG_LEVEL'].upcase.to_sym : default
167
170
  end
168
171
  end
169
172
  end
170
-
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  class Murmur3
3
4
  ## MurmurHash3 was written by Austin Appleby, and is placed in the public
4
5
  ## domain. The author hereby disclaims copyright to this source code.
@@ -9,7 +10,6 @@ class Murmur3
9
10
  ((x << r) | (x >> (32 - r))) & MASK32
10
11
  end
11
12
 
12
-
13
13
  def self.murmur3_32_fmix(h)
14
14
  h &= MASK32
15
15
  h ^= h >> 16
@@ -25,7 +25,7 @@ class Murmur3
25
25
  (k1 * 0x1b873593) & MASK32
26
26
  end
27
27
 
28
- def self.murmur3_32(str, seed=0)
28
+ def self.murmur3_32(str, seed = 0)
29
29
  h1 = seed
30
30
  numbers = str.unpack('V*C*')
31
31
  tailn = str.length % 4
@@ -33,7 +33,7 @@ class Murmur3
33
33
  for k1 in numbers
34
34
  h1 ^= murmur3_32__mmix(k1)
35
35
  h1 = murmur3_32_rotl(h1, 13)
36
- h1 = (h1*5 + 0xe6546b64) & MASK32
36
+ h1 = (h1 * 5 + 0xe6546b64) & MASK32
37
37
  end
38
38
 
39
39
  unless tail.empty?
@@ -47,5 +47,4 @@ class Murmur3
47
47
  h1 ^= str.length
48
48
  murmur3_32_fmix(h1)
49
49
  end
50
-
51
50
  end
@@ -1,17 +1,15 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Prefab
3
4
  class NoopCache
4
- def fetch(name, opts, &method)
5
+ def fetch(_name, _opts)
5
6
  yield
6
7
  end
7
8
 
8
- def write(name, value, opts=nil)
9
- end
9
+ def write(name, value, opts = nil); end
10
10
 
11
- def read(name)
12
- end
11
+ def read(name); end
13
12
 
14
- def delete(name)
15
- end
13
+ def delete(name); end
16
14
  end
17
15
  end
@@ -1,9 +1,8 @@
1
1
  # frozen_string_literal: true
2
- module Prefab
3
2
 
3
+ module Prefab
4
4
  class NoopStats
5
5
  # receives increment("prefab.ratelimit.limitcheck", {:tags=>["policy_group:page_view", "pass:true"]})
6
- def increment(name, opts={})
7
- end
6
+ def increment(name, opts = {}); end
8
7
  end
9
8
  end