gloo 6.3.0 → 6.4.0

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 (40) hide show
  1. checksums.yaml +4 -4
  2. data/CLAUDE.md +13 -0
  3. data/docs/language_objects.md +38 -0
  4. data/docs/language_scripting.md +41 -0
  5. data/docs/verbs.md +27 -2
  6. data/lib/VERSION +1 -1
  7. data/lib/VERSION_NOTES +10 -0
  8. data/lib/gloo/core/obj.rb +40 -1
  9. data/lib/gloo/core/parser.rb +30 -1
  10. data/lib/gloo/core/tokens.rb +44 -18
  11. data/lib/gloo/expr/l_string.rb +8 -4
  12. data/lib/gloo/objs/basic/script.rb +28 -2
  13. data/lib/gloo/objs/web/json.rb +4 -1
  14. data/lib/gloo/persist/comment_buffer.rb +58 -0
  15. data/lib/gloo/persist/declaration_ledger.rb +61 -0
  16. data/lib/gloo/persist/disc_mech.rb +15 -2
  17. data/lib/gloo/persist/file_loader.rb +201 -100
  18. data/lib/gloo/persist/file_saver.rb +251 -6
  19. data/lib/gloo/persist/file_storage.rb +10 -4
  20. data/lib/gloo/persist/indent_stack.rb +90 -0
  21. data/lib/gloo/persist/line_splitter.rb +18 -3
  22. data/lib/gloo/persist/persist_man.rb +159 -24
  23. data/lib/gloo/persist/script_body_collector.rb +102 -0
  24. data/lib/gloo/persist/shorthand_expander.rb +51 -0
  25. data/lib/gloo/persist/source/blank_node.rb +27 -0
  26. data/lib/gloo/persist/source/comment_node.rb +27 -0
  27. data/lib/gloo/persist/source/directive_node.rb +26 -0
  28. data/lib/gloo/persist/source/obj_node.rb +50 -0
  29. data/lib/gloo/persist/source/source_doc.rb +41 -0
  30. data/lib/gloo/verbs/load.rb +5 -0
  31. data/lib/gloo/verbs/reload.rb +3 -0
  32. data/lib/gloo/verbs/save.rb +57 -10
  33. data/test.gloo/lang/shorthand.test.gloo +29 -0
  34. data/test.gloo/objs/json.test.gloo +9 -0
  35. data/test.gloo/objs/script.test.gloo +1 -1
  36. data/test.gloo/objs/text.test.gloo +22 -1
  37. data/test.gloo/string/str.test.gloo +15 -0
  38. data/test.gloo/verbs/reload.test.gloo +57 -0
  39. data/test.gloo/verbs/save.test.gloo +115 -0
  40. metadata +14 -1
@@ -0,0 +1,50 @@
1
+ # Author:: Eric Crane (mailto:eric.crane@mac.com)
2
+ # Copyright:: Copyright (c) 2026 Eric Crane. All rights reserved.
3
+ #
4
+ # One object declaration in a source file, eg.
5
+ # name [type] : value
6
+ # Carries the raw text needed to reproduce the declaration unchanged,
7
+ # plus a back-reference to the heap object it created (or updated),
8
+ # so a save can tell whether the live value still matches what's on
9
+ # disk and, if so, leave the raw text alone.
10
+ #
11
+
12
+ module Gloo
13
+ module Persist
14
+ module Source
15
+ class ObjNode
16
+
17
+ # block_style is one of:
18
+ # :inline -- name [type] : value, all on one line
19
+ # :begin_end -- name [type] : BEGIN ... END
20
+ # :body -- name [type] :, followed by an indented,
21
+ # unparsed body (script commands)
22
+ attr_accessor :name, :raw_type, :raw_indent, :raw_tail, :block_style,
23
+ :raw_value, :raw_end_indent, :leading_doc, :trailing_comment, :obj
24
+ attr_reader :children
25
+
26
+ #
27
+ # Set up an object declaration node. Everything but the name
28
+ # and raw type is optional and commonly set afterward via the
29
+ # accessors above -- keeping the initializer small.
30
+ #
31
+ def initialize( name:, raw_type: )
32
+ @name = name
33
+ @raw_type = raw_type
34
+ @raw_indent = ''
35
+ @raw_tail = ''
36
+ @block_style = :inline
37
+ @raw_value = nil
38
+ # a begin_end block's closing END is not necessarily indented
39
+ # to match its declaration -- kept separately, raw.
40
+ @raw_end_indent = ''
41
+ @leading_doc = nil
42
+ @trailing_comment = nil
43
+ @obj = nil
44
+ @children = []
45
+ end
46
+
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,41 @@
1
+ # Author:: Eric Crane (mailto:eric.crane@mac.com)
2
+ # Copyright:: Copyright (c) 2026 Eric Crane. All rights reserved.
3
+ #
4
+ # The concrete source model for one loaded file: an ordered list of
5
+ # nodes (comments, blank lines, directives, and object declarations)
6
+ # that mirrors what the loader actually read, so a save can rewrite
7
+ # the file instead of regenerating it from the heap.
8
+ #
9
+ # The top level plays the same role as an Source::ObjNode's children
10
+ # list -- there is no special "root" wrapper, just the file's own
11
+ # ordered content, which may include more than one top-level object
12
+ # declaration (a file may legitimately declare several roots).
13
+ #
14
+
15
+ module Gloo
16
+ module Persist
17
+ module Source
18
+ class SourceDoc
19
+
20
+ attr_reader :children
21
+
22
+ #
23
+ # Set up an empty source document.
24
+ #
25
+ def initialize
26
+ @children = []
27
+ end
28
+
29
+ #
30
+ # The top-level object declarations in this file (usually one,
31
+ # per the "a file owns its declarations" model -- more than one
32
+ # only when the file legitimately declares several roots).
33
+ #
34
+ def roots
35
+ return @children.select { |n| n.is_a?( Source::ObjNode ) }
36
+ end
37
+
38
+ end
39
+ end
40
+ end
41
+ end
@@ -124,6 +124,11 @@ module Gloo
124
124
  "#{UNKNOWN_OPT_ERR} — The reference type given isn't file, ext, or lib.",
125
125
  "#{WRONG_NUM_ARGS_ERR} — load expects 2 or 3 arguments (the verb, an optional reference type, and the file/ext/lib name)."
126
126
  ],
127
+ :notes => 'Several files can contribute to one container: ' \
128
+ 'declare it in each file and add different children, and ' \
129
+ 'they merge in the heap. If two loaded files declare the ' \
130
+ 'same object with different values, the first one loaded ' \
131
+ 'wins and a warning is logged.',
127
132
  :examples => <<~EXAMPLES.strip
128
133
  > load my/project/file
129
134
  > load my/app/*
@@ -61,6 +61,9 @@ module Gloo
61
61
  'loaded again. Note that re-load does not trigger the ' \
62
62
  'on_load script to run. There is an on_reload message sent ' \
63
63
  'to all open files.',
64
+ :notes => 'If a file has changes that have not been saved, ' \
65
+ 'reloading discards them (a warning is logged, but the ' \
66
+ 'reload still proceeds).',
64
67
  :examples => <<~EXAMPLES.strip
65
68
  > reload
66
69
  EXAMPLES
@@ -10,14 +10,16 @@ module Gloo
10
10
 
11
11
  KEYWORD = 'save'.freeze
12
12
  KEYWORD_SHORT = 'sv'.freeze
13
+ TO = 'to'.freeze
14
+ MISSING_PATH_ERR = "'Save ... to' must include a path!".freeze
13
15
 
14
16
  #
15
17
  # Run the verb.
16
18
  #
17
19
  def run
18
- # TODO: Not currently using folders or keeping
19
- # track of where the object was loaded from.
20
- @engine.persist_man.save @tokens.second
20
+ return @engine.persist_man.save @tokens.second unless @tokens.index_of( TO )
21
+
22
+ run_save_to
21
23
  end
22
24
 
23
25
  #
@@ -34,6 +36,26 @@ module Gloo
34
36
  return KEYWORD_SHORT
35
37
  end
36
38
 
39
+ # ---------------------------------------------------------------------
40
+ # Private functions
41
+ # ---------------------------------------------------------------------
42
+
43
+ private
44
+
45
+ #
46
+ # Run 'save {obj} to {path}'.
47
+ #
48
+ def run_save_to
49
+ name = @tokens.before_token( TO )[ 1 ]
50
+ path = @tokens.after_token( TO )
51
+ unless path
52
+ @engine.err MISSING_PATH_ERR
53
+ return
54
+ end
55
+
56
+ @engine.persist_man.save_to( name, path )
57
+ end
58
+
37
59
  # ---------------------------------------------------------------------
38
60
  # Verb Documentation
39
61
  # ---------------------------------------------------------------------
@@ -45,17 +67,42 @@ module Gloo
45
67
  {
46
68
  :name => KEYWORD,
47
69
  :shortcut => KEYWORD_SHORT,
48
- :description => 'Save a previously loaded object to a .gloo ' \
49
- 'file. The path will be for the root level object that was ' \
50
- 'loaded earlier.',
51
- :syntax => [ 'save {path.to.object}' ],
70
+ :description => 'Save an object to a .gloo file. With no ' \
71
+ 'path, saves every file that owns a declaration in the ' \
72
+ "object's root (its file, or every contributing file for " \
73
+ 'a namespace shared across several files); with no object ' \
74
+ 'at all, saves every open file. An object not yet mapped ' \
75
+ 'to a file is saved fresh, either to a given path or to a ' \
76
+ "default path built from the object's own name.",
77
+ :syntax => [
78
+ 'save',
79
+ 'save {path.to.object}',
80
+ 'save {path.to.object} to {path}'
81
+ ],
52
82
  :parameters => [
53
- '{path.to.object} — Name of the object file that is to be saved.'
83
+ '{path.to.object} — Name of the object to save.',
84
+ '{path} — Where to save it, relative to the project root ' \
85
+ '(.gloo appended if omitted). Registers the mapping, so ' \
86
+ 'a later bare save includes it.'
87
+ ],
88
+ :result => 'The file(s) are updated with the latest object ' \
89
+ 'state. This is a rewrite, not a regeneration: comments, ' \
90
+ 'blank lines, and the original formatting are preserved, ' \
91
+ 'and only values that actually changed are re-written.',
92
+ :errors => [
93
+ "#{MISSING_PATH_ERR} — 'to' was given with nothing after it.",
94
+ 'Could not resolve object to save — the object was not found.',
95
+ 'Will not overwrite a file not already saved there — the ' \
96
+ 'target path exists but is not mapped to this object.'
54
97
  ],
55
- :result => 'The file is updated with the latest object state.',
56
- :notes => 'The save verb is not currently fully functional.',
98
+ :notes => 'An object can also be told to save itself: ' \
99
+ '`tell my_obj to save`. When several files contribute to ' \
100
+ 'one container (the namespace pattern), each file save only ' \
101
+ "rewrites that file's own declarations.",
57
102
  :examples => <<~EXAMPLES.strip
103
+ > save
58
104
  > save my_obj
105
+ > save my_obj to sub/my_obj
59
106
  EXAMPLES
60
107
  }
61
108
  end
@@ -0,0 +1,29 @@
1
+ #
2
+ # Nested container shorthand tests
3
+ #
4
+ # A dotted name in a declaration (page.core.title [string] :) creates
5
+ # a container for each prefix segment, then declares the real object
6
+ # under the last one.
7
+ #
8
+
9
+ tests [can] :
10
+ lang [can] :
11
+ shorthand [can] :
12
+
13
+ page.core.title [string] : Home
14
+ page.core.count [int] : 3
15
+
16
+ builds_the_container_chain [test] :
17
+ description [string] : a dotted name creates a container for each prefix segment.
18
+ on_test [script] :
19
+ eval ^^.page.core.title = 'Home'
20
+ assert "expected the shorthand-built value to be reachable"
21
+
22
+ check ^^.page for contains?
23
+ assert "expected 'page' to be a real container"
24
+
25
+ reuses_an_existing_prefix [test] :
26
+ description [string] : a second shorthand line reuses the same containers.
27
+ on_test [script] :
28
+ eval ^^.page.core.count = 3
29
+ assert "expected both shorthand lines to share the 'core' container"
@@ -20,6 +20,7 @@ tests [can] :
20
20
  built [json] :
21
21
  out [can] :
22
22
  found [string] :
23
+ assigned [json] :
23
24
 
24
25
  get_a_value [test] :
25
26
  description [string] : get pulls a value out by dotted path.
@@ -68,3 +69,11 @@ tests [can] :
68
69
  tell ^^.compact to get ( 'b.c' )
69
70
  eval it = '2'
70
71
  assert "expected the value to still be reachable after pretty"
72
+
73
+ assign_a_json_string_at_run_time [test] :
74
+ description [string] : a quote-containing literal can be put into an object at run time.
75
+ on_test [script] :
76
+ put '{"lang":"gloo","ok":true}' into tests.objs.json.assigned
77
+ tell ^^.assigned to get ( 'lang' )
78
+ eval it = 'gloo'
79
+ assert "expected the run-time JSON string to be assigned and readable"
@@ -18,6 +18,6 @@ tests [can] :
18
18
  assert "expected it to be 7"
19
19
 
20
20
  put "eval ^.b = true" into ^^.a
21
- tell run ^^.a
21
+ run ^^.a
22
22
  assert "expected it to be true"
23
23
 
@@ -12,6 +12,14 @@ tests [can] :
12
12
  three 3 tree
13
13
  END
14
14
 
15
+ # inside a block every line is literal - '#' lines and blank
16
+ # lines are kept, not treated as comments/blanks
17
+ hashed [text] : BEGIN
18
+ # a heading
19
+
20
+ - a list item
21
+ END
22
+
15
23
  b [string] :
16
24
 
17
25
  verify_text [test] :
@@ -56,12 +64,25 @@ tests [can] :
56
64
  assert "expected text to have 5 words"
57
65
 
58
66
  count_lines [test] :
59
- description [string] : Get the number of lines
67
+ description [string] : Get the number of lines
60
68
  on_test [script] :
61
69
  tell ^^.a to count_lines
62
70
  eval it = 3
63
71
  assert "expected text to have 3 lines"
64
72
 
73
+ block_keeps_hash_and_blank_lines [test] :
74
+ description [string] : a BEGIN/END block keeps '#' lines and blank lines verbatim
75
+ on_test [script] :
76
+ check ^^.hashed for substring? ( "# a heading" )
77
+ assert "expected the '#' line to be kept, not stripped as a comment"
78
+
79
+ check ^^.hashed for substring? ( "- a list item" )
80
+ assert "expected content after the blank line to be kept"
81
+
82
+ tell ^^.hashed to count_lines
83
+ eval it = 3
84
+ assert "expected 3 lines: heading, blank, list item"
85
+
65
86
  starts_with [test] :
66
87
  description [string] : Check if the string starts with a value
67
88
  on_test [script] :
@@ -21,6 +21,21 @@ tests [can] :
21
21
  eval ^^.s = "hello world"
22
22
  assert "expected s to be 'hello world'"
23
23
 
24
+ put_a_quote_containing_value [test] :
25
+ description [string] : Put a literal that contains quote characters
26
+ on_test [script] :
27
+ put '{"x":1}' into ^^.s
28
+ eval ^^.s = '{"x":1}'
29
+ assert "expected s to hold the JSON string"
30
+
31
+ put "it's here" into ^^.s
32
+ eval ^^.s = "it's here"
33
+ assert "expected s to hold the apostrophe string"
34
+
35
+ put "say \"hi\"" into ^^.s
36
+ eval ^^.s = 'say "hi"'
37
+ assert "expected s to hold the unescaped double-quote string"
38
+
24
39
  blank [test] :
25
40
  description [string] : Check to see if the string is blank
26
41
  on_test [script] :
@@ -0,0 +1,57 @@
1
+ #
2
+ # Reload message tests -- 'tell {obj} to reload' re-reads the file.
3
+ #
4
+ # The bare 'reload' verb restarts the engine (covered by the unit
5
+ # tests). These exercise per-object reload against a /tmp scratch file
6
+ # that gets rewritten between load and reload.
7
+ #
8
+
9
+ tests [can] :
10
+ verbs [can] :
11
+ reload [can] :
12
+
13
+ f [file] : /tmp/gloo_reload_test.gloo
14
+ v1 [text] : BEGIN
15
+ demo [container] :
16
+ msg [string] : original
17
+ END
18
+
19
+ v2 [text] : BEGIN
20
+ demo [container] :
21
+ msg [string] : edited outside gloo
22
+ added [string] : brand new
23
+ END
24
+
25
+ reload_picks_up_an_external_change [test] :
26
+ description [string] : editing the file on disk then reloading takes effect.
27
+ on_test [script] :
28
+ tell ^^.f to write ( ^^.v1 )
29
+ load /tmp/gloo_reload_test.gloo
30
+ eval demo.msg = 'original'
31
+ assert "sanity: loaded the first version"
32
+
33
+ tell ^^.f to write ( ^^.v2 )
34
+ tell demo to reload
35
+
36
+ eval demo.msg = 'edited outside gloo'
37
+ assert "reload should pick up the changed value"
38
+ eval demo.added = 'brand new'
39
+ assert "reload should pick up a newly added child"
40
+
41
+ tell demo to unload
42
+ tell ^^.f to delete
43
+
44
+ reload_discards_an_in_memory_edit [test] :
45
+ description [string] : an unsaved change is thrown away by reload.
46
+ on_test [script] :
47
+ tell ^^.f to write ( ^^.v1 )
48
+ load /tmp/gloo_reload_test.gloo
49
+
50
+ put 'not saved' into demo.msg
51
+ tell demo to reload
52
+
53
+ eval demo.msg = 'original'
54
+ assert "reload should restore the on-disk value"
55
+
56
+ tell demo to unload
57
+ tell ^^.f to delete
@@ -0,0 +1,115 @@
1
+ #
2
+ # Save verb tests -- real load -> edit -> save round trips.
3
+ #
4
+ # Each test writes a .gloo fixture to /tmp, loads it, does something,
5
+ # saves, reads the file back, and asserts on the raw text. Every test
6
+ # unloads its object and deletes its scratch file at the end so the
7
+ # next one starts clean.
8
+ #
9
+
10
+ tests [can] :
11
+ verbs [can] :
12
+ save [can] :
13
+ f [file] : /tmp/gloo_save_test.gloo
14
+ g [file] : /tmp/gloo_save_test_2.gloo
15
+ to_target [file] : /tmp/gloo_save_test_to.gloo
16
+ out [string] : BEGIN
17
+ #
18
+ # a comment above demo
19
+ #
20
+ demo [container] :
21
+ msg [string] : hello
22
+ END
23
+ err [bool] : false
24
+
25
+ on_error [script] :
26
+ put true into ^.err
27
+
28
+ #
29
+ # The fixture used by most tests: two comments, a changed-in-place
30
+ # value, and an untouched sibling.
31
+ #
32
+ fixture [text] : BEGIN
33
+ #
34
+ # a comment above demo
35
+ #
36
+ demo [container] :
37
+ msg [string] : hello
38
+ # a comment above other
39
+ other [string] : world
40
+ END
41
+
42
+ round_trip_preserves_comments_and_untouched_lines [test] :
43
+ description [string] : load, change one value, save -- comments and the untouched sibling survive.
44
+ on_test [script] :
45
+ put false into ^^.err
46
+ tell ^^.f to write ( ^^.fixture )
47
+ load /tmp/gloo_save_test.gloo
48
+ put 'changed' into demo.msg
49
+ save demo
50
+ eval ^^.err = false
51
+ assert "save should not error"
52
+ tell ^^.f to read ( ^^.out )
53
+ check ^^.out for substring? ( "# a comment above demo" )
54
+ assert "the leading comment block should survive"
55
+ check ^^.out for substring? ( "# a comment above other" )
56
+ assert "the inner comment should survive"
57
+ check ^^.out for substring? ( "msg [string] : changed" )
58
+ assert "the changed value should be written"
59
+ check ^^.out for substring? ( "other [string] : world" )
60
+ assert "the untouched sibling should be unchanged"
61
+ tell demo to unload
62
+ tell ^^.f to delete
63
+ unchanged_file_round_trips_byte_for_byte [test] :
64
+ description [string] : load then save with no change reproduces the file exactly.
65
+ on_test [script] :
66
+ tell ^^.f to write ( ^^.fixture )
67
+ load /tmp/gloo_save_test.gloo
68
+ save demo
69
+ tell ^^.f to read ( ^^.out )
70
+ eval ^^.out = ^^.fixture
71
+ assert "an unchanged save should reproduce the original text"
72
+ tell demo to unload
73
+ tell ^^.f to delete
74
+ deleting_an_object_drops_its_line [test] :
75
+ description [string] : removing a child and saving drops just that declaration.
76
+ on_test [script] :
77
+ tell ^^.f to write ( ^^.fixture )
78
+ load /tmp/gloo_save_test.gloo
79
+ tell demo.other to unload
80
+ save demo
81
+ tell ^^.f to read ( ^^.out )
82
+ check ^^.out for substring? ( "msg [string] : hello" )
83
+ assert "the kept sibling should still be there"
84
+ check ^^.out for substring? ( "other [string]" )
85
+ refute "the removed child's line should be gone"
86
+ tell demo to unload
87
+ tell ^^.f to delete
88
+ save_to_a_new_path_creates_the_file [test] :
89
+ description [string] : save {obj} to {path} writes a new file and registers it.
90
+ on_test [script] :
91
+ tell ^^.f to write ( ^^.fixture )
92
+ load /tmp/gloo_save_test.gloo
93
+ save demo to /tmp/gloo_save_test_to
94
+ check ^^.to_target for exists?
95
+ assert "save ... to should create the target file"
96
+ tell ^^.to_target to read ( ^^.out )
97
+ check ^^.out for substring? ( "msg [string] : hello" )
98
+ assert "the new file should hold the object"
99
+ tell demo to unload
100
+ tell ^^.f to delete
101
+ tell ^^.to_target to delete
102
+ reload_discards_unsaved_changes [test] :
103
+ description [string] : reload throws away edits that were not saved.
104
+ on_test [script] :
105
+ tell ^^.f to write ( ^^.fixture )
106
+ load /tmp/gloo_save_test.gloo
107
+ put 'not saved' into demo.msg
108
+ eval demo.msg = 'not saved'
109
+ assert "sanity: the edit landed"
110
+ tell demo to reload
111
+ eval demo.msg = 'hello'
112
+ assert "reload should restore the on-disk value"
113
+ tell demo to unload
114
+ tell ^^.f to delete
115
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gloo
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.3.0
4
+ version: 6.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eric Crane
@@ -384,12 +384,22 @@ files:
384
384
  - lib/gloo/objs/web/http_post.rb
385
385
  - lib/gloo/objs/web/json.rb
386
386
  - lib/gloo/objs/web/uri.rb
387
+ - lib/gloo/persist/comment_buffer.rb
388
+ - lib/gloo/persist/declaration_ledger.rb
387
389
  - lib/gloo/persist/disc_mech.rb
388
390
  - lib/gloo/persist/file_loader.rb
389
391
  - lib/gloo/persist/file_saver.rb
390
392
  - lib/gloo/persist/file_storage.rb
393
+ - lib/gloo/persist/indent_stack.rb
391
394
  - lib/gloo/persist/line_splitter.rb
392
395
  - lib/gloo/persist/persist_man.rb
396
+ - lib/gloo/persist/script_body_collector.rb
397
+ - lib/gloo/persist/shorthand_expander.rb
398
+ - lib/gloo/persist/source/blank_node.rb
399
+ - lib/gloo/persist/source/comment_node.rb
400
+ - lib/gloo/persist/source/directive_node.rb
401
+ - lib/gloo/persist/source/obj_node.rb
402
+ - lib/gloo/persist/source/source_doc.rb
393
403
  - lib/gloo/plugin/base.rb
394
404
  - lib/gloo/plugin/callback.rb
395
405
  - lib/gloo/plugin/ext_manager.rb
@@ -443,6 +453,7 @@ files:
443
453
  - test.gloo/lang/load_lib_directive.test.gloo
444
454
  - test.gloo/lang/naming.test.gloo
445
455
  - test.gloo/lang/ops.test.gloo
456
+ - test.gloo/lang/shorthand.test.gloo
446
457
  - test.gloo/math/add.test.gloo
447
458
  - test.gloo/math/div.test.gloo
448
459
  - test.gloo/math/mult.test.gloo
@@ -481,7 +492,9 @@ files:
481
492
  - test.gloo/verbs/log.test.gloo
482
493
  - test.gloo/verbs/move.test.gloo
483
494
  - test.gloo/verbs/put.test.gloo
495
+ - test.gloo/verbs/reload.test.gloo
484
496
  - test.gloo/verbs/run.test.gloo
497
+ - test.gloo/verbs/save.test.gloo
485
498
  - test.gloo/verbs/show.test.gloo
486
499
  - test.gloo/verbs/tell.test.gloo
487
500
  - test.gloo/verbs/throw.test.gloo