gloo 7.0.4 → 7.1.1
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 +4 -4
- data/README.md +2 -1
- data/docs/application.md +16 -2
- data/docs/development.md +1 -1
- data/docs/iterators.md +24 -0
- data/docs/language_objects.md +34 -0
- data/docs/language_syntax.md +26 -1
- data/docs/objects.md +1 -1
- data/docs/plugins.md +10 -4
- data/docs/testing.md +206 -0
- data/docs/verbs.md +7 -0
- data/lib/VERSION +1 -1
- data/lib/VERSION_NOTES +18 -2
- data/lib/gloo/app/engine.rb +19 -9
- data/lib/gloo/app/log.rb +2 -2
- data/lib/gloo/app/settings.rb +20 -3
- data/lib/gloo/core/gloo_system.rb +7 -0
- data/lib/gloo/core/invoker.rb +20 -7
- data/lib/gloo/core/obj.rb +22 -1
- data/lib/gloo/core/tokens.rb +20 -0
- data/lib/gloo/core/verb.rb +31 -0
- data/lib/gloo/exec/exec_env.rb +6 -3
- data/lib/gloo/exec/script.rb +7 -0
- data/lib/gloo/objs/basic/script.rb +9 -0
- data/lib/gloo/objs/basic/string_msgs.rb +6 -7
- data/lib/gloo/objs/basic/untyped.rb +2 -1
- data/lib/gloo/objs/ctrl/each.rb +4 -2
- data/lib/gloo/objs/ctrl/each_child.rb +1 -1
- data/lib/gloo/objs/ctrl/each_dir.rb +1 -1
- data/lib/gloo/objs/ctrl/each_file.rb +1 -1
- data/lib/gloo/objs/ctrl/each_line.rb +1 -1
- data/lib/gloo/objs/ctrl/each_word.rb +1 -1
- data/lib/gloo/objs/ctrl/repeat.rb +5 -3
- data/lib/gloo/objs/str_utils/cipher.rb +10 -2
- data/lib/gloo/objs/system/file_handle.rb +5 -2
- data/lib/gloo/objs/web/json.rb +7 -5
- data/lib/gloo/persist/declaration_ledger.rb +6 -6
- data/lib/gloo/persist/file_loader.rb +11 -1
- data/lib/gloo/persist/file_storage.rb +8 -2
- data/lib/gloo/persist/persist_man.rb +29 -1
- data/lib/gloo/verbs/break.rb +7 -2
- data/lib/gloo/verbs/context.rb +10 -2
- data/lib/gloo/verbs/eval.rb +5 -4
- data/lib/gloo/verbs/exists.rb +14 -2
- data/lib/gloo/verbs/invoke.rb +7 -6
- data/lib/gloo/verbs/load.rb +16 -2
- data/lib/gloo/verbs/log.rb +8 -4
- data/lib/gloo/verbs/save.rb +10 -3
- data/lib/gloo/verbs/show.rb +15 -10
- data/test.gloo/ctrl/each.test.gloo +21 -7
- data/test.gloo/lang/declaration.test.gloo +7 -2
- data/test.gloo/lang/exceptions.test.gloo +22 -0
- data/test.gloo/lang/gloo_sys.test.gloo +12 -0
- data/test.gloo/lang/naming.test.gloo +7 -2
- data/test.gloo/objs/cipher.test.gloo +27 -0
- data/test.gloo/objs/file.test.gloo +18 -2
- data/test.gloo/objs/fixtures/source_dir_fixture.gloo +6 -0
- data/test.gloo/objs/int.test.gloo +6 -3
- data/test.gloo/objs/json.test.gloo +2 -0
- data/test.gloo/objs/obj.test.gloo +33 -0
- data/test.gloo/objs/string.test.gloo +2 -2
- data/test.gloo/verbs/break.test.gloo +66 -0
- data/test.gloo/verbs/context.test.gloo +12 -0
- data/test.gloo/verbs/eval.test.gloo +8 -0
- data/test.gloo/verbs/exists.test.gloo +19 -0
- data/test.gloo/verbs/invoke.test.gloo +50 -0
- data/test.gloo/verbs/load.test.gloo +101 -2
- data/test.gloo/verbs/log.test.gloo +16 -0
- data/test.gloo/verbs/reload.test.gloo +9 -4
- data/test.gloo/verbs/save.test.gloo +41 -16
- data/test.gloo/verbs/show.test.gloo +32 -0
- metadata +5 -6
data/lib/gloo/app/settings.rb
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
#
|
|
6
6
|
|
|
7
7
|
require 'yaml'
|
|
8
|
+
require 'fileutils'
|
|
8
9
|
|
|
9
10
|
module Gloo
|
|
10
11
|
module App
|
|
@@ -137,9 +138,6 @@ module Gloo
|
|
|
137
138
|
@ext_path = File.join( @user_root, 'extensions' )
|
|
138
139
|
Dir.mkdir( @ext_path ) unless File.exist?( @ext_path )
|
|
139
140
|
|
|
140
|
-
@tmp_path = File.join( @user_root, 'tmp' )
|
|
141
|
-
Dir.mkdir( @tmp_path ) unless File.exist?( @tmp_path )
|
|
142
|
-
|
|
143
141
|
@debug_path = File.join( @user_root, 'debug' )
|
|
144
142
|
Dir.mkdir( @debug_path ) unless File.exist?( @debug_path )
|
|
145
143
|
end
|
|
@@ -156,6 +154,8 @@ module Gloo
|
|
|
156
154
|
@project_path = File.join( @user_root, 'projects' )
|
|
157
155
|
end
|
|
158
156
|
|
|
157
|
+
init_tmp_path( settings[ 'gloo' ][ 'tmp_path' ] )
|
|
158
|
+
|
|
159
159
|
@start_with = settings[ 'gloo' ][ 'start_with' ]
|
|
160
160
|
@list_indent = settings[ 'gloo' ][ 'list_indent' ]
|
|
161
161
|
@list_levels = settings[ 'gloo' ][ 'list_levels' ]
|
|
@@ -167,6 +167,16 @@ module Gloo
|
|
|
167
167
|
@theme = DEFAULT_THEME unless THEMES.include?( @theme )
|
|
168
168
|
end
|
|
169
169
|
|
|
170
|
+
#
|
|
171
|
+
# Set the tmp folder: the tmp_path setting if there is one (a
|
|
172
|
+
# leading ~ is expanded), or tmp under the user root. Created
|
|
173
|
+
# if it isn't there yet.
|
|
174
|
+
#
|
|
175
|
+
def init_tmp_path( path )
|
|
176
|
+
@tmp_path = path.blank? ? File.join( @user_root, 'tmp' ) : File.expand_path( path.to_s )
|
|
177
|
+
FileUtils.mkdir_p( @tmp_path ) unless File.exist?( @tmp_path )
|
|
178
|
+
end
|
|
179
|
+
|
|
170
180
|
#
|
|
171
181
|
# Get the app's required directories.
|
|
172
182
|
#
|
|
@@ -188,6 +198,7 @@ module Gloo
|
|
|
188
198
|
#
|
|
189
199
|
def get_default_settings
|
|
190
200
|
projects = File.join( @user_root, 'projects' )
|
|
201
|
+
tmp = File.join( @user_root, 'tmp' )
|
|
191
202
|
str = <<~TEXT
|
|
192
203
|
#
|
|
193
204
|
# Gloo configuration
|
|
@@ -200,6 +211,12 @@ module Gloo
|
|
|
200
211
|
#
|
|
201
212
|
project_path: #{projects}
|
|
202
213
|
|
|
214
|
+
#
|
|
215
|
+
# Folder for temporary files, such as scratch files written by
|
|
216
|
+
# tests. Scripts get it with $.gloo_tmp.
|
|
217
|
+
#
|
|
218
|
+
tmp_path: #{tmp}
|
|
219
|
+
|
|
203
220
|
#
|
|
204
221
|
# Run this script when starting up gloo.
|
|
205
222
|
# (Only if a script file is not specified.)
|
|
@@ -179,6 +179,11 @@ module Gloo
|
|
|
179
179
|
return @engine.settings.project_path
|
|
180
180
|
end
|
|
181
181
|
|
|
182
|
+
# Get the Gloo tmp directory
|
|
183
|
+
def msg_gloo_tmp
|
|
184
|
+
return @engine.settings.tmp_path
|
|
185
|
+
end
|
|
186
|
+
|
|
182
187
|
# The running app directory.
|
|
183
188
|
def msg_app
|
|
184
189
|
return @engine.settings.project_path
|
|
@@ -314,6 +319,8 @@ module Gloo
|
|
|
314
319
|
'gloo_config — Get the gloo configuration directory.',
|
|
315
320
|
'gloo_projects — Get the gloo projects directory.',
|
|
316
321
|
'gloo_log — Get the gloo logging directory.',
|
|
322
|
+
'gloo_tmp — Get the gloo tmp directory, for temporary files ' \
|
|
323
|
+
'(the tmp_path setting in gloo.yml).',
|
|
317
324
|
'screen_lines — Get the number of lines on screen.',
|
|
318
325
|
'screen_cols — Get the number of columns on screen.',
|
|
319
326
|
'platform_cpu — Get the platform CPU.',
|
data/lib/gloo/core/invoker.rb
CHANGED
|
@@ -18,26 +18,39 @@ module Gloo
|
|
|
18
18
|
#
|
|
19
19
|
# Resolve, validate and invoke the function at the given
|
|
20
20
|
# target path, with the given raw (unevaluated) arg tokens.
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
# unreliable result when that happens).
|
|
21
|
+
# For any failure, reports an error, puts false in `it` and
|
|
22
|
+
# returns nil - before the call (see failed), or inside the
|
|
23
|
+
# function itself (see Function#invoke).
|
|
25
24
|
#
|
|
26
25
|
def self.invoke( engine, target, arg_tokens )
|
|
27
26
|
if target.nil? || target.to_s.strip.empty?
|
|
28
27
|
engine.syntax_err NO_TARGET_ERR
|
|
29
|
-
return
|
|
28
|
+
return failed( engine )
|
|
30
29
|
end
|
|
31
30
|
|
|
32
31
|
func = resolve_function( engine, target )
|
|
33
|
-
return
|
|
32
|
+
return failed( engine ) unless func
|
|
34
33
|
|
|
34
|
+
# An arg that couldn't be worked out was already reported, but
|
|
35
|
+
# the function's own error tracking would clear it if the call
|
|
36
|
+
# went ahead.
|
|
37
|
+
errors_before = engine.heap.error.error_count
|
|
35
38
|
args = evaluate_arg_tokens( engine, arg_tokens )
|
|
36
|
-
return
|
|
39
|
+
return failed( engine ) if engine.heap.error.error_count > errors_before
|
|
40
|
+
return failed( engine ) unless params_count_ok?( engine, func, args )
|
|
37
41
|
|
|
38
42
|
return invoke_function( engine, func, args )
|
|
39
43
|
end
|
|
40
44
|
|
|
45
|
+
#
|
|
46
|
+
# The function couldn't be called (the problem was already
|
|
47
|
+
# reported): put false in `it`, and return nil.
|
|
48
|
+
#
|
|
49
|
+
def self.failed( engine )
|
|
50
|
+
engine.heap.it.set_to false
|
|
51
|
+
return nil
|
|
52
|
+
end
|
|
53
|
+
|
|
41
54
|
#
|
|
42
55
|
# Resolve the function object at the target path. Reports an
|
|
43
56
|
# error and returns nil if the path doesn't resolve to
|
data/lib/gloo/core/obj.rb
CHANGED
|
@@ -338,7 +338,7 @@ module Gloo
|
|
|
338
338
|
# Get a list of message names that this object receives.
|
|
339
339
|
#
|
|
340
340
|
def self.messages
|
|
341
|
-
return %w[save reload unload blank? contains? responds_to? doc]
|
|
341
|
+
return %w[save reload unload blank? contains? responds_to? doc source_file source_dir]
|
|
342
342
|
end
|
|
343
343
|
|
|
344
344
|
#
|
|
@@ -492,6 +492,27 @@ module Gloo
|
|
|
492
492
|
return self.doc
|
|
493
493
|
end
|
|
494
494
|
|
|
495
|
+
#
|
|
496
|
+
# The path of the file this object was loaded from, into 'it';
|
|
497
|
+
# blank if it didn't come from a file.
|
|
498
|
+
#
|
|
499
|
+
def msg_source_file
|
|
500
|
+
path = @engine.persist_man.source_file_of( self ).to_s
|
|
501
|
+
@engine.heap.it.set_to path
|
|
502
|
+
return path
|
|
503
|
+
end
|
|
504
|
+
|
|
505
|
+
#
|
|
506
|
+
# The folder of the file this object was loaded from, with no
|
|
507
|
+
# trailing slash, into 'it'; blank if it didn't come from a file.
|
|
508
|
+
#
|
|
509
|
+
def msg_source_dir
|
|
510
|
+
path = @engine.persist_man.source_file_of( self )
|
|
511
|
+
dir = path ? File.dirname( path ) : ''
|
|
512
|
+
@engine.heap.it.set_to dir
|
|
513
|
+
return dir
|
|
514
|
+
end
|
|
515
|
+
|
|
495
516
|
|
|
496
517
|
# ---------------------------------------------------------------------
|
|
497
518
|
# Render
|
data/lib/gloo/core/tokens.rb
CHANGED
|
@@ -176,6 +176,17 @@ module Gloo
|
|
|
176
176
|
return nil
|
|
177
177
|
end
|
|
178
178
|
|
|
179
|
+
#
|
|
180
|
+
# A copy of these tokens with one more token added at the end,
|
|
181
|
+
# taken as is (not split on spaces or quotes). The original is
|
|
182
|
+
# left alone.
|
|
183
|
+
#
|
|
184
|
+
def with_token( token )
|
|
185
|
+
copy = dup
|
|
186
|
+
copy.append_token token
|
|
187
|
+
return copy
|
|
188
|
+
end
|
|
189
|
+
|
|
179
190
|
#
|
|
180
191
|
# Get the item after a given token.
|
|
181
192
|
#
|
|
@@ -186,6 +197,15 @@ module Gloo
|
|
|
186
197
|
return nil
|
|
187
198
|
end
|
|
188
199
|
|
|
200
|
+
protected
|
|
201
|
+
|
|
202
|
+
#
|
|
203
|
+
# Add a token at the end, in a new list (see with_token).
|
|
204
|
+
#
|
|
205
|
+
def append_token( token )
|
|
206
|
+
@tokens += [ token ]
|
|
207
|
+
end
|
|
208
|
+
|
|
189
209
|
# ---------------------------------------------------------------------
|
|
190
210
|
# Private functions
|
|
191
211
|
# ---------------------------------------------------------------------
|
data/lib/gloo/core/verb.rb
CHANGED
|
@@ -83,6 +83,37 @@ module Gloo
|
|
|
83
83
|
return true
|
|
84
84
|
end
|
|
85
85
|
|
|
86
|
+
#
|
|
87
|
+
# For a verb whose arguments are literal text (a file name, a
|
|
88
|
+
# path, a name): a trailing ( expr ) is worked out and its value
|
|
89
|
+
# added as the last argument, so the text can be computed, as in
|
|
90
|
+
# load ( $.gloo_tmp '/x.gloo' ). The parser has already split the
|
|
91
|
+
# parenthetical off into params. Returns false if the expression
|
|
92
|
+
# couldn't be worked out (already reported), true otherwise.
|
|
93
|
+
#
|
|
94
|
+
def take_evaluated_arg
|
|
95
|
+
return true unless @params
|
|
96
|
+
|
|
97
|
+
value, ok = evaluate_expr( @params.tokens )
|
|
98
|
+
return false unless ok
|
|
99
|
+
|
|
100
|
+
@tokens = @tokens.with_token( value.to_s )
|
|
101
|
+
@params = nil
|
|
102
|
+
return true
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
#
|
|
106
|
+
# Work out an expression from the given tokens. Returns the value
|
|
107
|
+
# and whether it worked: false if the expression reported a
|
|
108
|
+
# problem (already reported), in which case the value is whatever
|
|
109
|
+
# it had worked out so far.
|
|
110
|
+
#
|
|
111
|
+
def evaluate_expr( tokens )
|
|
112
|
+
errors_before = @engine.heap.error.error_count
|
|
113
|
+
value = Gloo::Expr::Expression.new( @engine, tokens ).evaluate
|
|
114
|
+
return value, @engine.heap.error.error_count == errors_before
|
|
115
|
+
end
|
|
116
|
+
|
|
86
117
|
#
|
|
87
118
|
# Run the verb.
|
|
88
119
|
#
|
data/lib/gloo/exec/exec_env.rb
CHANGED
|
@@ -35,13 +35,16 @@ module Gloo
|
|
|
35
35
|
end
|
|
36
36
|
|
|
37
37
|
#
|
|
38
|
-
# Where the line now running is, for error messages: the
|
|
39
|
-
#
|
|
38
|
+
# Where the line now running is, for error messages: the file and
|
|
39
|
+
# line being loaded, or the running script and its line. While a
|
|
40
|
+
# file is being read, a problem is in that file, even when a
|
|
41
|
+
# script started the load.
|
|
40
42
|
#
|
|
41
43
|
def current_location
|
|
44
|
+
return @load_location if @load_location
|
|
42
45
|
return @running_script.location if @running_script
|
|
43
46
|
|
|
44
|
-
return
|
|
47
|
+
return nil
|
|
45
48
|
end
|
|
46
49
|
|
|
47
50
|
#
|
data/lib/gloo/exec/script.rb
CHANGED
|
@@ -115,6 +115,15 @@ module Gloo
|
|
|
115
115
|
def msg_run
|
|
116
116
|
s = Gloo::Exec::Script.new( @engine, self )
|
|
117
117
|
s.run
|
|
118
|
+
@broke_out = s.broke_out?
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
#
|
|
122
|
+
# Did a break end this script's last run? A loop uses this to
|
|
123
|
+
# stop when its do script breaks.
|
|
124
|
+
#
|
|
125
|
+
def broke_out?
|
|
126
|
+
return @broke_out == true
|
|
118
127
|
end
|
|
119
128
|
|
|
120
129
|
# ---------------------------------------------------------------------
|
|
@@ -57,7 +57,7 @@ module Gloo
|
|
|
57
57
|
'split ({from} {to}) — Get the substring from index {from} up to (not including) index {to}. Indexes are 0-based; out-of-range indexes are clamped to the start or end of the string. Both parameters are required. Does not change the value of the string. It will have the substring.',
|
|
58
58
|
'splitl ({index}) — Get the substring to the left of index {index} (same as split (0, {index})). A parameter is required. Does not change the value of the string. It will have the substring.',
|
|
59
59
|
'splitr ({index}) — Get the substring from index {index} to the end of the string (same as split ({index}, size)). A parameter is required. Does not change the value of the string. It will have the substring.',
|
|
60
|
-
'split_list ({delim} {dst.path}) — Split the string by {delim} and put the parts into children of the container at {dst.path} (or an alias that points to one), one part per child, in order. Existing children are matched by position and have their values set; extra parts get new (untyped) children, numbered from 1; extra existing children are left alone. Both parameters are required. Does not change the value of the string. It will
|
|
60
|
+
'split_list ({delim} {dst.path}) — Split the string by {delim} and put the parts into children of the container at {dst.path} (or an alias that points to one), one part per child, in order. Existing children are matched by position and have their values set; extra parts get new (untyped) children, numbered from 1; extra existing children are left alone. Both parameters are required. Does not change the value of the string. It will be true (also when the string is empty), or false if a parameter or the target is bad.',
|
|
61
61
|
'word_wrap ({width}) — Word-wrap the string to {width} columns, breaking on whitespace (never mid-word; an overlong word is left on its own line rather than broken). The {width} parameter is optional; it defaults to the terminal\'s current width. This message changes the value of the string. It will have the wrapped string.',
|
|
62
62
|
'page — Show the value in a pager (less), for viewing long content a screen at a time.'
|
|
63
63
|
]
|
|
@@ -239,11 +239,12 @@ module Gloo
|
|
|
239
239
|
# have their values set; if there are more parts than children,
|
|
240
240
|
# new (untyped) children are created for the extras, numbered
|
|
241
241
|
# from 1. Existing children beyond the part count are left alone.
|
|
242
|
-
# The string's own value is unchanged
|
|
243
|
-
#
|
|
242
|
+
# The string's own value is unchanged. 'it' is true once the parts
|
|
243
|
+
# are in place (also when there's nothing to split), or false if
|
|
244
|
+
# the parameters or the target are bad.
|
|
244
245
|
#
|
|
245
246
|
def msg_split_list
|
|
246
|
-
return @engine.heap.it.set_to(
|
|
247
|
+
return @engine.heap.it.set_to( true ) unless value
|
|
247
248
|
|
|
248
249
|
if @params&.token_count.to_i < 2
|
|
249
250
|
@engine.syntax_err MISSING_PARAM_MSG
|
|
@@ -265,9 +266,7 @@ module Gloo
|
|
|
265
266
|
child.set_value part
|
|
266
267
|
end
|
|
267
268
|
|
|
268
|
-
|
|
269
|
-
@engine.heap.it.set_to count
|
|
270
|
-
return count
|
|
269
|
+
return @engine.heap.it.set_to( true )
|
|
271
270
|
end
|
|
272
271
|
|
|
273
272
|
#
|
|
@@ -50,7 +50,8 @@ module Gloo
|
|
|
50
50
|
:description => 'An object with no type. A type declares ' \
|
|
51
51
|
'which messages an object can receive; an untyped object ' \
|
|
52
52
|
'receives only the base object messages (blank?, ' \
|
|
53
|
-
'contains?, responds_to?,
|
|
53
|
+
'contains?, responds_to?, doc, source_dir, source_file, ' \
|
|
54
|
+
'reload, unload) but can hold a ' \
|
|
54
55
|
'value of any kind. If no type is specified when an object ' \
|
|
55
56
|
'is created, it is untyped. Prefer untyped when you only ' \
|
|
56
57
|
'need to hold, compare, or show a value and do not need ' \
|
data/lib/gloo/objs/ctrl/each.rb
CHANGED
|
@@ -43,13 +43,15 @@ module Gloo
|
|
|
43
43
|
end
|
|
44
44
|
|
|
45
45
|
#
|
|
46
|
-
# Run the do script once.
|
|
46
|
+
# Run the do script once. Returns true if a break in it ended the
|
|
47
|
+
# run, so the loop should stop.
|
|
47
48
|
#
|
|
48
49
|
def run_do
|
|
49
50
|
o = find_child DO
|
|
50
|
-
return unless o
|
|
51
|
+
return false unless o
|
|
51
52
|
|
|
52
53
|
Gloo::Exec::Dispatch.message( @engine, 'run', o )
|
|
54
|
+
return o.respond_to?( :broke_out? ) && o.broke_out?
|
|
53
55
|
end
|
|
54
56
|
|
|
55
57
|
|
|
@@ -37,13 +37,15 @@ module Gloo
|
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
#
|
|
40
|
-
# Run the do script once.
|
|
40
|
+
# Run the do script once. Returns true if a break in it ended the
|
|
41
|
+
# run, so the loop should stop.
|
|
41
42
|
#
|
|
42
43
|
def run_do
|
|
43
44
|
o = find_child DO
|
|
44
|
-
return unless o
|
|
45
|
+
return false unless o
|
|
45
46
|
|
|
46
47
|
Gloo::Exec::Dispatch.message( @engine, 'run', o )
|
|
48
|
+
return o.respond_to?( :broke_out? ) && o.broke_out?
|
|
47
49
|
end
|
|
48
50
|
|
|
49
51
|
#
|
|
@@ -98,7 +100,7 @@ module Gloo
|
|
|
98
100
|
def msg_run
|
|
99
101
|
times.times do |index|
|
|
100
102
|
set_index index
|
|
101
|
-
run_do
|
|
103
|
+
break if run_do
|
|
102
104
|
end
|
|
103
105
|
end
|
|
104
106
|
|
|
@@ -209,7 +209,8 @@ module Gloo
|
|
|
209
209
|
{
|
|
210
210
|
:name => KEYWORD,
|
|
211
211
|
:shortcut => KEYWORD_SHORT,
|
|
212
|
-
:description => 'Tool to encrypt and decrypt data
|
|
212
|
+
:description => 'Tool to encrypt and decrypt data, with ' \
|
|
213
|
+
'AES-256-CBC.',
|
|
213
214
|
:children => [
|
|
214
215
|
'key (string) — The encryption key. Base64 encoded.',
|
|
215
216
|
'init_vector (string) — The initialization vector. Base64 encoded.',
|
|
@@ -218,8 +219,15 @@ module Gloo
|
|
|
218
219
|
:messages => [
|
|
219
220
|
'generate_keys — Generate an encryption key and initialization vector. The keys are base64 encoded.',
|
|
220
221
|
'encrypt — Encrypt the data. The data child is changed. It will have the encrypted data.',
|
|
221
|
-
'decrypt — Decrypt the data. The data child is changed. It will have the decrypted data.'
|
|
222
|
+
'decrypt — Decrypt the data. The data child is changed. It will have the decrypted data. With the wrong key or init_vector, decrypt usually reports an error and it is false; but not always (see notes).'
|
|
222
223
|
],
|
|
224
|
+
:notes => 'AES-CBC can\'t always tell that a key is wrong. A ' \
|
|
225
|
+
'wrong key usually leaves the decrypted data with padding ' \
|
|
226
|
+
'that doesn\'t check out, which is reported as an error. But ' \
|
|
227
|
+
'about 1 time in 256 the padding happens to look right: then ' \
|
|
228
|
+
'decrypt reports nothing, and the data is garbage rather than ' \
|
|
229
|
+
'the original. To be sure the key is right, keep a value you ' \
|
|
230
|
+
'can check, such as encrypting a known word alongside the data.',
|
|
223
231
|
:examples => <<~EXAMPLES.strip
|
|
224
232
|
#
|
|
225
233
|
# Encrypt and Decrypt a string.
|
|
@@ -74,7 +74,9 @@ module Gloo
|
|
|
74
74
|
end
|
|
75
75
|
|
|
76
76
|
#
|
|
77
|
-
# Read the contents of the file
|
|
77
|
+
# Read the contents of the file. With a destination, the contents
|
|
78
|
+
# go into it and 'it' is true; with none, the contents go in 'it'.
|
|
79
|
+
# 'it' is false if the file can't be read.
|
|
78
80
|
#
|
|
79
81
|
def msg_read
|
|
80
82
|
return @engine.heap.it.set_to( false ) unless check_file_exists?
|
|
@@ -91,6 +93,7 @@ module Gloo
|
|
|
91
93
|
end
|
|
92
94
|
|
|
93
95
|
o.set_value data
|
|
96
|
+
return @engine.heap.it.set_to( true )
|
|
94
97
|
end
|
|
95
98
|
@engine.heap.it.set_to data
|
|
96
99
|
end
|
|
@@ -290,7 +293,7 @@ module Gloo
|
|
|
290
293
|
'on disk. The string value of the file object is the path ' \
|
|
291
294
|
'and name of the file.',
|
|
292
295
|
:messages => [
|
|
293
|
-
'read ({into.obj}) — Read the file and put the data in the specified object. If {into.obj} is not specified, the data will be in it. If {into.obj} does not exist, that is an error.',
|
|
296
|
+
'read ({into.obj}) — Read the file and put the data in the specified object; it will be true. If {into.obj} is not specified, the data will be in it. If {into.obj} does not exist, or the file can\'t be read, that is an error and it will be false.',
|
|
294
297
|
'write ({from.obj}) — Write the data in {from.obj} into the file.',
|
|
295
298
|
'append ({data}) — Append the given data to the file as a new line. Adds a leading newline first if the file doesn\'t already end with one.',
|
|
296
299
|
'delete — Delete the file.',
|
data/lib/gloo/objs/web/json.rb
CHANGED
|
@@ -131,26 +131,28 @@ module Gloo
|
|
|
131
131
|
#
|
|
132
132
|
# Parse the JSON data and put it in objects.
|
|
133
133
|
# The additional parameter is the path to the destination
|
|
134
|
-
# for the parsed objects.
|
|
134
|
+
# for the parsed objects. 'it' is true once they're built, or
|
|
135
|
+
# false if the destination or the JSON is bad.
|
|
135
136
|
#
|
|
136
137
|
def msg_parse
|
|
137
138
|
if @params&.token_count&.positive?
|
|
138
139
|
pn = Gloo::Core::Pn.new( @engine, @params.tokens.first )
|
|
139
140
|
unless pn&.exists?
|
|
140
141
|
@engine.err Gloo::Core::NotFound.object( @params.tokens.first )
|
|
141
|
-
return
|
|
142
|
+
return @engine.heap.it.set_to( false )
|
|
142
143
|
end
|
|
143
144
|
else
|
|
144
145
|
@engine.syntax_err 'Destination path for parsed objects is required'
|
|
145
|
-
return
|
|
146
|
+
return @engine.heap.it.set_to( false )
|
|
146
147
|
end
|
|
147
148
|
parent = pn.resolve
|
|
148
149
|
|
|
149
150
|
json = nil
|
|
150
|
-
return unless attempt( "parse the JSON in #{self.pn}", JSON::ParserError
|
|
151
|
+
return false unless attempt( "parse the JSON in #{self.pn}", JSON::ParserError ) do
|
|
151
152
|
json = JSON.parse( self.value )
|
|
152
153
|
end
|
|
153
154
|
self.handle_json_to_obj( json, parent )
|
|
155
|
+
return @engine.heap.it.set_to( true )
|
|
154
156
|
end
|
|
155
157
|
|
|
156
158
|
# ---------------------------------------------------------------------
|
|
@@ -240,7 +242,7 @@ module Gloo
|
|
|
240
242
|
:messages => [
|
|
241
243
|
'get ({path}) — Get a value from the JSON data. Example: tell myjson to get (\'title\'). The parameter is the path in JSON to the value we want. The value is put into it.',
|
|
242
244
|
'set ({obj.path}) — Convert an object to an approximate JSON value. Example: tell myjson to set (my.object). The parameter is the path to the object used as the source. Note this is an approximate conversion — a gloo object can have both a simple value and be a container for child objects, which JSON can\'t represent the same way.',
|
|
243
|
-
'parse ({dst.path}) — Parse the JSON data and put values in the object specified by the parameter. Example: tell myjson to parse (path.to.dst).',
|
|
245
|
+
'parse ({dst.path}) — Parse the JSON data and put values in the object specified by the parameter; it will be true. If the destination is missing or the JSON is bad, that is an error and it will be false. Example: tell myjson to parse (path.to.dst).',
|
|
244
246
|
'pretty — Make the JSON format pretty. The value of the json is changed. It will have the pretty JSON.'
|
|
245
247
|
],
|
|
246
248
|
:examples => <<~EXAMPLES.strip
|
|
@@ -14,11 +14,10 @@ module Gloo
|
|
|
14
14
|
attr_reader :roots
|
|
15
15
|
|
|
16
16
|
#
|
|
17
|
-
# Set up a ledger for
|
|
17
|
+
# Set up a ledger for one file's load.
|
|
18
18
|
#
|
|
19
|
-
def initialize( engine
|
|
19
|
+
def initialize( engine )
|
|
20
20
|
@engine = engine
|
|
21
|
-
@pn = pn
|
|
22
21
|
@roots = []
|
|
23
22
|
@mine = {}.compare_by_identity
|
|
24
23
|
end
|
|
@@ -43,15 +42,16 @@ module Gloo
|
|
|
43
42
|
# `value`. If another file created it and the values differ, the
|
|
44
43
|
# new value is being ignored -- warn so it isn't a surprise. A
|
|
45
44
|
# duplicate name inside one file is left alone (a documented
|
|
46
|
-
# "first one wins").
|
|
45
|
+
# "first one wins"). The warning's location (this file and line)
|
|
46
|
+
# comes from the load.
|
|
47
47
|
#
|
|
48
48
|
def clash( prior, name, value )
|
|
49
49
|
return if @mine.key?( prior )
|
|
50
50
|
return if value.nil? || value.to_s.strip.empty?
|
|
51
51
|
return if prior.value.to_s == value.to_s
|
|
52
52
|
|
|
53
|
-
@engine.
|
|
54
|
-
"
|
|
53
|
+
@engine.warn(
|
|
54
|
+
"'#{name}' is already declared in another loaded file with a " \
|
|
55
55
|
"different value (#{prior.value.inspect} kept, #{value.inspect} ignored)."
|
|
56
56
|
)
|
|
57
57
|
end
|
|
@@ -48,11 +48,12 @@ module Gloo
|
|
|
48
48
|
@mech = @engine.platform.get_file_mech( @engine )
|
|
49
49
|
@pn = pn
|
|
50
50
|
@obj = nil
|
|
51
|
+
@found = false
|
|
51
52
|
@source_doc = Gloo::Persist::Source::SourceDoc.new
|
|
52
53
|
@trivia = Gloo::Persist::TriviaBuffer.new
|
|
53
54
|
@body = Gloo::Persist::ScriptBodyCollector.new
|
|
54
55
|
@shorthand = Gloo::Persist::ShorthandExpander.new( engine )
|
|
55
|
-
@ledger = Gloo::Persist::DeclarationLedger.new( engine
|
|
56
|
+
@ledger = Gloo::Persist::DeclarationLedger.new( engine )
|
|
56
57
|
@in_block = false
|
|
57
58
|
@block_value = ''
|
|
58
59
|
@body_started = false
|
|
@@ -66,6 +67,14 @@ module Gloo
|
|
|
66
67
|
return @ledger.roots
|
|
67
68
|
end
|
|
68
69
|
|
|
70
|
+
#
|
|
71
|
+
# Was the file there to read? False before load, or when the
|
|
72
|
+
# file couldn't be found (already reported as an error).
|
|
73
|
+
#
|
|
74
|
+
def found?
|
|
75
|
+
return @found
|
|
76
|
+
end
|
|
77
|
+
|
|
69
78
|
#
|
|
70
79
|
# Load the objects from the file.
|
|
71
80
|
#
|
|
@@ -74,6 +83,7 @@ module Gloo
|
|
|
74
83
|
@engine.err Gloo::Core::NotFound.file( @pn )
|
|
75
84
|
return
|
|
76
85
|
end
|
|
86
|
+
@found = true
|
|
77
87
|
|
|
78
88
|
@engine.log.debug "Loading file '#{@pn}'"
|
|
79
89
|
@indent_stack = IndentStack.new( @engine.heap.root, @source_doc )
|
|
@@ -8,6 +8,8 @@ module Gloo
|
|
|
8
8
|
module Persist
|
|
9
9
|
class FileStorage
|
|
10
10
|
|
|
11
|
+
NO_OBJECTS_WARNING = 'No objects in file; nothing loaded from '.freeze
|
|
12
|
+
|
|
11
13
|
attr_reader :obj, :pn, :roots, :source_doc
|
|
12
14
|
|
|
13
15
|
#
|
|
@@ -50,6 +52,10 @@ module Gloo
|
|
|
50
52
|
|
|
51
53
|
#
|
|
52
54
|
# Load the object from the file.
|
|
55
|
+
# A file that has no objects (empty, comments only, or only
|
|
56
|
+
# 'load lib' lines) isn't an error, so it's reported as a
|
|
57
|
+
# warning. A file that couldn't be found was already reported
|
|
58
|
+
# by the loader.
|
|
53
59
|
#
|
|
54
60
|
def load
|
|
55
61
|
fl = FileLoader.new( @engine, @pn )
|
|
@@ -59,8 +65,8 @@ module Gloo
|
|
|
59
65
|
@source_doc = fl.source_doc
|
|
60
66
|
if @obj
|
|
61
67
|
@engine.log.debug "Loaded object: #{@obj.name}"
|
|
62
|
-
|
|
63
|
-
@engine.
|
|
68
|
+
elsif fl.found?
|
|
69
|
+
@engine.warn "#{NO_OBJECTS_WARNING}#{@pn}"
|
|
64
70
|
end
|
|
65
71
|
end
|
|
66
72
|
|