gloo 6.1.0 → 6.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6d840aa7f080d3daedcc5bbb7311b5403d40ea859edef9d88caca22b76caee6c
4
- data.tar.gz: c324e249c1a307000b1de509573a5c03de4420bae941efb69ea0b1adcd927d47
3
+ metadata.gz: abd0d2250aa7924305d71bc59ae30d88646ca4cca4464a15fb3acec674aa2635
4
+ data.tar.gz: 928c5dd7dd0a90b28707ec6383958a2f70de344659c0e87a5de79ab37f2dde95
5
5
  SHA512:
6
- metadata.gz: 48cb54242371f5b6589ba0baacf71da8b75c4f1118fecb6ba78eccb17be0f03d920551f0d93d6512802827c7bfa0cae462cf05a993f77061f525d9d6277c9e8d
7
- data.tar.gz: 1bc77db8417820182b27b1f7b797f1587e21dc595d89d06b3250f8db983df149d9564f258bee5b4139182e3af95ceb9dfb23b07b533fcea5bbfe9f803a50eac1
6
+ metadata.gz: ffffea710873468a26f3fc01e02a141ed001d2960dedfb66288451119df7af7daf2814d530d4436988227c7c3dd21e2f442e8060c8a6f58b644484eef3b36362
7
+ data.tar.gz: 4daa427abc7ebcb4f054911a1d4bc54b2a9d239cfa7f3aab85894bcd32ce79ffa62b18106ab7e6699bbe9599fe73b73e01270cf6cd774b81b85ad6b3c81ba295
data/CLAUDE.md CHANGED
@@ -29,7 +29,7 @@ gloo/
29
29
 
30
30
  This project is the authoritative source for gloo language documentation — not the `vaults/gloo` Obsidian vault, whose old `doc/` folder was renamed to `doc_deprecated/` and retired.
31
31
 
32
- - **Narrative reference** — `docs/*.md`, ten flat files: `getting_started.md`, `application.md`, `language_objects.md`, `language_syntax.md`, `language_scripting.md`, `operators.md`, `iterators.md`, `objects.md`, `verbs.md`, `plugins.md`. Linked from the root `README.md`. Convention: no markdown link syntax between pages (plain-text pointers instead, e.g. "see Put" not `[Put](put.md)`) since these are read both on GitHub and in a terminal; `---` separates sections that came from different source material.
32
+ - **Narrative reference** — `docs/*.md`, eleven flat files: `getting_started.md`, `application.md`, `language_objects.md`, `language_syntax.md`, `language_scripting.md`, `operators.md`, `iterators.md`, `objects.md`, `verbs.md`, `plugins.md`, `web_app.md`. Linked from the root `README.md`. Convention: no markdown link syntax between pages (plain-text pointers instead, e.g. "see Put" not `[Put](put.md)`) since these are read both on GitHub and in a terminal; `---` separates sections that came from different source material.
33
33
  - **Verb/object reference** — each verb (`lib/gloo/verbs/*.rb`) and object type (`lib/gloo/objs/**/*.rb`) class defines `self.doc_data` (name, shortcut, description, syntax, parameters, result, errors, examples, notes — see `lib/gloo/docs/doc_data.rb`), rendered by the in-app interactive help shell (`help`/`?`, see `lib/gloo/docs/help_shell.rb`). When adding or changing a verb or object type, add/update its `doc_data` too.
34
34
  - Core-lib gems (`gloo_core_libraries`) follow the same `doc_data` pattern for their own verbs/objects; a narrative `doc/` folder per gem is planned but not yet built.
35
35
 
data/README.md CHANGED
@@ -47,6 +47,7 @@ Read in order for a guided tour of the language, top to bottom, or jump straight
47
47
  8. [Operators](docs/operators.md) — math and comparison operators
48
48
  9. [Iterators](docs/iterators.md) — each, repeat
49
49
  10. [Plugins](docs/plugins.md) — core libraries and user extensions
50
+ 11. [A Trivial Web App](docs/web_app.md) — a two-page "Hello World" built with the `gloo-web` core library
50
51
 
51
52
 
52
53
  ## License
data/docs/application.md CHANGED
@@ -64,6 +64,7 @@ When specifying a file there are a couple ways to reference the gloo file to ope
64
64
  - If a file is provided as a parameter this option does not need to be specified.
65
65
  --test - Run in Test mode
66
66
  --version - Show application version
67
+ --help - Show the help screen
67
68
  ```
68
69
 
69
70
  ## Configuration
@@ -86,12 +87,12 @@ gloo:
86
87
  # Run this script when starting up gloo.
87
88
  # (Only if a script file is not specified.)
88
89
  #
89
- start_with: start
90
+ start_with:
90
91
 
91
92
  #
92
93
  # Indentation (spaces) when showing an object outline.
93
94
  #
94
- list_indent: 3
95
+ list_indent: 2
95
96
 
96
97
  #
97
98
  # Show listing the object tree,
@@ -104,6 +105,23 @@ gloo:
104
105
  # Show debug statements in the log?
105
106
  #
106
107
  debug: false
108
+
109
+ #
110
+ # Color theme for console output: dark or light.
111
+ # Match this to your terminal's background.
112
+ #
113
+ theme: dark
114
+ ```
115
+
116
+ ## Color Theme
117
+
118
+ Gloo colors its console output (prompts, `help settings`, warnings/errors, listings, the help shell) to be readable against a terminal background. There's no auto-detection — set `theme: dark` or `theme: light` in `gloo.yml` to match your terminal, and it applies everywhere at once. Defaults to `dark` if unset or set to anything else.
119
+
120
+ To see the current theme and preview both palettes side by side (handy for comparing across terminals before you switch), use the `theme` help topic:
121
+
122
+ ```gloo
123
+ > help
124
+ help> theme
107
125
  ```
108
126
 
109
127
  ## Logging
@@ -133,11 +151,12 @@ Gloo has a built-in `help` verb (shortcut `?`) that enters an interactive help s
133
151
  help
134
152
  ```
135
153
 
136
- From the `help>` prompt, look up verbs, object types, settings, extensions, libraries, and narrative doc pages, or get detailed help for a specific verb, object, doc page, loaded library, or loaded extension:
154
+ From the `help>` prompt, look up verbs, object types, settings, the color theme, extensions, libraries, and narrative doc pages, or get detailed help for a specific verb, object, doc page, loaded library, or loaded extension:
137
155
 
138
156
  - `verbs` — list all verbs
139
157
  - `objects` — list all object types
140
158
  - `settings` — show application settings
159
+ - `theme` — show the current color theme, how to change it, and a preview of both palettes
141
160
  - `extensions` — list loaded extensions (only loaded extensions are shown; use `load ext {name}` first)
142
161
  - `libraries` — list loaded libraries (only loaded libraries are shown; use `load lib {name}` first)
143
162
  - `docs` — list all narrative doc pages (this page and its siblings)
@@ -153,6 +172,7 @@ From the `help>` prompt, look up verbs, object types, settings, extensions, libr
153
172
  help> verbs
154
173
  help> verb put
155
174
  help> object container
175
+ help> theme
156
176
  help> docs
157
177
  help> doc getting_started
158
178
  help> library db
@@ -161,4 +181,4 @@ help> quit
161
181
 
162
182
  ### Narrative Docs in the Shell
163
183
 
164
- This page and its nine siblings (`docs/*.md` in the interpreter's source) are the same files shown by `help> doc {name}` — there's no separate doc server or web mode. A `gloo --doc` local web server was considered and put off in favor of this: one system, no separate build/serve step.
184
+ This page and its ten siblings (`docs/*.md` in the interpreter's source) are the same files shown by `help> doc {name}` — there's no separate doc server or web mode. A `gloo --doc` local web server was considered and put off in favor of this: one system, no separate build/serve step.
@@ -55,9 +55,7 @@ Once Gloo is running you can interact with the gloo interpreter. Type the follow
55
55
 
56
56
  ### CLI, On Ruby
57
57
 
58
- Gloo is a scripting language and a CLI runtime engine. It was built primarily to run on the Mac and has hooks into several Mac technologies. It runs, at least nominally, on Windows and Linux as well.
59
-
60
- Gloo was built in Ruby as a gem. More than that, it has hooks into ruby, can run ruby code, and shares a lot the way ruby works.
58
+ Gloo is a scripting language and a CLI runtime engine. It was built and tested primarily on the Mac. It runs, at least nominally, on Windows and Linux as well.
61
59
 
62
60
  ### The Name "Gloo" and a Bit of History
63
61
 
@@ -109,4 +107,4 @@ Interaction with objects is done by sending messages to them.
109
107
 
110
108
  ## Source Code
111
109
 
112
- Gloo source code is in GitHub (https://github.com/ecrane/gloo), although the repository is currently private. It might be made public in the future if there is interest or need.
110
+ Gloo source code is in GitHub (https://github.com/ecrane/gloo). It's shared publicly for visibility rather than as a maintained open-source project.
@@ -129,7 +129,7 @@ Here are some of the value conversions that gloo will attempt:
129
129
  - decimal with integer value
130
130
  - `put 1 into d` => 1.0
131
131
  - string to boolean
132
- - if the string is ~ 'true' then the boolean is true, otherwise false
132
+ - if the string is (trimmed, case-insensitive) 'true' or 't' then the boolean is true; 'false' or 'f' is false; anything else is false
133
133
  - `put 'true' into bool` => true
134
134
  - boolean to string
135
135
  - simple to-string conversion: 'true' or 'false'
@@ -5,6 +5,7 @@
5
5
  - Color
6
6
  - Errors
7
7
  - Events
8
+ - Function Calls
8
9
  - Gloo System Objects
9
10
  - Here
10
11
  - It
@@ -24,6 +25,8 @@ black
24
25
  yellow
25
26
  ```
26
27
 
28
+ These are the common ones, but any color name from the `colorize` gem works too (e.g. `cyan`, `magenta`, or a `light_` variant of any of the above).
29
+
27
30
  The color names are considered as virtual objects but may also be referenced in variables. See the example below.
28
31
 
29
32
  ```gloo
@@ -54,14 +57,14 @@ To run a command that generates an error:
54
57
 
55
58
  ```
56
59
  > put 3 into
57
- 'put' must include 'into' target
60
+ Target (into) missing!
58
61
  ```
59
62
 
60
63
  Then, showing the error:
61
64
 
62
65
  ```
63
66
  > show error
64
- 'put' must include 'into' target
67
+ Target (into) missing!
65
68
  ```
66
69
 
67
70
  But, as mentioned, the next command will clear out the last error. If you need to keep track of the result of a command, you should put the error into another object.
@@ -144,6 +147,30 @@ error_data [can] :
144
147
 
145
148
  See also: Load, Reload, Unload, Save, Quit.
146
149
 
150
+ ## Function Calls
151
+
152
+ The `invoke` verb (shortcut `~>`) calls a function object (`[ƒ]`) as a standalone command, space-separated params:
153
+
154
+ ```gloo
155
+ invoke functions.add 3 4
156
+ show it
157
+ ```
158
+
159
+ `invoke( ... )` and `~>( ... )` are the inline forms of the same thing — usable anywhere an expression is evaluated (`show`, `put ... into`, `if`, `unless`, `eval`, and more), not just as a standalone command:
160
+
161
+ ```gloo
162
+ show invoke( functions.add 3 4 )
163
+ put ~>( functions.add 3 4 ) into total
164
+ show "Total: " + invoke( functions.add 3 4 )
165
+ if invoke( checks.is_ready ) then show 'ready'
166
+ ```
167
+
168
+ `invoke(...)` and `~>(...)` are exactly equivalent — just the full keyword and its shortcut, same as the standalone verb. Params stay space-separated inside the parens; each one is evaluated as a single token (a literal or object reference), same as the standalone verb — not a multi-token sub-expression, so `invoke( f 3+4 )` won't parse `3+4` as one param.
169
+
170
+ The parens must immediately follow the keyword with no space (`invoke(`, not `invoke (`) — that's what tells gloo it's a function call rather than `show`'s unrelated trailing `(color)` syntax, which always has a space before the paren.
171
+
172
+ See also: Color.
173
+
147
174
  ## Gloo System Objects
148
175
 
149
176
  The gloo system objects are virtual objects. That is, they can be accessed like other objects, but the values are set by the system. The values cannot be updated. The other difference is that the virtual objects do not show up in the object heap.
data/docs/plugins.md CHANGED
@@ -13,30 +13,74 @@ Be sure to load a core library (or extension) prior to loading a gloo file that
13
13
 
14
14
  Use the Load Verb to use an extension.
15
15
 
16
+ A core library ships as its own gem (`gloo-<name>`). `load lib <name>` requires the gem, installing it first via `gem install` if it isn't already present — so the explicit `gem install` step below is optional, but doing it yourself ahead of time is recommended so the install doesn't happen mid-script. Once loaded, a library's objects and verbs show up in the `help`/`?` shell exactly like built-ins:
17
+
18
+ ```gloo
19
+ > gem install gloo-yaml
20
+ > load lib yaml
21
+ help> object yaml
22
+ ```
23
+
16
24
  ### Available Core Libraries
17
25
 
18
26
  - **CLI** — Use the `gloo-cli` gem when building CLI applications.
19
27
  - Library Objects: Prompt, Colorize, Confirm, Select, Menu, Menu Item, Shell, Command
28
+ ```gloo
29
+ > gem install gloo-cli
30
+ > load lib cli
31
+ help> object prompt
32
+ ```
20
33
  - **Database** — Use the `gloo-db` gem and one or more of `gloo-sqlite`, `gloo-mysql`, `gloo-pg` connector gems.
21
34
  - Library Objects: Query, Table, SQLite, MySQL, Postgres
35
+ ```gloo
36
+ > gem install gloo-db gloo-sqlite
37
+ > load lib db
38
+ > load lib sqlite
39
+ help> object query
40
+ ```
22
41
  - **Email** — Use the `gloo-email` gem to send and receive email.
23
42
  - Library Objects: Email, Email SMTP, Email IMAP
43
+ ```gloo
44
+ > gem install gloo-email
45
+ > load lib email
46
+ help> object email_smtp
47
+ ```
24
48
  - **Markdown** — Use the `gloo-md` gem to render markdown.
25
49
  - Library Objects: Markdown, MD Doc (a markdown file with YAML frontmatter), Markdown Extensions (part of the markdown object)
50
+ ```gloo
51
+ > gem install gloo-md
52
+ > load lib md
53
+ help> object markdown
54
+ ```
26
55
  - **Test** — Use the `gloo-test` gem to manually include. See Test Runner for notes about the gloo test runner.
27
56
  - Library Objects: Test
28
57
  - Library Verbs: Assert, Refute
29
58
  - See also: Eval, It
59
+ ```gloo
60
+ > gem install gloo-test
61
+ > load lib test
62
+ help> verb assert
63
+ ```
30
64
  - **Web Server** — Use the `gloo-web` gem when building web applications.
31
65
  - Library Objects: Server, Page, Partial, Form, Field, Element
66
+ ```gloo
67
+ > gem install gloo-web
68
+ > load lib web
69
+ help> object page
70
+ ```
32
71
  - **YAML** — Use the `gloo-yaml` gem for YAML file read/write support.
33
72
  - Library Objects: YAML
73
+ ```gloo
74
+ > gem install gloo-yaml
75
+ > load lib yaml
76
+ help> object yaml
77
+ ```
34
78
 
35
79
  ## User Extensions
36
80
 
37
81
  A User Extension is a mechanism that can be used to add verbs and objects that are not built into gloo.
38
82
 
39
- Extensions are ruby code that live in the `extensions` folder inside the gloo root folder.
83
+ Extensions are ruby code that live in the `extensions` folder inside the gloo root folder (`~/gloo/extensions` by default — see `ext_path` in Settings).
40
84
 
41
85
  An extension is structured thus:
42
86
 
@@ -46,9 +90,287 @@ An extension is structured thus:
46
90
  /doc/
47
91
  /src/
48
92
  /test/
49
- /ext_name.rb
93
+ /ext_name_ext.rb
50
94
  ```
51
95
 
96
+ - `ext_name_ext.rb` — the extension's entry point. Loaded and registered when `load ext ext_name` runs.
97
+ - `src/` — the verb and/or object classes themselves, one file per class.
98
+ - `doc/` — narrative markdown for the extension (a `README.md` at the extension root plus optional per-object/verb `.md` files under `doc/` are the convention used by the built-in extensions — see e.g. `extensions/beep/`).
99
+ - `test/` — both Ruby unit tests (`*_test.rb`, minitest, same conventions as this project's own `test/` — see Test Suites in the root `CLAUDE.md`) and/or a gloo-language integration test (`*.test.gloo`).
100
+
52
101
  Be sure to load an extension (or core library) prior to loading a gloo file that includes object types defined in the extension.
53
102
 
54
- Use the Load Verb to use an extension.
103
+ Use the Load Verb to use an extension: `load ext ext_name`.
104
+
105
+ ### The extension entry point
106
+
107
+ `ext_name_ext.rb` defines a class named `<ExtName>Ext` (the extension's folder name, capitalized, plus `Ext`) that derives from `Gloo::Plugin::Base` and implements `register`. `register` is handed a `Gloo::Plugin::Callback` that it uses to register one or more verb and/or object classes:
108
+
109
+ ```ruby
110
+ #
111
+ # Registers the beep extension.
112
+ #
113
+ # This extension provides a simple beep command.
114
+ #
115
+ class BeepExt < Gloo::Plugin::Base
116
+
117
+ #
118
+ # Register verbs and objects.
119
+ #
120
+ def register( callback )
121
+ require_relative 'src/beep'
122
+
123
+ callback.register_verb( Beep )
124
+ end
125
+
126
+ end
127
+ ```
128
+
129
+ `callback.register_verb` and `callback.register_obj` both take a class, not an instance. Wrap the calls in a `begin`/`rescue` if the extension has external dependencies (a gem, a CLI tool on the `PATH`, etc.) that might not be present, so a missing dependency logs an error instead of crashing the whole extension load — see `extensions/stats/stats_ext.rb` or `extensions/git/git_ext.rb` for the pattern:
130
+
131
+ ```ruby
132
+ def register( callback )
133
+ require_relative 'src/git'
134
+
135
+ begin
136
+ callback.register_obj( Git )
137
+ rescue => e
138
+ puts "Failed to load Git extension: #{e.message}"
139
+ end
140
+ end
141
+ ```
142
+
143
+ ### Adding a Verb
144
+
145
+ A verb subclasses `Gloo::Core::Verb` and must implement `self.keyword`, `self.keyword_shortcut`, and `run`. Inside `run`, `@tokens` gives access to the parsed command line and `@engine` is the running engine (use `@engine.err` for user-facing errors, `@engine.heap.it` to set the implicit `it` result).
146
+
147
+ The simplest possible verb — `beep`, which takes no parameters (`extensions/beep/src/beep.rb`):
148
+
149
+ ```ruby
150
+ #
151
+ # Play a standard system beep sound.
152
+ #
153
+ class Beep < Gloo::Core::Verb
154
+
155
+ KEYWORD = 'beep'.freeze
156
+ KEYWORD_SHORT = 'b'.freeze
157
+
158
+ def self.keyword
159
+ return KEYWORD
160
+ end
161
+
162
+ def self.keyword_shortcut
163
+ return KEYWORD_SHORT
164
+ end
165
+
166
+ def run
167
+ print 7.chr
168
+ end
169
+
170
+ # ---------------------------------------------------------------------
171
+ # Verb Documentation
172
+ # ---------------------------------------------------------------------
173
+
174
+ def self.doc_data
175
+ {
176
+ :name => KEYWORD,
177
+ :shortcut => KEYWORD_SHORT,
178
+ :description => 'Play a standard system beep sound.',
179
+ :syntax => [ 'beep' ],
180
+ :result => 'A system beep (chime) is sounded.',
181
+ :examples => <<~EXAMPLES.strip
182
+ > beep
183
+ EXAMPLES
184
+ }
185
+ end
186
+
187
+ end
188
+ ```
189
+
190
+ A verb that reads a parameter — `alert`, which evaluates an expression and shows it as a system notification (`extensions/alert/src/alert.rb`):
191
+
192
+ ```ruby
193
+ class Alert < Gloo::Core::Verb
194
+
195
+ KEYWORD = 'alert'.freeze
196
+ KEYWORD_SHORT = '!'.freeze
197
+
198
+ MISSING_EXPR_ERR = 'Missing Expression!'.freeze
199
+ NO_RESULT_ERR = 'Expression evaluated with no result!'.freeze
200
+
201
+ def run
202
+ unless @tokens.token_count > 1
203
+ @engine.err MISSING_EXPR_ERR
204
+ return
205
+ end
206
+
207
+ expr = Gloo::Expr::Expression.new( @engine, @tokens.params )
208
+ result = expr.evaluate
209
+
210
+ if result
211
+ @engine.heap.it.set_to result
212
+ post_alert result
213
+ else
214
+ @engine.err NO_RESULT_ERR
215
+ end
216
+ end
217
+
218
+ def self.keyword
219
+ return KEYWORD
220
+ end
221
+
222
+ def self.keyword_shortcut
223
+ return KEYWORD_SHORT
224
+ end
225
+
226
+ private
227
+
228
+ def post_alert( msg )
229
+ @engine.log.info msg
230
+ return if @engine.args.quiet?
231
+
232
+ post_osx msg
233
+ end
234
+
235
+ def post_osx( msg )
236
+ cmd1 = '/usr/bin/osascript -e "display notification \"'
237
+ cmd2 = '\" with title \"Gloo\" "'
238
+ system( cmd1 + msg.to_s + cmd2 )
239
+ end
240
+
241
+ end
242
+ ```
243
+
244
+ Register it from `alert_ext.rb` with `callback.register_verb( Alert )`, and the verb `alert {message}` becomes available anywhere after `load ext alert`.
245
+
246
+ ### Adding an Object
247
+
248
+ An object subclasses `Gloo::Core::Obj` and must implement `self.typename` and `self.short_typename`. Objects typically:
249
+
250
+ - expose named children (settings/parameters) that are read with `find_child`
251
+ - optionally auto-add default children on creation, via `add_children_on_create?` and `add_default_children`
252
+ - respond to messages (`tell obj to some_message`) by overriding `self.messages` to list the message names and defining a `msg_<name>` method for each
253
+
254
+ `stats`, from `extensions/stats/src/stats.rb`, shows all three. It declares three children (`folder`, `types`, `skip`), adds them automatically on `create`, and implements three messages that delegate to a plain Ruby helper class (`Gloo::Utils::Stats`, in `extensions/stats/src/stats_util.rb`) that does the real work:
255
+
256
+ ```ruby
257
+ class Stats < Gloo::Core::Obj
258
+
259
+ KEYWORD = 'stats'.freeze
260
+ KEYWORD_SHORT = 'stat'.freeze
261
+ FOLDER = 'folder'.freeze
262
+ TYPES = 'types'.freeze
263
+ SKIP = 'skip'.freeze
264
+
265
+ def self.typename
266
+ return KEYWORD
267
+ end
268
+
269
+ def self.short_typename
270
+ return KEYWORD_SHORT
271
+ end
272
+
273
+ def path_value
274
+ o = find_child FOLDER
275
+ return o ? o.value : nil
276
+ end
277
+
278
+ def types_value
279
+ o = find_child TYPES
280
+ return o ? o.value : ''
281
+ end
282
+
283
+ def skip_list
284
+ o = find_child SKIP
285
+ val = o ? o.value : ''
286
+ return val.split ' '
287
+ end
288
+
289
+ # ---------------------------------------------------------------------
290
+ # Children
291
+ # ---------------------------------------------------------------------
292
+
293
+ def add_children_on_create?
294
+ return true
295
+ end
296
+
297
+ def add_default_children
298
+ fac = @engine.factory
299
+ fac.create_file FOLDER, '', self
300
+ fac.create_string TYPES, '', self
301
+ fac.create_can SKIP, self
302
+ end
303
+
304
+ # ---------------------------------------------------------------------
305
+ # Messages
306
+ # ---------------------------------------------------------------------
307
+
308
+ def self.messages
309
+ all = %w[show_all]
310
+ more = %w[show_busy_folders show_types]
311
+ return super + all + more
312
+ end
313
+
314
+ def msg_show_all
315
+ o = Gloo::Utils::Stats.new(
316
+ @engine, path_value, types_value, skip_list )
317
+ o.show_all
318
+ end
319
+
320
+ def msg_show_types
321
+ o = Gloo::Utils::Stats.new(
322
+ @engine, path_value, types_value, skip_list )
323
+ o.file_types
324
+ end
325
+
326
+ def msg_show_busy_folders
327
+ o = Gloo::Utils::Stats.new(
328
+ @engine, path_value, types_value, skip_list )
329
+ o.busy_folders
330
+ end
331
+
332
+ end
333
+ ```
334
+
335
+ `self.messages` should call `super` and append to it — the base `Gloo::Core::Obj` already contributes messages every object receives (`reload`, `unload`, `blank?`, `contains?`, `responds_to?`).
336
+
337
+ Used from gloo, once loaded:
338
+
339
+ ```gloo
340
+ main [can] :
341
+ stats [stats] :
342
+ folder [file] : /Users/me/dev/project
343
+ types [string] : rb erb js
344
+ skip [string] : .git tmp
345
+ on_load [script] :
346
+ tell main.stats to show_all
347
+ ```
348
+
349
+ Register it from `stats_ext.rb` with `callback.register_obj( Stats )`.
350
+
351
+ ### Custom `each` iterators
352
+
353
+ An extension's object can also plug into the built-in `each` verb by providing its own iterator. `extensions/git/src/each_repo.rb` shows the shape: a plain Ruby class (not a `Gloo::Core::Obj`) with `self.use_for?( iterator_obj )` — which returns `true` when the `each` loop's iterator object looks like a match (here, when it has a `repo` child) — and a `run` method that walks whatever it's iterating over, setting the loop's child value and calling `@iterator_obj.run_do` for each item. See the git extension for the full pattern; this hook only makes sense for extensions that also register a matching object type (here, `git_repo`).
354
+
355
+ ### Documenting the extension
356
+
357
+ Add `self.doc_data` to every verb/object class (see the `beep` and `stats` examples above) — this is what powers the in-app `help`/`?` shell once the extension is loaded, exactly as it does for built-in verbs and objects (see `lib/gloo/docs/doc_data.rb`). Also add a top-level `README.md` for the extension (usage, `load ext` line, list of verbs/objects, a pointer to `help> verb <name>` / `help> object <name>` for the full reference) — see `extensions/beep/README.md` or `extensions/git/README.md` for the expected shape and length.
358
+
359
+ ### Testing an extension
360
+
361
+ Add a Ruby unit test per verb/object class under `test/` (mirrors the conventions in the root `CLAUDE.md`'s Test Suites section — inherit from the project's `GlooTest`/`BaseEngineTest` base), and add a `*.test.gloo` integration test that loads the extension and exercises it end to end, e.g. `extensions/beep/test/beep.test.gloo`:
362
+
363
+ ```gloo
364
+ tests [can] :
365
+ beep [can] :
366
+
367
+ on_load [script] :
368
+ load ext beep
369
+
370
+ assert_verb [test] :
371
+ description [string] : The beep verb exists
372
+ on_test [script] :
373
+ exists? verb beep
374
+ assert "beep verb should exist"
375
+ beep
376
+ ```