gloo 6.0 → 6.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/CLAUDE.md +9 -3
  3. data/README.md +38 -7
  4. data/docs/application.md +164 -0
  5. data/docs/getting_started.md +112 -0
  6. data/docs/iterators.md +294 -0
  7. data/docs/language_objects.md +190 -0
  8. data/docs/language_scripting.md +62 -0
  9. data/docs/language_syntax.md +307 -0
  10. data/docs/objects.md +77 -0
  11. data/docs/operators.md +62 -0
  12. data/docs/plugins.md +54 -0
  13. data/docs/verbs.md +64 -0
  14. data/gloo.gemspec +5 -3
  15. data/lib/VERSION +1 -1
  16. data/lib/VERSION_NOTES +14 -0
  17. data/lib/gloo/app/platform.rb +29 -2
  18. data/lib/gloo/app/settings.rb +1 -1
  19. data/lib/gloo/core/gloo_system.rb +52 -1
  20. data/lib/gloo/docs/doc_data.rb +160 -0
  21. data/lib/gloo/docs/help_shell.rb +285 -0
  22. data/lib/gloo/docs/markdown_renderer.rb +39 -0
  23. data/lib/gloo/objs/basic/alias.rb +53 -0
  24. data/lib/gloo/objs/basic/boolean.rb +30 -0
  25. data/lib/gloo/objs/basic/container.rb +38 -0
  26. data/lib/gloo/objs/basic/decimal.rb +30 -0
  27. data/lib/gloo/objs/basic/integer.rb +58 -0
  28. data/lib/gloo/objs/basic/script.rb +31 -0
  29. data/lib/gloo/objs/basic/string.rb +51 -4
  30. data/lib/gloo/objs/basic/string_msgs.rb +20 -0
  31. data/lib/gloo/objs/basic/text.rb +51 -4
  32. data/lib/gloo/objs/basic/untyped.rb +21 -0
  33. data/lib/gloo/objs/ctrl/each.rb +63 -1
  34. data/lib/gloo/objs/ctrl/function.rb +69 -0
  35. data/lib/gloo/objs/ctrl/repeat.rb +41 -0
  36. data/lib/gloo/objs/dt/date.rb +43 -0
  37. data/lib/gloo/objs/dt/datetime.rb +50 -0
  38. data/lib/gloo/objs/dt/time.rb +43 -0
  39. data/lib/gloo/objs/str_utils/cipher.rb +59 -0
  40. data/lib/gloo/objs/str_utils/outline.rb +65 -1
  41. data/lib/gloo/objs/str_utils/password.rb +56 -0
  42. data/lib/gloo/objs/system/erb.rb +39 -0
  43. data/lib/gloo/objs/system/file_handle.rb +56 -0
  44. data/lib/gloo/objs/system/system.rb +29 -0
  45. data/lib/gloo/objs/web/http_get.rb +35 -0
  46. data/lib/gloo/objs/web/http_post.rb +33 -0
  47. data/lib/gloo/objs/web/json.rb +40 -0
  48. data/lib/gloo/objs/web/uri.rb +40 -0
  49. data/lib/gloo/shell/command_node.rb +39 -0
  50. data/lib/gloo/shell/context.rb +93 -0
  51. data/lib/gloo/shell/runner.rb +315 -0
  52. data/lib/gloo/verbs/break.rb +32 -0
  53. data/lib/gloo/verbs/check.rb +49 -0
  54. data/lib/gloo/verbs/cls.rb +18 -0
  55. data/lib/gloo/verbs/context.rb +47 -0
  56. data/lib/gloo/verbs/create.rb +42 -0
  57. data/lib/gloo/verbs/eval.rb +27 -0
  58. data/lib/gloo/verbs/execute.rb +27 -0
  59. data/lib/gloo/verbs/exists.rb +54 -2
  60. data/lib/gloo/verbs/files.rb +22 -0
  61. data/lib/gloo/verbs/help.rb +43 -178
  62. data/lib/gloo/verbs/if.rb +52 -0
  63. data/lib/gloo/verbs/invoke.rb +62 -0
  64. data/lib/gloo/verbs/list.rb +32 -0
  65. data/lib/gloo/verbs/load.rb +55 -2
  66. data/lib/gloo/verbs/log.rb +44 -0
  67. data/lib/gloo/verbs/move.rb +36 -1
  68. data/lib/gloo/verbs/put.rb +35 -0
  69. data/lib/gloo/verbs/quit.rb +19 -0
  70. data/lib/gloo/verbs/redirect.rb +52 -2
  71. data/lib/gloo/verbs/reload.rb +27 -0
  72. data/lib/gloo/verbs/run.rb +39 -0
  73. data/lib/gloo/verbs/save.rb +26 -0
  74. data/lib/gloo/verbs/show.rb +54 -0
  75. data/lib/gloo/verbs/tell.rb +32 -0
  76. data/lib/gloo/verbs/throw.rb +29 -0
  77. data/lib/gloo/verbs/unless.rb +50 -0
  78. data/lib/gloo/verbs/unload.rb +23 -0
  79. data/lib/gloo/verbs/version.rb +37 -3
  80. data/lib/gloo/verbs/wait.rb +26 -0
  81. metadata +28 -20
@@ -0,0 +1,315 @@
1
+ # Author:: Eric Crane (mailto:eric.crane@mac.com)
2
+ # Copyright:: Copyright (c) 2026 Eric Crane. All rights reserved.
3
+ #
4
+ # A shell runner. Drives a command-tree REPL with readline
5
+ # tab-completion.
6
+ #
7
+ # Adapted from gloo-cli's ShellRunner: that version took a `Shell`
8
+ # Gloo::Core::Obj and read its config (prompt, on_error, etc) from
9
+ # gloo-script-declared children. There's no such object tree for an
10
+ # interpreter-internal shell, so this version takes plain options
11
+ # instead. The Command Obj / cmd_obj_action(_with_context) mechanism
12
+ # was gloo-cli's way of running a gloo-declared Command object's
13
+ # action script; it isn't ported either — command nodes here always
14
+ # dispatch to a named method on the Runner (or a subclass of it).
15
+ #
16
+ # One addition beyond the gloo-cli original: a :dynamic node's
17
+ # generated children can carry a :child_method, so each one dispatches
18
+ # to a handler with the source item itself as `obj` (e.g. "verb put"
19
+ # dispatching to a detail-lookup method with "put" as the argument).
20
+ # gloo-cli didn't need this since it resolved a Command Obj instead.
21
+ #
22
+ require 'readline'
23
+
24
+ module Gloo
25
+ module Shell
26
+ class Runner
27
+
28
+ DEFAULT_PROMPT = ' -> '.freeze
29
+ UNKNOWN_COMMAND = 'Unknown command'.freeze
30
+
31
+ QUIT_NAME = 'quit'.freeze
32
+ QUIT_DESCRIPTION = 'Quit the application'.freeze
33
+ QUIT_METHOD = 'cmd_quit'.freeze
34
+
35
+ #
36
+ # Initialize the shell runner.
37
+ #
38
+ # @param engine [Gloo::App::Engine] The running gloo engine.
39
+ # Not used directly by the base Runner, but stored for
40
+ # subclasses' command methods to query (dictionary, heap, etc).
41
+ # @param opts [Hash] :prompt, :on_error, :on_unknown_command,
42
+ # :on_empty_command, :before_action, :after_action - all Procs
43
+ # except :prompt (String) and :include_quit (Boolean).
44
+ #
45
+ def initialize( engine, opts = {} )
46
+ @engine = engine
47
+ @prompt_text = opts[ :prompt ]
48
+ @on_error = opts[ :on_error ]
49
+ @on_unknown_command = opts[ :on_unknown_command ]
50
+ @on_empty_command = opts[ :on_empty_command ]
51
+ @before_action = opts[ :before_action ]
52
+ @after_action = opts[ :after_action ]
53
+ @include_quit = opts[ :include_quit ] || false
54
+
55
+ @context = Gloo::Shell::Context.new
56
+ @root = Gloo::Shell::CommandNode.new( nil )
57
+
58
+ add_quit_command if @include_quit
59
+ end
60
+
61
+ # ---------------------------------------------------------------------
62
+ # Shell control: start and stop
63
+ # ---------------------------------------------------------------------
64
+
65
+ #
66
+ # Start the shell.
67
+ #
68
+ def start
69
+ repl
70
+ end
71
+
72
+ #
73
+ # Flag the shell as done. Next time through the loop it will stop.
74
+ #
75
+ def stop
76
+ @context.done = true
77
+ end
78
+
79
+ #
80
+ # Get the prompt string.
81
+ #
82
+ def prompt
83
+ return @prompt_text ? "#{@prompt_text} " : DEFAULT_PROMPT
84
+ end
85
+
86
+ #
87
+ # Handle an empty command - run the on_empty_command hook if given.
88
+ #
89
+ def handle_empty_command
90
+ @on_empty_command&.call
91
+ end
92
+
93
+ #
94
+ # Handle an unknown command - run the on_unknown_command hook if
95
+ # given, otherwise show the default message.
96
+ #
97
+ def handle_unknown_command
98
+ return if @on_unknown_command&.call
99
+
100
+ puts UNKNOWN_COMMAND
101
+ end
102
+
103
+ #
104
+ # Run the before_action hook, if given.
105
+ #
106
+ def run_before_action
107
+ @before_action&.call
108
+ end
109
+
110
+ #
111
+ # Run the after_action hook, if given.
112
+ #
113
+ def run_after_action
114
+ @after_action&.call
115
+ end
116
+
117
+ #
118
+ # Run the on_error hook, if given.
119
+ #
120
+ def run_on_error
121
+ @on_error&.call
122
+ end
123
+
124
+ #
125
+ # Quit the shell.
126
+ #
127
+ def cmd_quit( _obj, context )
128
+ puts 'Quitting…'
129
+ context.done = true
130
+ end
131
+
132
+ # ---------------------------------------------------------------------
133
+ # Context
134
+ # ---------------------------------------------------------------------
135
+
136
+ #
137
+ # Set a context list, available to dynamic command nodes.
138
+ #
139
+ def set_context( key, value_list )
140
+ @context.set( key, value_list )
141
+ end
142
+
143
+ # ---------------------------------------------------------------------
144
+ # Tree building
145
+ # ---------------------------------------------------------------------
146
+
147
+ #
148
+ # Execute a command.
149
+ #
150
+ def execute_command( command_node, _args, _parent_node = nil )
151
+ if command_node.method
152
+ send( command_node.method, command_node.obj, @context )
153
+ elsif command_node.name && !command_node.description.empty?
154
+ puts "#{command_node.description}: #{command_node.name}"
155
+ end
156
+ end
157
+
158
+ #
159
+ # Build a command node from data.
160
+ #
161
+ def build_node_from_data( data )
162
+ if data[ :dynamic ]
163
+ return Gloo::Shell::CommandNode.new(
164
+ data[ :name ], description: data[ :description ], obj: data[ :obj ] ) do |ctx|
165
+ ctx.send( data[ :source ] ).map do |item|
166
+ Gloo::Shell::CommandNode.new( item, method: data[ :child_method ], obj: item )
167
+ end
168
+ end
169
+ elsif data[ :children ]
170
+ return Gloo::Shell::CommandNode.new(
171
+ data[ :name ], description: data[ :description ],
172
+ method: data[ :method ], obj: data[ :obj ] ) do |_ctx|
173
+ data[ :children ].map { |child_data| build_node_from_data( child_data ) }
174
+ end
175
+ else
176
+ return Gloo::Shell::CommandNode.new(
177
+ data[ :name ], description: data[ :description ],
178
+ method: data[ :method ], obj: data[ :obj ] )
179
+ end
180
+ end
181
+
182
+ #
183
+ # Add a command node to the root, dynamically.
184
+ #
185
+ # @param command_data [Hash] The command data hash.
186
+ #
187
+ def add_command_node( command_data )
188
+ node = build_node_from_data( command_data )
189
+
190
+ existing_block = @root.instance_variable_get( :@children_block )
191
+ if existing_block
192
+ existing_nodes = existing_block.call( @context )
193
+ all_nodes = existing_nodes + [ node ]
194
+ @root.instance_variable_set( :@children_block, proc { |_ctx| all_nodes } )
195
+ else
196
+ @root.instance_variable_set( :@children_block, proc { |_ctx| [ node ] } )
197
+ end
198
+
199
+ return node
200
+ end
201
+
202
+ # ---------------------------------------------------------------------
203
+ # REPL
204
+ # ---------------------------------------------------------------------
205
+
206
+ #
207
+ # Execute a single command from the given tokens and return.
208
+ #
209
+ def execute_once( tokens )
210
+ result = traverse( @root, tokens )
211
+ if result[ :node ]
212
+ run_before_action
213
+ execute_command( result[ :node ], tokens, result[ :parent ] )
214
+ run_after_action
215
+ else
216
+ handle_unknown_command
217
+ end
218
+ end
219
+
220
+ #
221
+ # Traverse the command tree to find the matching node.
222
+ #
223
+ # @param node [CommandNode] The current node.
224
+ # @param tokens [Array<String>] The tokens to traverse.
225
+ #
226
+ # @return [Hash] Hash with :node and :parent keys.
227
+ #
228
+ def traverse( node, tokens )
229
+ current = node
230
+ parent = nil
231
+
232
+ tokens.each do |token|
233
+ children = current.children( @context )
234
+ match = children.find { |c| c.name == token }
235
+ return { node: nil, parent: nil } unless match
236
+
237
+ parent = current
238
+ current = match
239
+ end
240
+
241
+ return { node: current, parent: parent }
242
+ end
243
+
244
+ #
245
+ # Setup readline completion.
246
+ #
247
+ def setup_completion
248
+ Readline.completion_append_character = ' '
249
+ Readline.basic_word_break_characters = " \t\n\"\\'`@$><=;|&{("
250
+
251
+ Readline.completion_proc = proc do |input|
252
+ buffer = Readline.line_buffer
253
+ tokens = buffer.split( ' ' )
254
+ tokens << '' if buffer.end_with?( ' ' )
255
+
256
+ result = traverse( @root, tokens[ 0..-2 ] )
257
+ current = result[ :node ]
258
+ options = current ? current.children( @context ).map( &:name ) : []
259
+
260
+ matches = options.grep( /^#{Regexp.escape( input )}/ )
261
+
262
+ if matches.length > 1
263
+ puts
264
+ current.children( @context ).each do |child|
265
+ puts "#{child.name.ljust( 15 )} #{child.description}" if matches.include?( child.name )
266
+ end
267
+ print "#{prompt}#{buffer}"
268
+ end
269
+
270
+ matches
271
+ end
272
+ end
273
+
274
+ #
275
+ # Run the REPL loop.
276
+ #
277
+ def repl
278
+ setup_completion
279
+
280
+ while !@context.done && ( line = Readline.readline( prompt, true ) )
281
+ tokens = line.strip.split( ' ' )
282
+ if tokens.empty?
283
+ handle_empty_command
284
+ next
285
+ end
286
+
287
+ result = traverse( @root, tokens )
288
+
289
+ if result[ :node ]
290
+ run_before_action
291
+ execute_command( result[ :node ], tokens, result[ :parent ] )
292
+ run_after_action
293
+ else
294
+ handle_unknown_command
295
+ end
296
+ end
297
+ end
298
+
299
+ # ---------------------------------------------------------------------
300
+ # Private
301
+ # ---------------------------------------------------------------------
302
+
303
+ private
304
+
305
+ #
306
+ # Add the built-in quit command, if enabled.
307
+ #
308
+ def add_quit_command
309
+ add_command_node(
310
+ { name: QUIT_NAME, description: QUIT_DESCRIPTION, method: QUIT_METHOD } )
311
+ end
312
+
313
+ end
314
+ end
315
+ end
@@ -39,6 +39,38 @@ module Gloo
39
39
 
40
40
  private
41
41
 
42
+ # ---------------------------------------------------------------------
43
+ # Verb Documentation
44
+ # ---------------------------------------------------------------------
45
+
46
+ #
47
+ # Get the verb's documentation data.
48
+ #
49
+ def self.doc_data
50
+ {
51
+ :name => KEYWORD,
52
+ :shortcut => KEYWORD_SHORT,
53
+ :description => 'Break out of the current script, stop running.',
54
+ :syntax => [ 'break' ],
55
+ :result => 'No more commands are executed in the currently ' \
56
+ 'running script. If there are other scripts in the stack, ' \
57
+ 'they will resume normally.',
58
+ :examples => <<~EXAMPLES.strip
59
+ #
60
+ # Break out of a script.
61
+ #
62
+ break_out [can] :
63
+ x [bool] : false
64
+ on_load [script] :
65
+ if ^.x then break
66
+ show 'should see this'
67
+ put true into ^.x
68
+ if ^.x then break
69
+ show 'should not see this'
70
+ EXAMPLES
71
+ }
72
+ end
73
+
42
74
  end
43
75
  end
44
76
  end
@@ -49,6 +49,55 @@ module Gloo
49
49
 
50
50
  private
51
51
 
52
+ # ---------------------------------------------------------------------
53
+ # Verb Documentation
54
+ # ---------------------------------------------------------------------
55
+
56
+ #
57
+ # Get the verb's documentation data.
58
+ #
59
+ def self.doc_data
60
+ {
61
+ :name => KEYWORD,
62
+ :shortcut => KEYWORD_SHORT,
63
+ :description => 'Send a message to an object to check for an ' \
64
+ 'object condition. This is the same as the tell verb, but ' \
65
+ 'gives better syntactical naming.',
66
+ :syntax => [ 'check {path.to.object} for {condition_message}' ],
67
+ :parameters => [
68
+ '{path.to.object} — The object that we want to send a condition_message to.',
69
+ '{message} — The condition_message to send.'
70
+ ],
71
+ :result => 'The result depends on the message that is sent, but ' \
72
+ 'by convention the result of the check will be in it.',
73
+ :errors => [
74
+ "#{UNKNOWN_MSG_ERR} — No message was specified, or the 'for' keyword is missing.",
75
+ 'Object was not found — The target of the message was not found.'
76
+ ],
77
+ :examples => <<~EXAMPLES.strip
78
+ #
79
+ # Base object checks.
80
+ #
81
+ obj [container] :
82
+ msg [string] :
83
+ on_load [script] :
84
+ show 'Does the obj container have children?'
85
+ check obj for contains?
86
+ show it
87
+
88
+ show 'Is the msg blank?'
89
+ check obj.msg for blank?
90
+ show it
91
+
92
+ put 'Hello, world!' into obj.msg
93
+ show obj.msg
94
+ show 'Is the msg still blank?'
95
+ check obj.msg for blank?
96
+ show it
97
+ EXAMPLES
98
+ }
99
+ end
100
+
52
101
  end
53
102
  end
54
103
  end
@@ -32,6 +32,24 @@ module Gloo
32
32
  return KEYWORD_SHORT
33
33
  end
34
34
 
35
+ # ---------------------------------------------------------------------
36
+ # Verb Documentation
37
+ # ---------------------------------------------------------------------
38
+
39
+ #
40
+ # Get the verb's documentation data.
41
+ #
42
+ def self.doc_data
43
+ {
44
+ :name => KEYWORD,
45
+ :shortcut => KEYWORD_SHORT,
46
+ :description => 'Clear the console screen.',
47
+ :syntax => [ 'clear' ],
48
+ :result => 'The screen is cleared and cursor set to the top.',
49
+ :examples => '> clear'
50
+ }
51
+ end
52
+
35
53
  end
36
54
  end
37
55
  end
@@ -57,6 +57,53 @@ module Gloo
57
57
  @engine.log.debug "Context set to #{@engine.heap.context}"
58
58
  end
59
59
 
60
+ # ---------------------------------------------------------------------
61
+ # Verb Documentation
62
+ # ---------------------------------------------------------------------
63
+
64
+ #
65
+ # Get the verb's documentation data.
66
+ #
67
+ def self.doc_data
68
+ {
69
+ :name => KEYWORD,
70
+ :shortcut => KEYWORD_SHORT,
71
+ :description => 'Get or set the current context. When no ' \
72
+ 'parameter is provided, the context will be shown. When the ' \
73
+ "optional path parameter is provided, the context will be set " \
74
+ "to that path. Use 'context root' to set the context back to " \
75
+ 'the root level. When context has been set, the pathname can ' \
76
+ 'start from the context container by use of the @. prefix.',
77
+ :syntax => [ 'context {path.to.new.context}' ],
78
+ :parameters => [
79
+ '{path.to.new.context} — Optional. The path to the new context when setting the context.'
80
+ ],
81
+ :result => 'Context is optionally set. It will be set to the ' \
82
+ 'new context path when we are changing context. Context is ' \
83
+ 'shown in either case.',
84
+ :notes => 'Providing a context that does not exist will not ' \
85
+ 'initially be a problem — you can set the context to an ' \
86
+ "object before it exists. However, use of a context that " \
87
+ "doesn't exist will be a problem.\n\n" \
88
+ "CLI Example:\n" \
89
+ "> context\n" \
90
+ " Context: root\n\n" \
91
+ "> context my.object.path\n" \
92
+ " Context: my.object.path\n\n" \
93
+ "> context root\n" \
94
+ " Context: root",
95
+ :examples => <<~EXAMPLES.strip
96
+ context [container] :
97
+ sub [container] :
98
+ msg [string] : Hello Gloo World!
99
+ on_load [script] :
100
+ @ context.sub
101
+ show @.msg
102
+ @ root
103
+ EXAMPLES
104
+ }
105
+ end
106
+
60
107
  end
61
108
  end
62
109
  end
@@ -69,6 +69,48 @@ module Gloo
69
69
  @engine.heap.it.set_to value
70
70
  end
71
71
 
72
+ # ---------------------------------------------------------------------
73
+ # Verb Documentation
74
+ # ---------------------------------------------------------------------
75
+
76
+ #
77
+ # Get the verb's documentation data.
78
+ #
79
+ def self.doc_data
80
+ {
81
+ :name => KEYWORD,
82
+ :shortcut => KEYWORD_SHORT,
83
+ :description => 'Create a new object of given type with given ' \
84
+ 'value. Both type and value are optional when creating an object.',
85
+ :syntax => [ 'create {new.object.path} as {type} : {value}' ],
86
+ :parameters => [
87
+ '{new.object.path} — The path and name of the new object.',
88
+ '{type} — The type of the new object. Optional; if not provided the object will be untyped.',
89
+ "{value} — The initial value for the new object. Optional; if not provided the object will have the default value for the type."
90
+ ],
91
+ :result => "The new object will be created and added to the " \
92
+ "object heap. It will be set to the new object's initial value.",
93
+ :errors => [
94
+ "#{NO_NAME_ERR} — The name of the object was not specified and the object cannot be created."
95
+ ],
96
+ :examples => <<~EXAMPLES.strip
97
+ # Basic examples of creating an object from the gloo shell:
98
+ > create x as integer : 1
99
+ > create s : "abc"
100
+ > create t
101
+
102
+ # Example of creating an object with an alias:
103
+ a [can] :
104
+ ln [alias] : x
105
+
106
+ on_load [script] :
107
+ create a.ln* as string
108
+ put 'test' into x
109
+ show a.ln
110
+ EXAMPLES
111
+ }
112
+ end
113
+
72
114
  end
73
115
  end
74
116
  end
@@ -38,6 +38,33 @@ module Gloo
38
38
  end
39
39
  end
40
40
 
41
+ # ---------------------------------------------------------------------
42
+ # Verb Documentation
43
+ # ---------------------------------------------------------------------
44
+
45
+ #
46
+ # Get the verb's documentation data.
47
+ #
48
+ def self.doc_data
49
+ {
50
+ :name => KEYWORD,
51
+ :shortcut => KEYWORD_SHORT,
52
+ :description => 'Evaluate an expression and put the result into it.',
53
+ :syntax => [ 'eval {expression}' ],
54
+ :parameters => [
55
+ '{expression} — The expression that will be evaluated. The expression is optional. If not provided, eval will result in true.'
56
+ ],
57
+ :result => 'The result of the expression evaluation is put ' \
58
+ 'into it. No other action is performed.',
59
+ :examples => <<~EXAMPLES.strip
60
+ > eval "me"
61
+ > eval "hello " "world"
62
+ > eval 132 * 23
63
+ > eval path.to.num = 1
64
+ EXAMPLES
65
+ }
66
+ end
67
+
41
68
  end
42
69
  end
43
70
  end
@@ -49,6 +49,33 @@ module Gloo
49
49
  return KEYWORD_SHORT
50
50
  end
51
51
 
52
+ # ---------------------------------------------------------------------
53
+ # Verb Documentation
54
+ # ---------------------------------------------------------------------
55
+
56
+ #
57
+ # Get the verb's documentation data.
58
+ #
59
+ def self.doc_data
60
+ {
61
+ :name => KEYWORD,
62
+ :shortcut => KEYWORD_SHORT,
63
+ :description => 'Execute a shell command. This verb is not ' \
64
+ 'available in the Web app.',
65
+ :syntax => [ 'exec {expression}' ],
66
+ :parameters => [
67
+ '{expression} — Evaluate the expression and execute in the shell.'
68
+ ],
69
+ :result => 'There is no result within gloo, any output is in the terminal.',
70
+ :errors => [
71
+ "#{MISSING_EXPR_ERR} — No expression is provided as parameter to the verb."
72
+ ],
73
+ :examples => <<~EXAMPLES.strip
74
+ > exec 'rake test'
75
+ EXAMPLES
76
+ }
77
+ end
78
+
52
79
  end
53
80
  end
54
81
  end
@@ -72,9 +72,9 @@ module Gloo
72
72
  return false
73
73
  end
74
74
 
75
- #
75
+ #
76
76
  # Check to see if an instance of an object exists.
77
- #
77
+ #
78
78
  def instance_exists?( pn )
79
79
  pn = Gloo::Core::Pn.new( @engine, pn )
80
80
  o = pn.resolve
@@ -82,6 +82,58 @@ module Gloo
82
82
  return true
83
83
  end
84
84
 
85
+ # ---------------------------------------------------------------------
86
+ # Verb Documentation
87
+ # ---------------------------------------------------------------------
88
+
89
+ #
90
+ # Get the verb's documentation data.
91
+ #
92
+ def self.doc_data
93
+ {
94
+ :name => KEYWORD,
95
+ :shortcut => KEYWORD_SHORT,
96
+ :description => 'Check to see if a verb or object type has ' \
97
+ 'been defined (or loaded). This verb can be used to check ' \
98
+ 'if a core library or extension has been loaded.',
99
+ :syntax => [ 'exists? |any,object,verb,instance| {keyword}' ],
100
+ :parameters => [
101
+ "Kind of Keyword — Check for the presence of a keyword of a kind. " \
102
+ "any (default, optional) checks for either an object or a verb; " \
103
+ "object checks for an object matching the keyword or keyword " \
104
+ "shortcut; verb checks for a verb matching the keyword or " \
105
+ "keyword shortcut; instance checks to see if an object " \
106
+ "instance exists at the pathname represented by keyword. " \
107
+ "`exists? any markdown` is identical to `exists? markdown`.",
108
+ '{keyword} — The verb or object keyword or keyword shortcut. ' \
109
+ 'Must be specified. For the instance option, the keyword is ' \
110
+ 'the pathname to an object instance.'
111
+ ],
112
+ :result => 'If the object or verb has been defined, then true, ' \
113
+ 'otherwise false. The result will be in it.',
114
+ :errors => [
115
+ "#{WRONG_NUM_ARGS_ERR} The kind of keyword is optional."
116
+ ],
117
+ :examples => <<~EXAMPLES.strip
118
+ #
119
+ # Example of exists? keyword.
120
+ #
121
+ exists [container] :
122
+
123
+ \ton_load [script] :
124
+ \t\texists? object markdown
125
+ \t\tshow it # false
126
+
127
+ \t\tload lib md
128
+ \t\texists? object markdown
129
+ \t\tshow it # true
130
+
131
+ \t\texists? instance exists.on_load
132
+ \t\tshow it # true
133
+ EXAMPLES
134
+ }
135
+ end
136
+
85
137
  end
86
138
  end
87
139
  end