rox-rollout 0.1.3

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 (100) hide show
  1. checksums.yaml +7 -0
  2. data/.circleci/config.yml +45 -0
  3. data/.gitignore +8 -0
  4. data/Gemfile +6 -0
  5. data/LICENSE +50 -0
  6. data/README_DEVELOP.md +19 -0
  7. data/Rakefile +16 -0
  8. data/_archive/.document +5 -0
  9. data/_archive/.rspec +1 -0
  10. data/_archive/Gemfile +15 -0
  11. data/_archive/Gemfile.lock +87 -0
  12. data/_archive/README.md +32 -0
  13. data/_archive/README.rdoc +19 -0
  14. data/_archive/Rakefile +50 -0
  15. data/_archive/lib/expr_function_definition.rb +52 -0
  16. data/_archive/lib/function_definition.rb +48 -0
  17. data/_archive/lib/function_token.rb +12 -0
  18. data/_archive/lib/object_extends.rb +12 -0
  19. data/_archive/lib/ruby_interpreter.rb +292 -0
  20. data/_archive/lib/stack.rb +48 -0
  21. data/_archive/lib/string_extends.rb +14 -0
  22. data/_archive/spec/ruby_interpreter_spec.rb +203 -0
  23. data/_archive/spec/spec_helper.rb +30 -0
  24. data/_archive/spec/stack_spec.rb +77 -0
  25. data/bin/console +14 -0
  26. data/bin/setup +8 -0
  27. data/e2e/container.rb +38 -0
  28. data/e2e/custom_props.rb +55 -0
  29. data/e2e/rox_e2e_test.rb +159 -0
  30. data/e2e/test_vars.rb +24 -0
  31. data/lib/rox.rb +5 -0
  32. data/lib/rox/core/client/buid.rb +82 -0
  33. data/lib/rox/core/client/device_properties.rb +45 -0
  34. data/lib/rox/core/client/internal_flags.rb +20 -0
  35. data/lib/rox/core/client/sdk_settings.rb +5 -0
  36. data/lib/rox/core/configuration/configuration.rb +5 -0
  37. data/lib/rox/core/configuration/configuration_fetched_args.rb +23 -0
  38. data/lib/rox/core/configuration/configuration_fetched_invoker.rb +37 -0
  39. data/lib/rox/core/configuration/configuration_parser.rb +85 -0
  40. data/lib/rox/core/configuration/fetcher_error.rb +13 -0
  41. data/lib/rox/core/configuration/fetcher_status.rb +10 -0
  42. data/lib/rox/core/configuration/models/experiment_model.rb +5 -0
  43. data/lib/rox/core/configuration/models/target_group_model.rb +5 -0
  44. data/lib/rox/core/consts/build.rb +8 -0
  45. data/lib/rox/core/consts/environment.rb +42 -0
  46. data/lib/rox/core/consts/property_type.rb +29 -0
  47. data/lib/rox/core/context/merged_context.rb +16 -0
  48. data/lib/rox/core/core.rb +131 -0
  49. data/lib/rox/core/entities/flag.rb +26 -0
  50. data/lib/rox/core/entities/flag_setter.rb +39 -0
  51. data/lib/rox/core/entities/variant.rb +56 -0
  52. data/lib/rox/core/impression/impression_args.rb +5 -0
  53. data/lib/rox/core/impression/impression_invoker.rb +41 -0
  54. data/lib/rox/core/impression/models/experiment.rb +14 -0
  55. data/lib/rox/core/impression/models/reporting_value.rb +5 -0
  56. data/lib/rox/core/logging/logging.rb +17 -0
  57. data/lib/rox/core/logging/no_op_logger.rb +11 -0
  58. data/lib/rox/core/network/configuration_fetch_result.rb +5 -0
  59. data/lib/rox/core/network/configuration_fetcher.rb +38 -0
  60. data/lib/rox/core/network/configuration_fetcher_base.rb +25 -0
  61. data/lib/rox/core/network/configuration_fetcher_roxy.rb +29 -0
  62. data/lib/rox/core/network/configuration_source.rb +9 -0
  63. data/lib/rox/core/network/request.rb +46 -0
  64. data/lib/rox/core/network/request_configuration_builder.rb +48 -0
  65. data/lib/rox/core/network/request_data.rb +5 -0
  66. data/lib/rox/core/network/response.rb +16 -0
  67. data/lib/rox/core/properties/custom_property.rb +18 -0
  68. data/lib/rox/core/properties/custom_property_type.rb +18 -0
  69. data/lib/rox/core/properties/device_property.rb +11 -0
  70. data/lib/rox/core/register/registerer.rb +35 -0
  71. data/lib/rox/core/reporting/error_reporter.rb +152 -0
  72. data/lib/rox/core/repositories/custom_property_repository.rb +61 -0
  73. data/lib/rox/core/repositories/experiment_repository.rb +21 -0
  74. data/lib/rox/core/repositories/flag_repository.rb +49 -0
  75. data/lib/rox/core/repositories/roxx/experiments_extensions.rb +82 -0
  76. data/lib/rox/core/repositories/roxx/properties_extensions.rb +26 -0
  77. data/lib/rox/core/repositories/target_group_repository.rb +17 -0
  78. data/lib/rox/core/roxx/core_stack.rb +22 -0
  79. data/lib/rox/core/roxx/evaluation_result.rb +28 -0
  80. data/lib/rox/core/roxx/node.rb +11 -0
  81. data/lib/rox/core/roxx/parser.rb +143 -0
  82. data/lib/rox/core/roxx/regular_expression_extensions.rb +33 -0
  83. data/lib/rox/core/roxx/string_tokenizer.rb +68 -0
  84. data/lib/rox/core/roxx/symbols.rb +14 -0
  85. data/lib/rox/core/roxx/token_type.rb +30 -0
  86. data/lib/rox/core/roxx/tokenized_expression.rb +119 -0
  87. data/lib/rox/core/roxx/value_compare_extensions.rb +137 -0
  88. data/lib/rox/core/security/signature_verifier.rb +18 -0
  89. data/lib/rox/core/utils/periodic_task.rb +12 -0
  90. data/lib/rox/core/utils/type_utils.rb +9 -0
  91. data/lib/rox/server/client/sdk_settings.rb +5 -0
  92. data/lib/rox/server/client/server_properties.rb +20 -0
  93. data/lib/rox/server/flags/rox_flag.rb +19 -0
  94. data/lib/rox/server/flags/rox_variant.rb +8 -0
  95. data/lib/rox/server/logging/server_logger.rb +35 -0
  96. data/lib/rox/server/rox_options.rb +27 -0
  97. data/lib/rox/server/rox_server.rb +83 -0
  98. data/lib/rox/version.rb +3 -0
  99. data/rox.gemspec +29 -0
  100. metadata +184 -0
@@ -0,0 +1,26 @@
1
+ require 'rox/core/roxx/token_type'
2
+
3
+ module Rox
4
+ module Core
5
+ class PropertiesExtensions
6
+ def initialize(parser, properties_repository)
7
+ @parser = parser
8
+ @properties_repository = properties_repository
9
+ end
10
+
11
+ def extend
12
+ @parser.add_operator('property') do |parser, stack, context|
13
+ prop_name = stack.pop.to_s
14
+ property = @properties_repository.custom_property(prop_name)
15
+
16
+ if property.nil?
17
+ stack.push(TokenType::UNDEFINED)
18
+ else
19
+ value = property.value(context)
20
+ stack.push(value.nil? ? TokenType::UNDEFINED : value)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,17 @@
1
+ module Rox
2
+ module Core
3
+ class TargetGroupRepository
4
+ def initialize
5
+ @target_groups = []
6
+ end
7
+
8
+ def target_groups=(target_groups)
9
+ @target_groups = target_groups
10
+ end
11
+
12
+ def target_group(id)
13
+ @target_groups.detect { |g| g.id == id }
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,22 @@
1
+ module Rox
2
+ module Core
3
+ class CoreStack
4
+ def initialize
5
+ @items = []
6
+ end
7
+
8
+ def push(item)
9
+ @items << item
10
+ nil
11
+ end
12
+
13
+ def pop
14
+ @items.pop
15
+ end
16
+
17
+ def peek
18
+ @items[-1]
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,28 @@
1
+ require 'rox/core/entities/flag'
2
+ require 'rox/core/utils/type_utils'
3
+
4
+ module Rox
5
+ module Core
6
+ class EvaluationResult
7
+ attr_reader :value
8
+
9
+ def initialize(value)
10
+ @value = value
11
+ end
12
+
13
+ def bool_value
14
+ return false if value.nil?
15
+ return value if Utils.boolean?(value)
16
+ nil
17
+ end
18
+
19
+ def string_value
20
+ return value if value.is_a? String
21
+ return nil if value.nil?
22
+ return Flag::FLAG_TRUE_VALUE if value
23
+ return Flag::FLAG_FALSE_VALUE unless value
24
+ nil
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,11 @@
1
+ module Rox
2
+ module Core
3
+ Node = Struct.new(:type, :value)
4
+
5
+ module NodeTypes
6
+ RAND = 'Rand'.freeze
7
+ RATOR = 'Rator'.freeze
8
+ UNKNOWN = 'Unknown'.freeze
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,143 @@
1
+ require 'digest'
2
+ require 'rox/core/roxx/core_stack'
3
+ require 'rox/core/roxx/evaluation_result'
4
+ require 'rox/core/roxx/value_compare_extensions'
5
+ require 'rox/core/roxx/regular_expression_extensions'
6
+ require 'rox/core/roxx/tokenized_expression'
7
+ require 'rox/core/utils/type_utils'
8
+ require 'rox/core/logging/logging'
9
+
10
+ module Rox
11
+ module Core
12
+ class Parser
13
+ def initialize
14
+ @operators_map = {}
15
+ set_basic_operators
16
+ ValueCompareExtensions.new(self).extend
17
+ RegularExpressionExtensions.new(self).extend
18
+ end
19
+
20
+ def add_operator(oper, &block)
21
+ @operators_map[oper] = block
22
+ end
23
+
24
+ def evaluate_expression(expression, context = nil)
25
+ stack = CoreStack.new
26
+ tokens = TokenizedExpression.new(expression, @operators_map.keys).tokens
27
+ reverse_tokens = tokens.reverse
28
+ begin
29
+ reverse_tokens.each do |token|
30
+ node = token
31
+ if node.type == NodeTypes::RAND
32
+ stack.push(node.value)
33
+ elsif node.type == NodeTypes::RATOR
34
+ handler = @operators_map[node.value]
35
+ handler.call(self, stack, context) unless handler.nil?
36
+ else
37
+ return EvaluationResult.new(nil)
38
+ end
39
+ end
40
+
41
+ result = stack.pop
42
+ result = nil if result == TokenType::UNDEFINED
43
+
44
+ EvaluationResult.new(result)
45
+ rescue StandardError => ex
46
+ Logging.logger.warn("Roxx Exception: Failed evaluate expression: #{ex}")
47
+ EvaluationResult.new(nil)
48
+ end
49
+ end
50
+
51
+ def set_basic_operators
52
+ add_operator('isUndefined') do |parser, stack, context|
53
+ op1 = stack.pop
54
+ if op1.is_a?(TokenType)
55
+ stack.push(op1 == TokenType::UNDEFINED)
56
+ else
57
+ stack.push(false)
58
+ end
59
+ end
60
+
61
+ add_operator('now') do |parser, stack, context|
62
+ stack.push((Time.now.to_f * 1000).to_i)
63
+ end
64
+
65
+ add_operator('and') do |parser, stack, context|
66
+ op1 = stack.pop
67
+ op2 = stack.pop
68
+ op1 = false if op1 == TokenType::UNDEFINED
69
+ op2 = false if op2 == TokenType::UNDEFINED
70
+ raise ArgumentError, 'should be boolean' unless Utils.boolean?(op1) && Utils.boolean?(op2)
71
+ stack.push(op1 && op2)
72
+ end
73
+
74
+ add_operator('or') do |parser, stack, context|
75
+ op1 = stack.pop
76
+ op2 = stack.pop
77
+ op1 = false if op1 == TokenType::UNDEFINED
78
+ op2 = false if op2 == TokenType::UNDEFINED
79
+ raise ArgumentError, 'should be boolean' unless Utils.boolean?(op1) && Utils.boolean?(op2)
80
+ stack.push(op1 || op2)
81
+ end
82
+
83
+ add_operator('ne') do |parser, stack, context|
84
+ op1 = stack.pop
85
+ op2 = stack.pop
86
+ op1 = false if op1 == TokenType::UNDEFINED
87
+ op2 = false if op2 == TokenType::UNDEFINED
88
+ stack.push(op1 != op2)
89
+ end
90
+
91
+ add_operator('eq') do |parser, stack, context|
92
+ op1 = stack.pop
93
+ op2 = stack.pop
94
+ op1 = false if op1 == TokenType::UNDEFINED
95
+ op2 = false if op2 == TokenType::UNDEFINED
96
+ stack.push(op1 == op2)
97
+ end
98
+
99
+ add_operator('not') do |parser, stack, context|
100
+ op1 = stack.pop
101
+ op1 = false if op1 == TokenType::UNDEFINED
102
+ raise ArgumentError, 'should be boolean' unless Utils.boolean?(op1)
103
+ stack.push(!op1)
104
+ end
105
+
106
+ add_operator('ifThen') do |parser, stack, context|
107
+ condition_expression = stack.pop
108
+ true_expression = stack.pop
109
+ false_expression = stack.pop
110
+ raise ArgumentError, 'should be boolean' unless Utils.boolean?(condition_expression)
111
+ if condition_expression
112
+ stack.push(true_expression)
113
+ else
114
+ stack.push(false_expression)
115
+ end
116
+ end
117
+
118
+ add_operator('inArray') do |parser, stack, context|
119
+ op1 = stack.pop
120
+ op2 = stack.pop
121
+ if op2.is_a?(Array)
122
+ stack.push(op2.include?(op1))
123
+ else
124
+ stack.push(false)
125
+ end
126
+ end
127
+
128
+ add_operator('md5') do |parser, stack, context|
129
+ op1 = stack.pop
130
+ raise ArgumentError, 'should be string' unless op1.is_a?(String)
131
+ stack.push(Digest::MD5.hexdigest(op1))
132
+ end
133
+
134
+ add_operator('concat') do |parser, stack, context|
135
+ op1 = stack.pop
136
+ op2 = stack.pop
137
+ raise ArgumentError, 'should be string' unless op1.is_a?(String) && op2.is_a?(String)
138
+ stack.push("#{op1}#{op2}")
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,33 @@
1
+ module Rox
2
+ module Core
3
+ class RegularExpressionExtensions
4
+ def initialize(parser)
5
+ @parser = parser
6
+ end
7
+
8
+ def extend
9
+ @parser.add_operator('match') do |parser, stack, context|
10
+ text = stack.pop
11
+ pattern = stack.pop
12
+ flags = stack.pop
13
+ raise ArgumentError, 'should be string' unless text.is_a?(String) && pattern.is_a?(String) && flags.is_a?(String)
14
+
15
+ options = 0
16
+ flags.each_char do |flag|
17
+ case flag
18
+ when 'i'
19
+ options |= Regexp::IGNORECASE
20
+ when 'x'
21
+ options |= Regexp::EXTENDED
22
+ when 'm'
23
+ options |= Regexp::MULTILINE
24
+ end
25
+ end
26
+
27
+ matched = !Regexp.new(pattern, options).match(text).nil?
28
+ stack.push(matched)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,68 @@
1
+ module Rox
2
+ module Core
3
+ class StringTokenizer
4
+ def initialize(text, delim, return_delims)
5
+ @current_position = 0
6
+ @new_position = -1
7
+ @text = text
8
+ @max_position = text.length
9
+ @delimiters = delim
10
+ @ret_delims = return_delims
11
+ end
12
+
13
+ def skip_delimiters(start_pos)
14
+ raise ArgumentError, 'delimiters is nil' if @delimiters.nil?
15
+
16
+ position = start_pos
17
+ while !@ret_delims && position < @max_position
18
+ c = @text[position]
19
+ break unless delimiter?(c)
20
+ position += 1
21
+ end
22
+ position
23
+ end
24
+
25
+ def scan_token(start_pos)
26
+ position = start_pos
27
+ while position < @max_position
28
+ c = @text[position]
29
+ break if delimiter?(c)
30
+ position += 1
31
+ end
32
+
33
+ if @ret_delims && start_pos == position
34
+ c = @text[position]
35
+ position += 1 if delimiter?(c)
36
+ end
37
+
38
+ position
39
+ end
40
+
41
+ def delimiter?(char)
42
+ @delimiters.include?(char)
43
+ end
44
+
45
+ def more_tokens?
46
+ @new_position = skip_delimiters(@current_position)
47
+ @new_position < @max_position
48
+ end
49
+
50
+ def next_token(delim = nil)
51
+ delims_changed = false
52
+ unless delim.nil?
53
+ @delimiters = delim
54
+ delims_changed = true
55
+ end
56
+
57
+ @current_position = @new_position >= 0 && !delims_changed ? @new_position : skip_delimiters(@current_position)
58
+ @new_position = -1
59
+
60
+ raise ArgumentError, 'invalid operation' if @current_position >= @max_position
61
+
62
+ start = @current_position
63
+ @current_position = scan_token(@current_position)
64
+ @text[start...@current_position]
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,14 @@
1
+ module Rox
2
+ module Core
3
+ module Symbols
4
+ ROXX_UNDEFINED = 'undefined'.freeze
5
+ ROXX_TRUE = 'true'.freeze
6
+ ROXX_FALSE = 'false'.freeze
7
+ ROXX_EMPTY_STRING = '""'.freeze
8
+ ROXX_STRING_TYPE = 'StringType'.freeze
9
+ ROXX_BOOL_TYPE = 'BooleanType'.freeze
10
+ ROXX_NUMBER_TYPE = 'NumberType'.freeze
11
+ ROXX_UNDEFINED_TYPE = 'UndefinedType'.freeze
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,30 @@
1
+ require 'rox/core/roxx/symbols'
2
+
3
+ module Rox
4
+ module Core
5
+ class TokenType
6
+ attr_accessor :text, :pattern
7
+
8
+ def self.from_token(token)
9
+ unless token.nil?
10
+ tested_token = token.downcase
11
+ [TokenType::STRING, TokenType::NUMBER, TokenType::BOOLEAN, TokenType::UNDEFINED].each do |token_type|
12
+ return token_type unless token_type.pattern.match(tested_token).nil?
13
+ end
14
+ end
15
+ TokenType::NOT_A_TYPE
16
+ end
17
+
18
+ def initialize(text, pattern)
19
+ @text = text
20
+ @pattern = Regexp.new(pattern)
21
+ end
22
+
23
+ NOT_A_TYPE = TokenType.new('NOT_A_TYPE', '')
24
+ STRING = TokenType.new(Symbols::ROXX_STRING_TYPE, '"((\\\\.)|[^\\\\"])*"')
25
+ NUMBER = TokenType.new(Symbols::ROXX_NUMBER_TYPE, '[\\-]{0,1}\\d+[\\.]\\d+|[\\-]{0,1}\\d+')
26
+ BOOLEAN = TokenType.new(Symbols::ROXX_BOOL_TYPE, "#{Symbols::ROXX_TRUE}|#{Symbols::ROXX_FALSE}")
27
+ UNDEFINED = TokenType.new(Symbols::ROXX_UNDEFINED_TYPE, Symbols::ROXX_UNDEFINED)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,119 @@
1
+ require 'rox/core/roxx/string_tokenizer'
2
+ require 'rox/core/roxx/node'
3
+ require 'rox/core/roxx/symbols'
4
+ require 'rox/core/roxx/token_type'
5
+
6
+ module Rox
7
+ module Core
8
+ class TokenizedExpression
9
+ DICT_START_DELIMITER = '{'.freeze
10
+ DICT_END_DELIMITER = '}'.freeze
11
+ ARRAY_START_DELIMITER = '['.freeze
12
+ ARRAY_END_DELIMITER = ']'.freeze
13
+ TOKEN_DELIMITERS = "{}[]():, \t\r\n\"".freeze
14
+ PRE_POST_STRING_CHAR = ''.freeze
15
+ STRING_DELIMITER = '"'.freeze
16
+ ESCAPED_QUOTE = '\\"'.freeze
17
+ ESCAPED_QUOTE_PLACEHOLDER = '\\RO_Q'.freeze
18
+
19
+ def initialize(expression, operators)
20
+ @expression = expression
21
+ @operators = operators
22
+ @result_list = nil
23
+ @array_accumulator = nil
24
+ @dict_accumulator = nil
25
+ @dict_key = nil
26
+ end
27
+
28
+ def tokens
29
+ tokenize(@expression)
30
+ end
31
+
32
+ def push_node(node)
33
+ if !@dict_accumulator.nil? && @dict_key.nil?
34
+ @dict_key = node.value.to_s
35
+ elsif !@dict_accumulator.nil? && !@dict_key.nil?
36
+ @dict_accumulator[@dict_key] = node.value
37
+ @dict_key = nil
38
+ elsif !@array_accumulator.nil?
39
+ @array_accumulator << node.value
40
+ else
41
+ @result_list << node
42
+ end
43
+ end
44
+
45
+ def tokenize(expression)
46
+ @result_list = []
47
+ @array_accumulator = nil
48
+ @dict_accumulator = nil
49
+ @dict_key = nil
50
+
51
+ delimiters_to_use = TokenizedExpression::TOKEN_DELIMITERS
52
+ normalized_expression = expression.gsub(TokenizedExpression::ESCAPED_QUOTE, TokenizedExpression::ESCAPED_QUOTE_PLACEHOLDER)
53
+ tokenizer = StringTokenizer.new(normalized_expression, delimiters_to_use, true)
54
+
55
+ token = nil
56
+ while tokenizer.more_tokens?
57
+ prev_token = token
58
+ token = tokenizer.next_token(delimiters_to_use)
59
+ in_string = delimiters_to_use == TokenizedExpression::STRING_DELIMITER
60
+
61
+ if !in_string && token == TokenizedExpression::DICT_START_DELIMITER
62
+ @dict_accumulator = {}
63
+ elsif !in_string && token == TokenizedExpression::DICT_END_DELIMITER
64
+ dict_result = @dict_accumulator
65
+ @dict_accumulator = nil
66
+ push_node(node_from_dict(dict_result))
67
+ elsif !in_string && token == TokenizedExpression::ARRAY_START_DELIMITER
68
+ @array_accumulator = []
69
+ elsif !in_string && token == TokenizedExpression::ARRAY_END_DELIMITER
70
+ array_result = @array_accumulator
71
+ @array_accumulator = nil
72
+ push_node(node_from_array(array_result))
73
+ elsif token == TokenizedExpression::STRING_DELIMITER
74
+ push_node(node_from_token(Symbols::ROXX_EMPTY_STRING)) if prev_token == TokenizedExpression::STRING_DELIMITER
75
+ delimiters_to_use = in_string ? TokenizedExpression::TOKEN_DELIMITERS : TokenizedExpression::STRING_DELIMITER
76
+ else
77
+ if delimiters_to_use == TokenizedExpression::STRING_DELIMITER
78
+ push_node(Node.new(NodeTypes::RAND, token.gsub(TokenizedExpression::ESCAPED_QUOTE_PLACEHOLDER, TokenizedExpression::ESCAPED_QUOTE)))
79
+ elsif !TokenizedExpression::TOKEN_DELIMITERS.include?(token) && token != TokenizedExpression::PRE_POST_STRING_CHAR
80
+ push_node(node_from_token(token))
81
+ end
82
+ end
83
+ end
84
+
85
+ @result_list
86
+ end
87
+
88
+ def node_from_array(items)
89
+ Node.new(NodeTypes::RAND, items)
90
+ end
91
+
92
+ def node_from_dict(items)
93
+ Node.new(NodeTypes::RAND, items)
94
+ end
95
+
96
+ def node_from_token(token)
97
+ return Node.new(NodeTypes::RATOR, token) if @operators.include?(token)
98
+ return Node.new(NodeTypes::RAND, true) if token == Symbols::ROXX_TRUE
99
+ return Node.new(NodeTypes::RAND, false) if token == Symbols::ROXX_FALSE
100
+ return Node.new(NodeTypes::RAND, TokenType::UNDEFINED) if token == Symbols::ROXX_UNDEFINED
101
+
102
+ token_type = TokenType.from_token(token)
103
+ return Node.new(NodeTypes::RAND, token[1...-1]) if token_type == TokenType::STRING
104
+ if token_type == TokenType::NUMBER
105
+ begin
106
+ return Node.new(NodeTypes::RAND, Integer(token))
107
+ rescue ArgumentError
108
+ begin
109
+ return Node.new(NodeTypes::RAND, Float(token))
110
+ rescue ArgumentError => ex
111
+ raise ArgumentError, "Excepted Number, got '#{token}' (#{token_type}): #{ex}"
112
+ end
113
+ end
114
+ end
115
+ Node.new(NodeTypes::UNKNOWN, nil)
116
+ end
117
+ end
118
+ end
119
+ end