rox-rollout 4.7.1 → 5.0.2

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 (116) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +34 -13
  3. data/.editorconfig +12 -0
  4. data/.github/workflows/ruby.yml +20 -0
  5. data/.rubocop.yml +17 -0
  6. data/Gemfile +2 -2
  7. data/README.md +32 -0
  8. data/Rakefile +12 -9
  9. data/bin/console +3 -4
  10. data/e2e/container.rb +11 -14
  11. data/e2e/custom_props.rb +9 -9
  12. data/e2e/rox_e2e_test.rb +17 -19
  13. data/e2e/test_vars.rb +3 -6
  14. data/e2e-server/run_server.sh +12 -0
  15. data/e2e-server/server.rb +158 -0
  16. data/example/local.rb +40 -0
  17. data/lib/rox/core/analytics.rb +18 -0
  18. data/lib/rox/core/client/buid.rb +8 -8
  19. data/lib/rox/core/client/device_properties.rb +7 -1
  20. data/lib/rox/core/client/dynamic_api.rb +53 -15
  21. data/lib/rox/core/client/internal_flags.rb +14 -2
  22. data/lib/rox/core/client/sdk_settings.rb +1 -1
  23. data/lib/rox/core/configuration/configuration.rb +1 -1
  24. data/lib/rox/core/configuration/configuration_fetched_args.rb +2 -2
  25. data/lib/rox/core/configuration/configuration_fetched_invoker.rb +8 -3
  26. data/lib/rox/core/configuration/configuration_parser.rb +38 -37
  27. data/lib/rox/core/configuration/fetcher_error.rb +1 -1
  28. data/lib/rox/core/configuration/fetcher_status.rb +1 -1
  29. data/lib/rox/core/configuration/models/experiment_model.rb +1 -1
  30. data/lib/rox/core/configuration/models/target_group_model.rb +1 -1
  31. data/lib/rox/core/consts/build.rb +2 -2
  32. data/lib/rox/core/consts/environment.rb +10 -8
  33. data/lib/rox/core/consts/property_type.rb +16 -17
  34. data/lib/rox/core/context/merged_context.rb +2 -1
  35. data/lib/rox/core/core.rb +89 -38
  36. data/lib/rox/core/entities/default_flag_values.rb +10 -0
  37. data/lib/rox/core/entities/flag.rb +22 -7
  38. data/lib/rox/core/entities/flag_setter.rb +6 -6
  39. data/lib/rox/core/entities/rox_double.rb +11 -0
  40. data/lib/rox/core/entities/rox_int.rb +11 -0
  41. data/lib/rox/core/entities/{variant.rb → rox_string.rb} +20 -13
  42. data/lib/rox/core/error_handling/exception_trigger.rb +10 -0
  43. data/lib/rox/core/error_handling/userspace_handler_exception.rb +12 -0
  44. data/lib/rox/core/error_handling/userspace_unhandled_error_invoker.rb +41 -0
  45. data/lib/rox/core/impression/impression_args.rb +2 -2
  46. data/lib/rox/core/impression/impression_invoker.rb +41 -7
  47. data/lib/rox/core/impression/models/experiment.rb +1 -1
  48. data/lib/rox/core/impression/models/reporting_value.rb +10 -2
  49. data/lib/rox/core/logging/logging.rb +3 -3
  50. data/lib/rox/core/logging/no_op_logger.rb +1 -1
  51. data/lib/rox/core/network/configuration_fetcher.rb +2 -2
  52. data/lib/rox/core/network/configuration_fetcher_roxy.rb +2 -2
  53. data/lib/rox/core/network/configuration_fetcher_self_managed.rb +30 -0
  54. data/lib/rox/core/network/configuration_source.rb +1 -1
  55. data/lib/rox/core/network/request.rb +1 -1
  56. data/lib/rox/core/network/request_configuration_builder.rb +5 -5
  57. data/lib/rox/core/network/request_data.rb +1 -1
  58. data/lib/rox/core/network/response.rb +6 -8
  59. data/lib/rox/core/network/state_sender.rb +63 -19
  60. data/lib/rox/core/notifications/notification_listener.rb +4 -4
  61. data/lib/rox/core/properties/custom_property.rb +1 -1
  62. data/lib/rox/core/properties/custom_property_type.rb +1 -1
  63. data/lib/rox/core/properties/device_property.rb +2 -2
  64. data/lib/rox/core/properties/property_factory.rb +132 -0
  65. data/lib/rox/core/register/registerer.rb +13 -12
  66. data/lib/rox/core/reporting/error_reporter.rb +14 -13
  67. data/lib/rox/core/repositories/experiment_repository.rb +2 -4
  68. data/lib/rox/core/repositories/flag_repository.rb +7 -7
  69. data/lib/rox/core/repositories/roxx/experiments_extensions.rb +8 -8
  70. data/lib/rox/core/repositories/roxx/properties_extensions.rb +32 -7
  71. data/lib/rox/core/repositories/target_group_repository.rb +2 -4
  72. data/lib/rox/core/roxx/evaluation_result.rb +2 -0
  73. data/lib/rox/core/roxx/node.rb +1 -1
  74. data/lib/rox/core/roxx/parser.rb +35 -21
  75. data/lib/rox/core/roxx/regular_expression_extensions.rb +6 -3
  76. data/lib/rox/core/roxx/string_tokenizer.rb +3 -1
  77. data/lib/rox/core/roxx/symbols.rb +1 -1
  78. data/lib/rox/core/roxx/token_type.rb +1 -1
  79. data/lib/rox/core/roxx/tokenized_expression.rb +16 -12
  80. data/lib/rox/core/roxx/value_compare_extensions.rb +49 -29
  81. data/lib/rox/core/security/signature_verifier.rb +3 -3
  82. data/lib/rox/core/security/signature_verifier_mock.rb +12 -0
  83. data/lib/rox/core/utils/type_utils.rb +1 -1
  84. data/lib/rox/server/client/server_properties.rb +1 -1
  85. data/lib/rox/server/flags/normalize_flag_type.rb +25 -0
  86. data/lib/rox/server/flags/rox_double.rb +8 -0
  87. data/lib/rox/server/flags/rox_flag.rb +1 -1
  88. data/lib/rox/server/flags/rox_int.rb +8 -0
  89. data/lib/rox/server/flags/rox_string.rb +8 -0
  90. data/lib/rox/server/flags/server_entities_provider.rb +14 -4
  91. data/lib/rox/server/logging/server_logger.rb +2 -2
  92. data/lib/rox/server/rox_options.rb +39 -8
  93. data/lib/rox/server/rox_server.rb +84 -59
  94. data/lib/rox/version.rb +1 -1
  95. data/rox.gemspec +11 -9
  96. metadata +62 -33
  97. data/CODEOWNERS +0 -1
  98. data/README_DEVELOP.md +0 -25
  99. data/_archive/.document +0 -5
  100. data/_archive/.rspec +0 -1
  101. data/_archive/Gemfile +0 -15
  102. data/_archive/Gemfile.lock +0 -87
  103. data/_archive/README.md +0 -32
  104. data/_archive/README.rdoc +0 -19
  105. data/_archive/Rakefile +0 -50
  106. data/_archive/lib/expr_function_definition.rb +0 -52
  107. data/_archive/lib/function_definition.rb +0 -48
  108. data/_archive/lib/function_token.rb +0 -12
  109. data/_archive/lib/object_extends.rb +0 -12
  110. data/_archive/lib/ruby_interpreter.rb +0 -292
  111. data/_archive/lib/stack.rb +0 -48
  112. data/_archive/lib/string_extends.rb +0 -14
  113. data/_archive/spec/ruby_interpreter_spec.rb +0 -203
  114. data/_archive/spec/spec_helper.rb +0 -30
  115. data/_archive/spec/stack_spec.rb +0 -77
  116. data/lib/rox/server/flags/rox_variant.rb +0 -8
@@ -6,4 +6,4 @@ module Rox
6
6
  ROXY = 'Roxy'.freeze
7
7
  end
8
8
  end
9
- end
9
+ end
@@ -28,7 +28,7 @@ module Rox
28
28
  request.body = JSON.dump(payload)
29
29
  end
30
30
 
31
- resp = Net::HTTP.start(uri.hostname, uri.port, :use_ssl => uri.scheme == 'https') do |http|
31
+ resp = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http|
32
32
  http.request(request)
33
33
  end
34
34
 
@@ -5,25 +5,25 @@ require 'rox/core/consts/property_type'
5
5
  module Rox
6
6
  module Core
7
7
  class RequestConfigurationBuilder
8
- def initialize(sdk_settings, buid, device_properties, roxy_url)
8
+ def initialize(sdk_settings, buid, device_properties)
9
9
  @sdk_settings = sdk_settings
10
10
  @buid = buid
11
11
  @device_properties = device_properties
12
- @roxy_url = roxy_url
12
+ @rox_options = device_properties.rox_options
13
13
  end
14
14
 
15
15
  def build_for_roxy
16
- roxy_endpoint = URI.join(@roxy_url, Rox::Core::Environment.roxy_internal_path).to_s
16
+ roxy_endpoint = URI.join(@rox_options.roxy_url, Rox::Core::Environment.roxy_internal_path).to_s
17
17
  build_request_with_full_params(roxy_endpoint)
18
18
  end
19
19
 
20
20
  def build_for_cdn
21
21
  RequestData.new("#{Rox::Core::Environment.cdn_path}/#{relative_path}",
22
- Rox::Core::PropertyType::DISTINCT_ID.name => @device_properties.distinct_id)
22
+ Rox::Core::PropertyType::DISTINCT_ID.name => @device_properties.distinct_id)
23
23
  end
24
24
 
25
25
  def build_for_api
26
- build_request_with_full_params("#{Rox::Core::Environment.api_path}/#{relative_path}")
26
+ build_request_with_full_params("#{Rox::Core::Environment.api_path(@rox_options.self_managed_options&.server_url)}/#{relative_path}")
27
27
  end
28
28
 
29
29
  def relative_path
@@ -2,4 +2,4 @@ module Rox
2
2
  module Core
3
3
  RequestData = Struct.new(:url, :query_params)
4
4
  end
5
- end
5
+ end
@@ -6,7 +6,7 @@ module Rox
6
6
  class Response
7
7
  attr_accessor :status_code, :text, :content_type
8
8
 
9
- def initialize(status_code, text, content_type='application/octet-stream')
9
+ def initialize(status_code, text, content_type = 'application/octet-stream')
10
10
  @status_code = status_code
11
11
  @text = text
12
12
  @content_type = content_type
@@ -21,13 +21,11 @@ module Rox
21
21
  end
22
22
 
23
23
  def missing_via_response_body?
24
- begin
25
- @status_code == 200 && @content_type == 'application/json' &&
26
- [404, "404"].include?(JSON.parse(text)['result'])
27
- rescue JSON::ParserError
28
- Logging.logger.error("Failed to parse JSON response: #{text}")
29
- false
30
- end
24
+ @status_code == 200 && @content_type == 'application/json' &&
25
+ [404, '404'].include?(JSON.parse(text)['result'])
26
+ rescue JSON::ParserError
27
+ Logging.logger.error("Failed to parse JSON response: #{text}")
28
+ false
31
29
  end
32
30
  end
33
31
  end
@@ -18,7 +18,7 @@ module Rox
18
18
  @flag_repository = flag_repository
19
19
  @custom_property_repository = custom_property_repository
20
20
  @request = Request.new
21
- @debouncer = Debouncer.new(1, Proc.new { self.send })
21
+ @debouncer = Debouncer.new(1, proc { send })
22
22
  end
23
23
 
24
24
  def delayed_send
@@ -30,21 +30,35 @@ module Rox
30
30
  serialized_feature_flags = StateSender.seralize_flag_repository(@flag_repository)
31
31
  serialized_custom_properties = StateSender.serialize_custom_properties_repository(@custom_property_repository)
32
32
 
33
- state_payload = StateSender.state_payload(serialized_feature_flags, serialized_custom_properties, @device_properties, @sdk_settings.dev_mode_secret)
34
- md5_signature = StateSender.md5_signature(serialized_feature_flags, serialized_custom_properties, @device_properties, @sdk_settings.dev_mode_secret)
33
+ state_payload = StateSender.state_payload(serialized_feature_flags, serialized_custom_properties,
34
+ @device_properties, @sdk_settings.dev_mode_secret)
35
+ md5_signature = StateSender.md5_signature(serialized_feature_flags, serialized_custom_properties,
36
+ @device_properties, @sdk_settings.dev_mode_secret)
35
37
 
36
- response = get_state_from_CDN(rollout_key, md5_signature)
37
- if !response.success?
38
- Rox::Core::Logging.logger.debug("Failed to fetch state from CDN. Sending state to API...")
39
- response = send_state_to_API(rollout_key, md5_signature, state_payload)
38
+ unless @device_properties.rox_options.self_managed?
39
+ response = get_state_from_CDN(rollout_key, md5_signature)
40
40
  if response.success?
41
- Rox::Core::Logging.logger.debug("Successfully sent state to API.")
41
+ Rox::Core::Logging.logger.debug('Successfully fetched state from CDN')
42
+ return
42
43
  else
43
- Rox::Core::Logging.logger.debug("Failed to send state to API.")
44
+ Rox::Core::Logging.logger.debug('Failed to fetch state from CDN. Sending state to API...')
44
45
  end
45
- else
46
- Rox::Core::Logging.logger.debug("Successfully fetched state from CDN")
47
46
  end
47
+
48
+ response = send_state_to_API(rollout_key, md5_signature, state_payload)
49
+ message = if response.success?
50
+ 'Successfully sent state to API.'
51
+ else
52
+ 'Failed to send state to API.'
53
+ end
54
+ Rox::Core::Logging.logger.debug(message)
55
+ end
56
+
57
+ def dump_state
58
+ serialized_feature_flags = StateSender.seralize_flag_repository_with_values(@flag_repository)
59
+ serialized_custom_properties = StateSender.serialize_custom_properties_repository_with_values(@custom_property_repository)
60
+ StateSender.state_payload(serialized_feature_flags, serialized_custom_properties, @device_properties,
61
+ @sdk_settings.dev_mode_secret)
48
62
  end
49
63
 
50
64
  def get_state_from_CDN(rollout_key, md5_signature)
@@ -54,11 +68,14 @@ module Rox
54
68
  end
55
69
 
56
70
  def send_state_to_API(rollout_key, md5_signature, state_payload)
57
- @request.send_post("#{Rox::Core::Environment.state_api_path}/#{rollout_key}/#{md5_signature}", state_payload)
71
+ @request.send_post(
72
+ "#{Rox::Core::Environment.state_api_path(@device_properties.rox_options.self_managed_options&.server_url)}/#{rollout_key}/#{md5_signature}", state_payload
73
+ )
58
74
  end
59
75
 
60
76
  def self.md5_signature(serialized_feature_flags, serialized_custom_properties, device_properties, dev_mode_secret)
61
- values = self.state_payload(serialized_feature_flags, serialized_custom_properties, device_properties, dev_mode_secret).values
77
+ values = state_payload(serialized_feature_flags, serialized_custom_properties, device_properties,
78
+ dev_mode_secret).values
62
79
 
63
80
  hash = Digest::MD5.hexdigest(values.join('|'))
64
81
  hash.upcase
@@ -66,18 +83,19 @@ module Rox
66
83
 
67
84
  def self.state_payload(seralized_flag_repository, serialized_custom_property_repository, device_properties, dev_mode_secret)
68
85
  values = {}
86
+ # be careful adding here properties, md5 signature uses all props
87
+ # to add more payload data, please change the md5_signature to use only the relevant properties (the current ones creating the payload)
69
88
  values[PropertyType::APP_KEY.name] = device_properties.all_properties[PropertyType::APP_KEY.name]
70
89
  values[PropertyType::PLATFORM.name] = device_properties.all_properties[PropertyType::PLATFORM.name]
71
- values.merge!(device_properties.all_properties)
72
- values.merge!({feature_flags: seralized_flag_repository})
73
- values.merge!({custom_properties: serialized_custom_property_repository})
74
- values["devModeSecret"] = dev_mode_secret
90
+ values.merge!({ feature_flags: seralized_flag_repository })
91
+ values.merge!({ custom_properties: serialized_custom_property_repository })
92
+ values['devModeSecret'] = dev_mode_secret
75
93
  values
76
94
  end
77
95
 
78
96
  def self.seralize_flag_repository(flag_repository)
79
97
  flags = []
80
- flag_repository.all_flags.sort_by{|flag| flag.name }.each do |f|
98
+ flag_repository.all_flags.sort_by(&:name).each do |f|
81
99
  flags << {
82
100
  name: f.name,
83
101
  defaultValue: f.default_value,
@@ -87,11 +105,37 @@ module Rox
87
105
  flags
88
106
  end
89
107
 
108
+ def self.seralize_flag_repository_with_values(flag_repository)
109
+ flags = []
110
+ flag_repository.all_flags.sort_by(&:name).each do |f|
111
+ flags << {
112
+ name: f.name,
113
+ enabled: f.enabled?,
114
+ defaultValue: f.default_value,
115
+ options: f.options
116
+ }
117
+ end
118
+ flags
119
+ end
120
+
90
121
  def self.serialize_custom_properties_repository(custom_property_repository)
91
122
  properties = []
92
- custom_property_repository.all_custom_properties.sort_by{|prop| prop.name }.each do |p|
123
+ custom_property_repository.all_custom_properties.sort_by(&:name).each do |p|
124
+ properties << {
125
+ name: p.name,
126
+ type: p.type.type,
127
+ externalType: p.type.external_type
128
+ }
129
+ end
130
+ properties
131
+ end
132
+
133
+ def self.serialize_custom_properties_repository_with_values(custom_property_repository)
134
+ properties = []
135
+ custom_property_repository.all_custom_properties.sort_by(&:name).each do |p|
93
136
  properties << {
94
137
  name: p.name,
138
+ value: p.value(nil),
95
139
  type: p.type.type,
96
140
  externalType: p.type.external_type
97
141
  }
@@ -1,4 +1,4 @@
1
- require "em-eventsource"
1
+ require 'em-eventsource'
2
2
 
3
3
  module Rox
4
4
  module Core
@@ -15,7 +15,7 @@ module Rox
15
15
  end
16
16
 
17
17
  def start
18
- sse_url = @listen_url.chomp('/') + '/' + @app_key
18
+ sse_url = "#{@listen_url.chomp('/')}/#{@app_key}"
19
19
  @thread = Thread.new do
20
20
  EM.run do
21
21
  source = EventMachine::EventSource.new(sse_url)
@@ -37,9 +37,9 @@ module Rox
37
37
  end
38
38
 
39
39
  def stop
40
- @thread.terminate unless @thread.nil?
40
+ @thread&.terminate
41
41
  @thread = nil
42
42
  end
43
43
  end
44
44
  end
45
- end
45
+ end
@@ -15,4 +15,4 @@ module Rox
15
15
  end
16
16
  end
17
17
  end
18
- end
18
+ end
@@ -15,4 +15,4 @@ module Rox
15
15
  SEMVER = CustomPropertyType.new('semver', 'Semver')
16
16
  end
17
17
  end
18
- end
18
+ end
@@ -4,8 +4,8 @@ module Rox
4
4
  module Core
5
5
  class DeviceProperty < CustomProperty
6
6
  def initialize(name, type, value = nil)
7
- super('rox.' + name, type, value)
7
+ super("rox.#{name}", type, value)
8
8
  end
9
9
  end
10
10
  end
11
- end
11
+ end
@@ -0,0 +1,132 @@
1
+ require 'securerandom'
2
+ require 'rox/server/rox_options'
3
+ require 'rox/server/client/sdk_settings'
4
+ require 'rox/server/client/server_properties'
5
+ require 'rox/core/properties/device_property'
6
+ require 'rox/core/properties/custom_property'
7
+ require 'rox/core/properties/custom_property_type'
8
+ require 'rox/core/consts/property_type'
9
+
10
+ module Rox
11
+ module Core
12
+ # Consolidates creation of all the internal properties
13
+ class PropertyFactory
14
+ def initialize(server_properties)
15
+ @server_properties = server_properties
16
+ end
17
+
18
+ def platform
19
+ property = Rox::Core::PropertyType::PLATFORM
20
+ type = Rox::Core::CustomPropertyType::STRING
21
+
22
+ Rox::Core::DeviceProperty.new(
23
+ property.name,
24
+ type,
25
+ @server_properties.get(property)
26
+ )
27
+ end
28
+
29
+ def app_release
30
+ property = Rox::Core::PropertyType::APP_RELEASE
31
+ type = Rox::Core::CustomPropertyType::SEMVER
32
+
33
+ Rox::Core::DeviceProperty.new(
34
+ property.name,
35
+ type,
36
+ @server_properties.get(property)
37
+ )
38
+ end
39
+
40
+ def distinct_id
41
+ property = Rox::Core::PropertyType::DISTINCT_ID
42
+ type = Rox::Core::CustomPropertyType::STRING
43
+
44
+ Rox::Core::DeviceProperty.new(
45
+ property.name,
46
+ type
47
+ ) do |_|
48
+ SecureRandom.uuid
49
+ end
50
+ end
51
+
52
+ def internal_real_platform
53
+ property = Rox::Core::PropertyType::PLATFORM
54
+ type = Rox::Core::CustomPropertyType::STRING
55
+
56
+ Rox::Core::DeviceProperty.new(
57
+ 'internal.realPlatform',
58
+ type,
59
+ @server_properties.get(property)
60
+ )
61
+ end
62
+
63
+ def internal_custom_platform
64
+ property = Rox::Core::PropertyType::PLATFORM
65
+ type = Rox::Core::CustomPropertyType::STRING
66
+
67
+ Rox::Core::DeviceProperty.new(
68
+ 'internal.customPlatform',
69
+ type,
70
+ @server_properties.get(property)
71
+ )
72
+ end
73
+
74
+ def internal_app_key
75
+ type = Rox::Core::CustomPropertyType::STRING
76
+
77
+ Rox::Core::DeviceProperty.new(
78
+ 'internal.appKey',
79
+ type,
80
+ @server_properties.rollout_key
81
+ )
82
+ end
83
+
84
+ def internal_distinct_id
85
+ type = Rox::Core::CustomPropertyType::STRING
86
+
87
+ Rox::Core::DeviceProperty.new(
88
+ "internal.#{Rox::Core::PropertyType::DISTINCT_ID.name}",
89
+ type
90
+ ) do
91
+ SecureRandom.uuid
92
+ end
93
+ end
94
+
95
+ def internal_lib_version
96
+ type = Rox::Core::CustomPropertyType::SEMVER
97
+
98
+ Rox::Core::DeviceProperty.new(
99
+ 'internal.lib_version',
100
+ type,
101
+ @server_properties.lib_version
102
+ )
103
+ end
104
+
105
+ def internal_api_version
106
+ property = Rox::Core::PropertyType::API_VERSION
107
+ type = Rox::Core::CustomPropertyType::SEMVER
108
+
109
+ Rox::Core::DeviceProperty.new(
110
+ 'internal.api_version',
111
+ type,
112
+ property
113
+ )
114
+ end
115
+
116
+ # rubocop:disable Metrics/MethodLength
117
+ def all_properties
118
+ [
119
+ platform,
120
+ app_release,
121
+ distinct_id,
122
+ internal_real_platform,
123
+ internal_custom_platform,
124
+ internal_app_key,
125
+ internal_distinct_id,
126
+ internal_lib_version,
127
+ internal_api_version
128
+ ]
129
+ end
130
+ end
131
+ end
132
+ end
@@ -7,25 +7,26 @@ module Rox
7
7
  @mutex = Mutex.new
8
8
  end
9
9
 
10
- def register_instance(container, ns)
11
- raise ArgumentError, 'A namespace cannot be null' if ns.nil?
10
+ def register_instance(container, namespace)
11
+ raise ArgumentError, 'A namespace cannot be null' if namespace.nil?
12
12
 
13
13
  @mutex.synchronize do
14
- raise ArgumentError, "A container with the given namespace (#{ns}) has already been registered" if @namespaces.include?(ns)
14
+ if @namespaces.include?(namespace)
15
+ raise ArgumentError,
16
+ "A container with the given namespace (#{namespace}) has already been registered"
17
+ end
15
18
  end
16
19
 
17
- @namespaces << ns
20
+ @namespaces << namespace
18
21
 
19
- container.instance_variables().each do |attribute_name|
22
+ container.instance_variables.each do |attribute_name|
20
23
  begin
21
24
  value = container.instance_variable_get(attribute_name)
22
- if value != nil && value.is_a?(Variant)
23
- var_name = attribute_name.to_s();
24
- # removing the attribute starting @ (if [always] exists)
25
- if (var_name[0] == '@')
26
- var_name[0] = '';
27
- end
28
- @flag_repository.add_flag(value, ns == '' ? var_name : "#{ns}.#{var_name}")
25
+ if !value.nil? && value.is_a?(RoxString)
26
+ var_name = attribute_name.to_s
27
+ # removing the attribute starting @ (if [always] exists)
28
+ var_name[0] = '' if var_name[0] == '@'
29
+ @flag_repository.add_flag(value, namespace == '' ? var_name : "#{namespace}.#{var_name}")
29
30
  end
30
31
  rescue StandardError
31
32
  next
@@ -13,6 +13,7 @@ module Rox
13
13
 
14
14
  def report(message, ex)
15
15
  return if @device_properties.rollout_environment == 'LOCAL'
16
+ return if @device_properties.rox_options.self_managed?
16
17
 
17
18
  Logging.logger.error("Error report: #{message}", ex)
18
19
 
@@ -33,8 +34,8 @@ module Rox
33
34
  begin
34
35
  @request.send_post(ErrorReporter::BUGSNAG_NOTIFY_URL, payload)
35
36
  Logging.logger.debug('Bugsnag error report was sent')
36
- rescue StandardError => ex
37
- Logging.logger.error('Failed to send bugsnag error ', ex)
37
+ rescue StandardError => e
38
+ Logging.logger.error('Failed to send bugsnag error ', e)
38
39
  end
39
40
  end
40
41
 
@@ -49,13 +50,13 @@ module Rox
49
50
 
50
51
  def add_metadata(message, ev)
51
52
  inner_data = {
52
- 'message' => message,
53
- 'deviceId' => @device_properties.distinct_id,
54
- 'buid' => @buid.to_s
53
+ 'message' => message,
54
+ 'deviceId' => @device_properties.distinct_id,
55
+ 'buid' => @buid.to_s
55
56
  }
56
57
 
57
58
  metadata = {
58
- 'data' => inner_data
59
+ 'data' => inner_data
59
60
  }
60
61
 
61
62
  ev['metaData'] = metadata
@@ -88,15 +89,15 @@ module Rox
88
89
 
89
90
  def add_notifier(payload)
90
91
  notifier = {
91
- 'name' => 'Rollout Ruby SDK',
92
- 'version' => @device_properties.lib_version
92
+ 'name' => 'Rollout Ruby SDK',
93
+ 'version' => @device_properties.lib_version
93
94
  }
94
95
  payload['notifier'] = notifier
95
96
  end
96
97
 
97
98
  def add_user(id, rollout_key, ev)
98
99
  user = {
99
- id => rollout_key
100
+ id => rollout_key
100
101
  }
101
102
  ev['user'] = user
102
103
  end
@@ -121,13 +122,13 @@ module Rox
121
122
 
122
123
  def add_app(ev)
123
124
  app = {
124
- 'releaseStage' => @device_properties.rollout_environment,
125
- 'version' => @device_properties.lib_version
125
+ 'releaseStage' => @device_properties.rollout_environment,
126
+ 'version' => @device_properties.lib_version
126
127
  }
127
128
  ev['app'] = app
128
129
  end
129
130
 
130
- STACK_TRACE_LINE_REGEX = /^((?:[a-zA-Z]:)?[^:]+):(\d+)(?::in `([^']+)')?$/
131
+ STACK_TRACE_LINE_REGEX = /^((?:[a-zA-Z]:)?[^:]+):(\d+)(?::in `([^']+)')?$/.freeze
131
132
 
132
133
  def parse_stack_trace(stack_trace)
133
134
  stack = []
@@ -149,4 +150,4 @@ module Rox
149
150
  end
150
151
  end
151
152
  end
152
- end
153
+ end
@@ -5,9 +5,7 @@ module Rox
5
5
  @experiments = []
6
6
  end
7
7
 
8
- def experiments=(experiments)
9
- @experiments = experiments
10
- end
8
+ attr_writer :experiments
11
9
 
12
10
  def experiment_by_flag(flag_name)
13
11
  @experiments.detect { |e| e.flags.include?(flag_name) }
@@ -18,4 +16,4 @@ module Rox
18
16
  end
19
17
  end
20
18
  end
21
- end
19
+ end
@@ -2,29 +2,29 @@ module Rox
2
2
  module Core
3
3
  class FlagRepository
4
4
  def initialize
5
- @variants = {}
5
+ @strings = {}
6
6
  @flag_added_handlers = []
7
7
  @mutex = Mutex.new
8
8
  @handlers_mutex = Mutex.new
9
9
  end
10
10
 
11
- def add_flag(variant, name)
12
- variant.name = name if variant.name.nil? || variant.name.empty?
11
+ def add_flag(string, name)
12
+ string.name = name if string.name.nil? || string.name.empty?
13
13
  @mutex.synchronize do
14
- @variants[name] = variant
14
+ @strings[name] = string
15
15
  end
16
- raise_flag_added_event(variant)
16
+ raise_flag_added_event(string)
17
17
  end
18
18
 
19
19
  def flag(name)
20
20
  @mutex.synchronize do
21
- return @variants[name]
21
+ return @strings[name]
22
22
  end
23
23
  end
24
24
 
25
25
  def all_flags
26
26
  @mutex.synchronize do
27
- return @variants.values
27
+ return @strings.values
28
28
  end
29
29
  end
30
30
 
@@ -11,13 +11,13 @@ module Rox
11
11
  end
12
12
 
13
13
  def extend
14
- @parser.add_operator('mergeSeed') do |parser, stack, context|
14
+ @parser.add_operator('mergeSeed') do |_parser, stack, _context|
15
15
  seed1 = stack.pop
16
16
  seed2 = stack.pop
17
17
  stack.push("#{seed1}.#{seed2}")
18
18
  end
19
19
 
20
- @parser.add_operator('isInPercentage') do |parser, stack, context|
20
+ @parser.add_operator('isInPercentage') do |_parser, stack, _context|
21
21
  percentage = stack.pop
22
22
  seed = stack.pop
23
23
 
@@ -27,7 +27,7 @@ module Rox
27
27
  stack.push(bucket <= percentage)
28
28
  end
29
29
 
30
- @parser.add_operator('isInPercentageRange') do |parser, stack, context|
30
+ @parser.add_operator('isInPercentageRange') do |_parser, stack, _context|
31
31
  percentage_low = stack.pop
32
32
  percentage_high = stack.pop
33
33
  seed = stack.pop
@@ -42,17 +42,17 @@ module Rox
42
42
  @parser.add_operator('flagValue') do |parser, stack, context|
43
43
  feature_flag_identifier = stack.pop
44
44
  result = Flag::FLAG_FALSE_VALUE
45
- variant = @flags_repository.flag(feature_flag_identifier)
45
+ string = @flags_repository.flag(feature_flag_identifier)
46
46
 
47
- if !variant.nil?
48
- result = variant.value(context)
49
- else
47
+ if string.nil?
50
48
  flags_experiment = @experiment_repository.experiment_by_flag(feature_flag_identifier)
51
49
 
52
50
  if !flags_experiment.nil? && !flags_experiment.condition.nil? && !flags_experiment.condition.empty?
53
51
  experiment_eval_result = parser.evaluate_expression(flags_experiment.condition, context).string_value
54
52
  result = experiment_eval_result if !experiment_eval_result.nil? && !experiment_eval_result.empty?
55
53
  end
54
+ else
55
+ result = string.value(context)
56
56
  end
57
57
 
58
58
  stack.push(result)
@@ -79,4 +79,4 @@ module Rox
79
79
  end
80
80
  end
81
81
  end
82
- end
82
+ end