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 +4 -4
- data/CLAUDE.md +1 -1
- data/README.md +1 -0
- data/docs/application.md +24 -4
- data/docs/getting_started.md +2 -4
- data/docs/language_objects.md +1 -1
- data/docs/language_syntax.md +29 -2
- data/docs/plugins.md +325 -3
- data/docs/web_app.md +211 -0
- data/lib/VERSION +1 -1
- data/lib/VERSION_NOTES +6 -0
- data/lib/gloo/app/engine.rb +17 -2
- data/lib/gloo/app/log.rb +5 -4
- data/lib/gloo/app/platform.rb +5 -0
- data/lib/gloo/app/prompt.rb +2 -1
- data/lib/gloo/app/settings.rb +25 -15
- data/lib/gloo/app/table.rb +7 -3
- data/lib/gloo/app/theme.rb +144 -0
- data/lib/gloo/core/invoker.rb +102 -0
- data/lib/gloo/core/parser.rb +48 -7
- data/lib/gloo/core/tokens.rb +81 -1
- data/lib/gloo/docs/help_shell.rb +67 -20
- data/lib/gloo/docs/markdown_renderer.rb +7 -7
- data/lib/gloo/expr/call.rb +54 -0
- data/lib/gloo/expr/expression.rb +3 -0
- data/lib/gloo/objs/basic/string.rb +5 -25
- data/lib/gloo/objs/basic/string_msgs.rb +192 -2
- data/lib/gloo/objs/basic/text.rb +5 -26
- data/lib/gloo/objs/ctrl/function.rb +17 -4
- data/lib/gloo/verbs/help.rb +8 -5
- data/lib/gloo/verbs/invoke.rb +39 -46
- data/lib/gloo/verbs/list.rb +5 -4
- data/test.gloo/objs/string.test.gloo +54 -0
- data/test.gloo/verbs/invoke.test.gloo +73 -0
- metadata +5 -3
- data/.DS_Store +0 -0
- data/.travis.yml +0 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: abd0d2250aa7924305d71bc59ae30d88646ca4cca4464a15fb3acec674aa2635
|
|
4
|
+
data.tar.gz: 928c5dd7dd0a90b28707ec6383958a2f70de344659c0e87a5de79ab37f2dde95
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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`,
|
|
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:
|
|
90
|
+
start_with:
|
|
90
91
|
|
|
91
92
|
#
|
|
92
93
|
# Indentation (spaces) when showing an object outline.
|
|
93
94
|
#
|
|
94
|
-
list_indent:
|
|
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
|
|
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.
|
data/docs/getting_started.md
CHANGED
|
@@ -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
|
|
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)
|
|
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.
|
data/docs/language_objects.md
CHANGED
|
@@ -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
|
|
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'
|
data/docs/language_syntax.md
CHANGED
|
@@ -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
|
-
|
|
60
|
+
Target (into) missing!
|
|
58
61
|
```
|
|
59
62
|
|
|
60
63
|
Then, showing the error:
|
|
61
64
|
|
|
62
65
|
```
|
|
63
66
|
> show error
|
|
64
|
-
|
|
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
|
-
/
|
|
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
|
+
```
|