rox-rollout 4.1.0 → 5.0.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 (121) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +51 -23
  3. data/.editorconfig +12 -0
  4. data/.github/workflows/ruby.yml +20 -0
  5. data/.gitignore +2 -0
  6. data/.rubocop.yml +17 -0
  7. data/Gemfile +2 -2
  8. data/README.md +32 -0
  9. data/Rakefile +12 -9
  10. data/bin/console +3 -4
  11. data/e2e-server/run_server.sh +12 -0
  12. data/e2e-server/server.rb +158 -0
  13. data/e2e/container.rb +11 -14
  14. data/e2e/custom_props.rb +9 -9
  15. data/e2e/rox_e2e_test.rb +18 -20
  16. data/e2e/test_vars.rb +3 -6
  17. data/example/local.rb +40 -0
  18. data/lib/rox/core/analytics.rb +18 -0
  19. data/lib/rox/core/client/buid.rb +9 -44
  20. data/lib/rox/core/client/device_properties.rb +8 -2
  21. data/lib/rox/core/client/dynamic_api.rb +53 -15
  22. data/lib/rox/core/client/internal_flags.rb +14 -2
  23. data/lib/rox/core/client/sdk_settings.rb +1 -1
  24. data/lib/rox/core/configuration/configuration.rb +1 -1
  25. data/lib/rox/core/configuration/configuration_fetched_args.rb +2 -2
  26. data/lib/rox/core/configuration/configuration_fetched_invoker.rb +8 -3
  27. data/lib/rox/core/configuration/configuration_parser.rb +39 -38
  28. data/lib/rox/core/configuration/fetcher_error.rb +1 -1
  29. data/lib/rox/core/configuration/fetcher_status.rb +1 -1
  30. data/lib/rox/core/configuration/models/experiment_model.rb +1 -1
  31. data/lib/rox/core/configuration/models/target_group_model.rb +1 -1
  32. data/lib/rox/core/consts/build.rb +3 -3
  33. data/lib/rox/core/consts/environment.rb +34 -10
  34. data/lib/rox/core/consts/property_type.rb +18 -17
  35. data/lib/rox/core/context/merged_context.rb +2 -1
  36. data/lib/rox/core/core.rb +101 -33
  37. data/lib/rox/core/entities/default_flag_values.rb +10 -0
  38. data/lib/rox/core/entities/flag.rb +22 -7
  39. data/lib/rox/core/entities/flag_setter.rb +6 -6
  40. data/lib/rox/core/entities/rox_double.rb +11 -0
  41. data/lib/rox/core/entities/rox_int.rb +11 -0
  42. data/lib/rox/core/entities/{variant.rb → rox_string.rb} +20 -13
  43. data/lib/rox/core/error_handling/exception_trigger.rb +10 -0
  44. data/lib/rox/core/error_handling/userspace_handler_exception.rb +12 -0
  45. data/lib/rox/core/error_handling/userspace_unhandled_error_invoker.rb +41 -0
  46. data/lib/rox/core/impression/impression_args.rb +2 -2
  47. data/lib/rox/core/impression/impression_invoker.rb +41 -7
  48. data/lib/rox/core/impression/models/experiment.rb +1 -1
  49. data/lib/rox/core/impression/models/reporting_value.rb +10 -2
  50. data/lib/rox/core/logging/logging.rb +3 -3
  51. data/lib/rox/core/logging/no_op_logger.rb +1 -1
  52. data/lib/rox/core/network/configuration_fetch_result.rb +1 -1
  53. data/lib/rox/core/network/configuration_fetcher.rb +9 -8
  54. data/lib/rox/core/network/configuration_fetcher_base.rb +1 -1
  55. data/lib/rox/core/network/configuration_fetcher_roxy.rb +4 -4
  56. data/lib/rox/core/network/configuration_fetcher_self_managed.rb +30 -0
  57. data/lib/rox/core/network/configuration_source.rb +1 -1
  58. data/lib/rox/core/network/request.rb +3 -3
  59. data/lib/rox/core/network/request_configuration_builder.rb +12 -9
  60. data/lib/rox/core/network/request_data.rb +1 -1
  61. data/lib/rox/core/network/response.rb +20 -4
  62. data/lib/rox/core/network/state_sender.rb +146 -0
  63. data/lib/rox/core/notifications/notification_listener.rb +4 -4
  64. data/lib/rox/core/properties/custom_property.rb +1 -1
  65. data/lib/rox/core/properties/custom_property_type.rb +1 -1
  66. data/lib/rox/core/properties/device_property.rb +2 -2
  67. data/lib/rox/core/properties/property_factory.rb +132 -0
  68. data/lib/rox/core/register/registerer.rb +13 -12
  69. data/lib/rox/core/reporting/error_reporter.rb +14 -13
  70. data/lib/rox/core/repositories/custom_property_repository.rb +1 -1
  71. data/lib/rox/core/repositories/experiment_repository.rb +2 -4
  72. data/lib/rox/core/repositories/flag_repository.rb +8 -8
  73. data/lib/rox/core/repositories/roxx/experiments_extensions.rb +8 -8
  74. data/lib/rox/core/repositories/roxx/properties_extensions.rb +32 -7
  75. data/lib/rox/core/repositories/target_group_repository.rb +2 -4
  76. data/lib/rox/core/roxx/evaluation_result.rb +2 -0
  77. data/lib/rox/core/roxx/node.rb +1 -1
  78. data/lib/rox/core/roxx/parser.rb +46 -20
  79. data/lib/rox/core/roxx/regular_expression_extensions.rb +6 -3
  80. data/lib/rox/core/roxx/string_tokenizer.rb +3 -1
  81. data/lib/rox/core/roxx/symbols.rb +1 -1
  82. data/lib/rox/core/roxx/token_type.rb +1 -1
  83. data/lib/rox/core/roxx/tokenized_expression.rb +16 -12
  84. data/lib/rox/core/roxx/value_compare_extensions.rb +49 -29
  85. data/lib/rox/core/security/signature_verifier.rb +3 -3
  86. data/lib/rox/core/security/signature_verifier_mock.rb +12 -0
  87. data/lib/rox/core/utils/debouncer.rb +18 -0
  88. data/lib/rox/core/utils/type_utils.rb +1 -1
  89. data/lib/rox/server/client/sdk_settings.rb +1 -1
  90. data/lib/rox/server/client/server_properties.rb +1 -1
  91. data/lib/rox/server/flags/normalize_flag_type.rb +25 -0
  92. data/lib/rox/server/flags/rox_double.rb +8 -0
  93. data/lib/rox/server/flags/rox_flag.rb +1 -1
  94. data/lib/rox/server/flags/rox_int.rb +8 -0
  95. data/lib/rox/server/flags/rox_string.rb +8 -0
  96. data/lib/rox/server/flags/server_entities_provider.rb +14 -4
  97. data/lib/rox/server/logging/server_logger.rb +2 -2
  98. data/lib/rox/server/rox_options.rb +39 -8
  99. data/lib/rox/server/rox_server.rb +81 -60
  100. data/lib/rox/version.rb +1 -1
  101. data/rox.gemspec +13 -9
  102. metadata +95 -36
  103. data/README_DEVELOP.md +0 -19
  104. data/_archive/.document +0 -5
  105. data/_archive/.rspec +0 -1
  106. data/_archive/Gemfile +0 -15
  107. data/_archive/Gemfile.lock +0 -87
  108. data/_archive/README.md +0 -32
  109. data/_archive/README.rdoc +0 -19
  110. data/_archive/Rakefile +0 -50
  111. data/_archive/lib/expr_function_definition.rb +0 -52
  112. data/_archive/lib/function_definition.rb +0 -48
  113. data/_archive/lib/function_token.rb +0 -12
  114. data/_archive/lib/object_extends.rb +0 -12
  115. data/_archive/lib/ruby_interpreter.rb +0 -292
  116. data/_archive/lib/stack.rb +0 -48
  117. data/_archive/lib/string_extends.rb +0 -14
  118. data/_archive/spec/ruby_interpreter_spec.rb +0 -203
  119. data/_archive/spec/spec_helper.rb +0 -30
  120. data/_archive/spec/stack_spec.rb +0 -77
  121. data/lib/rox/server/flags/rox_variant.rb +0 -8
data/e2e/custom_props.rb CHANGED
@@ -2,31 +2,31 @@ module E2E
2
2
  class CustomProps
3
3
  def self.create_custom_props
4
4
  Rox::Server::RoxServer.set_custom_string_property('string_prop1', 'Hello')
5
- Rox::Server::RoxServer.set_custom_string_property('string_prop2') do |context|
5
+ Rox::Server::RoxServer.set_custom_string_property('string_prop2') do |_context|
6
6
  TestVars.is_computed_string_prop_called = true
7
7
  'World'
8
8
  end
9
9
 
10
10
  Rox::Server::RoxServer.set_custom_boolean_property('bool_prop1', true)
11
- Rox::Server::RoxServer.set_custom_boolean_property('bool_prop2') do |context|
11
+ Rox::Server::RoxServer.set_custom_boolean_property('bool_prop2') do |_context|
12
12
  TestVars.is_computed_boolean_prop_called = true
13
13
  false
14
14
  end
15
15
 
16
16
  Rox::Server::RoxServer.set_custom_int_property('int_prop1', 6)
17
- Rox::Server::RoxServer.set_custom_int_property('int_prop2') do |context|
17
+ Rox::Server::RoxServer.set_custom_int_property('int_prop2') do |_context|
18
18
  TestVars.is_computed_int_prop_called = true
19
19
  28
20
20
  end
21
21
 
22
22
  Rox::Server::RoxServer.set_custom_float_property('float_prop1', 3.14)
23
- Rox::Server::RoxServer.set_custom_float_property('float_prop2') do |context|
23
+ Rox::Server::RoxServer.set_custom_float_property('float_prop2') do |_context|
24
24
  TestVars.is_computed_float_prop_called = true
25
25
  1.618
26
26
  end
27
27
 
28
28
  Rox::Server::RoxServer.set_custom_semver_property('smvr_prop1', '9.11.2001')
29
- Rox::Server::RoxServer.set_custom_semver_property('smvr_prop2') do |context|
29
+ Rox::Server::RoxServer.set_custom_semver_property('smvr_prop2') do |_context|
30
30
  TestVars.is_computed_semver_prop_called = true
31
31
  '20.7.1969'
32
32
  end
@@ -35,15 +35,15 @@ module E2E
35
35
  context['isDuckAndCover']
36
36
  end
37
37
 
38
- Rox::Server::RoxServer.set_custom_boolean_property('bool_prop_target_group_operand1') do |context|
38
+ Rox::Server::RoxServer.set_custom_boolean_property('bool_prop_target_group_operand1') do |_context|
39
39
  TestVars.target_group1
40
40
  end
41
41
 
42
- Rox::Server::RoxServer.set_custom_boolean_property('bool_prop_target_group_operand2') do |context|
42
+ Rox::Server::RoxServer.set_custom_boolean_property('bool_prop_target_group_operand2') do |_context|
43
43
  TestVars.target_group2
44
44
  end
45
45
 
46
- Rox::Server::RoxServer.set_custom_boolean_property('bool_prop_target_group_for_dependency') do |context|
46
+ Rox::Server::RoxServer.set_custom_boolean_property('bool_prop_target_group_for_dependency') do |_context|
47
47
  TestVars.is_prop_for_target_group_for_dependency
48
48
  end
49
49
 
@@ -52,4 +52,4 @@ module E2E
52
52
  end
53
53
  end
54
54
  end
55
- end
55
+ end
data/e2e/rox_e2e_test.rb CHANGED
@@ -1,4 +1,4 @@
1
- require "minitest/autorun"
1
+ require 'minitest/autorun'
2
2
  require 'rox/server/rox_options'
3
3
  require 'rox/server/rox_server'
4
4
  require_relative 'container'
@@ -7,7 +7,7 @@ require_relative 'test_vars'
7
7
 
8
8
  module E2E
9
9
  class Logger
10
- def debug(message, ex = nil)
10
+ def debug(message, _ex = nil)
11
11
  puts 'Before Rox.Setup', message
12
12
  end
13
13
 
@@ -15,7 +15,7 @@ module E2E
15
15
  puts 'Before Rox.Setup', message, ex
16
16
  end
17
17
 
18
- def warn(message, ex = nil)
18
+ def warn(message, _ex = nil)
19
19
  puts 'Before Rox.Setup', message
20
20
  end
21
21
  end
@@ -30,8 +30,8 @@ module E2E
30
30
  end
31
31
 
32
32
  impression_handler = proc do |e|
33
- if !e.nil? && !e.reporting_value.nil?
34
- TestVars.is_impression_raised = true if e.reporting_value.name == 'flag_for_impression'
33
+ if !e.nil? && !e.reporting_value.nil? && (e.reporting_value.name == 'flag_for_impression')
34
+ TestVars.is_impression_raised = true
35
35
  end
36
36
  TestVars.impression_returned_args = e
37
37
  end
@@ -44,7 +44,7 @@ module E2E
44
44
  )
45
45
 
46
46
  @@container = Container.new
47
- Rox::Server::RoxServer.register('', @@container)
47
+ Rox::Server::RoxServer.register(@@container)
48
48
  CustomProps.create_custom_props
49
49
  Rox::Server::RoxServer.setup('5b82864ebc3aec37aff1fdd5', option).join
50
50
 
@@ -56,7 +56,7 @@ module E2E
56
56
  assert_equal false, @@container.simple_flag_overwritten.enabled?
57
57
  end
58
58
 
59
- def test_variant
59
+ def test_string
60
60
  assert_equal 'red', @@container.variant.value
61
61
  end
62
62
 
@@ -87,9 +87,9 @@ module E2E
87
87
  end
88
88
  end
89
89
 
90
- def test_variant_with_context
91
- some_positive_context = {'isDuckAndCover' => true}
92
- some_negative_context = {'isDuckAndCover' => false}
90
+ def test_string_with_context
91
+ some_positive_context = { 'isDuckAndCover' => true }
92
+ some_negative_context = { 'isDuckAndCover' => false }
93
93
 
94
94
  assert_equal 'red', @@container.variant_with_context.value
95
95
 
@@ -121,18 +121,16 @@ module E2E
121
121
  assert_equal true, TestVars.is_impression_raised
122
122
  TestVars.is_impression_raised = false
123
123
 
124
- context = {'var' => 'val'}
124
+ context = { 'var' => 'val' }
125
125
  flag_impression_value = @@container.flag_for_impression_with_experiment_and_context.enabled?(context)
126
126
  refute_nil TestVars.impression_returned_args
127
127
  refute_nil TestVars.impression_returned_args.reporting_value
128
- assert_equal 'true', TestVars.impression_returned_args.reporting_value.value
128
+ assert_equal true, TestVars.impression_returned_args.reporting_value.value
129
129
  assert_equal true, flag_impression_value
130
- assert_equal 'flag_for_impression_with_experiment_and_context', TestVars.impression_returned_args.reporting_value.name
130
+ assert_equal 'flag_for_impression_with_experiment_and_context',
131
+ TestVars.impression_returned_args.reporting_value.name
131
132
 
132
133
  refute_nil TestVars.impression_returned_args
133
- refute_nil TestVars.impression_returned_args.experiment
134
- assert_equal '5b8f85ecbc3aec37aff20841', TestVars.impression_returned_args.experiment.identifier
135
- assert_equal 'flag for impression with experiment and context', TestVars.impression_returned_args.experiment.name
136
134
 
137
135
  assert_equal 'val', TestVars.impression_returned_args.context['var']
138
136
  end
@@ -147,13 +145,13 @@ module E2E
147
145
  assert_equal false, @@container.flag_for_dependency.enabled?
148
146
  end
149
147
 
150
- def test_variant_dependency_with_context
151
- some_positive_context = {'isDuckAndCover' => true}
152
- some_negative_context = {'isDuckAndCover' => false}
148
+ def test_string_dependency_with_context
149
+ some_positive_context = { 'isDuckAndCover' => true }
150
+ some_negative_context = { 'isDuckAndCover' => false }
153
151
 
154
152
  assert_equal 'White', @@container.flag_color_dependent_with_context.value
155
153
  assert_equal 'White', @@container.flag_color_dependent_with_context.value(some_negative_context)
156
154
  assert_equal 'Yellow', @@container.flag_color_dependent_with_context.value(some_positive_context)
157
155
  end
158
156
  end
159
- end
157
+ end
data/e2e/test_vars.rb CHANGED
@@ -1,11 +1,8 @@
1
1
  module E2E
2
2
  module TestVars
3
3
  class << self
4
- attr_accessor :is_computed_boolean_prop_called, :is_computed_string_prop_called, :is_computed_int_prop_called, :is_computed_float_prop_called, :is_computed_semver_prop_called
5
- attr_accessor :target_group1, :target_group2
6
- attr_accessor :is_impression_raised, :is_prop_for_target_group_for_dependency
7
-
8
- attr_accessor :configuration_fetched_count, :impression_returned_args
4
+ attr_accessor :is_computed_boolean_prop_called, :is_computed_string_prop_called, :is_computed_int_prop_called,
5
+ :is_computed_float_prop_called, :is_computed_semver_prop_called, :target_group1, :target_group2, :is_impression_raised, :is_prop_for_target_group_for_dependency, :configuration_fetched_count, :impression_returned_args
9
6
  end
10
7
 
11
8
  @is_computed_boolean_prop_called = false
@@ -21,4 +18,4 @@ module E2E
21
18
  @configuration_fetched_count = 0
22
19
  @impression_returned_args = nil
23
20
  end
24
- end
21
+ end
data/example/local.rb ADDED
@@ -0,0 +1,40 @@
1
+ $LOAD_PATH.unshift File.expand_path('../lib', __dir__)
2
+
3
+ require 'rox/server/rox_server'
4
+ require 'rox/server/rox_options'
5
+
6
+ API_HOST = 'http://localhost:8557'.freeze
7
+ APP_KEY = '600571e330819d4842999e4f'.freeze
8
+ DEV_MODE_SECRET = 'e56cda16749d8d0a9b91d34c'.freeze
9
+
10
+ class Flags
11
+ attr_accessor :boolean_flag, :string_flag, :int_flag, :double_flag
12
+
13
+ def initialize
14
+ # Define the feature flags
15
+ @boolean_flag = Rox::Server::RoxFlag.new(true)
16
+ @string_flag = Rox::Server::RoxString.new('option 1', ['option 1', 'option 2', 'option 3'])
17
+ @int_flag = Rox::Server::RoxInt.new(1, [1, 2, 3])
18
+ @double_flag = Rox::Server::RoxDouble.new(4.0, [5.0, 6.0])
19
+ end
20
+ end
21
+
22
+ flags = Flags.new
23
+ Rox::Server::RoxServer.register(flags)
24
+
25
+ options = Rox::Server::RoxOptions.new(
26
+ self_managed_options: Rox::Server::SelfManagedOptions.new(
27
+ server_url: API_HOST,
28
+ analytics_url: 'http://127.0.0.1:8787'
29
+ ),
30
+ dev_mode_key: DEV_MODE_SECRET
31
+ )
32
+
33
+ Rox::Server::RoxServer.setup(APP_KEY, options)
34
+
35
+ puts "boolean_flag is #{flags.boolean_flag.enabled?}"
36
+ puts "boolean_flag is #{Rox::Server::RoxServer.dynamic_api.enabled?('boolean_flag', true)} (dynamic api)"
37
+ puts "boolean_flag is #{Rox::Server::RoxServer.dynamic_api.enabled?('boolean_flag', true)} (dynamic api)"
38
+ puts "string_flag is #{flags.string_flag.value}"
39
+ puts "int_flag is #{flags.int_flag.value}"
40
+ puts "double_flag is #{flags.double_flag.value}"
@@ -0,0 +1,18 @@
1
+ require 'segment/analytics'
2
+
3
+ module Rox
4
+ module Core
5
+ # Analytics based on segment client
6
+ # https://segment.com/docs/connections/sources/catalog/libraries/server/ruby/
7
+ class Analytics
8
+ attr_reader :client
9
+
10
+ def initialize(key)
11
+ @client = Segment::Analytics.new({
12
+ write_key: key,
13
+ on_error: proc { |_status, msg| print msg }
14
+ })
15
+ end
16
+ end
17
+ end
18
+ end
@@ -6,20 +6,15 @@ module Rox
6
6
  module Core
7
7
  class BUID
8
8
  BUID_GENERATORS = [
9
- PropertyType::PLATFORM,
10
- PropertyType::APP_KEY,
11
- PropertyType::LIB_VERSION,
12
- PropertyType::API_VERSION,
13
- PropertyType::CUSTOM_PROPERTIES,
14
- PropertyType::FEATURE_FLAGS,
15
- PropertyType::REMOTE_VARIABLES
9
+ PropertyType::PLATFORM,
10
+ PropertyType::APP_KEY,
11
+ PropertyType::LIB_VERSION,
12
+ PropertyType::API_VERSION
16
13
  ].freeze
17
14
 
18
- def initialize(sdk_settings, device_properties, flag_repository, custom_property_repository)
15
+ def initialize(sdk_settings, device_properties, _flag_repository, _custom_property_repository)
19
16
  @sdk_settings = sdk_settings
20
17
  @device_properties = device_properties
21
- @flag_repository = flag_repository
22
- @custom_property_repository = custom_property_repository
23
18
  @buid = nil
24
19
  end
25
20
 
@@ -30,53 +25,23 @@ module Rox
30
25
  values << properties[pt.name] if properties.include?(pt.name)
31
26
  end
32
27
 
33
- values << serialize_feature_flags
34
- values << serialize_custom_properties
35
-
36
28
  hash = Digest::MD5.hexdigest(values.join('|'))
37
29
 
38
30
  @buid = hash.upcase
39
31
  end
40
32
 
41
33
  def query_string_parts
42
- generators = BUID::BUID_GENERATORS.map {|pt, _| pt.name}
34
+ generators = BUID::BUID_GENERATORS.map { |pt, _| pt.name }
43
35
 
44
36
  {
45
- PropertyType::BUID.name => value,
46
- PropertyType::BUID_GENERATORS_LIST.name => generators.join(','),
47
- PropertyType::FEATURE_FLAGS.name => serialize_feature_flags,
48
- PropertyType::REMOTE_VARIABLES.name => '[]',
49
- PropertyType::CUSTOM_PROPERTIES.name => serialize_custom_properties,
37
+ PropertyType::BUID.name => value,
38
+ PropertyType::BUID_GENERATORS_LIST.name => generators.join(',')
50
39
  }
51
40
  end
52
41
 
53
- def serialize_feature_flags
54
- flags = []
55
- @flag_repository.all_flags.each do |f|
56
- flags << {
57
- name: f.name,
58
- defaultValue: f.default_value,
59
- options: f.options
60
- }
61
- end
62
- JSON.dump(flags)
63
- end
64
-
65
- def serialize_custom_properties
66
- properties = []
67
- @custom_property_repository.all_custom_properties.each do |p|
68
- properties << {
69
- name: p.name,
70
- type: p.type.type,
71
- externalType: p.type.external_type
72
- }
73
- end
74
- JSON.dump(properties)
75
- end
76
-
77
42
  def to_s
78
43
  @buid
79
44
  end
80
45
  end
81
46
  end
82
- end
47
+ end
@@ -4,11 +4,17 @@ require 'rox/core/consts/build'
4
4
  module Rox
5
5
  module Core
6
6
  class DeviceProperties
7
+ attr_reader :rox_options
8
+
7
9
  def initialize(sdk_settings, rox_options)
8
10
  @sdk_settings = sdk_settings
9
11
  @rox_options = rox_options
10
12
  end
11
13
 
14
+ def get(property)
15
+ all_properties[property.name]
16
+ end
17
+
12
18
  def all_properties
13
19
  {
14
20
  PropertyType::PACKAGE_NAME.name => @rox_options.version,
@@ -20,7 +26,7 @@ module Rox
20
26
  PropertyType::APP_RELEASE.name => @rox_options.version,
21
27
  PropertyType::DISTINCT_ID.name => distinct_id,
22
28
  PropertyType::APP_KEY.name => @sdk_settings.api_key,
23
- PropertyType::PLATFORM.name => Build::PLATFORM,
29
+ PropertyType::PLATFORM.name => Build::PLATFORM
24
30
  }
25
31
  end
26
32
 
@@ -42,4 +48,4 @@ module Rox
42
48
  end
43
49
  end
44
50
  end
45
- end
51
+ end
@@ -1,4 +1,5 @@
1
1
  require 'rox/core/entities/flag'
2
+ require 'rox/server/flags/normalize_flag_type'
2
3
 
3
4
  module Rox
4
5
  module Core
@@ -9,28 +10,65 @@ module Rox
9
10
  end
10
11
 
11
12
  def enabled?(name, default_value, context = nil)
12
- variant = @flag_repository.flag(name)
13
- if variant.nil?
14
- variant = @entities_provider.create_flag(default_value)
15
- @flag_repository.add_flag(variant, name)
16
- end
13
+ raise ArgumentError, 'flag name should be a string' unless name.is_a?(String)
14
+ raise ArgumentError, 'default value should be boolean' unless [true, false].include?(default_value)
17
15
 
18
- return default_value unless variant.is_a?(Flag)
16
+ string = @flag_repository.flag(name)
17
+ if string.nil?
18
+ string = @entities_provider.create_flag(default_value)
19
+ @flag_repository.add_flag(string, name)
20
+ end
19
21
 
20
- is_enabled = variant.internal_enabled?(context, nil_instead_of_default: true)
21
- is_enabled.nil? ? default_value : is_enabled
22
+ merged_context = MergedContext.new(string.parser&.global_context, context)
23
+ return_value = unless string.is_a?(Flag)
24
+ default_value
25
+ else
26
+ is_enabled = string.internal_enabled?(context, nil_instead_of_default: true)
27
+ is_enabled.nil? ? default_value : is_enabled
28
+ end
29
+ string.send_impressions(return_value, merged_context)
30
+ return_value
22
31
  end
23
32
 
24
33
  def value(name, default_value, context = nil, options = [])
25
- variant = @flag_repository.flag(name)
26
- if variant.nil?
27
- variant = @entities_provider.create_variant(default_value, options)
28
- @flag_repository.add_flag(variant, name)
34
+ generic_value(name, default_value, context, options)
35
+ end
36
+
37
+ def int_value(name, default_value, context = nil, options = [])
38
+ create_method = @entities_provider.method(:create_int)
39
+ normalize_method = Rox::Server::NormalizeFlagType.method(:normalize_int)
40
+ generic_value(name, default_value, context, options, Integer, create_method, normalize_method)
41
+ end
42
+
43
+ def double_value(name, default_value, context = nil, options = [])
44
+ create_method = @entities_provider.method(:create_double)
45
+ normalize_method = Rox::Server::NormalizeFlagType.method(:normalize_float)
46
+ generic_value(name, default_value, context, options, Float, create_method, normalize_method)
47
+ end
48
+
49
+ private
50
+
51
+ def generic_value(name, default_value, context, options, flag_type = String, create_method = nil, normalize_method = Rox::Server::NormalizeFlagType.method(:normalize_string))
52
+ unless name.is_a?(String)
53
+ raise ArgumentError, 'DynamicApi error - name must be string'
54
+ end
55
+
56
+ unless default_value.is_a?(flag_type)
57
+ raise ArgumentError, "DynamicApi default value must be of #{flag_type} type. Received #{default_value}"
58
+ end
59
+
60
+ string = @flag_repository.flag(name)
61
+ if string.nil?
62
+ string = create_method.nil? ? @entities_provider.create_string(default_value, options) : create_method.call(default_value, options)
63
+ @flag_repository.add_flag(string, name)
29
64
  end
30
65
 
31
- value = variant.internal_value(context, nil_instead_of_default: true)
32
- value.nil? ? default_value : value
66
+ merged_context = MergedContext.new(string.parser&.global_context, context)
67
+ value = string.internal_value(context, nil_instead_of_default: true)
68
+ return_value = value.nil? ? normalize_method.call(default_value) : normalize_method.call(value)
69
+ string.send_impressions(return_value, merged_context)
70
+ return_value
33
71
  end
34
72
  end
35
73
  end
36
- end
74
+ end