gloo 7.1 → 7.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Rakefile +0 -2
- data/docs/application.md +9 -0
- data/docs/development.md +22 -2
- data/docs/iterators.md +25 -1
- data/docs/language_syntax.md +1 -1
- data/docs/plugins.md +1 -1
- data/docs/verbs.md +2 -1
- data/lib/VERSION +1 -1
- data/lib/VERSION_NOTES +16 -0
- data/lib/gloo/app/args.rb +3 -5
- data/lib/gloo/app/log.rb +2 -2
- data/lib/gloo/core/invoker.rb +20 -7
- data/lib/gloo/core/pn.rb +5 -0
- data/lib/gloo/core/verb.rb +14 -3
- 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/ctrl/each.rb +5 -3
- data/lib/gloo/objs/ctrl/each_child.rb +6 -2
- 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 +4 -3
- 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/persist/declaration_ledger.rb +6 -6
- data/lib/gloo/persist/disc_mech.rb +38 -20
- data/lib/gloo/persist/file_loader.rb +1 -1
- data/lib/gloo/persist/persist_man.rb +1 -1
- data/lib/gloo/verbs/break.rb +7 -2
- data/lib/gloo/verbs/create.rb +4 -2
- data/lib/gloo/verbs/eval.rb +5 -4
- data/lib/gloo/verbs/invoke.rb +7 -6
- data/lib/gloo/verbs/load.rb +7 -1
- data/lib/gloo/verbs/log.rb +8 -4
- data/lib/gloo/verbs/show.rb +15 -10
- data/lib/gloo.rb +18 -4
- data/lib/run.rb +3 -9
- data/test.gloo/app/embed.test.gloo +31 -0
- data/test.gloo/app/fixtures/embed_harness.rb +15 -0
- data/test.gloo/ctrl/each.test.gloo +72 -0
- data/test.gloo/lang/exceptions.test.gloo +22 -0
- data/test.gloo/objs/cipher.test.gloo +27 -0
- data/test.gloo/objs/int.test.gloo +6 -3
- data/test.gloo/verbs/break.test.gloo +66 -0
- data/test.gloo/verbs/create.test.gloo +25 -0
- data/test.gloo/verbs/eval.test.gloo +8 -0
- data/test.gloo/verbs/invoke.test.gloo +50 -0
- data/test.gloo/verbs/load.test.gloo +34 -0
- data/test.gloo/verbs/log.test.gloo +16 -0
- data/test.gloo/verbs/show.test.gloo +32 -0
- metadata +3 -1
|
@@ -28,22 +28,30 @@ module Gloo
|
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
#
|
|
31
|
-
# Get all the gloo files in the folder (partial path).
|
|
31
|
+
# Get all the gloo files in the folder (partial path). The folder
|
|
32
|
+
# can end with the start of a file name, as a prefix (folder/a).
|
|
32
33
|
#
|
|
33
34
|
def get_all_files_in( folder )
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
dir = folder_for_files( folder )
|
|
36
|
+
return Dir.glob( "#{dir}*.gloo" )
|
|
37
|
+
end
|
|
36
38
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
#
|
|
40
|
+
# Where to look for a folder of files: an absolute or ~ folder as
|
|
41
|
+
# given (~ expanded), anything else in the project folder, or if it
|
|
42
|
+
# isn't there, in the gloo home.
|
|
43
|
+
#
|
|
44
|
+
def folder_for_files( folder )
|
|
45
|
+
return folder.sub( '~', Dir.home ) if folder.start_with?( '~' )
|
|
46
|
+
return folder if File.absolute_path?( folder )
|
|
42
47
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
48
|
+
dir = File.join( @engine.settings.project_path, folder )
|
|
49
|
+
return dir if Dir.exist?( dir )
|
|
50
|
+
|
|
51
|
+
@log.debug "Folder does not exist in project: #{folder}"
|
|
52
|
+
dir = File.join( @engine.settings.user_root, folder )
|
|
53
|
+
@log.debug "Looking in gloo home? found == #{Dir.exist?( dir )}"
|
|
54
|
+
return dir
|
|
47
55
|
end
|
|
48
56
|
|
|
49
57
|
#
|
|
@@ -65,23 +73,33 @@ module Gloo
|
|
|
65
73
|
return true
|
|
66
74
|
end
|
|
67
75
|
|
|
68
|
-
#
|
|
69
|
-
# Expand a single file path.
|
|
70
|
-
#
|
|
76
|
+
#
|
|
77
|
+
# Expand a single file path. The .gloo extension is optional: it's
|
|
78
|
+
# added when the name doesn't end with it, for a full or ~ path
|
|
79
|
+
# and for a name in the project or gloo home.
|
|
80
|
+
#
|
|
71
81
|
def expand( name )
|
|
72
|
-
# Try full path
|
|
82
|
+
# Try the name as given: a full path, or relative to the working
|
|
83
|
+
# folder (eg. gloo hello_world.gloo).
|
|
73
84
|
ext_path = File.expand_path( name )
|
|
74
85
|
return [ ext_path ] if self.valid?( ext_path )
|
|
75
86
|
|
|
76
|
-
|
|
77
|
-
|
|
87
|
+
full_name = name.end_with?( file_ext ) ? name : "#{name}#{file_ext}"
|
|
88
|
+
|
|
89
|
+
# A full or ~ path without the extension.
|
|
90
|
+
if name.start_with?( '~' ) || File.absolute_path?( name )
|
|
91
|
+
ext_path = File.expand_path( full_name )
|
|
92
|
+
return [ ext_path ] if self.valid?( ext_path )
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Try in projects
|
|
78
96
|
pn = File.join( @engine.settings.project_path, full_name )
|
|
79
97
|
return [ pn ] if self.valid?( pn )
|
|
80
|
-
|
|
98
|
+
|
|
81
99
|
# Try in user root
|
|
82
100
|
pn = File.join( @engine.settings.user_root, full_name )
|
|
83
101
|
return [ pn ] if self.valid?( pn )
|
|
84
|
-
|
|
102
|
+
|
|
85
103
|
return nil
|
|
86
104
|
end
|
|
87
105
|
|
|
@@ -53,7 +53,7 @@ module Gloo
|
|
|
53
53
|
@trivia = Gloo::Persist::TriviaBuffer.new
|
|
54
54
|
@body = Gloo::Persist::ScriptBodyCollector.new
|
|
55
55
|
@shorthand = Gloo::Persist::ShorthandExpander.new( engine )
|
|
56
|
-
@ledger = Gloo::Persist::DeclarationLedger.new( engine
|
|
56
|
+
@ledger = Gloo::Persist::DeclarationLedger.new( engine )
|
|
57
57
|
@in_block = false
|
|
58
58
|
@block_value = ''
|
|
59
59
|
@body_started = false
|
|
@@ -396,7 +396,7 @@ module Gloo
|
|
|
396
396
|
#
|
|
397
397
|
def warn_if_dirty( fs )
|
|
398
398
|
saver = Gloo::Persist::FileSaver.new( @engine, fs.pn, fs.obj, fs.source_doc )
|
|
399
|
-
@engine.
|
|
399
|
+
@engine.warn "#{RELOAD_DIRTY_WARNING}#{fs.pn}" if saver.dirty?
|
|
400
400
|
end
|
|
401
401
|
|
|
402
402
|
end
|
data/lib/gloo/verbs/break.rb
CHANGED
|
@@ -51,11 +51,16 @@ module Gloo
|
|
|
51
51
|
{
|
|
52
52
|
:name => KEYWORD,
|
|
53
53
|
:shortcut => KEYWORD_SHORT,
|
|
54
|
-
:description => 'Break out of the current script, stop running.'
|
|
54
|
+
:description => 'Break out of the current script, stop running. ' \
|
|
55
|
+
'If that script is the do script of a loop (repeat, or any ' \
|
|
56
|
+
'kind of each), the whole loop ends.',
|
|
55
57
|
:syntax => [ 'break' ],
|
|
56
58
|
:result => 'No more commands are executed in the currently ' \
|
|
57
59
|
'running script. If there are other scripts in the stack, ' \
|
|
58
|
-
'they will resume normally.',
|
|
60
|
+
'they will resume normally. In a loop\'s do script, the loop ' \
|
|
61
|
+
'ends too and runs no more passes; the script that ran the ' \
|
|
62
|
+
'loop carries on. A break in a script the do script runs ' \
|
|
63
|
+
'(eg. with run) ends only that script, not the loop.',
|
|
59
64
|
:examples => <<~EXAMPLES.strip
|
|
60
65
|
#
|
|
61
66
|
# Break out of a script.
|
data/lib/gloo/verbs/create.rb
CHANGED
|
@@ -111,7 +111,9 @@ module Gloo
|
|
|
111
111
|
'value. Both type and value are optional when creating an object.',
|
|
112
112
|
:syntax => [ 'create {new.object.path} as {type} : {value}' ],
|
|
113
113
|
:parameters => [
|
|
114
|
-
'{new.object.path} — The path and name of the new object.'
|
|
114
|
+
'{new.object.path} — The path and name of the new object. ' \
|
|
115
|
+
'Like any path, it can start from the root, from here in ' \
|
|
116
|
+
'a script (^.box.new, ^^.new), or from the context (@.new).',
|
|
115
117
|
'{type} — The type of the new object. Optional; if not provided the object will be untyped.',
|
|
116
118
|
"{value} — The initial value for the new object. Optional; if not provided the object will have the default value for the type."
|
|
117
119
|
],
|
|
@@ -123,7 +125,7 @@ module Gloo
|
|
|
123
125
|
"to the existing object's current value.",
|
|
124
126
|
:errors => [
|
|
125
127
|
"#{NO_NAME_ERR} — The name of the object was not specified and the object cannot be created.",
|
|
126
|
-
"Could not create '{path}': Object '{parent.path}' was not found. — The parent container named in the path does not exist.
|
|
128
|
+
"Could not create '{path}': Object '{parent.path}' was not found. — The parent container named in the path does not exist. Every container above the new object must already exist. Nothing is created, and it is false.",
|
|
127
129
|
"#{format( BAD_NAME_ERR, '{name}' )} — The name has parentheses or quotes, or there are extra words between the name and as / : — create takes a name as written. Nothing is created, and it is false."
|
|
128
130
|
],
|
|
129
131
|
:examples => <<~EXAMPLES.strip
|
data/lib/gloo/verbs/eval.rb
CHANGED
|
@@ -30,9 +30,8 @@ module Gloo
|
|
|
30
30
|
#
|
|
31
31
|
def run
|
|
32
32
|
if @tokens.token_count > 1
|
|
33
|
-
|
|
34
|
-
result
|
|
35
|
-
@engine.heap.it.set_to result
|
|
33
|
+
result, ok = evaluate_expr( @tokens.params )
|
|
34
|
+
@engine.heap.it.set_to( ok ? result : false )
|
|
36
35
|
else
|
|
37
36
|
@engine.heap.it.set_to true
|
|
38
37
|
end
|
|
@@ -61,7 +60,9 @@ module Gloo
|
|
|
61
60
|
'{expression} — The expression that will be evaluated. The expression is optional. If not provided, eval will result in true.'
|
|
62
61
|
],
|
|
63
62
|
:result => 'The result of the expression evaluation is put ' \
|
|
64
|
-
'into it. No other action is performed.'
|
|
63
|
+
'into it. No other action is performed. If the expression ' \
|
|
64
|
+
'fails (eg. it names a missing object), the error is ' \
|
|
65
|
+
'reported and it is false.',
|
|
65
66
|
:examples => <<~EXAMPLES.strip,
|
|
66
67
|
> eval "me"
|
|
67
68
|
> eval "hello " "world"
|
data/lib/gloo/verbs/invoke.rb
CHANGED
|
@@ -60,7 +60,8 @@ module Gloo
|
|
|
60
60
|
'{path.to.function} — The function we want to invoke.',
|
|
61
61
|
'{params} — The list of parameters to the function.'
|
|
62
62
|
],
|
|
63
|
-
:result => 'The result of the function is put into it
|
|
63
|
+
:result => 'The result of the function is put into it; if ' \
|
|
64
|
+
'anything goes wrong, it is false. The ' \
|
|
64
65
|
'inline forms (invoke(...), ~>(...)) can be used anywhere ' \
|
|
65
66
|
'an expression is evaluated - show, put ... into, if, ' \
|
|
66
67
|
'unless, eval, and more - and evaluate to the result ' \
|
|
@@ -69,13 +70,13 @@ module Gloo
|
|
|
69
70
|
"#{Gloo::Core::Invoker::NO_TARGET_ERR} — No function reference was given.",
|
|
70
71
|
"Object '{path.to.function}' was not found. — The path doesn't resolve to any object.",
|
|
71
72
|
"#{Gloo::Core::Invoker::NOT_FUNCTION_ERR}{path.to.function} — The path resolves to an object that isn't a function.",
|
|
72
|
-
"#{Gloo::Core::Invoker::PARAM_COUNT_ERR}{path.to.function} (expected N, got N) — The number of params given doesn't match what the function declares."
|
|
73
|
+
"#{Gloo::Core::Invoker::PARAM_COUNT_ERR}{path.to.function} (expected N, got N) — The number of params given doesn't match what the function declares.",
|
|
74
|
+
"Object '{param}' was not found. — A param names an object that doesn't exist. The function isn't run."
|
|
73
75
|
],
|
|
74
76
|
:notes => 'If the function itself fails during invocation ' \
|
|
75
|
-
'(its on_invoke script hits an error), it is
|
|
76
|
-
'
|
|
77
|
-
'
|
|
78
|
-
'failure inside the function. ' \
|
|
77
|
+
'(its on_invoke script hits an error), it is false rather ' \
|
|
78
|
+
'than an unreliable result. The underlying error is ' \
|
|
79
|
+
'whatever was reported by the failure inside the function. ' \
|
|
79
80
|
'Inline call params are space-separated, same as the ' \
|
|
80
81
|
'standalone verb - each one is evaluated as a single ' \
|
|
81
82
|
'token (a literal or object reference), not a multi-token ' \
|
data/lib/gloo/verbs/load.rb
CHANGED
|
@@ -115,7 +115,12 @@ module Gloo
|
|
|
115
115
|
'load [ext|lib] ( {expression} )'
|
|
116
116
|
],
|
|
117
117
|
:parameters => [
|
|
118
|
-
'{file_name} — Name of the object file that is to be loaded
|
|
118
|
+
'{file_name} — Name of the object file that is to be loaded: ' \
|
|
119
|
+
'relative to the project, a full path, or starting with ~. ' \
|
|
120
|
+
'The .gloo extension is optional. ' \
|
|
121
|
+
'End it with * to load every .gloo file in a folder (a ' \
|
|
122
|
+
'folder in the project, a full path, or one starting with ' \
|
|
123
|
+
'~); anything before the * is the start of the file names.',
|
|
119
124
|
'reference type — By default, the type is file. File can be ' \
|
|
120
125
|
'specified, but does not need to be. Use ext to load a ' \
|
|
121
126
|
'User Extension. Use lib to load a Core Library.',
|
|
@@ -154,6 +159,7 @@ module Gloo
|
|
|
154
159
|
> load my/project/file
|
|
155
160
|
> load my/app/*
|
|
156
161
|
> load ~/.my_app/settings.gloo
|
|
162
|
+
> load ~/.my_app/plugins/*
|
|
157
163
|
|
|
158
164
|
# Load a file whose name is worked out
|
|
159
165
|
> load ( $.gloo_tmp '/scratch.gloo' )
|
data/lib/gloo/verbs/log.rb
CHANGED
|
@@ -50,11 +50,12 @@ module Gloo
|
|
|
50
50
|
# Write to the specified logger.
|
|
51
51
|
#
|
|
52
52
|
def write_to_log
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
# A failed expression is still logged as far as it got, but it
|
|
54
|
+
# is false.
|
|
55
|
+
result, ok = evaluate_expr( @tokens.params )
|
|
55
56
|
level = log_level_specified( result )
|
|
56
57
|
@engine.log.write result, level
|
|
57
|
-
@engine.heap.it.set_to result
|
|
58
|
+
@engine.heap.it.set_to( ok ? result : false )
|
|
58
59
|
end
|
|
59
60
|
|
|
60
61
|
#
|
|
@@ -106,7 +107,10 @@ module Gloo
|
|
|
106
107
|
'not specified, the message is written as DEBUG level.'
|
|
107
108
|
],
|
|
108
109
|
:result => 'The message is written to the log at the ' \
|
|
109
|
-
'specified level. It will contain the log message.'
|
|
110
|
+
'specified level. It will contain the log message. If the ' \
|
|
111
|
+
'expression fails, the error is reported and what was ' \
|
|
112
|
+
'worked out so far is still logged, but it is false. A ' \
|
|
113
|
+
'level that can\'t be worked out falls back to debug.',
|
|
110
114
|
:notes => "Use `log clear` from the CLI to clear out both the " \
|
|
111
115
|
"standard log and the error log.\n\n" \
|
|
112
116
|
"> log clear",
|
data/lib/gloo/verbs/show.rb
CHANGED
|
@@ -16,10 +16,11 @@ module Gloo
|
|
|
16
16
|
#
|
|
17
17
|
def run
|
|
18
18
|
if @tokens.token_count > 1
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
# A failed expression is still shown as far as it got (a best
|
|
20
|
+
# guess, and handy when debugging), but it is false.
|
|
21
|
+
result, ok = evaluate_expr( @tokens.params )
|
|
21
22
|
@engine.log.show get_formatted_string( result )
|
|
22
|
-
@engine.heap.it.set_to result
|
|
23
|
+
@engine.heap.it.set_to( ok ? result : false )
|
|
23
24
|
else
|
|
24
25
|
@engine.log.show ''
|
|
25
26
|
end
|
|
@@ -46,14 +47,16 @@ module Gloo
|
|
|
46
47
|
private
|
|
47
48
|
|
|
48
49
|
#
|
|
49
|
-
# Get the formatted string
|
|
50
|
+
# Get the formatted string: in the color given in the params, if
|
|
51
|
+
# any. A color that can't be worked out (already reported) shows
|
|
52
|
+
# the string plain.
|
|
50
53
|
#
|
|
51
54
|
def get_formatted_string( str )
|
|
52
55
|
if @params&.token_count&.positive?
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
return @engine.platform.get_colorized_string( str,
|
|
56
|
+
val, ok = evaluate_expr( @params.tokens )
|
|
57
|
+
return str unless ok && val
|
|
58
|
+
|
|
59
|
+
return @engine.platform.get_colorized_string( str, val.to_sym )
|
|
57
60
|
end
|
|
58
61
|
return str
|
|
59
62
|
end
|
|
@@ -79,11 +82,13 @@ module Gloo
|
|
|
79
82
|
'{target} — The object that we want to see. The target ' \
|
|
80
83
|
'might be the path to an object, a literal or an ' \
|
|
81
84
|
'expression to be evaluated before being shown.',
|
|
82
|
-
'{color} — Optional color for the text.'
|
|
85
|
+
'{color} — Optional color for the text. If the color can\'t be worked out, the error is reported and the text is shown plain.'
|
|
83
86
|
],
|
|
84
87
|
:result => "The object's value is shown, or the literal, or " \
|
|
85
88
|
'the result of the evaluated expression is shown. It will ' \
|
|
86
|
-
"contain the object's value."
|
|
89
|
+
"contain the object's value. If the expression fails (eg. " \
|
|
90
|
+
'it names a missing object), the error is reported and ' \
|
|
91
|
+
'what was worked out so far is still shown, but it is false.',
|
|
87
92
|
:examples => <<~EXAMPLES.strip,
|
|
88
93
|
> show "me"
|
|
89
94
|
> show "hello " "world"
|
data/lib/gloo.rb
CHANGED
|
@@ -9,13 +9,27 @@ path = File.dirname( File.absolute_path( __FILE__ ) )
|
|
|
9
9
|
require File.join( path, 'dependencies.rb' )
|
|
10
10
|
|
|
11
11
|
module Gloo
|
|
12
|
-
def self.run
|
|
13
|
-
params = []
|
|
14
|
-
( params << '--cli' ) if ARGV.count.zero?
|
|
15
12
|
|
|
13
|
+
#
|
|
14
|
+
# Run gloo as the command, with the command line's arguments.
|
|
15
|
+
# This is the only place that reads ARGV; an engine created
|
|
16
|
+
# in code uses only the params it's given.
|
|
17
|
+
#
|
|
18
|
+
def self.run( argv = ARGV )
|
|
16
19
|
platform = Gloo::App::Platform.new
|
|
17
20
|
context = Gloo::App::EngineContext.new(
|
|
18
|
-
|
|
21
|
+
params_for( argv ), platform, Gloo::App::Log, nil )
|
|
19
22
|
Gloo::App::Engine.new( context ).start
|
|
20
23
|
end
|
|
24
|
+
|
|
25
|
+
#
|
|
26
|
+
# Get the engine params for the given command line arguments.
|
|
27
|
+
# With no arguments, gloo runs in CLI mode.
|
|
28
|
+
#
|
|
29
|
+
def self.params_for( argv )
|
|
30
|
+
params = argv.dup
|
|
31
|
+
( params << '--cli' ) if params.empty?
|
|
32
|
+
return params
|
|
33
|
+
end
|
|
34
|
+
|
|
21
35
|
end
|
data/lib/run.rb
CHANGED
|
@@ -5,14 +5,8 @@
|
|
|
5
5
|
# From the /lib/ directory: ruby run.rb
|
|
6
6
|
#
|
|
7
7
|
|
|
8
|
-
#
|
|
8
|
+
# Load gloo from source, then run it with the command line's arguments.
|
|
9
9
|
path = File.dirname( File.absolute_path( __FILE__ ) )
|
|
10
|
-
require File.join( path, '
|
|
10
|
+
require File.join( path, 'gloo.rb' )
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
( params << '--cli' ) if ARGV.count.zero?
|
|
14
|
-
|
|
15
|
-
platform = Gloo::App::Platform.new
|
|
16
|
-
context = Gloo::App::EngineContext.new(
|
|
17
|
-
params, platform, Gloo::App::Log, nil )
|
|
18
|
-
Gloo::App::Engine.new( context ).start
|
|
12
|
+
Gloo.run
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Embedded gloo tests.
|
|
3
|
+
# An engine created in code by another Ruby program uses only the
|
|
4
|
+
# params it's given, never that program's command line (ARGV).
|
|
5
|
+
# The engine running these tests was started as the command, so the
|
|
6
|
+
# check runs a separate Ruby program (a fixture) with [system].
|
|
7
|
+
#
|
|
8
|
+
|
|
9
|
+
tests.app.embed [can] :
|
|
10
|
+
|
|
11
|
+
# The harness, beside this file; found with source_dir.
|
|
12
|
+
harness [string] : /fixtures/embed_harness.rb
|
|
13
|
+
host_arg [string] : host_arg.gloo
|
|
14
|
+
no_files [string] : 0
|
|
15
|
+
where [string] :
|
|
16
|
+
|
|
17
|
+
run_harness [system] :
|
|
18
|
+
command [string] :
|
|
19
|
+
get_output [bool] : true
|
|
20
|
+
result [string] :
|
|
21
|
+
|
|
22
|
+
ignores_host_argv [test] :
|
|
23
|
+
description [string] : An engine created in code ignores the host program's command line.
|
|
24
|
+
on_test [script] :
|
|
25
|
+
check ^^ for source_dir
|
|
26
|
+
put it into ^^.where
|
|
27
|
+
# Paths are quoted in case the folder has spaces.
|
|
28
|
+
put "ruby '" ^^.where ^^.harness "' " ^^.host_arg into ^^.run_harness.command
|
|
29
|
+
tell ^^.run_harness to run
|
|
30
|
+
eval ^^.run_harness.result = ^^.no_files
|
|
31
|
+
assert "expected the embedded engine to be given no files"
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#
|
|
2
|
+
# A Ruby program that creates a gloo engine in code, as an embedding
|
|
3
|
+
# app would, and prints how many files the engine was given.
|
|
4
|
+
#
|
|
5
|
+
# Run it with words on its own command line: the engine must not
|
|
6
|
+
# take them as files, so this should always print 0. The engine is
|
|
7
|
+
# never started, so nothing is loaded or saved even if it does.
|
|
8
|
+
#
|
|
9
|
+
# Requires this repo's lib/gloo by path, so it checks the source,
|
|
10
|
+
# not an installed gloo gem.
|
|
11
|
+
#
|
|
12
|
+
require_relative '../../../lib/gloo'
|
|
13
|
+
|
|
14
|
+
context = Gloo::App::EngineContext.new( [ '--quiet' ] )
|
|
15
|
+
print Gloo::App::Engine.new( context ).args.files.count
|
|
@@ -20,6 +20,27 @@ tests.ctrl.each [can] :
|
|
|
20
20
|
eval ^^.count + 1
|
|
21
21
|
put it into ^^.count
|
|
22
22
|
|
|
23
|
+
seen [string] :
|
|
24
|
+
lines [text] : BEGIN
|
|
25
|
+
one
|
|
26
|
+
|
|
27
|
+
two
|
|
28
|
+
END
|
|
29
|
+
|
|
30
|
+
lns [each] :
|
|
31
|
+
line [string] :
|
|
32
|
+
in [alias] : tests.ctrl.each.lines
|
|
33
|
+
do [script] :
|
|
34
|
+
put tests.ctrl.each.seen + '[' + ^.line + ']' into tests.ctrl.each.seen
|
|
35
|
+
|
|
36
|
+
each_line_without_line_endings [test] :
|
|
37
|
+
description [string] : each line gives each line without its line ending; a blank line is empty.
|
|
38
|
+
on_test [script] :
|
|
39
|
+
put '' into ^^.seen
|
|
40
|
+
tell ^^.lns to run
|
|
41
|
+
eval ^^.seen = '[one][][two]'
|
|
42
|
+
assert "expected each line without its line ending"
|
|
43
|
+
|
|
23
44
|
each_word [test] :
|
|
24
45
|
description [string] : Count words with each word
|
|
25
46
|
on_test [script] :
|
|
@@ -137,3 +158,54 @@ tests.ctrl.each_folder [can] :
|
|
|
137
158
|
eval ^^.count = 2
|
|
138
159
|
assert "expected a and a/deep"
|
|
139
160
|
tell ^^.remove_tree to run
|
|
161
|
+
|
|
162
|
+
#
|
|
163
|
+
# Each child with group_by: on_group_start sees the group's first
|
|
164
|
+
# child and on_group_end its last. Each start and end logs the id of
|
|
165
|
+
# the child it sees.
|
|
166
|
+
#
|
|
167
|
+
|
|
168
|
+
tests.ctrl.each_group [can] :
|
|
169
|
+
|
|
170
|
+
starts [string] :
|
|
171
|
+
ends [string] :
|
|
172
|
+
|
|
173
|
+
items [can] :
|
|
174
|
+
a [can] :
|
|
175
|
+
id [string] : a
|
|
176
|
+
kind [string] : x
|
|
177
|
+
b [can] :
|
|
178
|
+
id [string] : b
|
|
179
|
+
kind [string] : x
|
|
180
|
+
c [can] :
|
|
181
|
+
id [string] : c
|
|
182
|
+
kind [string] : y
|
|
183
|
+
d [can] :
|
|
184
|
+
id [string] : d
|
|
185
|
+
kind [string] : y
|
|
186
|
+
|
|
187
|
+
grouped [each] :
|
|
188
|
+
child [alias] :
|
|
189
|
+
in [alias] : tests.ctrl.each_group.items
|
|
190
|
+
group_by [string] : kind
|
|
191
|
+
on_group_start [script] :
|
|
192
|
+
put tests.ctrl.each_group.starts + tests.ctrl.each_group.grouped.child.id into tests.ctrl.each_group.starts
|
|
193
|
+
on_group_end [script] :
|
|
194
|
+
put tests.ctrl.each_group.ends + tests.ctrl.each_group.grouped.child.id into tests.ctrl.each_group.ends
|
|
195
|
+
do [script] :
|
|
196
|
+
|
|
197
|
+
group_start_sees_first_child [test] :
|
|
198
|
+
description [string] : on_group_start sees the first child of the new group.
|
|
199
|
+
on_test [script] :
|
|
200
|
+
put '' into ^^.starts
|
|
201
|
+
tell ^^.grouped to run
|
|
202
|
+
eval ^^.starts = 'ac'
|
|
203
|
+
assert "expected each group to start with its first child"
|
|
204
|
+
|
|
205
|
+
group_end_sees_last_child [test] :
|
|
206
|
+
description [string] : on_group_end sees the last child of the group that's ending.
|
|
207
|
+
on_test [script] :
|
|
208
|
+
put '' into ^^.ends
|
|
209
|
+
tell ^^.grouped to run
|
|
210
|
+
eval ^^.ends = 'bd'
|
|
211
|
+
assert "expected each group to end with its last child"
|
|
@@ -23,6 +23,18 @@ tests.lang.exceptions [can] :
|
|
|
23
23
|
kind [string] :
|
|
24
24
|
location [string] :
|
|
25
25
|
|
|
26
|
+
# A scratch file with a mistake in it, for the location of an error in
|
|
27
|
+
# a loaded file.
|
|
28
|
+
broken_file [file] :
|
|
29
|
+
broken_name [string] : /gloo_exceptions_location.gloo
|
|
30
|
+
broken_src [text] : BEGIN
|
|
31
|
+
broken_location_demo [can] :
|
|
32
|
+
count [int : 3
|
|
33
|
+
END
|
|
34
|
+
|
|
35
|
+
on_load [script] :
|
|
36
|
+
put $.gloo_tmp ^.broken_name into ^.broken_file
|
|
37
|
+
|
|
26
38
|
confirm_throw_fires_on_exception [test] :
|
|
27
39
|
description [string] : Confirm throw fires on_exception and populates exception_data, but does not fire on_error.
|
|
28
40
|
expect_errors [bool] : true
|
|
@@ -127,3 +139,13 @@ tests.lang.exceptions [can] :
|
|
|
127
139
|
eval ^^.num = 0
|
|
128
140
|
assert "expected the best guess, 0"
|
|
129
141
|
|
|
142
|
+
confirm_error_location_in_a_loaded_file [test] :
|
|
143
|
+
description [string] : an error in a file a script loads names that file and line, not the script.
|
|
144
|
+
expect_errors [bool] : true
|
|
145
|
+
on_test [script] :
|
|
146
|
+
tell ^^.broken_file to write ( ^^.broken_src )
|
|
147
|
+
load ( ^^.broken_file )
|
|
148
|
+
check ^^.error_data.location for ends_with? ( 'gloo_exceptions_location.gloo:2' )
|
|
149
|
+
assert "expected the location to be the loaded file and line"
|
|
150
|
+
tell broken_location_demo to unload
|
|
151
|
+
tell ^^.broken_file to delete
|
|
@@ -41,3 +41,30 @@ tests.objs.cipher [can] :
|
|
|
41
41
|
tell tests.objs.cipher.b to decrypt
|
|
42
42
|
eval tests.objs.cipher.b.data = ^^.plaintext
|
|
43
43
|
assert "expected the second cipher to decrypt with the shared key"
|
|
44
|
+
|
|
45
|
+
# Fixed values, so the results never vary: 'hello' encrypted with key
|
|
46
|
+
# ('k' x 32) and iv ('i' x 16), and a wrong key ('0' x 32) whose
|
|
47
|
+
# garbage fails the padding check. (AES-CBC can't always tell a key is
|
|
48
|
+
# wrong: about 1 wrong key in 256 gives garbage with no error.)
|
|
49
|
+
fixed_iv [string] : aWlpaWlpaWlpaWlpaWlpaQ==
|
|
50
|
+
hello_encrypted [string] : aRyXOIIhJzBhh+BthfFstw==
|
|
51
|
+
wrong_key [string] : MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA=
|
|
52
|
+
err_fired [bool] : false
|
|
53
|
+
|
|
54
|
+
on_error [script] :
|
|
55
|
+
put true into ^.err_fired
|
|
56
|
+
|
|
57
|
+
wrong_key_is_an_error [test] :
|
|
58
|
+
description [string] : decrypt with a wrong key that fails the padding check reports an error.
|
|
59
|
+
expect_errors [bool] : true
|
|
60
|
+
on_test [script] :
|
|
61
|
+
put false into ^^.err_fired
|
|
62
|
+
create tests.objs.cipher.w as cipher
|
|
63
|
+
put ^^.wrong_key into tests.objs.cipher.w.key
|
|
64
|
+
put ^^.fixed_iv into tests.objs.cipher.w.init_vector
|
|
65
|
+
put ^^.hello_encrypted into tests.objs.cipher.w.data
|
|
66
|
+
tell tests.objs.cipher.w to decrypt
|
|
67
|
+
eval it = false
|
|
68
|
+
assert "expected it to be false"
|
|
69
|
+
eval ^^.err_fired = true
|
|
70
|
+
assert "expected on_error to fire for the wrong key"
|
|
@@ -48,10 +48,13 @@ tests.objs.int [can] :
|
|
|
48
48
|
eval ^^.a <= 100
|
|
49
49
|
assert "expected it to be less than or equal to 100"
|
|
50
50
|
|
|
51
|
+
# A random value is only checked for its range: two random values
|
|
52
|
+
# are equal now and then, so 'not equal' would fail at random.
|
|
51
53
|
tell ^^.a to randomize (10000)
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
54
|
+
eval ^^.a >= 0
|
|
55
|
+
assert "expected it to be greater than or equal to 0"
|
|
56
|
+
eval ^^.a < 10000
|
|
57
|
+
assert "expected it to be less than 10000"
|
|
55
58
|
|
|
56
59
|
format_int [test] :
|
|
57
60
|
description [string] : Format an integer
|
|
@@ -18,3 +18,69 @@ tests.verbs.break [can] :
|
|
|
18
18
|
tell ^^.s to run
|
|
19
19
|
eval ^^.b
|
|
20
20
|
assert "expected b to be true"
|
|
21
|
+
|
|
22
|
+
# Loops whose do script breaks on its second pass.
|
|
23
|
+
passes [int] : 0
|
|
24
|
+
after [int] : 0
|
|
25
|
+
|
|
26
|
+
rep [repeat] :
|
|
27
|
+
times [int] : 4
|
|
28
|
+
index [int] :
|
|
29
|
+
do [script] :
|
|
30
|
+
put tests.verbs.break.passes + 1 into tests.verbs.break.passes
|
|
31
|
+
if tests.verbs.break.passes = 2 then break
|
|
32
|
+
put tests.verbs.break.after + 1 into tests.verbs.break.after
|
|
33
|
+
|
|
34
|
+
kids [can] :
|
|
35
|
+
a [string] : a
|
|
36
|
+
b [string] : b
|
|
37
|
+
c [string] : c
|
|
38
|
+
|
|
39
|
+
each_kid [each] :
|
|
40
|
+
child [alias] :
|
|
41
|
+
in [alias] : tests.verbs.break.kids
|
|
42
|
+
do [script] :
|
|
43
|
+
put tests.verbs.break.passes + 1 into tests.verbs.break.passes
|
|
44
|
+
if tests.verbs.break.passes = 2 then break
|
|
45
|
+
put tests.verbs.break.after + 1 into tests.verbs.break.after
|
|
46
|
+
|
|
47
|
+
inner [repeat] :
|
|
48
|
+
times [int] : 3
|
|
49
|
+
index [int] :
|
|
50
|
+
do [script] :
|
|
51
|
+
if tests.verbs.break.inner.index = 1 then break
|
|
52
|
+
put tests.verbs.break.after + 1 into tests.verbs.break.after
|
|
53
|
+
|
|
54
|
+
outer [repeat] :
|
|
55
|
+
times [int] : 2
|
|
56
|
+
index [int] :
|
|
57
|
+
do [script] :
|
|
58
|
+
tell tests.verbs.break.inner to run
|
|
59
|
+
|
|
60
|
+
break_ends_a_repeat [test] :
|
|
61
|
+
description [string] : break in a repeat's do script ends the loop.
|
|
62
|
+
on_test [script] :
|
|
63
|
+
put 0 into ^^.passes
|
|
64
|
+
put 0 into ^^.after
|
|
65
|
+
tell ^^.rep to run
|
|
66
|
+
eval ^^.passes = 2
|
|
67
|
+
assert "expected the loop to stop on the pass that broke"
|
|
68
|
+
eval ^^.after = 1
|
|
69
|
+
assert "expected only the first pass to get past the break"
|
|
70
|
+
|
|
71
|
+
break_ends_an_each [test] :
|
|
72
|
+
description [string] : break in an each's do script ends the loop.
|
|
73
|
+
on_test [script] :
|
|
74
|
+
put 0 into ^^.passes
|
|
75
|
+
put 0 into ^^.after
|
|
76
|
+
tell ^^.each_kid to run
|
|
77
|
+
eval ^^.passes = 2
|
|
78
|
+
assert "expected the loop to stop on the pass that broke"
|
|
79
|
+
|
|
80
|
+
break_ends_only_the_inner_loop [test] :
|
|
81
|
+
description [string] : break in an inner loop ends that loop, not the outer one.
|
|
82
|
+
on_test [script] :
|
|
83
|
+
put 0 into ^^.after
|
|
84
|
+
tell ^^.outer to run
|
|
85
|
+
eval ^^.after = 2
|
|
86
|
+
assert "expected each of the 2 inner loops to get past its break once"
|