prefab-cloud-ruby 0.19.0 → 0.21.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.envrc.sample +3 -0
  3. data/.github/workflows/ruby.yml +4 -0
  4. data/.gitmodules +3 -0
  5. data/Gemfile +12 -12
  6. data/Gemfile.lock +16 -14
  7. data/README.md +1 -1
  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 +33 -24
  13. data/lib/prefab/config_client.rb +55 -66
  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 +6 -5
  21. data/lib/prefab/local_config_parser.rb +110 -0
  22. data/lib/prefab/logger_client.rb +30 -36
  23. data/lib/prefab/murmer3.rb +3 -4
  24. data/lib/prefab/noop_cache.rb +5 -7
  25. data/lib/prefab/noop_stats.rb +2 -3
  26. data/lib/prefab/options.rb +11 -9
  27. data/lib/prefab/ratelimit_client.rb +11 -13
  28. data/lib/prefab/sse_logger.rb +3 -2
  29. data/lib/prefab/weighted_value_resolver.rb +42 -0
  30. data/lib/prefab/yaml_config_parser.rb +32 -0
  31. data/lib/prefab-cloud-ruby.rb +7 -2
  32. data/lib/prefab_pb.rb +49 -43
  33. data/lib/prefab_services_pb.rb +0 -1
  34. data/prefab-cloud-ruby.gemspec +28 -19
  35. data/test/.prefab.unit_tests.config.yaml +3 -2
  36. data/test/integration_test.rb +98 -0
  37. data/test/integration_test_helpers.rb +37 -0
  38. data/test/test_client.rb +32 -31
  39. data/test/test_config_client.rb +21 -20
  40. data/test/test_config_loader.rb +48 -37
  41. data/test/test_config_resolver.rb +312 -135
  42. data/test/test_config_value_unwrapper.rb +83 -0
  43. data/test/test_criteria_evaluator.rb +533 -0
  44. data/test/test_feature_flag_client.rb +35 -347
  45. data/test/test_helper.rb +18 -14
  46. data/test/test_integration.rb +33 -0
  47. data/test/test_local_config_parser.rb +78 -0
  48. data/test/test_logger.rb +90 -42
  49. data/test/test_weighted_value_resolver.rb +65 -0
  50. metadata +24 -27
  51. data/lib/prefab/config_helper.rb +0 -31
  52. data/run_test_harness_server.sh +0 -8
  53. data/test/harness_server.rb +0 -64
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'yaml'
4
3
  module Prefab
5
4
  class ConfigLoader
6
5
  attr_reader :highwater_mark
@@ -19,21 +18,19 @@ module Prefab
19
18
  @api_config.each_key do |k|
20
19
  rtn[k] = @api_config[k]
21
20
  end
22
- rtn = rtn.merge(@local_overrides)
23
- rtn
21
+ rtn.merge(@local_overrides)
24
22
  end
25
23
 
26
24
  def set(config, source)
27
25
  # don't overwrite newer values
28
- if @api_config[config.key] && @api_config[config.key][:config].id >= config.id
29
- return
30
- end
26
+ return if @api_config[config.key] && @api_config[config.key][:config].id >= config.id
31
27
 
32
28
  if config.rows.empty?
33
29
  @api_config.delete(config.key)
34
30
  else
35
31
  if @api_config[config.key]
36
- @base_client.log_internal Logger::DEBUG, "Replace #{config.key} with value from #{source} #{ @api_config[config.key][:config].id} -> #{config.id}"
32
+ @base_client.log_internal Logger::DEBUG,
33
+ "Replace #{config.key} with value from #{source} #{@api_config[config.key][:config].id} -> #{config.id}"
37
34
  end
38
35
  @api_config[config.key] = { source: source, config: config }
39
36
  end
@@ -56,7 +53,7 @@ module Prefab
56
53
 
57
54
  def load_classpath_config
58
55
  classpath_dir = @prefab_options.prefab_config_classpath_dir
59
- rtn = load_glob(File.join(classpath_dir, ".prefab.default.config.yaml"))
56
+ rtn = load_glob(File.join(classpath_dir, '.prefab.default.config.yaml'))
60
57
  @prefab_options.prefab_envs.each do |env|
61
58
  rtn = rtn.merge load_glob(File.join(classpath_dir, ".prefab.#{env}.config.yaml"))
62
59
  end
@@ -65,7 +62,7 @@ module Prefab
65
62
 
66
63
  def load_local_overrides
67
64
  override_dir = @prefab_options.prefab_config_override_dir
68
- rtn = load_glob(File.join(override_dir, ".prefab.overrides.config.yaml"))
65
+ rtn = load_glob(File.join(override_dir, '.prefab.default.config.yaml'))
69
66
  @prefab_options.prefab_envs.each do |env|
70
67
  rtn = rtn.merge load_glob(File.join(override_dir, ".prefab.#{env}.config.yaml"))
71
68
  end
@@ -75,113 +72,9 @@ module Prefab
75
72
  def load_glob(glob)
76
73
  rtn = {}
77
74
  Dir.glob(glob).each do |file|
78
- @base_client.log_internal Logger::INFO, "Load #{file}"
79
- yaml = load(file)
80
- yaml.each do |k, v|
81
- load_kv(k, v, rtn, file)
82
- end
75
+ Prefab::YAMLConfigParser.new(file, @base_client).merge(rtn)
83
76
  end
84
77
  rtn
85
78
  end
86
-
87
- def load_kv(k, v, rtn, file)
88
- if v.class == Hash
89
- if v['feature_flag']
90
- rtn[k] = feature_flag_config(file, k, v)
91
- else
92
- v.each do |nest_k, nest_v|
93
- nested_key = "#{k}.#{nest_k}"
94
- nested_key = k if nest_k == "_"
95
- load_kv(nested_key, nest_v, rtn, file)
96
- end
97
- end
98
- else
99
- rtn[k] = {
100
- source: file,
101
- match: "default",
102
- config: Prefab::Config.new(
103
- key: k,
104
- rows: [
105
- Prefab::ConfigRow.new(value: Prefab::ConfigValue.new(value_from(k, v)))
106
- ]
107
- )
108
- }
109
- end
110
- end
111
-
112
- def load(filename)
113
- if File.exist? filename
114
- @base_client.log_internal Logger::INFO, "Load #{filename}"
115
- YAML.load_file(filename)
116
- else
117
- @base_client.log_internal Logger::INFO, "No file #{filename}"
118
- {}
119
- end
120
- end
121
-
122
- def value_from(key, raw)
123
- case raw
124
- when String
125
- if key.start_with? Prefab::LoggerClient::BASE_KEY
126
- prefab_log_level_resolve = Prefab::LogLevel.resolve(raw.upcase.to_sym) || Prefab::LogLevel::NOT_SET_LOG_LEVEL
127
- { log_level: prefab_log_level_resolve }
128
- else
129
- { string: raw }
130
- end
131
- when Integer
132
- { int: raw }
133
- when TrueClass, FalseClass
134
- { bool: raw }
135
- when Float
136
- { double: raw }
137
- end
138
- end
139
-
140
- def feature_flag_config(file, key, value)
141
- criteria = Prefab::Criteria.new(operator: 'ALWAYS_TRUE')
142
-
143
- if value['criteria']
144
- criteria = Prefab::Criteria.new(criteria_values(value['criteria']))
145
- end
146
-
147
- row = Prefab::ConfigRow.new(
148
- value: Prefab::ConfigValue.new(
149
- feature_flag: Prefab::FeatureFlag.new(
150
- active: true,
151
- inactive_variant_idx: -1, # not supported
152
- rules: [
153
- Prefab::Rule.new(
154
- variant_weights: [
155
- Prefab::VariantWeight.new(variant_idx: 0, weight: 1000)
156
- ],
157
- criteria: criteria
158
- )
159
- ]
160
- )
161
- )
162
- )
163
-
164
- unless value.has_key?('value')
165
- raise Prefab::Error, "Feature flag config `#{key}` #{file} must have a `value`"
166
- end
167
-
168
- {
169
- source: file,
170
- match: key,
171
- config: Prefab::Config.new(
172
- key: key,
173
- variants: [Prefab::FeatureFlagVariant.new(value_from(key, value['value']))],
174
- rows: [row]
175
- )
176
- }
177
- end
178
-
179
- def criteria_values(criteria_hash)
180
- if RUBY_VERSION < '2.7'
181
- criteria_hash.transform_keys(&:to_sym)
182
- else
183
- criteria_hash
184
- end
185
- end
186
79
  end
187
80
  end
@@ -1,17 +1,16 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Prefab
3
4
  class ConfigResolver
4
- include Prefab::ConfigHelper
5
- NAMESPACE_DELIMITER = "."
6
-
7
5
  attr_accessor :project_env_id # this will be set by the config_client when it gets an API response
8
6
 
9
7
  def initialize(base_client, config_loader)
10
8
  @lock = Concurrent::ReadWriteLock.new
11
9
  @local_store = {}
12
- @namespace = base_client.options.namespace
10
+ @additional_properties = { Prefab::CriteriaEvaluator::NAMESPACE_KEY => base_client.options.namespace }
13
11
  @config_loader = config_loader
14
- @project_env_id = 0
12
+ @project_env_id = 0 # we don't know this yet, it is set from the API results
13
+ @base_client = base_client
15
14
  make_local
16
15
  end
17
16
 
@@ -22,82 +21,53 @@ module Prefab
22
21
  v = @local_store[k]
23
22
  elements = [k.slice(0..49).ljust(50)]
24
23
  if v.nil?
25
- elements << "tombstone"
24
+ elements << 'tombstone'
26
25
  else
27
- value = v[:value]
28
- elements << value_of(value).to_s.slice(0..34).ljust(35)
29
- elements << value_of(value).class.to_s.slice(0..6).ljust(7)
26
+ config = evaluate(v[:config], {})
27
+ value = Prefab::ConfigValueUnwrapper.unwrap(config, k, {})
28
+ elements << value.to_s.slice(0..34).ljust(35)
29
+ elements << value.class.to_s.slice(0..6).ljust(7)
30
30
  elements << "Match: #{v[:match]}".slice(0..29).ljust(30)
31
31
  elements << "Source: #{v[:source]}"
32
32
  end
33
- str += elements.join(" | ") << "\n"
33
+ str += elements.join(' | ') << "\n"
34
34
  end
35
35
  end
36
36
  str
37
37
  end
38
38
 
39
- def get(property)
40
- config = _get(property)
41
- config ? value_of(config[:value]) : nil
42
- end
39
+ def raw(key)
40
+ via_key = @local_store[key]
43
41
 
44
- def get_config(property)
45
- config = _get(property)
46
- config ? config[:config] : nil
42
+ via_key ? via_key[:config] : nil
47
43
  end
48
44
 
49
- def _get(key)
45
+ def get(key, lookup_key, properties = {})
50
46
  @lock.with_read_lock do
51
- @local_store[key]
47
+ raw_config = raw(key)
48
+
49
+ return nil unless raw_config
50
+
51
+ evaluate(raw(key), lookup_key, properties)
52
52
  end
53
53
  end
54
54
 
55
+ def evaluate(config, lookup_key, properties = {})
56
+ props = properties.merge(@additional_properties).merge(Prefab::CriteriaEvaluator::LOOKUP_KEY => lookup_key)
57
+
58
+ Prefab::CriteriaEvaluator.new(config,
59
+ project_env_id: @project_env_id, resolver: self, base_client: @base_client).evaluate(props)
60
+ end
61
+
55
62
  def update
56
63
  make_local
57
64
  end
58
65
 
59
66
  private
60
67
 
61
- # Should client a.b.c see key in namespace a.b? yes
62
- # Should client a.b.c see key in namespace a.b.c? yes
63
- # Should client a.b.c see key in namespace a.b.d? no
64
- # Should client a.b.c see key in namespace ""? yes
65
- #
66
- def starts_with_ns?(key_namespace, client_namespace)
67
- zipped = key_namespace.split(NAMESPACE_DELIMITER).zip(client_namespace.split(NAMESPACE_DELIMITER))
68
- mapped = zipped.map do |k, c|
69
- (k.nil? || k.empty?) || k == c
70
- end
71
- [mapped.all?, mapped.size]
72
- end
73
-
74
68
  def make_local
75
- store = {}
76
- @config_loader.calc_config.each do |key, config_resolver_obj|
77
- config = config_resolver_obj[:config]
78
- sortable = config.rows.map do |row|
79
- if row.project_env_id != 0
80
- if row.project_env_id == @project_env_id
81
- if !row.namespace.empty?
82
- (starts_with, count) = starts_with_ns?(row.namespace, @namespace)
83
- # rubocop:disable BlockNesting
84
- { sortable: 2 + count, match: "nm:#{row.namespace}", value: row.value, config: config} if starts_with
85
- else
86
- { sortable: 1, match: "env:#{row.project_env_id}", value: row.value, config: config}
87
- end
88
- end
89
- else
90
- match = config_resolver_obj[:match] || "default"
91
- { sortable: 0, match: match, value: row.value, config: config}
92
- end
93
- end.compact
94
- to_store = sortable.sort_by { |h| h[:sortable] }.last
95
- to_store[:source] = config_resolver_obj[:source]
96
- store[key] = to_store
97
- end
98
-
99
69
  @lock.with_write_lock do
100
- @local_store = store
70
+ @local_store = @config_loader.calc_config
101
71
  end
102
72
  end
103
73
  end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Prefab
4
+ class ConfigValueUnwrapper
5
+ def self.unwrap(config_value, config_key, properties)
6
+ return nil unless config_value
7
+
8
+ case config_value.type
9
+ when :int, :string, :double, :bool, :log_level
10
+ config_value.public_send(config_value.type)
11
+ when :string_list
12
+ config_value.string_list.values
13
+ when :weighted_values
14
+ lookup_key = properties[Prefab::CriteriaEvaluator::LOOKUP_KEY]
15
+ weights = config_value.weighted_values.weighted_values
16
+ value = Prefab::WeightedValueResolver.new(weights, config_key, lookup_key).resolve
17
+ unwrap(value.value, config_key, properties)
18
+ else
19
+ raise "Unknown type: #{config_value.type}"
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Prefab
4
+ class CriteriaEvaluator
5
+ LOOKUP_KEY = 'LOOKUP'
6
+ NAMESPACE_KEY = 'NAMESPACE'
7
+ NO_MATCHING_ROWS = [].freeze
8
+
9
+ def initialize(config, project_env_id:, resolver:, base_client:)
10
+ @config = config
11
+ @project_env_id = project_env_id
12
+ @resolver = resolver
13
+ @base_client = base_client
14
+ end
15
+
16
+ def evaluate(properties)
17
+ # TODO: optimize this and perhaps do it elsewhere
18
+ props = properties.transform_keys(&:to_s)
19
+
20
+ matching_environment_row_values.each do |conditional_value|
21
+ return conditional_value.value if all_criteria_match?(conditional_value, props)
22
+ end
23
+
24
+ default_row_values.each do |conditional_value|
25
+ return conditional_value.value if all_criteria_match?(conditional_value, props)
26
+ end
27
+
28
+ nil
29
+ end
30
+
31
+ def all_criteria_match?(conditional_value, props)
32
+ conditional_value.criteria.all? do |criterion|
33
+ evaluate_criteron(criterion, props)
34
+ end
35
+ end
36
+
37
+ def evaluate_criteron(criterion, properties)
38
+ value_from_properties = properties[criterion.property_name]
39
+
40
+ case criterion.operator
41
+ when :LOOKUP_KEY_IN, :PROP_IS_ONE_OF
42
+ matches?(criterion, value_from_properties, properties)
43
+ when :LOOKUP_KEY_NOT_IN, :PROP_IS_NOT_ONE_OF
44
+ !matches?(criterion, value_from_properties, properties)
45
+ when :IN_SEG
46
+ in_segment?(criterion, properties)
47
+ when :NOT_IN_SEG
48
+ !in_segment?(criterion, properties)
49
+ when :PROP_ENDS_WITH_ONE_OF
50
+ return false unless value_from_properties
51
+
52
+ criterion.value_to_match.string_list.values.any? do |ending|
53
+ value_from_properties.end_with?(ending)
54
+ end
55
+ when :PROP_DOES_NOT_END_WITH_ONE_OF
56
+ return true unless value_from_properties
57
+
58
+ criterion.value_to_match.string_list.values.none? do |ending|
59
+ value_from_properties.end_with?(ending)
60
+ end
61
+ when :HIERARCHICAL_MATCH
62
+ value_from_properties.start_with?(criterion.value_to_match.string)
63
+ when :ALWAYS_TRUE
64
+ true
65
+ else
66
+ @base_client.log.info("Unknown Operator: #{criterion.operator}")
67
+ false
68
+ end
69
+ end
70
+
71
+ private
72
+
73
+ def matching_environment_row_values
74
+ @config.rows.find { |row| row.project_env_id == @project_env_id }&.values || NO_MATCHING_ROWS
75
+ end
76
+
77
+ def default_row_values
78
+ @config.rows.find { |row| row.project_env_id != @project_env_id }&.values || NO_MATCHING_ROWS
79
+ end
80
+
81
+ def in_segment?(criterion, properties)
82
+ @resolver.get(criterion.value_to_match.string, properties[LOOKUP_KEY], properties).bool
83
+ end
84
+
85
+ def matches?(criterion, value_from_properties, properties)
86
+ criterion_value_or_values = Prefab::ConfigValueUnwrapper.unwrap(criterion.value_to_match, @config.key, properties)
87
+
88
+ case criterion_value_or_values
89
+ when Google::Protobuf::RepeatedField
90
+ criterion_value_or_values.include?(value_from_properties)
91
+ else
92
+ criterion_value_or_values == value_from_properties
93
+ end
94
+ end
95
+ end
96
+ end
@@ -5,7 +5,7 @@ module Prefab
5
5
  class InvalidApiKeyError < Prefab::Error
6
6
  def initialize(key)
7
7
  if key.nil? || key.empty?
8
- message = "No API key. Set PREFAB_API_KEY env var or use PREFAB_DATASOURCES=LOCAL_ONLY"
8
+ message = 'No API key. Set PREFAB_API_KEY env var or use PREFAB_DATASOURCES=LOCAL_ONLY'
9
9
 
10
10
  super(message)
11
11
  else
@@ -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,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Prefab
3
4
  class InternalLogger < Logger
4
5
  def initialize(path, logger)
@@ -6,23 +7,23 @@ module Prefab
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