gloo 6.0.1 → 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 +9 -3
- data/README.md +39 -7
- data/docs/application.md +184 -0
- data/docs/getting_started.md +110 -0
- data/docs/iterators.md +294 -0
- data/docs/language_objects.md +190 -0
- data/docs/language_scripting.md +62 -0
- data/docs/language_syntax.md +334 -0
- data/docs/objects.md +77 -0
- data/docs/operators.md +62 -0
- data/docs/plugins.md +376 -0
- data/docs/verbs.md +64 -0
- data/docs/web_app.md +211 -0
- data/gloo.gemspec +3 -1
- data/lib/VERSION +1 -1
- data/lib/VERSION_NOTES +16 -0
- data/lib/gloo/app/engine.rb +17 -2
- data/lib/gloo/app/log.rb +5 -4
- data/lib/gloo/app/platform.rb +34 -2
- 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/gloo_system.rb +52 -1
- 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/doc_data.rb +160 -0
- data/lib/gloo/docs/help_shell.rb +332 -0
- data/lib/gloo/docs/markdown_renderer.rb +39 -0
- data/lib/gloo/expr/call.rb +54 -0
- data/lib/gloo/expr/expression.rb +3 -0
- data/lib/gloo/objs/basic/alias.rb +53 -0
- data/lib/gloo/objs/basic/boolean.rb +30 -0
- data/lib/gloo/objs/basic/container.rb +38 -0
- data/lib/gloo/objs/basic/decimal.rb +30 -0
- data/lib/gloo/objs/basic/integer.rb +58 -0
- data/lib/gloo/objs/basic/script.rb +31 -0
- data/lib/gloo/objs/basic/string.rb +31 -4
- data/lib/gloo/objs/basic/string_msgs.rb +212 -2
- data/lib/gloo/objs/basic/text.rb +30 -4
- data/lib/gloo/objs/basic/untyped.rb +21 -0
- data/lib/gloo/objs/ctrl/each.rb +63 -1
- data/lib/gloo/objs/ctrl/function.rb +86 -4
- data/lib/gloo/objs/ctrl/repeat.rb +41 -0
- data/lib/gloo/objs/dt/date.rb +43 -0
- data/lib/gloo/objs/dt/datetime.rb +50 -0
- data/lib/gloo/objs/dt/time.rb +43 -0
- data/lib/gloo/objs/str_utils/cipher.rb +59 -0
- data/lib/gloo/objs/str_utils/outline.rb +65 -1
- data/lib/gloo/objs/str_utils/password.rb +56 -0
- data/lib/gloo/objs/system/erb.rb +39 -0
- data/lib/gloo/objs/system/file_handle.rb +56 -0
- data/lib/gloo/objs/system/system.rb +29 -0
- data/lib/gloo/objs/web/http_get.rb +35 -0
- data/lib/gloo/objs/web/http_post.rb +33 -0
- data/lib/gloo/objs/web/json.rb +40 -0
- data/lib/gloo/objs/web/uri.rb +40 -0
- data/lib/gloo/shell/command_node.rb +39 -0
- data/lib/gloo/shell/context.rb +93 -0
- data/lib/gloo/shell/runner.rb +315 -0
- data/lib/gloo/verbs/break.rb +32 -0
- data/lib/gloo/verbs/check.rb +49 -0
- data/lib/gloo/verbs/cls.rb +18 -0
- data/lib/gloo/verbs/context.rb +47 -0
- data/lib/gloo/verbs/create.rb +42 -0
- data/lib/gloo/verbs/eval.rb +27 -0
- data/lib/gloo/verbs/execute.rb +27 -0
- data/lib/gloo/verbs/exists.rb +54 -2
- data/lib/gloo/verbs/files.rb +22 -0
- data/lib/gloo/verbs/help.rb +46 -178
- data/lib/gloo/verbs/if.rb +52 -0
- data/lib/gloo/verbs/invoke.rb +88 -33
- data/lib/gloo/verbs/list.rb +37 -4
- data/lib/gloo/verbs/load.rb +55 -2
- data/lib/gloo/verbs/log.rb +44 -0
- data/lib/gloo/verbs/move.rb +36 -1
- data/lib/gloo/verbs/put.rb +35 -0
- data/lib/gloo/verbs/quit.rb +19 -0
- data/lib/gloo/verbs/redirect.rb +52 -2
- data/lib/gloo/verbs/reload.rb +27 -0
- data/lib/gloo/verbs/run.rb +39 -0
- data/lib/gloo/verbs/save.rb +26 -0
- data/lib/gloo/verbs/show.rb +54 -0
- data/lib/gloo/verbs/tell.rb +32 -0
- data/lib/gloo/verbs/throw.rb +29 -0
- data/lib/gloo/verbs/unless.rb +50 -0
- data/lib/gloo/verbs/unload.rb +23 -0
- data/lib/gloo/verbs/version.rb +37 -3
- data/lib/gloo/verbs/wait.rb +26 -0
- data/test.gloo/objs/string.test.gloo +54 -0
- data/test.gloo/verbs/invoke.test.gloo +73 -0
- metadata +26 -10
- data/.DS_Store +0 -0
- data/.travis.yml +0 -5
data/docs/operators.md
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Operators
|
|
2
|
+
|
|
3
|
+
Gloo operators can be used to do basic math and to compare values.
|
|
4
|
+
|
|
5
|
+
**Contents**
|
|
6
|
+
|
|
7
|
+
- Math Operators
|
|
8
|
+
- Comparison Operators
|
|
9
|
+
- Example
|
|
10
|
+
|
|
11
|
+
## Math Operators
|
|
12
|
+
|
|
13
|
+
These are the gloo math operators:
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
+ addition
|
|
17
|
+
- subtraction
|
|
18
|
+
* multiplication
|
|
19
|
+
/ division
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Comparison Operators
|
|
23
|
+
|
|
24
|
+
Strings, integers, and decimal numbers can be compared.
|
|
25
|
+
|
|
26
|
+
These are the gloo comparison operators:
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
= equal (== also works, as an alternate spelling — not a separate identity check)
|
|
30
|
+
!= not equal
|
|
31
|
+
> greater than
|
|
32
|
+
< less than
|
|
33
|
+
>= greater than or equal to
|
|
34
|
+
<= less than or equal to
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Example
|
|
38
|
+
|
|
39
|
+
Here are some examples of math operator usage:
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
> show 2 + 5
|
|
43
|
+
> put 12 / 3 into x
|
|
44
|
+
> show 23 * 3 - 6
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
And some examples of comparison operator usage:
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
> show 2 = 2
|
|
51
|
+
> show 2 != 2
|
|
52
|
+
> show 2 > 2
|
|
53
|
+
> show 2 < 2
|
|
54
|
+
> show 2 >= 2
|
|
55
|
+
> show 2 <= 2
|
|
56
|
+
|
|
57
|
+
> if a = b then show "the strings are equal"
|
|
58
|
+
> if x > y then run my_script
|
|
59
|
+
> put x != y into my_bool
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
See also: Put, Show.
|
data/docs/plugins.md
ADDED
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
# Plugins
|
|
2
|
+
|
|
3
|
+
**Contents**
|
|
4
|
+
|
|
5
|
+
- Core Libraries
|
|
6
|
+
- User Extensions
|
|
7
|
+
|
|
8
|
+
## Core Libraries
|
|
9
|
+
|
|
10
|
+
Core Libraries extend gloo functionality, primarily by adding object types and potentially verbs.
|
|
11
|
+
|
|
12
|
+
Be sure to load a core library (or extension) prior to loading a gloo file that includes object types defined in the library.
|
|
13
|
+
|
|
14
|
+
Use the Load Verb to use an extension.
|
|
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
|
+
|
|
24
|
+
### Available Core Libraries
|
|
25
|
+
|
|
26
|
+
- **CLI** — Use the `gloo-cli` gem when building CLI applications.
|
|
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
|
+
```
|
|
33
|
+
- **Database** — Use the `gloo-db` gem and one or more of `gloo-sqlite`, `gloo-mysql`, `gloo-pg` connector gems.
|
|
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
|
+
```
|
|
41
|
+
- **Email** — Use the `gloo-email` gem to send and receive email.
|
|
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
|
+
```
|
|
48
|
+
- **Markdown** — Use the `gloo-md` gem to render markdown.
|
|
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
|
+
```
|
|
55
|
+
- **Test** — Use the `gloo-test` gem to manually include. See Test Runner for notes about the gloo test runner.
|
|
56
|
+
- Library Objects: Test
|
|
57
|
+
- Library Verbs: Assert, Refute
|
|
58
|
+
- See also: Eval, It
|
|
59
|
+
```gloo
|
|
60
|
+
> gem install gloo-test
|
|
61
|
+
> load lib test
|
|
62
|
+
help> verb assert
|
|
63
|
+
```
|
|
64
|
+
- **Web Server** — Use the `gloo-web` gem when building web applications.
|
|
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
|
+
```
|
|
71
|
+
- **YAML** — Use the `gloo-yaml` gem for YAML file read/write support.
|
|
72
|
+
- Library Objects: YAML
|
|
73
|
+
```gloo
|
|
74
|
+
> gem install gloo-yaml
|
|
75
|
+
> load lib yaml
|
|
76
|
+
help> object yaml
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## User Extensions
|
|
80
|
+
|
|
81
|
+
A User Extension is a mechanism that can be used to add verbs and objects that are not built into gloo.
|
|
82
|
+
|
|
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).
|
|
84
|
+
|
|
85
|
+
An extension is structured thus:
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
~/gloo/extensions/
|
|
89
|
+
/ext_name
|
|
90
|
+
/doc/
|
|
91
|
+
/src/
|
|
92
|
+
/test/
|
|
93
|
+
/ext_name_ext.rb
|
|
94
|
+
```
|
|
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
|
+
|
|
101
|
+
Be sure to load an extension (or core library) prior to loading a gloo file that includes object types defined in the extension.
|
|
102
|
+
|
|
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
|
+
```
|
data/docs/verbs.md
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Verbs
|
|
2
|
+
|
|
3
|
+
Verbs are the commands that make up a gloo script — `put`, `show`, `run`, `tell`, and 25 others. Every statement in gloo starts with a verb.
|
|
4
|
+
|
|
5
|
+
Verbs aren't just for scripts, though. They're also the interactive language of the gloo application itself: run `gloo` in CLI mode (see Application, Running Gloo) and you can type these same verbs directly at the prompt, one at a time, in a REPL.
|
|
6
|
+
|
|
7
|
+
**Contents**
|
|
8
|
+
|
|
9
|
+
- Run
|
|
10
|
+
- Tell
|
|
11
|
+
- Put
|
|
12
|
+
|
|
13
|
+
This page walks through three of the most commonly used verbs to get a feel for how they work together. For the complete list of verbs, their full syntax, and every error they can raise, use the in-app help: enter `help` (or `?`), then `verbs` to list them all, or `verb {name}` for detail on one (see Application, Help).
|
|
14
|
+
|
|
15
|
+
## Run
|
|
16
|
+
|
|
17
|
+
`run` runs a script or other runnable object — the same as sending it a `run` message.
|
|
18
|
+
|
|
19
|
+
```gloo
|
|
20
|
+
run {path.to.object}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
```gloo
|
|
24
|
+
> run my.script
|
|
25
|
+
|
|
26
|
+
> create s as script : "show 3 + 4"
|
|
27
|
+
> run s
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Tell
|
|
31
|
+
|
|
32
|
+
`tell` sends a message to an object, asking it to do something. Where `run` executes a runnable object, `tell` is the general-purpose way to invoke any message an object supports (`up`, `count`, `inc`, `randomize` — see Objects).
|
|
33
|
+
|
|
34
|
+
```gloo
|
|
35
|
+
tell {path.to.object} to {message}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
```gloo
|
|
39
|
+
> tell an.obj to unload
|
|
40
|
+
> tell the.script to run
|
|
41
|
+
> tell my.str to up
|
|
42
|
+
> tell the.container to count
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Put
|
|
46
|
+
|
|
47
|
+
`put` evaluates an expression and stores the result in an object.
|
|
48
|
+
|
|
49
|
+
```gloo
|
|
50
|
+
put {expression} into {dst.path}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
```gloo
|
|
54
|
+
> put 'one' into str
|
|
55
|
+
> put 123 into x
|
|
56
|
+
> put 3 + 5 into x
|
|
57
|
+
> put TRUE into flag
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
`it` also picks up the result of the evaluation, same as with other verbs — see It.
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
`run`, `tell`, and `put` cover a lot of ground on their own, but there are 26 more verbs — `show`, `if`, `create`, `each`, `check`, and so on — all documented in-app. Enter `help` (or `?`), then `verbs` to browse them. (This page itself is also viewable in-app: `help> doc verbs`.)
|
data/docs/web_app.md
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
# A Trivial Web App
|
|
2
|
+
|
|
3
|
+
**Contents**
|
|
4
|
+
|
|
5
|
+
- Overview
|
|
6
|
+
- File and Folder Layout
|
|
7
|
+
- start.gloo
|
|
8
|
+
- app/app.gloo
|
|
9
|
+
- layout/primary.gloo
|
|
10
|
+
- shared/nav.gloo
|
|
11
|
+
- page/home.gloo
|
|
12
|
+
- page/about.gloo
|
|
13
|
+
- Running It
|
|
14
|
+
- Where To Go From Here
|
|
15
|
+
|
|
16
|
+
## Overview
|
|
17
|
+
|
|
18
|
+
This walks through the smallest complete gloo web app: a "Hello World" with two pages (`home` and `about`) sharing a common layout and nav bar. It uses the `gloo-web` core library — see Plugins for how core libraries are installed and loaded in general.
|
|
19
|
+
|
|
20
|
+
The app runs in App Mode (`gloo --app {path}`, see Application) — gloo looks for a `start.gloo` file at the root of the app folder and runs it. That file loads everything else and starts the web server.
|
|
21
|
+
|
|
22
|
+
## File and Folder Layout
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
hello/
|
|
26
|
+
start.gloo
|
|
27
|
+
app/
|
|
28
|
+
app.gloo
|
|
29
|
+
layout/
|
|
30
|
+
primary.gloo
|
|
31
|
+
shared/
|
|
32
|
+
nav.gloo
|
|
33
|
+
page/
|
|
34
|
+
home.gloo
|
|
35
|
+
about.gloo
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
- `start.gloo` — the entry point. Loads the `web` core library, then everything under `app/`, `layout/`, `shared/`, and `page/`, then starts the server.
|
|
39
|
+
- `app/app.gloo` — the `app` object: the app's URL and its `svr` (web server), including server config and the default routes (layout, home page).
|
|
40
|
+
- `layout/primary.gloo` — the page layout shared by every page: the HTML shell, the nav bar, and where a page's own head/body content gets inserted.
|
|
41
|
+
- `shared/nav.gloo` — a partial (reusable fragment) for the nav bar, included by the layout.
|
|
42
|
+
- `page/home.gloo`, `page/about.gloo` — the two pages. Every `[page]` object loaded under the root `page` container automatically becomes a route: `page.home` answers `/`, `page.about` answers `/about`. Routes are wired up by the router when the server starts — there's no separate routing table to maintain by hand.
|
|
43
|
+
|
|
44
|
+
## start.gloo
|
|
45
|
+
|
|
46
|
+
```gloo
|
|
47
|
+
#
|
|
48
|
+
# Start the hello app.
|
|
49
|
+
#
|
|
50
|
+
# Run it:
|
|
51
|
+
# gloo --app ~/gloo/projects/apps/hello
|
|
52
|
+
#
|
|
53
|
+
|
|
54
|
+
start [container] :
|
|
55
|
+
|
|
56
|
+
on_load [script] :
|
|
57
|
+
|
|
58
|
+
# Load the web core library.
|
|
59
|
+
load lib web
|
|
60
|
+
|
|
61
|
+
# Load the app's own objects.
|
|
62
|
+
load app/*
|
|
63
|
+
load layout/*
|
|
64
|
+
load shared/*
|
|
65
|
+
load page/*
|
|
66
|
+
|
|
67
|
+
# Start the server and open it in a browser.
|
|
68
|
+
tell app.svr to start
|
|
69
|
+
tell app.url to open
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## app/app.gloo
|
|
73
|
+
|
|
74
|
+
```gloo
|
|
75
|
+
#
|
|
76
|
+
# The hello app: web server config and default routes.
|
|
77
|
+
#
|
|
78
|
+
|
|
79
|
+
app [can] :
|
|
80
|
+
|
|
81
|
+
# The app's URL.
|
|
82
|
+
url [uri] : http://localhost:8080/
|
|
83
|
+
|
|
84
|
+
# The web server for the app.
|
|
85
|
+
svr [svr] :
|
|
86
|
+
|
|
87
|
+
config [container] :
|
|
88
|
+
scheme [string] : http
|
|
89
|
+
host [string] : localhost
|
|
90
|
+
port [string] : 8080
|
|
91
|
+
|
|
92
|
+
on_start [script] : show 'hello app started'
|
|
93
|
+
on_stop [script] : show 'hello app stopped'
|
|
94
|
+
|
|
95
|
+
# Default layout and home page.
|
|
96
|
+
layout [alias] : layout.primary
|
|
97
|
+
home [alias] : page.home
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
`svr` is a `gloo-web` object type (see Plugins — Core Libraries). `layout` and `home` are conventional aliases: `layout` points at the partial used to wrap every page that doesn't specify its own, and `home` points at the page served for `/`. A real app would also set `error [alias] : page.err` to control the page shown on a server error, but it's optional — gloo falls back to a generic message if it's not set.
|
|
101
|
+
|
|
102
|
+
## layout/primary.gloo
|
|
103
|
+
|
|
104
|
+
```gloo
|
|
105
|
+
#
|
|
106
|
+
# The shared page layout: HTML shell + nav bar.
|
|
107
|
+
# Every page renders inside this unless it specifies its own layout.
|
|
108
|
+
#
|
|
109
|
+
|
|
110
|
+
layout [can] :
|
|
111
|
+
primary [part] :
|
|
112
|
+
content [can] :
|
|
113
|
+
|
|
114
|
+
html_open [text] : BEGIN
|
|
115
|
+
<!DOCTYPE html>
|
|
116
|
+
<html lang="en">
|
|
117
|
+
<head>
|
|
118
|
+
<%= head %>
|
|
119
|
+
</head>
|
|
120
|
+
<body>
|
|
121
|
+
END
|
|
122
|
+
|
|
123
|
+
nav [alias] : shared.nav
|
|
124
|
+
body [string] : <%= body %>
|
|
125
|
+
|
|
126
|
+
html_close [text] : BEGIN
|
|
127
|
+
</body>
|
|
128
|
+
</html>
|
|
129
|
+
END
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
`primary` is a `[part]` (partial) — see Plugins for the `gloo-web` object list. `<%= head %>` and `<%= body %>` are filled in automatically by the page being rendered: whatever that page defines under its own `head` and `body` children. `nav` is an alias to the shared nav partial below, rendered inline wherever it appears in the layout's content.
|
|
133
|
+
|
|
134
|
+
## shared/nav.gloo
|
|
135
|
+
|
|
136
|
+
```gloo
|
|
137
|
+
#
|
|
138
|
+
# The shared nav bar, included by the layout.
|
|
139
|
+
#
|
|
140
|
+
|
|
141
|
+
shared [can] :
|
|
142
|
+
nav [part] :
|
|
143
|
+
content [text] : BEGIN
|
|
144
|
+
<nav>
|
|
145
|
+
<a href="/">Home</a>
|
|
146
|
+
<a href="/about">About</a>
|
|
147
|
+
</nav>
|
|
148
|
+
END
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## page/home.gloo
|
|
152
|
+
|
|
153
|
+
```gloo
|
|
154
|
+
#
|
|
155
|
+
# The home page ("/").
|
|
156
|
+
#
|
|
157
|
+
|
|
158
|
+
page [can] :
|
|
159
|
+
home [page] :
|
|
160
|
+
|
|
161
|
+
params [can] :
|
|
162
|
+
msg [string] : Hello, World!
|
|
163
|
+
|
|
164
|
+
head [e] :
|
|
165
|
+
content [can] :
|
|
166
|
+
title [e] : Hello
|
|
167
|
+
|
|
168
|
+
body [e] :
|
|
169
|
+
content [can] :
|
|
170
|
+
h1 [e] : <%= msg %>
|
|
171
|
+
p [e] : This is the home page.
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
`page.home` is what `app.svr.home` points to, so it answers requests to `/`. `params` declares values the page's content can reference — here just `msg`, used in the `<h1>` via `<%= msg %>`. `head` and `title` and `body`, `h1`, `p` are `[e]` (element) objects — see Plugins — the building blocks the layout's `<%= head %>`/`<%= body %>` render.
|
|
175
|
+
|
|
176
|
+
## page/about.gloo
|
|
177
|
+
|
|
178
|
+
```gloo
|
|
179
|
+
#
|
|
180
|
+
# The about page ("/about"), reached by name automatically —
|
|
181
|
+
# no routing table entry required.
|
|
182
|
+
#
|
|
183
|
+
|
|
184
|
+
page [can] :
|
|
185
|
+
about [page] :
|
|
186
|
+
|
|
187
|
+
head [e] :
|
|
188
|
+
content [can] :
|
|
189
|
+
title [e] : About
|
|
190
|
+
|
|
191
|
+
body [e] :
|
|
192
|
+
content [can] :
|
|
193
|
+
h1 [e] : About
|
|
194
|
+
p [e] : A trivial two-page gloo web app.
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Because this page is named `about` and lives directly under the root `page` container, it's automatically routed to `/about` the moment the server starts — see File and Folder Layout above.
|
|
198
|
+
|
|
199
|
+
## Running It
|
|
200
|
+
|
|
201
|
+
```shell
|
|
202
|
+
gloo --app ~/gloo/projects/apps/hello
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
This runs `start.gloo`, which starts the server and opens `http://localhost:8080/` in a browser. Visit `/about` to see the second page. Stop the app the same way as any other gloo app (`q` at the prompt, or `Ctrl-C`).
|
|
206
|
+
|
|
207
|
+
Once the app is running, `gloo-web`'s objects (`page`, `part`, `e`, `svr`, `form`, `field`) are all documented in-app — `help> object page`, etc. — see Plugins.
|
|
208
|
+
|
|
209
|
+
## Where To Go From Here
|
|
210
|
+
|
|
211
|
+
This example deliberately leaves out most of what `gloo-web` supports: forms and fields (`form`, `field`), page parameters populated from query strings, sessions, static assets (images/CSS/JS served from an `asset/` folder, with `image_tag`/`css_tag`/`js_tag` layout helpers), a database-backed page (`gloo-db` plus a `sqlite`/`mysql`/`postgres` driver — see Plugins), and a dedicated error page. Each of those follows the same shape shown here: an object type from `gloo-web` (or another core library), loaded the same way, documented the same way in `help`.
|