gloo 7.1.2 → 7.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 +23 -0
- data/docs/application.md +47 -2
- data/docs/development.md +10 -0
- data/docs/iterators.md +22 -5
- data/docs/language_objects.md +20 -15
- data/docs/language_scripting.md +6 -2
- data/docs/plugins.md +1 -1
- data/docs/testing.md +4 -7
- data/docs/verbs.md +23 -3
- data/lib/VERSION +1 -1
- data/lib/VERSION_NOTES +13 -0
- data/lib/dependencies.rb +4 -1
- data/lib/gloo/app/engine.rb +18 -6
- data/lib/gloo/core/obj.rb +0 -23
- data/lib/gloo/exec/script.rb +12 -2
- data/lib/gloo/objs/basic/script.rb +5 -28
- data/lib/gloo/objs/ctrl/each.rb +4 -3
- data/lib/gloo/objs/ctrl/repeat.rb +4 -3
- data/lib/gloo/persist/declaration_ledger.rb +9 -9
- data/lib/gloo/persist/declaration_writer.rb +208 -0
- data/lib/gloo/persist/disc_mech.rb +70 -39
- data/lib/gloo/persist/file_loader.rb +125 -66
- data/lib/gloo/persist/file_saver.rb +130 -198
- data/lib/gloo/persist/file_storage.rb +15 -4
- data/lib/gloo/persist/file_style.rb +89 -0
- data/lib/gloo/persist/line_splitter.rb +16 -1
- data/lib/gloo/persist/persist_man.rb +112 -30
- data/lib/gloo/persist/save_index.rb +211 -0
- data/lib/gloo/persist/script_body_collector.rb +16 -21
- data/lib/gloo/persist/source/blank_node.rb +10 -3
- data/lib/gloo/persist/source/comment_node.rb +10 -2
- data/lib/gloo/persist/source/directive_node.rb +10 -2
- data/lib/gloo/persist/source/obj_node.rb +174 -9
- data/lib/gloo/persist/source/source_doc.rb +54 -0
- data/lib/gloo/persist/subtree_extractor.rb +9 -37
- data/lib/gloo/persist/trivia_buffer.rb +7 -7
- data/lib/gloo/verbs/break.rb +99 -10
- data/lib/gloo/verbs/load.rb +27 -21
- data/lib/gloo/verbs/move.rb +42 -3
- data/lib/gloo/verbs/save.rb +26 -4
- data/test.gloo/app/exit_status.test.gloo +34 -0
- data/test.gloo/app/fixtures/exit_after_error.gloo +9 -0
- data/test.gloo/lang/declaration.test.gloo +36 -0
- data/test.gloo/lang/fixtures/mixed_indent.gloo +5 -0
- data/test.gloo/lang/naming.test.gloo +44 -6
- data/test.gloo/verbs/break.test.gloo +104 -11
- data/test.gloo/verbs/fixtures/load_beside.gloo +6 -0
- data/test.gloo/verbs/fixtures/lossless_text.gloo +7 -0
- data/test.gloo/verbs/fixtures/lossless_text_saved.gloo +9 -0
- data/test.gloo/verbs/load.test.gloo +18 -0
- data/test.gloo/verbs/move.test.gloo +39 -0
- data/test.gloo/verbs/save.test.gloo +239 -0
- metadata +10 -1
data/lib/gloo/verbs/move.rb
CHANGED
|
@@ -13,9 +13,15 @@ module Gloo
|
|
|
13
13
|
TO = 'to'.freeze
|
|
14
14
|
MISSING_SRC_ERR = 'Object to move was not specified!'.freeze
|
|
15
15
|
MISSING_DST_ERR = "'Move' must include 'to' parent object!".freeze
|
|
16
|
+
NAME_TAKEN_ERR = "Could not move '%s': '%s' already has a child named '%s'.".freeze
|
|
17
|
+
INSIDE_ITSELF_ERR = "Could not move '%s': it can't go inside itself.".freeze
|
|
16
18
|
|
|
17
19
|
#
|
|
18
20
|
# Run the verb.
|
|
21
|
+
# A name is unique in its container, so an object can't move into
|
|
22
|
+
# one that already has a child with its name; nor can it move
|
|
23
|
+
# inside itself. Moving it to the parent it's already in does
|
|
24
|
+
# nothing.
|
|
19
25
|
#
|
|
20
26
|
def run
|
|
21
27
|
dst = lookup_dst
|
|
@@ -23,6 +29,9 @@ module Gloo
|
|
|
23
29
|
|
|
24
30
|
o = lookup_obj
|
|
25
31
|
return unless o
|
|
32
|
+
return if dst.equal?( o.parent )
|
|
33
|
+
return refuse( format( INSIDE_ITSELF_ERR, o.pn ) ) if inside?( dst, o )
|
|
34
|
+
return refuse( format( NAME_TAKEN_ERR, o.pn, dst.pn, o.name ) ) if dst.contains_child?( o.name )
|
|
26
35
|
|
|
27
36
|
o.parent.remove_child o
|
|
28
37
|
dst.add_child o
|
|
@@ -48,6 +57,28 @@ module Gloo
|
|
|
48
57
|
|
|
49
58
|
private
|
|
50
59
|
|
|
60
|
+
#
|
|
61
|
+
# Report why the object can't be moved; nothing moves, and it is
|
|
62
|
+
# false.
|
|
63
|
+
#
|
|
64
|
+
def refuse( msg )
|
|
65
|
+
@engine.err msg
|
|
66
|
+
@engine.heap.it.set_to false
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
#
|
|
70
|
+
# Is dst the object itself, or somewhere under it?
|
|
71
|
+
#
|
|
72
|
+
def inside?( dst, obj )
|
|
73
|
+
o = dst
|
|
74
|
+
while o
|
|
75
|
+
return true if o.equal?( obj )
|
|
76
|
+
|
|
77
|
+
o = o.parent
|
|
78
|
+
end
|
|
79
|
+
return false
|
|
80
|
+
end
|
|
81
|
+
|
|
51
82
|
#
|
|
52
83
|
# Lookup the object that we're moving.
|
|
53
84
|
#
|
|
@@ -97,18 +128,26 @@ module Gloo
|
|
|
97
128
|
{
|
|
98
129
|
:name => KEYWORD,
|
|
99
130
|
:shortcut => KEYWORD_SHORT,
|
|
100
|
-
:description => 'Move an object to a new parent.'
|
|
131
|
+
:description => 'Move an object to a new parent. A name is unique ' \
|
|
132
|
+
'in its container, so the new parent must not already have a ' \
|
|
133
|
+
'child with the same name.',
|
|
101
134
|
:syntax => [ 'move {path.to.object} to {new.parent}' ],
|
|
102
135
|
:parameters => [
|
|
103
136
|
'{path.to.object} — The object that we want to move.',
|
|
104
137
|
'{new.parent} — The new location for the object.'
|
|
105
138
|
],
|
|
106
|
-
:result => 'The object will now be in the new location.'
|
|
139
|
+
:result => 'The object will now be in the new location. Moving it ' \
|
|
140
|
+
'to the parent it is already in does nothing. A pure action: it ' \
|
|
141
|
+
'is left alone, unless the move is refused.',
|
|
107
142
|
:errors => [
|
|
108
143
|
"#{MISSING_SRC_ERR} The {path.to.object} is not specified.",
|
|
109
144
|
"Object '{path.to.object}' was not found. — The {path.to.object} cannot be resolved.",
|
|
110
145
|
"#{MISSING_DST_ERR} The {new.parent} is not specified.",
|
|
111
|
-
"Object '{new.parent}' was not found. — The {new.parent} cannot be resolved."
|
|
146
|
+
"Object '{new.parent}' was not found. — The {new.parent} cannot be resolved.",
|
|
147
|
+
"#{format( NAME_TAKEN_ERR, '{path.to.object}', '{new.parent}', '{name}' )} — " \
|
|
148
|
+
'The new parent already has a child with that name. Nothing moves, and it is false.',
|
|
149
|
+
"#{format( INSIDE_ITSELF_ERR, '{path.to.object}' )} — The new parent is the " \
|
|
150
|
+
'object itself or something under it. Nothing moves, and it is false.'
|
|
112
151
|
],
|
|
113
152
|
:examples => <<~EXAMPLES.strip
|
|
114
153
|
can [can] :
|
data/lib/gloo/verbs/save.rb
CHANGED
|
@@ -91,8 +91,13 @@ module Gloo
|
|
|
91
91
|
],
|
|
92
92
|
:parameters => [
|
|
93
93
|
'{path.to.object} — Name of the object to save.',
|
|
94
|
-
'{path} — Where to save it
|
|
95
|
-
'(.gloo appended if omitted).
|
|
94
|
+
'{path} — Where to save it: a full path, one starting ' \
|
|
95
|
+
'with ~, or a relative name (.gloo appended if omitted). ' \
|
|
96
|
+
'A relative name goes in the first place a relative load ' \
|
|
97
|
+
'looks: the app folder in App mode; otherwise next to the ' \
|
|
98
|
+
"saving script's file (the projects folder for a script " \
|
|
99
|
+
'that did not come from a file), or the working folder for ' \
|
|
100
|
+
'a command typed at the prompt. Registers the mapping, so ' \
|
|
96
101
|
'a later bare save includes it.',
|
|
97
102
|
'( {expression} ) — Instead of a literal path, an expression ' \
|
|
98
103
|
'in parentheses: it is worked out and its value is used as ' \
|
|
@@ -105,7 +110,14 @@ module Gloo
|
|
|
105
110
|
'A declaration you never touched comes back byte-for-byte. ' \
|
|
106
111
|
'An object counts as changed only when its value is set or ' \
|
|
107
112
|
'it is created, moved, or deleted (its doc comment goes with ' \
|
|
108
|
-
'it); changes to its children do not change it. ' \
|
|
113
|
+
'it); changes to its children do not change it. A changed ' \
|
|
114
|
+
'declaration keeps its name, type and spacing; only its ' \
|
|
115
|
+
'value is written again. A new object goes after the last ' \
|
|
116
|
+
"child of its parent's first declaration, in the file's " \
|
|
117
|
+
'indentation and type spellings. An object declared on more ' \
|
|
118
|
+
'than one line has its value on the first: a change rewrites ' \
|
|
119
|
+
'only that line, and deleting or moving it takes all its ' \
|
|
120
|
+
'lines. ' \
|
|
109
121
|
'With a path, the object also stops being declared in its ' \
|
|
110
122
|
'old file (if it had one) -- both files are rewritten ' \
|
|
111
123
|
'together.',
|
|
@@ -122,7 +134,17 @@ module Gloo
|
|
|
122
134
|
'container from nested-container shorthand; extract a ' \
|
|
123
135
|
'child that does, or a shallower ancestor that does.'
|
|
124
136
|
],
|
|
125
|
-
:notes => '
|
|
137
|
+
:notes => 'A value that cannot be written exactly (a block ' \
|
|
138
|
+
'value with no final line break, a line that is just END, ' \
|
|
139
|
+
'bytes that are not UTF-8) is written as closely as possible, ' \
|
|
140
|
+
"with a warning: Could not save '{path}' exactly: {why}. A " \
|
|
141
|
+
'changed script body loses the comments and blank lines ' \
|
|
142
|
+
'inside it. A new top-level object has no file yet: a bare ' \
|
|
143
|
+
'save leaves it out and warns (Not saved (no file yet): ' \
|
|
144
|
+
'{name}.); save {name} gives it a file of its own, named ' \
|
|
145
|
+
'after it and placed the same way as a relative path. ' \
|
|
146
|
+
'See doc verbs, Load & Save. ' \
|
|
147
|
+
'An object can also be told to save itself: ' \
|
|
126
148
|
'`tell my_obj to save`. When several files contribute to ' \
|
|
127
149
|
'one container (the namespace pattern), each file save only ' \
|
|
128
150
|
"rewrites that file's own declarations. Extraction (save " \
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Exit status of a script run.
|
|
3
|
+
# `gloo file.gloo` exits 1 if anything went wrong at any point in the
|
|
4
|
+
# run, not just on its last line. The engine running these tests was
|
|
5
|
+
# started in Test mode, so the check runs gloo again with [system],
|
|
6
|
+
# on a fixture beside this file.
|
|
7
|
+
#
|
|
8
|
+
|
|
9
|
+
tests.app.exit_status [can] :
|
|
10
|
+
|
|
11
|
+
# The interpreter and the fixture, both found from source_dir.
|
|
12
|
+
run_rb [string] : /../../lib/run.rb
|
|
13
|
+
fixture [string] : /fixtures/exit_after_error.gloo
|
|
14
|
+
quiet [string] : --quiet
|
|
15
|
+
# The fixture's error output isn't part of these tests' output.
|
|
16
|
+
discard [string] : > /dev/null 2>&1
|
|
17
|
+
where [string] :
|
|
18
|
+
|
|
19
|
+
run_gloo [system] :
|
|
20
|
+
command [string] :
|
|
21
|
+
get_output [bool] : false
|
|
22
|
+
result [bool] :
|
|
23
|
+
|
|
24
|
+
error_then_success_exits_1 [test] :
|
|
25
|
+
description [string] : A run with an error on an earlier line exits non-zero, though its last line works.
|
|
26
|
+
on_test [script] :
|
|
27
|
+
check ^^ for source_dir
|
|
28
|
+
put it into ^^.where
|
|
29
|
+
# Paths are quoted in case the folder has spaces.
|
|
30
|
+
put "ruby '" ^^.where ^^.run_rb "' " ^^.quiet " '" ^^.where ^^.fixture "' " ^^.discard into ^^.run_gloo.command
|
|
31
|
+
tell ^^.run_gloo to run
|
|
32
|
+
# result is false when the command exits non-zero.
|
|
33
|
+
eval ^^.run_gloo.result
|
|
34
|
+
refute "expected the run to exit non-zero"
|
|
@@ -41,3 +41,39 @@ END
|
|
|
41
41
|
on_test [script] :
|
|
42
42
|
eval ^^.closed_then_colon = 8
|
|
43
43
|
assert "expected the value 8"
|
|
44
|
+
|
|
45
|
+
# A fixture beside this file whose lines mix tabs and spaces, on one
|
|
46
|
+
# line and from line to line: a tab counts as two spaces.
|
|
47
|
+
mixed_indent_path [string] : /fixtures/mixed_indent.gloo
|
|
48
|
+
where [string] :
|
|
49
|
+
|
|
50
|
+
a_tab_and_spaces_on_one_line_add_up [test] :
|
|
51
|
+
description [string] : a tab plus two spaces is two levels deep, in either order.
|
|
52
|
+
on_test [script] :
|
|
53
|
+
check ^^ for source_dir
|
|
54
|
+
put it into ^^.where
|
|
55
|
+
load ( ^^.where ^^.mixed_indent_path )
|
|
56
|
+
tell mixed_indent_fixture.a to count
|
|
57
|
+
eval it = 2
|
|
58
|
+
assert "expected x and y under a"
|
|
59
|
+
eval mixed_indent_fixture.b = 3
|
|
60
|
+
assert "expected b beside a"
|
|
61
|
+
tell mixed_indent_fixture to unload
|
|
62
|
+
|
|
63
|
+
# Spaces just inside the brackets are allowed.
|
|
64
|
+
spaced_int [ int ] : 5
|
|
65
|
+
spaced_after [int ]: 6
|
|
66
|
+
spaced_text [text ] : BEGIN
|
|
67
|
+
one
|
|
68
|
+
END
|
|
69
|
+
|
|
70
|
+
spaces_inside_the_brackets_are_allowed [test] :
|
|
71
|
+
description [string] : a space just inside a type's brackets doesn't change the type.
|
|
72
|
+
on_test [script] :
|
|
73
|
+
eval ^^.spaced_int = 5
|
|
74
|
+
assert "expected [ int ] to be an integer 5"
|
|
75
|
+
eval ^^.spaced_after + 1 = 7
|
|
76
|
+
assert "expected [int ]: to be an integer 6"
|
|
77
|
+
check ^^.spaced_text for starts_with? ( 'one' )
|
|
78
|
+
assert "expected [text ] to read its block"
|
|
79
|
+
|
|
@@ -4,9 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
tests.lang.naming [can] :
|
|
6
6
|
|
|
7
|
-
dup [string] : first
|
|
8
|
-
dup [string] : second
|
|
9
|
-
|
|
10
7
|
Alpha [string] : mixed case
|
|
11
8
|
|
|
12
9
|
1 [string] : numeric name
|
|
@@ -18,9 +15,24 @@ tests.lang.naming [can] :
|
|
|
18
15
|
# test so the syntax error it reports belongs to that test.
|
|
19
16
|
nameless_file [file] :
|
|
20
17
|
|
|
18
|
+
# A fixture that declares one name twice, loaded inside its tests so
|
|
19
|
+
# the warning about the ignored value belongs to them.
|
|
20
|
+
dup_file [file] :
|
|
21
|
+
|
|
21
22
|
# Scratch files live in the gloo tmp folder ($.gloo_tmp).
|
|
22
23
|
on_load [script] :
|
|
23
24
|
put $.gloo_tmp '/gloo_naming_test.gloo' into ^.nameless_file
|
|
25
|
+
put $.gloo_tmp '/gloo_naming_dup_test.gloo' into ^.dup_file
|
|
26
|
+
|
|
27
|
+
dup_src [text] : BEGIN
|
|
28
|
+
dup_fixture [container] :
|
|
29
|
+
dup [string] : first
|
|
30
|
+
dup [string] : second
|
|
31
|
+
box [container] :
|
|
32
|
+
x [string] : ex
|
|
33
|
+
box [container] :
|
|
34
|
+
y [string] : why
|
|
35
|
+
END
|
|
24
36
|
|
|
25
37
|
nameless_src [text] : BEGIN
|
|
26
38
|
naming_fixture [container] :
|
|
@@ -28,10 +40,36 @@ naming_fixture [container] :
|
|
|
28
40
|
END
|
|
29
41
|
|
|
30
42
|
first_of_a_duplicate_name_wins [test] :
|
|
31
|
-
description [string] :
|
|
43
|
+
description [string] : a second declaration of a name is the same object; the first value wins.
|
|
44
|
+
expect_errors [bool] : true
|
|
45
|
+
on_test [script] :
|
|
46
|
+
tell ^^.dup_file to write ( ^^.dup_src )
|
|
47
|
+
load ( ^^.dup_file )
|
|
48
|
+
eval dup_fixture.dup = 'first'
|
|
49
|
+
assert "expected the first value to win"
|
|
50
|
+
|
|
51
|
+
tell dup_fixture to count
|
|
52
|
+
eval it = 2
|
|
53
|
+
assert "expected one 'dup' and one 'box', not four objects"
|
|
54
|
+
|
|
55
|
+
tell dup_fixture to unload
|
|
56
|
+
tell ^^.dup_file to delete
|
|
57
|
+
|
|
58
|
+
a_container_declared_twice_merges [test] :
|
|
59
|
+
description [string] : a container declared twice is one container with the children of both.
|
|
60
|
+
expect_errors [bool] : true
|
|
32
61
|
on_test [script] :
|
|
33
|
-
|
|
34
|
-
|
|
62
|
+
tell ^^.dup_file to write ( ^^.dup_src )
|
|
63
|
+
load ( ^^.dup_file )
|
|
64
|
+
tell dup_fixture.box to count
|
|
65
|
+
eval it = 2
|
|
66
|
+
assert "expected x and y in the one box"
|
|
67
|
+
|
|
68
|
+
eval dup_fixture.box.y = 'why'
|
|
69
|
+
assert "expected the second declaration's child to be there"
|
|
70
|
+
|
|
71
|
+
tell dup_fixture to unload
|
|
72
|
+
tell ^^.dup_file to delete
|
|
35
73
|
|
|
36
74
|
path_lookup_is_case_insensitive [test] :
|
|
37
75
|
description [string] : a pathname segment matches a name regardless of case.
|
|
@@ -8,7 +8,7 @@ tests.verbs.break [can] :
|
|
|
8
8
|
|
|
9
9
|
s [script] :
|
|
10
10
|
if ^.b then break
|
|
11
|
-
|
|
11
|
+
|
|
12
12
|
# Should not get here
|
|
13
13
|
put false into ^.b
|
|
14
14
|
|
|
@@ -19,16 +19,27 @@ tests.verbs.break [can] :
|
|
|
19
19
|
eval ^^.b
|
|
20
20
|
assert "expected b to be true"
|
|
21
21
|
|
|
22
|
-
#
|
|
22
|
+
# The last error, for the break loop errors.
|
|
23
|
+
on_error [script] :
|
|
24
|
+
error_data [can] :
|
|
25
|
+
message [string] :
|
|
26
|
+
|
|
27
|
+
not_in_a_loop [string] : Could not break loop: not in a loop.
|
|
28
|
+
|
|
29
|
+
# Loops whose do script breaks on one pass: skip_on for a plain
|
|
30
|
+
# break, end_on for break loop (0 never breaks).
|
|
23
31
|
passes [int] : 0
|
|
24
32
|
after [int] : 0
|
|
33
|
+
skip_on [int] : 0
|
|
34
|
+
end_on [int] : 0
|
|
25
35
|
|
|
26
36
|
rep [repeat] :
|
|
27
37
|
times [int] : 4
|
|
28
38
|
index [int] :
|
|
29
39
|
do [script] :
|
|
30
40
|
put tests.verbs.break.passes + 1 into tests.verbs.break.passes
|
|
31
|
-
if tests.verbs.break.passes =
|
|
41
|
+
if tests.verbs.break.passes = tests.verbs.break.skip_on then break
|
|
42
|
+
if tests.verbs.break.passes = tests.verbs.break.end_on then break loop
|
|
32
43
|
put tests.verbs.break.after + 1 into tests.verbs.break.after
|
|
33
44
|
|
|
34
45
|
kids [can] :
|
|
@@ -41,14 +52,15 @@ tests.verbs.break [can] :
|
|
|
41
52
|
in [alias] : tests.verbs.break.kids
|
|
42
53
|
do [script] :
|
|
43
54
|
put tests.verbs.break.passes + 1 into tests.verbs.break.passes
|
|
44
|
-
if tests.verbs.break.passes =
|
|
55
|
+
if tests.verbs.break.passes = tests.verbs.break.skip_on then break
|
|
56
|
+
if tests.verbs.break.passes = tests.verbs.break.end_on then break loop
|
|
45
57
|
put tests.verbs.break.after + 1 into tests.verbs.break.after
|
|
46
58
|
|
|
47
59
|
inner [repeat] :
|
|
48
60
|
times [int] : 3
|
|
49
61
|
index [int] :
|
|
50
62
|
do [script] :
|
|
51
|
-
if tests.verbs.break.inner.index = 1 then break
|
|
63
|
+
if tests.verbs.break.inner.index = 1 then break loop
|
|
52
64
|
put tests.verbs.break.after + 1 into tests.verbs.break.after
|
|
53
65
|
|
|
54
66
|
outer [repeat] :
|
|
@@ -57,30 +69,111 @@ tests.verbs.break [can] :
|
|
|
57
69
|
do [script] :
|
|
58
70
|
tell tests.verbs.break.inner to run
|
|
59
71
|
|
|
60
|
-
|
|
61
|
-
|
|
72
|
+
# The form the apps use to skip an item: unless ... do break.
|
|
73
|
+
skipped [string] :
|
|
74
|
+
skip_b [each] :
|
|
75
|
+
child [alias] :
|
|
76
|
+
in [alias] : tests.verbs.break.kids
|
|
77
|
+
do [script] :
|
|
78
|
+
check tests.verbs.break.skip_b.child for starts_with?( 'b' )
|
|
79
|
+
unless it = false do break
|
|
80
|
+
put tests.verbs.break.skipped + tests.verbs.break.skip_b.child into tests.verbs.break.skipped
|
|
81
|
+
|
|
82
|
+
# break loop is only valid directly in a loop's do script.
|
|
83
|
+
lone [script] :
|
|
84
|
+
break loop
|
|
85
|
+
|
|
86
|
+
loop_helper [script] :
|
|
87
|
+
break loop
|
|
88
|
+
|
|
89
|
+
via_loop [repeat] :
|
|
90
|
+
times [int] : 2
|
|
91
|
+
index [int] :
|
|
92
|
+
do [script] :
|
|
93
|
+
put tests.verbs.break.passes + 1 into tests.verbs.break.passes
|
|
94
|
+
run tests.verbs.break.loop_helper
|
|
95
|
+
|
|
96
|
+
break_skips_the_rest_of_a_repeat_pass [test] :
|
|
97
|
+
description [string] : break in a repeat's do script skips to the next pass.
|
|
62
98
|
on_test [script] :
|
|
63
99
|
put 0 into ^^.passes
|
|
64
100
|
put 0 into ^^.after
|
|
101
|
+
put 0 into ^^.end_on
|
|
102
|
+
put 2 into ^^.skip_on
|
|
103
|
+
tell ^^.rep to run
|
|
104
|
+
eval ^^.passes = 4
|
|
105
|
+
assert "expected every pass to run"
|
|
106
|
+
eval ^^.after = 3
|
|
107
|
+
assert "expected only the pass that broke to stop early"
|
|
108
|
+
|
|
109
|
+
break_skips_the_rest_of_an_each_pass [test] :
|
|
110
|
+
description [string] : break in an each's do script skips to the next child.
|
|
111
|
+
on_test [script] :
|
|
112
|
+
put 0 into ^^.passes
|
|
113
|
+
put 0 into ^^.after
|
|
114
|
+
put 0 into ^^.end_on
|
|
115
|
+
put 2 into ^^.skip_on
|
|
116
|
+
tell ^^.each_kid to run
|
|
117
|
+
eval ^^.after = 2
|
|
118
|
+
assert "expected every child but the one that broke to get past it"
|
|
119
|
+
|
|
120
|
+
unless_do_break_skips_an_item [test] :
|
|
121
|
+
description [string] : unless ... do break in an each skips that item, as the apps use it.
|
|
122
|
+
on_test [script] :
|
|
123
|
+
put '' into ^^.skipped
|
|
124
|
+
tell ^^.skip_b to run
|
|
125
|
+
eval ^^.skipped = 'ac'
|
|
126
|
+
assert "expected b to be skipped and c still reached"
|
|
127
|
+
|
|
128
|
+
break_loop_ends_a_repeat [test] :
|
|
129
|
+
description [string] : break loop in a repeat's do script ends the loop.
|
|
130
|
+
on_test [script] :
|
|
131
|
+
put 0 into ^^.passes
|
|
132
|
+
put 0 into ^^.after
|
|
133
|
+
put 0 into ^^.skip_on
|
|
134
|
+
put 2 into ^^.end_on
|
|
65
135
|
tell ^^.rep to run
|
|
66
136
|
eval ^^.passes = 2
|
|
67
137
|
assert "expected the loop to stop on the pass that broke"
|
|
68
138
|
eval ^^.after = 1
|
|
69
139
|
assert "expected only the first pass to get past the break"
|
|
70
140
|
|
|
71
|
-
|
|
72
|
-
description [string] : break in an each's do script ends the loop.
|
|
141
|
+
break_loop_ends_an_each [test] :
|
|
142
|
+
description [string] : break loop in an each's do script ends the loop.
|
|
73
143
|
on_test [script] :
|
|
74
144
|
put 0 into ^^.passes
|
|
75
145
|
put 0 into ^^.after
|
|
146
|
+
put 0 into ^^.skip_on
|
|
147
|
+
put 2 into ^^.end_on
|
|
76
148
|
tell ^^.each_kid to run
|
|
77
149
|
eval ^^.passes = 2
|
|
78
150
|
assert "expected the loop to stop on the pass that broke"
|
|
79
151
|
|
|
80
|
-
|
|
81
|
-
description [string] : break in an inner loop ends that loop, not the outer one.
|
|
152
|
+
break_loop_ends_only_the_inner_loop [test] :
|
|
153
|
+
description [string] : break loop in an inner loop ends that loop, not the outer one.
|
|
82
154
|
on_test [script] :
|
|
83
155
|
put 0 into ^^.after
|
|
84
156
|
tell ^^.outer to run
|
|
85
157
|
eval ^^.after = 2
|
|
86
158
|
assert "expected each of the 2 inner loops to get past its break once"
|
|
159
|
+
|
|
160
|
+
break_loop_outside_a_loop_is_an_error [test] :
|
|
161
|
+
description [string] : break loop in a script that isn't a loop's do is an error.
|
|
162
|
+
expect_errors [bool] : true
|
|
163
|
+
on_test [script] :
|
|
164
|
+
put '' into ^^.error_data.message
|
|
165
|
+
run ^^.lone
|
|
166
|
+
eval ^^.error_data.message = ^^.not_in_a_loop
|
|
167
|
+
assert "expected the not-in-a-loop error"
|
|
168
|
+
|
|
169
|
+
break_loop_in_a_helper_is_an_error [test] :
|
|
170
|
+
description [string] : break loop in a script the do runs is an error, and the loop goes on.
|
|
171
|
+
expect_errors [bool] : true
|
|
172
|
+
on_test [script] :
|
|
173
|
+
put '' into ^^.error_data.message
|
|
174
|
+
put 0 into ^^.passes
|
|
175
|
+
tell ^^.via_loop to run
|
|
176
|
+
eval ^^.error_data.message = ^^.not_in_a_loop
|
|
177
|
+
assert "expected the not-in-a-loop error"
|
|
178
|
+
eval ^^.passes = 2
|
|
179
|
+
assert "expected the loop to go on"
|
|
@@ -172,3 +172,21 @@ END
|
|
|
172
172
|
assert "expected the full path without .gloo to load"
|
|
173
173
|
tell computed_demo to unload
|
|
174
174
|
tell ^^.computed_f to delete
|
|
175
|
+
|
|
176
|
+
# A relative name looks next to the loading file first; these scripts
|
|
177
|
+
# are declared in this file, so fixtures/ is the folder beside it.
|
|
178
|
+
load_a_file_beside_this_one [test] :
|
|
179
|
+
description [string] : A relative load finds a file next to the file the script came from.
|
|
180
|
+
on_test [script] :
|
|
181
|
+
load fixtures/load_beside
|
|
182
|
+
eval load_beside_demo.s = 'beside'
|
|
183
|
+
assert "expected fixtures/load_beside.gloo to load from beside this file"
|
|
184
|
+
tell load_beside_demo to unload
|
|
185
|
+
|
|
186
|
+
load_a_prefix_beside_this_one [test] :
|
|
187
|
+
description [string] : A relative wildcard with a file name prefix finds the files next to the loading file.
|
|
188
|
+
on_test [script] :
|
|
189
|
+
load fixtures/load_beside*
|
|
190
|
+
eval load_beside_demo.s = 'beside'
|
|
191
|
+
assert "expected fixtures/load_beside*.gloo to load from beside this file"
|
|
192
|
+
tell load_beside_demo to unload
|
|
@@ -16,3 +16,42 @@ tests.verbs.move [can] :
|
|
|
16
16
|
assert "expected a to be in t"
|
|
17
17
|
exists? instance tests.verbs.move.c.a
|
|
18
18
|
refute "expected a not to be in c"
|
|
19
|
+
|
|
20
|
+
# A name is unique in its container: a move onto a taken name, or
|
|
21
|
+
# inside itself, is refused.
|
|
22
|
+
taken [container] :
|
|
23
|
+
a [string] : moving
|
|
24
|
+
dst [container] :
|
|
25
|
+
a [string] : already here
|
|
26
|
+
outer [container] :
|
|
27
|
+
inner [container] :
|
|
28
|
+
msg [string] :
|
|
29
|
+
|
|
30
|
+
on_error [script] :
|
|
31
|
+
error_data [can] :
|
|
32
|
+
message [string] :
|
|
33
|
+
|
|
34
|
+
moving_onto_a_taken_name_is_refused [test] :
|
|
35
|
+
description [string] : A move into a container with a child of the same name is an error; nothing moves.
|
|
36
|
+
expect_errors [bool] : true
|
|
37
|
+
on_test [script] :
|
|
38
|
+
move ^^.taken.a to ^^.dst
|
|
39
|
+
eval it = false
|
|
40
|
+
assert "expected it to be false"
|
|
41
|
+
eval ^^.dst.a = 'already here'
|
|
42
|
+
assert "expected the child already there to be untouched"
|
|
43
|
+
exists? instance ^^.taken.a
|
|
44
|
+
assert "expected the object not to have moved"
|
|
45
|
+
put ^^.error_data.message into ^^.msg
|
|
46
|
+
check ^^.msg for starts_with? ( 'Could not move' )
|
|
47
|
+
assert "expected a could-not-move error"
|
|
48
|
+
|
|
49
|
+
moving_inside_itself_is_refused [test] :
|
|
50
|
+
description [string] : A move into the object's own child is an error; nothing moves.
|
|
51
|
+
expect_errors [bool] : true
|
|
52
|
+
on_test [script] :
|
|
53
|
+
move ^^.outer to ^^.outer.inner
|
|
54
|
+
eval it = false
|
|
55
|
+
assert "expected it to be false"
|
|
56
|
+
exists? instance ^^.outer.inner
|
|
57
|
+
assert "expected outer to still be in place"
|