gloo 7.1.3 → 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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +23 -0
  3. data/docs/application.md +47 -2
  4. data/docs/development.md +10 -0
  5. data/docs/language_objects.md +20 -15
  6. data/docs/language_scripting.md +6 -2
  7. data/docs/testing.md +4 -7
  8. data/docs/verbs.md +23 -3
  9. data/lib/VERSION +1 -1
  10. data/lib/VERSION_NOTES +8 -0
  11. data/lib/dependencies.rb +4 -1
  12. data/lib/gloo/app/engine.rb +18 -6
  13. data/lib/gloo/core/obj.rb +0 -23
  14. data/lib/gloo/objs/basic/script.rb +0 -23
  15. data/lib/gloo/persist/declaration_ledger.rb +9 -9
  16. data/lib/gloo/persist/declaration_writer.rb +208 -0
  17. data/lib/gloo/persist/disc_mech.rb +70 -39
  18. data/lib/gloo/persist/file_loader.rb +125 -66
  19. data/lib/gloo/persist/file_saver.rb +130 -198
  20. data/lib/gloo/persist/file_storage.rb +15 -4
  21. data/lib/gloo/persist/file_style.rb +89 -0
  22. data/lib/gloo/persist/line_splitter.rb +16 -1
  23. data/lib/gloo/persist/persist_man.rb +112 -30
  24. data/lib/gloo/persist/save_index.rb +211 -0
  25. data/lib/gloo/persist/script_body_collector.rb +16 -21
  26. data/lib/gloo/persist/source/blank_node.rb +10 -3
  27. data/lib/gloo/persist/source/comment_node.rb +10 -2
  28. data/lib/gloo/persist/source/directive_node.rb +10 -2
  29. data/lib/gloo/persist/source/obj_node.rb +174 -9
  30. data/lib/gloo/persist/source/source_doc.rb +54 -0
  31. data/lib/gloo/persist/subtree_extractor.rb +9 -37
  32. data/lib/gloo/persist/trivia_buffer.rb +7 -7
  33. data/lib/gloo/verbs/load.rb +27 -21
  34. data/lib/gloo/verbs/move.rb +42 -3
  35. data/lib/gloo/verbs/save.rb +26 -4
  36. data/test.gloo/app/exit_status.test.gloo +34 -0
  37. data/test.gloo/app/fixtures/exit_after_error.gloo +9 -0
  38. data/test.gloo/lang/declaration.test.gloo +36 -0
  39. data/test.gloo/lang/fixtures/mixed_indent.gloo +5 -0
  40. data/test.gloo/lang/naming.test.gloo +44 -6
  41. data/test.gloo/verbs/fixtures/load_beside.gloo +6 -0
  42. data/test.gloo/verbs/fixtures/lossless_text.gloo +7 -0
  43. data/test.gloo/verbs/fixtures/lossless_text_saved.gloo +9 -0
  44. data/test.gloo/verbs/load.test.gloo +18 -0
  45. data/test.gloo/verbs/move.test.gloo +39 -0
  46. data/test.gloo/verbs/save.test.gloo +239 -0
  47. metadata +10 -1
@@ -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
+
@@ -0,0 +1,5 @@
1
+ mixed_indent_fixture [can] :
2
+ a [can] :
3
+ x [int] : 1
4
+ y [int] : 2
5
+ b [int] : 3
@@ -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] : when two siblings share a name, the path always reaches the first.
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
- eval ^^.dup = 'first'
34
- assert "expected the first 'dup' to be the one reached"
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.
@@ -0,0 +1,6 @@
1
+ #
2
+ # Loaded by load.test.gloo with a plain relative name, from the
3
+ # folder beside that test file. Not a test file itself.
4
+ #
5
+ load_beside_demo [can] :
6
+ s [string] : beside
@@ -0,0 +1,7 @@
1
+ lossless_text [can] :
2
+ log [text] : BEGIN
3
+ Started.
4
+ END
5
+ entry [text] : BEGIN
6
+ Saved.
7
+ END
@@ -0,0 +1,9 @@
1
+ lossless_text [can] :
2
+ log [text] : BEGIN
3
+ Started.
4
+ Saved.
5
+ Saved.
6
+ END
7
+ entry [text] : BEGIN
8
+ Saved.
9
+ END
@@ -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"
@@ -222,3 +222,242 @@ END
222
222
  assert "reload should restore the on-disk value"
223
223
  tell demo to unload
224
224
  tell ^^.f to delete
225
+
226
+ # -------------------------------------------------------------------
227
+ # Lossless save (7.2): an untouched declaration is written back
228
+ # exactly; a changed one changes only its own line.
229
+ # -------------------------------------------------------------------
230
+
231
+ body_fixture [text] : BEGIN
232
+ lossless_body [can] :
233
+ n [int] : 0
234
+ s [script] :
235
+ put 1 into ^.n
236
+
237
+ # a comment inside the body
238
+ put ^.n + 1 into ^.n # an inline comment
239
+ put ^.n + \
240
+ 2 into ^.n
241
+ after [string] : after
242
+ END
243
+
244
+ directive_fixture [text] : BEGIN
245
+ #
246
+ # A comment block above the directive.
247
+ #
248
+ load lib yaml
249
+
250
+ lossless_lib [can] :
251
+ cfg [yaml] :
252
+ END
253
+
254
+ untyped_fixture [text] : BEGIN
255
+ lossless_untyped [can] :
256
+ plain : no type given
257
+ END
258
+
259
+ untyped_changed [text] : BEGIN
260
+ lossless_untyped [can] :
261
+ plain : changed
262
+ END
263
+
264
+ same_name_fixture [text] : BEGIN
265
+ lossless_same [can] :
266
+ a [string] : First A
267
+ a [string] : Second A
268
+ END
269
+
270
+ same_name_changed [text] : BEGIN
271
+ lossless_same [can] :
272
+ a [string] : Changed
273
+ a [string] : Second A
274
+ END
275
+
276
+ shorthand_fixture [text] : BEGIN
277
+ lossless_short [can] :
278
+ x [int] : 1
279
+
280
+ lossless_short.b [can] :
281
+ y [int] : 2
282
+ END
283
+
284
+ style_fixture [text] : BEGIN
285
+ lossless_style [can] :
286
+ n [int] : 1
287
+ END
288
+
289
+ style_changed [text] : BEGIN
290
+ lossless_style [can] :
291
+ n [int] : 1
292
+ k [int] : 5
293
+ END
294
+
295
+ # A text value's fixture has its own BEGIN/END blocks, so it can't be
296
+ # a text block here: it's a file beside this one.
297
+ text_fixture [file] :
298
+ text_saved [file] :
299
+ text_src [string] :
300
+ text_want [string] :
301
+ where [string] :
302
+
303
+ utf8_fixture [text] : BEGIN
304
+ # Café — ünïcödé 🎉
305
+ lossless_utf8 [can] :
306
+ greeting [string] : héllo wörld 👋
307
+ END
308
+
309
+ untouched_script_body_round_trips [test] :
310
+ description [string] : blank lines, comments and a continuation in a script body survive a save.
311
+ on_test [script] :
312
+ tell ^^.f to write ( ^^.body_fixture )
313
+ load ( ^^.f )
314
+ tell lossless_body.s to run
315
+ eval lossless_body.n = 4
316
+ assert "sanity: the body ran, continuation and all"
317
+ put 0 into lossless_body.n
318
+ save lossless_body
319
+ tell ^^.f to read ( ^^.out )
320
+ eval ^^.out = ^^.body_fixture
321
+ assert "expected the body exactly as written"
322
+ tell lossless_body to unload
323
+ tell ^^.f to delete
324
+
325
+ directive_stays_below_its_comments [test] :
326
+ description [string] : a load lib directive stays where it was written.
327
+ on_test [script] :
328
+ tell ^^.f to write ( ^^.directive_fixture )
329
+ load ( ^^.f )
330
+ save lossless_lib
331
+ tell ^^.f to read ( ^^.out )
332
+ eval ^^.out = ^^.directive_fixture
333
+ assert "expected the directive below the comment block"
334
+ tell lossless_lib to unload
335
+ tell ^^.f to delete
336
+
337
+ untyped_stays_untyped [test] :
338
+ description [string] : an untyped declaration is saved without a type, changed or not.
339
+ on_test [script] :
340
+ tell ^^.f to write ( ^^.untyped_fixture )
341
+ load ( ^^.f )
342
+ save lossless_untyped
343
+ tell ^^.f to read ( ^^.out )
344
+ eval ^^.out = ^^.untyped_fixture
345
+ assert "expected the untouched declaration exactly as written"
346
+ put 'changed' into lossless_untyped.plain
347
+ save lossless_untyped
348
+ tell ^^.f to read ( ^^.out )
349
+ eval ^^.out = ^^.untyped_changed
350
+ assert "expected only the value to change"
351
+ tell lossless_untyped to unload
352
+ tell ^^.f to delete
353
+
354
+ an_edit_changes_only_the_first_same_name_line [test] :
355
+ description [string] : the first declaration holds the value; a later same-name line is kept as written.
356
+ expect_errors [bool] : true
357
+ on_test [script] :
358
+ tell ^^.f to write ( ^^.same_name_fixture )
359
+ load ( ^^.f )
360
+ put 'Changed' into lossless_same.a
361
+ save lossless_same
362
+ tell ^^.f to read ( ^^.out )
363
+ eval ^^.out = ^^.same_name_changed
364
+ assert "expected Second A to stay"
365
+ tell lossless_same to unload
366
+ tell ^^.f to delete
367
+
368
+ a_shorthand_child_is_written_once [test] :
369
+ description [string] : a container plus shorthand into it saves exactly as written.
370
+ on_test [script] :
371
+ tell ^^.f to write ( ^^.shorthand_fixture )
372
+ load ( ^^.f )
373
+ save lossless_short
374
+ tell ^^.f to read ( ^^.out )
375
+ eval ^^.out = ^^.shorthand_fixture
376
+ assert "expected the shorthand child not to be written again"
377
+ tell lossless_short to unload
378
+ tell ^^.f to delete
379
+
380
+ a_new_child_follows_the_files_style [test] :
381
+ description [string] : a new object is written with the file's indentation and type spelling.
382
+ on_test [script] :
383
+ tell ^^.f to write ( ^^.style_fixture )
384
+ load ( ^^.f )
385
+ create lossless_style.k as integer : 5
386
+ save lossless_style
387
+ tell ^^.f to read ( ^^.out )
388
+ eval ^^.out = ^^.style_changed
389
+ assert "expected two spaces and [int]"
390
+ tell lossless_style to unload
391
+ tell ^^.f to delete
392
+
393
+ appending_to_text_does_not_indent_it [test] :
394
+ description [string] : a changed text value is written exactly, so saving it twice adds nothing.
395
+ on_test [script] :
396
+ check ^^ for source_dir
397
+ put it into ^^.where
398
+ put ^^.where '/fixtures/lossless_text.gloo' into ^^.text_fixture
399
+ put ^^.where '/fixtures/lossless_text_saved.gloo' into ^^.text_saved
400
+ tell ^^.text_fixture to read ( ^^.text_src )
401
+ tell ^^.text_saved to read ( ^^.text_want )
402
+ tell ^^.f to write ( ^^.text_src )
403
+ load ( ^^.f )
404
+ put lossless_text.log + lossless_text.entry into lossless_text.log
405
+ save lossless_text
406
+ put lossless_text.log + lossless_text.entry into lossless_text.log
407
+ save lossless_text
408
+ tell ^^.f to read ( ^^.out )
409
+ eval ^^.out = ^^.text_want
410
+ assert "expected the lines with no added indentation"
411
+ tell lossless_text to unload
412
+ tell ^^.f to delete
413
+
414
+ utf8_round_trips [test] :
415
+ description [string] : non-ASCII text loads and saves exactly.
416
+ on_test [script] :
417
+ tell ^^.f to write ( ^^.utf8_fixture )
418
+ load ( ^^.f )
419
+ eval lossless_utf8.greeting = 'héllo wörld 👋'
420
+ assert "expected the value as written"
421
+ save lossless_utf8
422
+ tell ^^.f to read ( ^^.out )
423
+ eval ^^.out = ^^.utf8_fixture
424
+ assert "expected the file exactly as written"
425
+ tell lossless_utf8 to unload
426
+ tell ^^.f to delete
427
+
428
+
429
+ # -------------------------------------------------------------------
430
+ # Where a new file saved with a relative name goes (7.2): next to
431
+ # the saving script's file. These scripts are declared in this
432
+ # file, so that's the folder this file is in.
433
+ # -------------------------------------------------------------------
434
+
435
+ beside_target [file] :
436
+
437
+ save_to_a_relative_name_beside_this_file [test] :
438
+ description [string] : save {obj} to {relative name} writes the file next to the file the script came from.
439
+ on_test [script] :
440
+ check ^^ for source_dir
441
+ put it '/fixtures/save_beside.gloo' into ^^.beside_target
442
+ create save_beside_demo as can
443
+ create save_beside_demo.s as string : beside
444
+ save save_beside_demo to fixtures/save_beside
445
+ check ^^.beside_target for exists?
446
+ assert "expected fixtures/save_beside.gloo beside this file"
447
+ tell ^^.beside_target to read ( ^^.out )
448
+ check ^^.out for substring? ( "s [string] : beside" )
449
+ assert "expected the saved object in the file"
450
+ tell save_beside_demo to unload
451
+ tell ^^.beside_target to delete
452
+
453
+ save_a_new_root_beside_this_file [test] :
454
+ description [string] : save of a top-level object with no file yet writes it next to the file the script came from.
455
+ on_test [script] :
456
+ check ^^ for source_dir
457
+ put it '/save_beside_root.gloo' into ^^.beside_target
458
+ create save_beside_root as can
459
+ save save_beside_root
460
+ check ^^.beside_target for exists?
461
+ assert "expected save_beside_root.gloo beside this file"
462
+ tell save_beside_root to unload
463
+ tell ^^.beside_target to delete
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: 7.1.3
4
+ version: '7.2'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eric Crane
@@ -389,13 +389,16 @@ files:
389
389
  - lib/gloo/objs/web/json.rb
390
390
  - lib/gloo/objs/web/uri.rb
391
391
  - lib/gloo/persist/declaration_ledger.rb
392
+ - lib/gloo/persist/declaration_writer.rb
392
393
  - lib/gloo/persist/disc_mech.rb
393
394
  - lib/gloo/persist/file_loader.rb
394
395
  - lib/gloo/persist/file_saver.rb
395
396
  - lib/gloo/persist/file_storage.rb
397
+ - lib/gloo/persist/file_style.rb
396
398
  - lib/gloo/persist/indent_stack.rb
397
399
  - lib/gloo/persist/line_splitter.rb
398
400
  - lib/gloo/persist/persist_man.rb
401
+ - lib/gloo/persist/save_index.rb
399
402
  - lib/gloo/persist/script_body_collector.rb
400
403
  - lib/gloo/persist/shorthand_expander.rb
401
404
  - lib/gloo/persist/source/blank_node.rb
@@ -443,7 +446,9 @@ files:
443
446
  - lib/gloo/verbs/wait.rb
444
447
  - lib/run.rb
445
448
  - test.gloo/app/embed.test.gloo
449
+ - test.gloo/app/exit_status.test.gloo
446
450
  - test.gloo/app/fixtures/embed_harness.rb
451
+ - test.gloo/app/fixtures/exit_after_error.gloo
447
452
  - test.gloo/basic.test.gloo
448
453
  - test.gloo/ctrl/each.test.gloo
449
454
  - test.gloo/dt/date.test.gloo
@@ -455,6 +460,7 @@ files:
455
460
  - test.gloo/lang/dt_comparisons.test.gloo
456
461
  - test.gloo/lang/exceptions.test.gloo
457
462
  - test.gloo/lang/failures.test.gloo
463
+ - test.gloo/lang/fixtures/mixed_indent.gloo
458
464
  - test.gloo/lang/gloo_sys.test.gloo
459
465
  - test.gloo/lang/here.test.gloo
460
466
  - test.gloo/lang/it.test.gloo
@@ -495,6 +501,9 @@ files:
495
501
  - test.gloo/verbs/create.test.gloo
496
502
  - test.gloo/verbs/eval.test.gloo
497
503
  - test.gloo/verbs/exists.test.gloo
504
+ - test.gloo/verbs/fixtures/load_beside.gloo
505
+ - test.gloo/verbs/fixtures/lossless_text.gloo
506
+ - test.gloo/verbs/fixtures/lossless_text_saved.gloo
498
507
  - test.gloo/verbs/if.test.gloo
499
508
  - test.gloo/verbs/invoke.test.gloo
500
509
  - test.gloo/verbs/list.test.gloo