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.
- checksums.yaml +5 -5
- data/.circleci/config.yml +51 -23
- data/.editorconfig +12 -0
- data/.github/workflows/ruby.yml +20 -0
- data/.gitignore +2 -0
- data/.rubocop.yml +17 -0
- data/Gemfile +2 -2
- data/README.md +32 -0
- data/Rakefile +12 -9
- data/bin/console +3 -4
- data/e2e-server/run_server.sh +12 -0
- data/e2e-server/server.rb +158 -0
- data/e2e/container.rb +11 -14
- data/e2e/custom_props.rb +9 -9
- data/e2e/rox_e2e_test.rb +18 -20
- data/e2e/test_vars.rb +3 -6
- data/example/local.rb +40 -0
- data/lib/rox/core/analytics.rb +18 -0
- data/lib/rox/core/client/buid.rb +9 -44
- data/lib/rox/core/client/device_properties.rb +8 -2
- data/lib/rox/core/client/dynamic_api.rb +53 -15
- data/lib/rox/core/client/internal_flags.rb +14 -2
- data/lib/rox/core/client/sdk_settings.rb +1 -1
- data/lib/rox/core/configuration/configuration.rb +1 -1
- data/lib/rox/core/configuration/configuration_fetched_args.rb +2 -2
- data/lib/rox/core/configuration/configuration_fetched_invoker.rb +8 -3
- data/lib/rox/core/configuration/configuration_parser.rb +39 -38
- data/lib/rox/core/configuration/fetcher_error.rb +1 -1
- data/lib/rox/core/configuration/fetcher_status.rb +1 -1
- data/lib/rox/core/configuration/models/experiment_model.rb +1 -1
- data/lib/rox/core/configuration/models/target_group_model.rb +1 -1
- data/lib/rox/core/consts/build.rb +3 -3
- data/lib/rox/core/consts/environment.rb +34 -10
- data/lib/rox/core/consts/property_type.rb +18 -17
- data/lib/rox/core/context/merged_context.rb +2 -1
- data/lib/rox/core/core.rb +101 -33
- data/lib/rox/core/entities/default_flag_values.rb +10 -0
- data/lib/rox/core/entities/flag.rb +22 -7
- data/lib/rox/core/entities/flag_setter.rb +6 -6
- data/lib/rox/core/entities/rox_double.rb +11 -0
- data/lib/rox/core/entities/rox_int.rb +11 -0
- data/lib/rox/core/entities/{variant.rb → rox_string.rb} +20 -13
- data/lib/rox/core/error_handling/exception_trigger.rb +10 -0
- data/lib/rox/core/error_handling/userspace_handler_exception.rb +12 -0
- data/lib/rox/core/error_handling/userspace_unhandled_error_invoker.rb +41 -0
- data/lib/rox/core/impression/impression_args.rb +2 -2
- data/lib/rox/core/impression/impression_invoker.rb +41 -7
- data/lib/rox/core/impression/models/experiment.rb +1 -1
- data/lib/rox/core/impression/models/reporting_value.rb +10 -2
- data/lib/rox/core/logging/logging.rb +3 -3
- data/lib/rox/core/logging/no_op_logger.rb +1 -1
- data/lib/rox/core/network/configuration_fetch_result.rb +1 -1
- data/lib/rox/core/network/configuration_fetcher.rb +9 -8
- data/lib/rox/core/network/configuration_fetcher_base.rb +1 -1
- data/lib/rox/core/network/configuration_fetcher_roxy.rb +4 -4
- data/lib/rox/core/network/configuration_fetcher_self_managed.rb +30 -0
- data/lib/rox/core/network/configuration_source.rb +1 -1
- data/lib/rox/core/network/request.rb +3 -3
- data/lib/rox/core/network/request_configuration_builder.rb +12 -9
- data/lib/rox/core/network/request_data.rb +1 -1
- data/lib/rox/core/network/response.rb +20 -4
- data/lib/rox/core/network/state_sender.rb +146 -0
- data/lib/rox/core/notifications/notification_listener.rb +4 -4
- data/lib/rox/core/properties/custom_property.rb +1 -1
- data/lib/rox/core/properties/custom_property_type.rb +1 -1
- data/lib/rox/core/properties/device_property.rb +2 -2
- data/lib/rox/core/properties/property_factory.rb +132 -0
- data/lib/rox/core/register/registerer.rb +13 -12
- data/lib/rox/core/reporting/error_reporter.rb +14 -13
- data/lib/rox/core/repositories/custom_property_repository.rb +1 -1
- data/lib/rox/core/repositories/experiment_repository.rb +2 -4
- data/lib/rox/core/repositories/flag_repository.rb +8 -8
- data/lib/rox/core/repositories/roxx/experiments_extensions.rb +8 -8
- data/lib/rox/core/repositories/roxx/properties_extensions.rb +32 -7
- data/lib/rox/core/repositories/target_group_repository.rb +2 -4
- data/lib/rox/core/roxx/evaluation_result.rb +2 -0
- data/lib/rox/core/roxx/node.rb +1 -1
- data/lib/rox/core/roxx/parser.rb +46 -20
- data/lib/rox/core/roxx/regular_expression_extensions.rb +6 -3
- data/lib/rox/core/roxx/string_tokenizer.rb +3 -1
- data/lib/rox/core/roxx/symbols.rb +1 -1
- data/lib/rox/core/roxx/token_type.rb +1 -1
- data/lib/rox/core/roxx/tokenized_expression.rb +16 -12
- data/lib/rox/core/roxx/value_compare_extensions.rb +49 -29
- data/lib/rox/core/security/signature_verifier.rb +3 -3
- data/lib/rox/core/security/signature_verifier_mock.rb +12 -0
- data/lib/rox/core/utils/debouncer.rb +18 -0
- data/lib/rox/core/utils/type_utils.rb +1 -1
- data/lib/rox/server/client/sdk_settings.rb +1 -1
- data/lib/rox/server/client/server_properties.rb +1 -1
- data/lib/rox/server/flags/normalize_flag_type.rb +25 -0
- data/lib/rox/server/flags/rox_double.rb +8 -0
- data/lib/rox/server/flags/rox_flag.rb +1 -1
- data/lib/rox/server/flags/rox_int.rb +8 -0
- data/lib/rox/server/flags/rox_string.rb +8 -0
- data/lib/rox/server/flags/server_entities_provider.rb +14 -4
- data/lib/rox/server/logging/server_logger.rb +2 -2
- data/lib/rox/server/rox_options.rb +39 -8
- data/lib/rox/server/rox_server.rb +81 -60
- data/lib/rox/version.rb +1 -1
- data/rox.gemspec +13 -9
- metadata +95 -36
- data/README_DEVELOP.md +0 -19
- data/_archive/.document +0 -5
- data/_archive/.rspec +0 -1
- data/_archive/Gemfile +0 -15
- data/_archive/Gemfile.lock +0 -87
- data/_archive/README.md +0 -32
- data/_archive/README.rdoc +0 -19
- data/_archive/Rakefile +0 -50
- data/_archive/lib/expr_function_definition.rb +0 -52
- data/_archive/lib/function_definition.rb +0 -48
- data/_archive/lib/function_token.rb +0 -12
- data/_archive/lib/object_extends.rb +0 -12
- data/_archive/lib/ruby_interpreter.rb +0 -292
- data/_archive/lib/stack.rb +0 -48
- data/_archive/lib/string_extends.rb +0 -14
- data/_archive/spec/ruby_interpreter_spec.rb +0 -203
- data/_archive/spec/spec_helper.rb +0 -30
- data/_archive/spec/stack_spec.rb +0 -77
- data/lib/rox/server/flags/rox_variant.rb +0 -8
@@ -7,25 +7,26 @@ module Rox
|
|
7
7
|
@mutex = Mutex.new
|
8
8
|
end
|
9
9
|
|
10
|
-
def register_instance(container,
|
11
|
-
raise ArgumentError, 'A namespace cannot be null' if
|
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
|
-
|
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 <<
|
20
|
+
@namespaces << namespace
|
18
21
|
|
19
|
-
container.instance_variables
|
22
|
+
container.instance_variables.each do |attribute_name|
|
20
23
|
begin
|
21
24
|
value = container.instance_variable_get(attribute_name)
|
22
|
-
if value
|
23
|
-
var_name = attribute_name.to_s
|
24
|
-
|
25
|
-
if
|
26
|
-
|
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 =>
|
37
|
-
Logging.logger.error('Failed to send bugsnag error ',
|
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
|
-
|
53
|
-
|
54
|
-
|
53
|
+
'message' => message,
|
54
|
+
'deviceId' => @device_properties.distinct_id,
|
55
|
+
'buid' => @buid.to_s
|
55
56
|
}
|
56
57
|
|
57
58
|
metadata = {
|
58
|
-
|
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
|
-
|
92
|
-
|
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
|
-
|
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
|
-
|
125
|
-
|
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
|
-
|
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
|
-
@
|
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(
|
12
|
-
|
11
|
+
def add_flag(string, name)
|
12
|
+
string.name = name if string.name.nil? || string.name.empty?
|
13
13
|
@mutex.synchronize do
|
14
|
-
@
|
14
|
+
@strings[name] = string
|
15
15
|
end
|
16
|
-
raise_flag_added_event(
|
16
|
+
raise_flag_added_event(string)
|
17
17
|
end
|
18
18
|
|
19
19
|
def flag(name)
|
20
20
|
@mutex.synchronize do
|
21
|
-
return @
|
21
|
+
return @strings[name]
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
25
|
def all_flags
|
26
26
|
@mutex.synchronize do
|
27
|
-
return @
|
27
|
+
return @strings.values
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
@@ -46,4 +46,4 @@ module Rox
|
|
46
46
|
end
|
47
47
|
end
|
48
48
|
end
|
49
|
-
end
|
49
|
+
end
|
@@ -11,13 +11,13 @@ module Rox
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def extend
|
14
|
-
@parser.add_operator('mergeSeed') do |
|
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 |
|
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 |
|
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
|
-
|
45
|
+
string = @flags_repository.flag(feature_flag_identifier)
|
46
46
|
|
47
|
-
if
|
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
|
@@ -1,26 +1,51 @@
|
|
1
1
|
require 'rox/core/roxx/token_type'
|
2
|
+
require 'rox/core/error_handling/exception_trigger'
|
3
|
+
require 'rox/core/error_handling/userspace_handler_exception'
|
2
4
|
|
3
5
|
module Rox
|
4
6
|
module Core
|
5
7
|
class PropertiesExtensions
|
6
|
-
def initialize(parser, properties_repository)
|
8
|
+
def initialize(parser, properties_repository, dynamic_property_rule_handler = nil)
|
7
9
|
@parser = parser
|
8
10
|
@properties_repository = properties_repository
|
11
|
+
@dynamic_property_rule_handler = dynamic_property_rule_handler
|
9
12
|
end
|
10
13
|
|
11
14
|
def extend
|
12
|
-
@parser.add_operator('property') do |
|
15
|
+
@parser.add_operator('property') do |_parser, stack, context|
|
13
16
|
prop_name = stack.pop.to_s
|
14
17
|
property = @properties_repository.custom_property(prop_name)
|
18
|
+
value = get_value(prop_name, property, context)
|
15
19
|
|
16
|
-
|
17
|
-
|
20
|
+
stack.push(value.nil? ? TokenType::UNDEFINED : value)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def get_value(prop_name, property, context)
|
27
|
+
if property.nil?
|
28
|
+
if @dynamic_property_rule_handler.nil?
|
29
|
+
TokenType::UNDEFINED
|
18
30
|
else
|
19
|
-
|
20
|
-
stack.push(value.nil? ? TokenType::UNDEFINED : value)
|
31
|
+
get_value_from_dynamic_property_rule_handler(prop_name, context)
|
21
32
|
end
|
33
|
+
else
|
34
|
+
get_value_from_property(property, context)
|
22
35
|
end
|
23
36
|
end
|
37
|
+
|
38
|
+
def get_value_from_dynamic_property_rule_handler(prop_name, context)
|
39
|
+
@dynamic_property_rule_handler.call(prop_name, context)
|
40
|
+
rescue StandardError => e
|
41
|
+
raise Rox::Core::UserspaceHandlerException, handler, ExceptionTrigger::DYNAMIC_PROPERTIES_RULE, e
|
42
|
+
end
|
43
|
+
|
44
|
+
def get_value_from_property(property, context)
|
45
|
+
property.value(context)
|
46
|
+
rescue StandardError => e
|
47
|
+
raise Rox::Core::UserspaceHandlerException, handler, ExceptionTrigger::CUSTOM_PROPERTY_GENERATOR, e
|
48
|
+
end
|
24
49
|
end
|
25
50
|
end
|
26
|
-
end
|
51
|
+
end
|
@@ -5,13 +5,11 @@ module Rox
|
|
5
5
|
@target_groups = []
|
6
6
|
end
|
7
7
|
|
8
|
-
|
9
|
-
@target_groups = target_groups
|
10
|
-
end
|
8
|
+
attr_writer :target_groups
|
11
9
|
|
12
10
|
def target_group(id)
|
13
11
|
@target_groups.detect { |g| g.id == id }
|
14
12
|
end
|
15
13
|
end
|
16
14
|
end
|
17
|
-
end
|
15
|
+
end
|
@@ -13,6 +13,7 @@ module Rox
|
|
13
13
|
def bool_value
|
14
14
|
return false if value.nil?
|
15
15
|
return value if Utils.boolean?(value)
|
16
|
+
|
16
17
|
nil
|
17
18
|
end
|
18
19
|
|
@@ -21,6 +22,7 @@ module Rox
|
|
21
22
|
return nil if value.nil?
|
22
23
|
return Flag::FLAG_TRUE_VALUE if value
|
23
24
|
return Flag::FLAG_FALSE_VALUE unless value
|
25
|
+
|
24
26
|
nil
|
25
27
|
end
|
26
28
|
end
|
data/lib/rox/core/roxx/node.rb
CHANGED
data/lib/rox/core/roxx/parser.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'digest'
|
2
|
+
require 'base64'
|
2
3
|
require 'rox/core/roxx/core_stack'
|
3
4
|
require 'rox/core/roxx/evaluation_result'
|
4
5
|
require 'rox/core/roxx/value_compare_extensions'
|
@@ -6,19 +7,24 @@ require 'rox/core/roxx/regular_expression_extensions'
|
|
6
7
|
require 'rox/core/roxx/tokenized_expression'
|
7
8
|
require 'rox/core/utils/type_utils'
|
8
9
|
require 'rox/core/logging/logging'
|
10
|
+
require 'rox/core/error_handling/userspace_handler_exception'
|
9
11
|
|
10
12
|
module Rox
|
11
13
|
module Core
|
12
14
|
class Parser
|
13
|
-
|
15
|
+
attr_accessor :global_context
|
16
|
+
|
17
|
+
def initialize(user_unhandled_error_invoker)
|
14
18
|
@operators_map = {}
|
19
|
+
@global_context = nil
|
15
20
|
set_basic_operators
|
21
|
+
@user_unhandled_error_invoker = user_unhandled_error_invoker
|
16
22
|
ValueCompareExtensions.new(self).extend
|
17
23
|
RegularExpressionExtensions.new(self).extend
|
18
24
|
end
|
19
25
|
|
20
|
-
def add_operator(
|
21
|
-
@operators_map[
|
26
|
+
def add_operator(operator, &block)
|
27
|
+
@operators_map[operator] = block
|
22
28
|
end
|
23
29
|
|
24
30
|
def evaluate_expression(expression, context = nil)
|
@@ -28,11 +34,12 @@ module Rox
|
|
28
34
|
begin
|
29
35
|
reverse_tokens.each do |token|
|
30
36
|
node = token
|
31
|
-
|
37
|
+
case node.type
|
38
|
+
when NodeTypes::RAND
|
32
39
|
stack.push(node.value)
|
33
|
-
|
40
|
+
when NodeTypes::RATOR
|
34
41
|
handler = @operators_map[node.value]
|
35
|
-
handler
|
42
|
+
handler&.call(self, stack, context)
|
36
43
|
else
|
37
44
|
return EvaluationResult.new(nil)
|
38
45
|
end
|
@@ -42,14 +49,18 @@ module Rox
|
|
42
49
|
result = nil if result == TokenType::UNDEFINED
|
43
50
|
|
44
51
|
EvaluationResult.new(result)
|
45
|
-
rescue
|
46
|
-
|
52
|
+
rescue Rox::Core::UserspaceHandlerException => e
|
53
|
+
@user_unhandled_error_invoker.invoke(e.exception_source, e.exception_trigger, e.exception)
|
54
|
+
Logging.logger.warn("Roxx Exception: Failed evaluate expression, user unhandled expression: #{e}")
|
55
|
+
EvaluationResult.new(nil)
|
56
|
+
rescue StandardError => e
|
57
|
+
Logging.logger.warn("Roxx Exception: Failed evaluate expression: #{e}")
|
47
58
|
EvaluationResult.new(nil)
|
48
59
|
end
|
49
60
|
end
|
50
61
|
|
51
62
|
def set_basic_operators
|
52
|
-
add_operator('isUndefined') do |
|
63
|
+
add_operator('isUndefined') do |_parser, stack, _context|
|
53
64
|
op1 = stack.pop
|
54
65
|
if op1.is_a?(TokenType)
|
55
66
|
stack.push(op1 == TokenType::UNDEFINED)
|
@@ -58,29 +69,31 @@ module Rox
|
|
58
69
|
end
|
59
70
|
end
|
60
71
|
|
61
|
-
add_operator('now') do |
|
72
|
+
add_operator('now') do |_parser, stack, _context|
|
62
73
|
stack.push((Time.now.to_f * 1000).to_i)
|
63
74
|
end
|
64
75
|
|
65
|
-
add_operator('and') do |
|
76
|
+
add_operator('and') do |_parser, stack, _context|
|
66
77
|
op1 = stack.pop
|
67
78
|
op2 = stack.pop
|
68
79
|
op1 = false if op1 == TokenType::UNDEFINED
|
69
80
|
op2 = false if op2 == TokenType::UNDEFINED
|
70
81
|
raise ArgumentError, 'should be boolean' unless Utils.boolean?(op1) && Utils.boolean?(op2)
|
82
|
+
|
71
83
|
stack.push(op1 && op2)
|
72
84
|
end
|
73
85
|
|
74
|
-
add_operator('or') do |
|
86
|
+
add_operator('or') do |_parser, stack, _context|
|
75
87
|
op1 = stack.pop
|
76
88
|
op2 = stack.pop
|
77
89
|
op1 = false if op1 == TokenType::UNDEFINED
|
78
90
|
op2 = false if op2 == TokenType::UNDEFINED
|
79
91
|
raise ArgumentError, 'should be boolean' unless Utils.boolean?(op1) && Utils.boolean?(op2)
|
92
|
+
|
80
93
|
stack.push(op1 || op2)
|
81
94
|
end
|
82
95
|
|
83
|
-
add_operator('ne') do |
|
96
|
+
add_operator('ne') do |_parser, stack, _context|
|
84
97
|
op1 = stack.pop
|
85
98
|
op2 = stack.pop
|
86
99
|
op1 = false if op1 == TokenType::UNDEFINED
|
@@ -88,7 +101,7 @@ module Rox
|
|
88
101
|
stack.push(op1 != op2)
|
89
102
|
end
|
90
103
|
|
91
|
-
add_operator('eq') do |
|
104
|
+
add_operator('eq') do |_parser, stack, _context|
|
92
105
|
op1 = stack.pop
|
93
106
|
op2 = stack.pop
|
94
107
|
op1 = false if op1 == TokenType::UNDEFINED
|
@@ -96,18 +109,20 @@ module Rox
|
|
96
109
|
stack.push(op1 == op2)
|
97
110
|
end
|
98
111
|
|
99
|
-
add_operator('not') do |
|
112
|
+
add_operator('not') do |_parser, stack, _context|
|
100
113
|
op1 = stack.pop
|
101
114
|
op1 = false if op1 == TokenType::UNDEFINED
|
102
115
|
raise ArgumentError, 'should be boolean' unless Utils.boolean?(op1)
|
116
|
+
|
103
117
|
stack.push(!op1)
|
104
118
|
end
|
105
119
|
|
106
|
-
add_operator('ifThen') do |
|
120
|
+
add_operator('ifThen') do |_parser, stack, _context|
|
107
121
|
condition_expression = stack.pop
|
108
122
|
true_expression = stack.pop
|
109
123
|
false_expression = stack.pop
|
110
124
|
raise ArgumentError, 'should be boolean' unless Utils.boolean?(condition_expression)
|
125
|
+
|
111
126
|
if condition_expression
|
112
127
|
stack.push(true_expression)
|
113
128
|
else
|
@@ -115,7 +130,7 @@ module Rox
|
|
115
130
|
end
|
116
131
|
end
|
117
132
|
|
118
|
-
add_operator('inArray') do |
|
133
|
+
add_operator('inArray') do |_parser, stack, _context|
|
119
134
|
op1 = stack.pop
|
120
135
|
op2 = stack.pop
|
121
136
|
if op2.is_a?(Array)
|
@@ -125,7 +140,7 @@ module Rox
|
|
125
140
|
end
|
126
141
|
end
|
127
142
|
|
128
|
-
add_operator('md5') do |
|
143
|
+
add_operator('md5') do |_parser, stack, _context|
|
129
144
|
op1 = stack.pop
|
130
145
|
if op1.is_a?(String)
|
131
146
|
stack.push(Digest::MD5.hexdigest(op1))
|
@@ -134,7 +149,7 @@ module Rox
|
|
134
149
|
end
|
135
150
|
end
|
136
151
|
|
137
|
-
add_operator('concat') do |
|
152
|
+
add_operator('concat') do |_parser, stack, _context|
|
138
153
|
op1 = stack.pop
|
139
154
|
op2 = stack.pop
|
140
155
|
if op1.is_a?(String) && op2.is_a?(String)
|
@@ -143,7 +158,18 @@ module Rox
|
|
143
158
|
stack.push(TokenType::UNDEFINED)
|
144
159
|
end
|
145
160
|
end
|
161
|
+
|
162
|
+
add_operator('b64d') do |_parser, stack, _context|
|
163
|
+
op1 = stack.pop
|
164
|
+
if op1.is_a?(String)
|
165
|
+
decoded = Base64.decode64(op1)
|
166
|
+
decoded = decoded.force_encoding('UTF-8')
|
167
|
+
stack.push(decoded)
|
168
|
+
else
|
169
|
+
stack.push(TokenType::UNDEFINED)
|
170
|
+
end
|
171
|
+
end
|
146
172
|
end
|
147
173
|
end
|
148
174
|
end
|
149
|
-
end
|
175
|
+
end
|