cloudrail_si 0.1.5

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 (90) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +3 -0
  3. data/examples/README.md +3 -0
  4. data/examples/simple/index.rb +11 -0
  5. data/lib/cloudrail_si.rb +41 -0
  6. data/lib/cloudrail_si/RedirectReceivers.rb +40 -0
  7. data/lib/cloudrail_si/Settings.rb +12 -0
  8. data/lib/cloudrail_si/errors/DetailErrors.rb +13 -0
  9. data/lib/cloudrail_si/errors/InternalError.rb +10 -0
  10. data/lib/cloudrail_si/errors/UserError.rb +11 -0
  11. data/lib/cloudrail_si/helpers/Helper.rb +151 -0
  12. data/lib/cloudrail_si/helpers/LimitedReadableStream.rb +55 -0
  13. data/lib/cloudrail_si/helpers/SequenceReadableStream.rb +59 -0
  14. data/lib/cloudrail_si/servicecode/InitSelfTest.rb +92 -0
  15. data/lib/cloudrail_si/servicecode/Interpreter.rb +213 -0
  16. data/lib/cloudrail_si/servicecode/Sandbox.rb +361 -0
  17. data/lib/cloudrail_si/servicecode/VarAddress.rb +11 -0
  18. data/lib/cloudrail_si/servicecode/commands/AwaitCodeRedirect.rb +48 -0
  19. data/lib/cloudrail_si/servicecode/commands/Break.rb +16 -0
  20. data/lib/cloudrail_si/servicecode/commands/CallFunc.rb +26 -0
  21. data/lib/cloudrail_si/servicecode/commands/Clone.rb +18 -0
  22. data/lib/cloudrail_si/servicecode/commands/Concat.rb +22 -0
  23. data/lib/cloudrail_si/servicecode/commands/Conditional.rb +27 -0
  24. data/lib/cloudrail_si/servicecode/commands/Create.rb +56 -0
  25. data/lib/cloudrail_si/servicecode/commands/Delete.rb +21 -0
  26. data/lib/cloudrail_si/servicecode/commands/Get.rb +25 -0
  27. data/lib/cloudrail_si/servicecode/commands/GetMimeType.rb +1005 -0
  28. data/lib/cloudrail_si/servicecode/commands/JumpRel.rb +18 -0
  29. data/lib/cloudrail_si/servicecode/commands/Pull.rb +34 -0
  30. data/lib/cloudrail_si/servicecode/commands/Push.rb +32 -0
  31. data/lib/cloudrail_si/servicecode/commands/Return.rb +16 -0
  32. data/lib/cloudrail_si/servicecode/commands/Set.rb +23 -0
  33. data/lib/cloudrail_si/servicecode/commands/Size.rb +26 -0
  34. data/lib/cloudrail_si/servicecode/commands/ThrowError.rb +17 -0
  35. data/lib/cloudrail_si/servicecode/commands/array/Uint8ToBase64.rb +25 -0
  36. data/lib/cloudrail_si/servicecode/commands/debug/Out.rb +24 -0
  37. data/lib/cloudrail_si/servicecode/commands/hash/md5.rb +29 -0
  38. data/lib/cloudrail_si/servicecode/commands/hash/sha1.rb +30 -0
  39. data/lib/cloudrail_si/servicecode/commands/http/RequestCall.rb +51 -0
  40. data/lib/cloudrail_si/servicecode/commands/json/Parse.rb +40 -0
  41. data/lib/cloudrail_si/servicecode/commands/json/Stringify.rb +21 -0
  42. data/lib/cloudrail_si/servicecode/commands/math/Floor.rb +27 -0
  43. data/lib/cloudrail_si/servicecode/commands/math/MathCombine.rb +35 -0
  44. data/lib/cloudrail_si/servicecode/commands/object/GetKeyArray.rb +21 -0
  45. data/lib/cloudrail_si/servicecode/commands/object/GetKeyValueArrays.rb +29 -0
  46. data/lib/cloudrail_si/servicecode/commands/stream/MakeJoinedStream.rb +38 -0
  47. data/lib/cloudrail_si/servicecode/commands/stream/MakeLimitedStream.rb +23 -0
  48. data/lib/cloudrail_si/servicecode/commands/stream/StreamToString.rb +25 -0
  49. data/lib/cloudrail_si/servicecode/commands/stream/StringToStream.rb +20 -0
  50. data/lib/cloudrail_si/servicecode/commands/string/Base64Encode.rb +42 -0
  51. data/lib/cloudrail_si/servicecode/commands/string/Format.rb +43 -0
  52. data/lib/cloudrail_si/servicecode/commands/string/IndexOf.rb +29 -0
  53. data/lib/cloudrail_si/servicecode/commands/string/LastIndexOf.rb +29 -0
  54. data/lib/cloudrail_si/servicecode/commands/string/Split.rb +29 -0
  55. data/lib/cloudrail_si/servicecode/commands/string/StringTransform.rb +29 -0
  56. data/lib/cloudrail_si/servicecode/commands/string/Substr.rb +30 -0
  57. data/lib/cloudrail_si/servicecode/commands/string/Substring.rb +30 -0
  58. data/lib/cloudrail_si/services/Facebook.rb +528 -0
  59. data/lib/cloudrail_si/services/FacebookPage.rb +310 -0
  60. data/lib/cloudrail_si/services/Foursquare.rb +314 -0
  61. data/lib/cloudrail_si/services/GitHub.rb +354 -0
  62. data/lib/cloudrail_si/services/GooglePlaces.rb +309 -0
  63. data/lib/cloudrail_si/services/GooglePlus.rb +367 -0
  64. data/lib/cloudrail_si/services/Instagram.rb +342 -0
  65. data/lib/cloudrail_si/services/LinkedIn.rb +363 -0
  66. data/lib/cloudrail_si/services/MicrosoftLive.rb +346 -0
  67. data/lib/cloudrail_si/services/Nexmo.rb +173 -0
  68. data/lib/cloudrail_si/services/Slack.rb +318 -0
  69. data/lib/cloudrail_si/services/Twilio.rb +173 -0
  70. data/lib/cloudrail_si/services/Twitter.rb +795 -0
  71. data/lib/cloudrail_si/services/Yahoo.rb +408 -0
  72. data/lib/cloudrail_si/services/Yelp.rb +389 -0
  73. data/lib/cloudrail_si/statistics/Statistics.rb +125 -0
  74. data/lib/cloudrail_si/types/Address.rb +9 -0
  75. data/lib/cloudrail_si/types/Charge.rb +33 -0
  76. data/lib/cloudrail_si/types/CloudMetaData.rb +19 -0
  77. data/lib/cloudrail_si/types/CreditCard.rb +76 -0
  78. data/lib/cloudrail_si/types/Date.rb +49 -0
  79. data/lib/cloudrail_si/types/DateOfBirth.rb +16 -0
  80. data/lib/cloudrail_si/types/Error.rb +21 -0
  81. data/lib/cloudrail_si/types/Location.rb +8 -0
  82. data/lib/cloudrail_si/types/POI.rb +17 -0
  83. data/lib/cloudrail_si/types/Refund.rb +25 -0
  84. data/lib/cloudrail_si/types/SandboxObject.rb +20 -0
  85. data/lib/cloudrail_si/types/SpaceAllocation.rb +13 -0
  86. data/lib/cloudrail_si/types/Subscription.rb +27 -0
  87. data/lib/cloudrail_si/types/SubscriptionPlan.rb +26 -0
  88. data/lib/cloudrail_si/types/Types.rb +43 -0
  89. data/lib/cloudrail_si/version.rb +3 -0
  90. metadata +205 -0
@@ -0,0 +1,213 @@
1
+ require 'json'
2
+
3
+ require_relative '../Helpers/helper'
4
+ require_relative '../servicecode/VarAddress'
5
+
6
+ require_relative './commands/AwaitCodeRedirect'
7
+ require_relative './commands/CallFunc'
8
+ require_relative './commands/Break'
9
+ require_relative './commands/Clone'
10
+ require_relative './commands/Concat'
11
+ require_relative './commands/Conditional'
12
+ require_relative './commands/Create'
13
+ require_relative './commands/Delete'
14
+ require_relative './commands/Get'
15
+ require_relative './commands/GetMimeType'
16
+ require_relative './commands/JumpRel'
17
+ require_relative './commands/Pull'
18
+ require_relative './commands/Push'
19
+ require_relative './commands/Return'
20
+ require_relative './commands/Set'
21
+ require_relative './commands/Size'
22
+ require_relative './commands/ThrowError'
23
+ require_relative './commands/array/Uint8ToBase64'
24
+ require_relative './commands/debug/Out'
25
+ require_relative './commands/hash/Sha1'
26
+ require_relative './commands/hash/Md5'
27
+ require_relative './commands/json/Parse'
28
+ require_relative './commands/json/Stringify'
29
+ require_relative './commands/http/RequestCall'
30
+ require_relative './commands/math/Floor'
31
+ require_relative './commands/math/MathCombine'
32
+ require_relative './commands/object/GetKeyArray'
33
+ require_relative './commands/object/GetKeyValueArrays'
34
+ require_relative './commands/string/Base64Encode'
35
+ require_relative './commands/string/Format'
36
+ require_relative './commands/string/IndexOf'
37
+ require_relative './commands/string/LastIndexOf'
38
+ require_relative './commands/string/Split'
39
+ require_relative './commands/string/StringTransform'
40
+ require_relative './commands/string/Substr'
41
+ require_relative './commands/string/Substring'
42
+ require_relative './commands/stream/StreamToString'
43
+ require_relative './commands/stream/StringToStream'
44
+ require_relative './commands/stream/MakeJoinedStream'
45
+ require_relative './commands/stream/MakeLimitedStream'
46
+
47
+ module CloudRailSi
48
+ module ServiceCode
49
+ class Interpreter
50
+ attr_reader :sandbox
51
+
52
+ def initialize(sandbox)
53
+ @sandbox = sandbox
54
+
55
+ @COMMAND_LIST = [
56
+ CallFunc.new,
57
+ Break.new,
58
+ Clone.new,
59
+ Create.new,
60
+ Delete.new,
61
+ Get.new,
62
+ JumpRel.new,
63
+ Pull.new,
64
+ Push.new,
65
+ Return.new,
66
+ Set.new,
67
+ Size.new,
68
+ Uint8ToBase64.new,
69
+ Sha1.new,
70
+ Md5.new,
71
+ Base64Encode.new,
72
+ StreamToString.new,
73
+ StringToStream.new,
74
+ MakeJoinedStream.new,
75
+ MakeLimitedStream.new,
76
+ RequestCall.new,
77
+ Out.new,
78
+ AwaitCodeRedirect.new,
79
+ GetMimeType.new,
80
+ Conditional.new('if==than', lambda { |c| (c == 0) }, false),
81
+ Conditional.new('if>=than', lambda { |c| (c >= 0) }, true),
82
+ Conditional.new('if>than', lambda { |c| (c > 0) }, true),
83
+ Conditional.new('if<=than', lambda { |c| (c <= 0) }, true),
84
+ Conditional.new('if<than', lambda { |c| (c < 0) }, true),
85
+ Conditional.new('if!=than', lambda { |c| (c != 0) }, false),
86
+ ThrowError.new,
87
+ Parse.new,
88
+ Stringify.new,
89
+ MathCombine.new('math.add', lambda { |elems| elems.reduce(0, :+) }),
90
+ MathCombine.new('math.multiply', lambda { |elems| elems.reduce(1, :*) }),
91
+ MathCombine.new('math.max', lambda { |elems | elems.max }),
92
+ MathCombine.new('math.min', lambda{ |elems | elems | elems.min }),
93
+ Floor.new,
94
+ GetKeyArray.new,
95
+ GetKeyValueArrays.new,
96
+ Concat.new,
97
+ Format.new,
98
+ IndexOf.new,
99
+ LastIndexOf.new,
100
+ Split.new,
101
+ Substr.new,
102
+ Substring.new,
103
+ StringTransform.new('string.lowerCase', lambda { |str| str.downcase }),
104
+ StringTransform.new('string.upperCase', lambda { |str| str.upcase }),
105
+ StringTransform.new('string.urlEncode', lambda { |str| URI::encode_www_form_component(str) }),
106
+ StringTransform.new('string.urlDecode', lambda { |str| URI::decode_www_form_component(str, Encoding::UTF_8) })
107
+ ]
108
+ @COMMANDS = {}
109
+ @COMMAND_LIST.each { |command|
110
+ @COMMANDS[command.get_identifier()] = command
111
+ }
112
+ end
113
+
114
+ def call_function(function_name, *parameters)
115
+ @sandbox.create_new_stack_level(function_name, 0)
116
+ Helper.add_all(@sandbox.current_parameters(), parameters)
117
+ if (@sandbox.current_function_code().nil?)
118
+ error_message = "Service code error: function #{function_name} not found"
119
+ raise Errors::InternalError.new(error_message)
120
+ end
121
+ return run_sync() # this was an async run
122
+ end
123
+
124
+ def call_function_sync(function_name, *parameters)
125
+ @sandbox.create_new_stack_level(function_name, 0)
126
+ Helper.add_all(@sandbox.current_parameters(), parameters)
127
+ if (@sandbox.current_function_code().nil?)
128
+ error_message = "Service code error: function #{function_name} not found"
129
+ raise Errors::InternalError.new(error_message)
130
+ end
131
+ return run_sync()
132
+ end
133
+
134
+ def run
135
+ raise Errors::InternalError.new('interpreter.run not supported.')
136
+ end
137
+
138
+ def run_sync
139
+ begin
140
+ while (@sandbox.current_service_code_line() < @sandbox.current_function_code().length && @sandbox.current_service_code_line() >= 0)
141
+ command = @sandbox.current_function_code()[@sandbox.current_service_code_line()]
142
+ Helper.log "\n\n\n#{command}"
143
+ if (@COMMANDS[command[0]].nil?)
144
+ raise Errors::InternalError.new("Unknown command: #{command[0]}")
145
+ end
146
+ command_parameters = Interpreter.decode_command_parameters(command)
147
+ @COMMANDS[command[0]].execute(@sandbox, command_parameters)
148
+ return if !@sandbox.thrown_error.nil?
149
+ @sandbox.increment_current_service_code_line(1)
150
+ while ((@sandbox.current_service_code_line() >= @sandbox.current_function_code().length ||
151
+ @sandbox.current_service_code_line() < 0) && @sandbox.code_function_name_stack.length > 1)
152
+ @sandbox.return_from_function()
153
+ end
154
+ end
155
+
156
+ rescue => e
157
+ raise e if (e.class.name == CloudRailSi::Errors::UserError)
158
+ error_message = 'Service code error in function ' + @sandbox.current_function_name() + ' at line ' + @sandbox.current_service_code_line().to_s + ' with message: ' + e.message
159
+ raise CloudRailSi::Errors::InternalError.new(error_message)
160
+ end
161
+ end
162
+
163
+ def self.decode_command_parameters(command)
164
+ command_parameters = command.clone[1..-1] # first param was function name
165
+ (0..command_parameters.length).each do |i|
166
+ if (Helper.is_string(command_parameters[i]))
167
+ if (command_parameters[i].index('$') === 0)
168
+ command_parameters[i] = VarAddress.new(command_parameters[i][1..-1])
169
+ elsif (command_parameters[i].index('\\$') === 0)
170
+ command_parameters[i] = command_parameters[i][1..-1]
171
+ end
172
+ end
173
+ end
174
+ return command_parameters
175
+ end
176
+
177
+ def get_parameter(idx)
178
+ @sandbox.get_parameter(idx, 0)
179
+ end
180
+
181
+ def save_as_string
182
+ @sandbox.peristent_storage.to_json
183
+ end
184
+
185
+ def load_as_string(saved_state)
186
+ @sandbox.persistent_storage = JSON.parse(saved_state)
187
+ end
188
+
189
+ def resume_function(function_name, *parameters)
190
+ if (@sandbox.parameters_stack.length === 0)
191
+ first_parameters = []
192
+ @sandbox.parameters_stack.push(first_parameters)
193
+ else
194
+ first_parameters = @sandbox.parameters_stack[0]
195
+ end
196
+ (0..parameters.length).each do |i|
197
+ if (Helper.is_object(parameters[i]))
198
+ m = parameters[i]
199
+ Helper.clear(m)
200
+ Helper.put_all(m, first_parameters[i])
201
+ else
202
+ if (i >= first_parameters.length)
203
+ first_parameters.push(parameters[i])
204
+ else
205
+ first_parameters[i] = parameters[i]
206
+ end
207
+ end
208
+ end
209
+ return run_sync()
210
+ end
211
+ end
212
+ end
213
+ end
@@ -0,0 +1,361 @@
1
+ require_relative './Interpreter'
2
+ require_relative '../errors/InternalError'
3
+ require_relative '../helpers/Helper'
4
+
5
+ module CloudRailSi
6
+ module ServiceCode
7
+ class Sandbox
8
+ attr_reader :thrown_error
9
+ attr_reader :code_function_name_stack
10
+ attr_reader :local_variables_stack
11
+ attr_reader :instance_dependency_storage
12
+ attr_reader :code_line_stack
13
+
14
+ def is_sandbox
15
+ true
16
+ end
17
+
18
+ def initialize(service_code, persistent_storage, instance_dependency_storage)
19
+ @local_variables_stack = []
20
+ @parameters_stack = []
21
+ @code_function_name_stack = []
22
+ @code_line_stack = []
23
+ @persistent_storage = []
24
+ @service_code = service_code
25
+ @persistent_storage = persistent_storage
26
+ @instance_dependency_storage = instance_dependency_storage
27
+ @LIST_MAX_ADD_JUMP_ALLOWED = 32
28
+ @thrown_error = nil
29
+ end
30
+
31
+ def set_thrown_error(thrown_error)
32
+ Helper.debug
33
+ @thrown_error = thrown_error
34
+ end
35
+
36
+ def create_new_stack_level(function_name, code_line)
37
+ @local_variables_stack.push([])
38
+ @parameters_stack.push([])
39
+ @code_function_name_stack.push(function_name)
40
+ @code_line_stack.push(code_line)
41
+ end
42
+
43
+ def current_parameters
44
+ return nil if (@parameters_stack.length === 0)
45
+ @parameters_stack[-1]
46
+ end
47
+
48
+ def current_function_name
49
+ return nil if (@code_function_name_stack.length === 0)
50
+ @code_function_name_stack[-1]
51
+ end
52
+
53
+ def current_function_code
54
+ @service_code[current_function_name()]
55
+ end
56
+
57
+ def current_service_code_line
58
+ return -1 if (@code_line_stack.length === 0)
59
+ return @code_line_stack[-1]
60
+ end
61
+
62
+ def increment_current_service_code_line(amount)
63
+ @code_line_stack[-1] += amount if @code_line_stack.length
64
+ end
65
+ def return_from_function
66
+ return if (@code_function_name_stack.length <= 1)
67
+
68
+ call_function_command_parameters = Interpreter.decode_command_parameters(@service_code[@code_function_name_stack[-2]][@code_line_stack[-2]])
69
+
70
+ (0..call_function_command_parameters.length - 1).each do |i|
71
+ parameter_var = call_function_command_parameters[i]
72
+ if Helper.is_var_address(parameter_var)
73
+ value = @parameters_stack[-1][i - 1]
74
+ set_variable(parameter_var, value, -2)
75
+ end
76
+ end
77
+ @code_function_name_stack.pop()
78
+ @code_line_stack.pop()
79
+ @local_variables_stack.pop()
80
+ @parameters_stack.pop()
81
+ increment_current_service_code_line(1)
82
+ end
83
+ def set_variable(var_address, value, stacklevel=-1)
84
+ if Helper.is_var_address(var_address)
85
+ var_address_parts = decode_variable_address(var_address)
86
+ else
87
+ var_address_parts = var_address
88
+ end
89
+
90
+ variables = get_stack_for_address_part(var_address_parts[0], stacklevel)
91
+ var_idx = var_address_parts[1]
92
+ if (var_address_parts.length <= 2)
93
+ if (variables.length == var_idx)
94
+ variables.push(value)
95
+ elsif (variables.length > var_idx)
96
+ variables[var_idx] = value
97
+ elsif (variables.length + @LIST_MAX_ADD_JUMP_ALLOWED > var_idx)
98
+ (0..var_idx - variables.length + 1).each do |i|
99
+ variables.push(nil)
100
+ end
101
+ variables[var_idx] = value
102
+ else
103
+ raise Errors::InternalError.new("Could not decode variable #{var_address_parts.join(':')}")
104
+ end
105
+ return true
106
+ end
107
+
108
+ return set_entry(variables[var_idx], var_address_parts[2..-1], value)
109
+ end
110
+
111
+ def get_variable(var_address, stacklevel=-1, empty_is_null=false)
112
+ if Helper.is_var_address(var_address)
113
+ var_address_parts = decode_variable_address(var_address)
114
+ else
115
+ var_address_parts = var_address
116
+ end
117
+ variables = get_stack_for_address_part(var_address_parts[0], stacklevel)
118
+
119
+ return nil if (empty_is_null && var_address_parts[1] >= variables.length)
120
+
121
+ local_entry = variables[var_address_parts[1]]
122
+ return local_entry if (var_address_parts.length <= 2)
123
+ get_entry(local_entry, var_address_parts[2..-1], empty_is_null)
124
+ end
125
+
126
+ def delete_variable(var_address_parts, stacklevel=-1)
127
+ variables = get_stack_for_address_part(var_address_parts[0], stacklevel)
128
+ var_idx = var_address_parts[1]
129
+ if (var_address_parts.length <= 2)
130
+ variables[var_idx] = nil if (var_idx < variables.length)
131
+ return true
132
+ end
133
+ delete_entry(variables[var_idx], var_address_parts[2..-1])
134
+ end
135
+ def get_stack_for_address_part(part, stacklevel)
136
+ if (part == 'L')
137
+ variables = @local_variables_stack[stacklevel]
138
+ elsif (part == 'P')
139
+ variables = @parameters_stack[stacklevel]
140
+ elsif (part == 'S')
141
+ variables = @persistent_storage
142
+ else
143
+ raise Errors::InternalError.new("Could not attribute variable part #{part}")
144
+ end
145
+ return variables
146
+ end
147
+
148
+ def decode_variable_address(var_address)
149
+ dec_adr = []
150
+ adr = var_address.instance_variable_get(:@address_string)
151
+ Helper.assert(adr[0] != '$')
152
+ if (adr[0] < '0' || adr[0] > '9')
153
+ dec_adr.push(adr[0])
154
+ adr = adr[1..-1]
155
+ end
156
+ adr_parts = adr.split('.')
157
+ (0..adr_parts.length - 1).each do |i|
158
+ part = adr_parts[i]
159
+ if (Helper.is_number_string(part))
160
+ dec_adr.push(Integer(part))
161
+ else
162
+ dec_adr.push(part)
163
+ end
164
+ end
165
+ return dec_adr
166
+ end
167
+
168
+ def set_entry(container, var_address, value)
169
+ if (var_address.length > 1)
170
+ next_container = get_entry(container, var_address[0..-2], false)
171
+
172
+ return set_entry(next_container, var_address[1..-1], value)
173
+ end
174
+ var_address_part = var_address[0]
175
+
176
+ if (Helper.is_array(container))
177
+ if (Helper.is_number_string(var_address_part))
178
+ var_address_part = Integer(var_address_part)
179
+ end
180
+ if (!Helper.is_number(var_address_part) || var_address_part >= container.length)
181
+ raise Errors::InternalError.new('Invalid index while indexing into an array')
182
+ end
183
+ idx = var_address_part
184
+ list = container
185
+ if (list.length + @LIST_MAX_ADD_JUMP_ALLOWED <= idx)
186
+ (idx - list.length + 1).times do |i|
187
+ list.push(nil)
188
+ end
189
+ end
190
+ list[idx] = value
191
+ elsif (Helper.is_object(container))
192
+ if (!Helper.is_string(var_address_part))
193
+ var_address_part = var_address_part.to_s
194
+ end
195
+
196
+ #There are three ways to interpret an address; we try them all
197
+ begin
198
+ container.instance_variable_set('@' + var_address_part, value)
199
+ rescue
200
+ end
201
+ begin
202
+ container.send(Helper.to_snake_case(var_address_part) + "=", value)
203
+ rescue
204
+ end
205
+ begin
206
+ container[var_address_part] = value
207
+ rescue
208
+ end
209
+ elsif Helper.is_sandbox(container)
210
+ if (!Helper.is_string(var_address_part))
211
+ var_address_part = var_address_part.to_s
212
+ end
213
+ container.set(var_address_part, value)
214
+ end
215
+ return false
216
+ end
217
+ def get_entry(container, var_address, empty_is_null)
218
+ entry = ''
219
+ var_address_part = var_address[0]
220
+ if (Helper.is_array(container) || Helper.is_string(container))
221
+ if (Helper.is_number_string(var_address_part))
222
+ var_address_part = Integer(var_address_part)
223
+ end
224
+ if (!Helper.is_number(var_address_part))
225
+ var_address_part = 0 #TODO: for paypal, transactions is missing if the count is zero; this "fixes" it but might break other things.
226
+ # raise Errors::InternalError.new('Invalid index while indexing into an array or string')
227
+ end
228
+ if (!(empty_is_null && var_address_part >= container.length))
229
+ entry = container[var_address_part]
230
+ end
231
+ elsif (Helper.is_object(container))
232
+ if (!Helper.is_string(var_address_part))
233
+ var_address_part = var_address_part.to_s
234
+ end
235
+ if (container.nil? && (!empty_is_null))
236
+ entry = {}
237
+ else
238
+ begin
239
+ entry = container.instance_variable_get('@' + var_address_part) # will fail if var_address_part starts with a number; set to nil if doesn't exist
240
+ rescue
241
+ end
242
+ if !entry
243
+ begin
244
+ entry = container[var_address_part]
245
+ rescue
246
+ begin
247
+ entry = container.send(Helper.to_snake_case(var_address_part))
248
+ rescue
249
+ entry = {}
250
+ Helper.debug
251
+ end
252
+ end
253
+ end
254
+ end
255
+ elsif Helper.is_sandbox(container)
256
+ if (!Helper.is_string(var_address_part))
257
+ var_address_part = var_address_part.to_s
258
+ end
259
+ entry = container.get(var_address_part)
260
+ end
261
+ if (var_address.length > 1)
262
+ return get_entry( entry, var_address[1..-1], empty_is_null)
263
+ end
264
+ return entry
265
+ end
266
+ def delete_entry(container, var_address)
267
+ if (var_address.length > 1)
268
+ next_container = get_entry(container, var_address, false)
269
+ return delete_entry(next_container, var_address[1..-1])
270
+ end
271
+ var_address_part = var_address[0]
272
+ if (Helper.is_array(container))
273
+ if (Helper.is_number_string(var_address_part))
274
+ var_address_part = Integer(var_address_part)
275
+ end
276
+ if (!Helper.is_number(var_address_part) || var_address_part >= container.length)
277
+ raise Errors::InternalError.new('Invalid index while indexing into an array')
278
+ end
279
+ idx = var_address_part
280
+ list = container
281
+ if (idx < list.length)
282
+ list.delete_at(idx)
283
+ end
284
+ while (list.length && list[-1].nil?)
285
+ list.pop()
286
+ end
287
+ elsif (Helper.is_object(container))
288
+ var_address_part = var_address_part.to_s
289
+ container.delete(var_address_part)
290
+ elsif Helper.is_sandbox(container)
291
+ var_address_part = var_address_part.to_s
292
+ container.set(var_address_part, nil)
293
+ end
294
+ return false
295
+ end
296
+ def call_function(function_name, parameters)
297
+ create_new_stack_level(function_name, -1)
298
+ parameter_stack = current_parameters()
299
+ Helper.add_all(parameter_stack, parameters)
300
+ end
301
+ def compare_variables(a_obj, b_obj, command_id, type_check)
302
+ a_obj = Helper.resolve(self, a_obj, false)
303
+ b_obj = Helper.resolve(self, b_obj, false)
304
+ if (!type_check && (a_obj.nil? || b_obj.nil?))
305
+ return 0 if (a_obj.nil? && b_obj.nil?)
306
+ return -1
307
+ end
308
+
309
+ if ((a_obj.is_a? Numeric) && (b_obj.is_a? Numeric))
310
+ # doesn't matter if one is int and other is float
311
+ elsif (a_obj.class != b_obj.class)
312
+ Helper.debug
313
+ return -1 if !type_check
314
+ raise Errors::InternalError.new("Command #{command_id} compares arguments of different types")
315
+ end
316
+
317
+ return Helper.compare(a_obj, b_obj)
318
+ end
319
+ def save_state_to_string
320
+ savelist = []
321
+ savelist.push(@code_function_name_stack)
322
+ savelist.push(@code_line_stack)
323
+ savelist.push(@local_variables_stack)
324
+ savelist.push(@parameters_stack)
325
+ savelist.push(@persistent_storage)
326
+ as_json = savelist.to_json
327
+ # TODO: Add support for objects such as CustomDate
328
+
329
+ return as_json
330
+ end
331
+ def load_state_from_string(saved_state)
332
+ savelist = JSON.parse(saved_state)
333
+
334
+ # TODO: Add support for objects such as CustomDate
335
+ @code_function_name_stack = savelist[0]
336
+ @code_line_stack = savelist[1]
337
+ @local_variables_stack = savelist[2]
338
+ merge_stacks = lambda { |json_stack, stack|
339
+ (json_stack.length).times do |i|
340
+ if (i >= stack.length)
341
+ stack.push(json_stack[i])
342
+ else
343
+ stack[i] = json_stack[i]
344
+ end
345
+ end
346
+ }
347
+ json_parameters_stack = savelist[3]
348
+ json_persistent_storage = savelist[4]
349
+ merge_stacks(json_parameters_stack, @parameters_stack)
350
+ merge_stacks(json_persistent_storage, @persistent_storage)
351
+ end
352
+ def get_parameter(idx, stacklevel)
353
+ return nil if (@parameters_stack.length === 0 || stacklevel >= @parameters_stack.length || idx >= @parameters_stack[stacklevel].length)
354
+ @parameters_stack[stacklevel][idx]
355
+ end
356
+ def get_params_stack
357
+ @parameters_stack
358
+ end
359
+ end
360
+ end
361
+ end