gloo 6.1.0 → 6.2.1

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.
@@ -21,8 +21,46 @@ module Gloo
21
21
  .map { |m| m.to_s.sub( /\Amsg_/, '' ) }
22
22
  end
23
23
 
24
+ #
25
+ # Documentation for each message this mixin implements, for use
26
+ # in String and Text's doc_data (see help_shell). Kept here as
27
+ # the single source, since String and Text share the exact
28
+ # same message set and would otherwise have to keep two
29
+ # hand-written copies of this list in sync.
30
+ #
31
+ def self.message_docs
32
+ return [
33
+ 'up — Convert the string to uppercase. This message changes the value of the string.',
34
+ 'down — Convert the string to lowercase. This message changes the value of the string.',
35
+ 'size — Get the size of the string. It will have the string size.',
36
+ 'count_chars — Count the number of characters in the string. It will have the character count.',
37
+ 'count_words — Count the number of words in the string. It will have the word count.',
38
+ 'count_lines — Count the number of lines in the string. It will have the line count.',
39
+ 'starts_with? ({str}) — Check if the string starts with the given string. A parameter is required: the string to look for at the beginning of this string. It will have a boolean.',
40
+ 'ends_with? ({str}) — Check if the string ends with the given string. A parameter is required: the string to look for at the end of this string. It will have a boolean.',
41
+ 'substring? ({str}) — Check if the string includes the given sub-string. A parameter is required: the string to look for in this string. It will have a boolean.',
42
+ 'format_for_html — Format this string for HTML output. Tabs, spaces and returns are converted to HTML elements. The value of the string is changed.',
43
+ 'encode64 — Base64 encode the string. This message changes the value of the string. It will have the encoded string.',
44
+ 'decode64 — Decode the string from Base64. This message changes the value of the string. It will have the decoded string.',
45
+ 'escape — Escape the string to make it URL safe. This message changes the value of the string. It will have the escaped string.',
46
+ 'unescape — Unescape the string (from URL safe format). This message changes the value of the string. It will have the unescaped string.',
47
+ 'gen_uuid — Set the value of the string to a newly generated, random UUID. This message changes the value of the string.',
48
+ 'gen_alphanumeric ({len}) — Set the value of the string to a newly generated, random alphanumeric string. The {len} parameter is optional; the length is 10 if not specified. This message changes the value of the string.',
49
+ 'gen_hex ({len}) — Set the value of the string to a newly generated, random hex string. The {len} parameter is optional; the length is 10 if not specified. This message changes the value of the string.',
50
+ 'gen_base64 ({len}) — Set the value of the string to a newly generated, random base64 string. The {len} parameter is optional; the length is 12 if not specified. This message changes the value of the string.',
51
+ 'trim — Strip whitespace from the beginning and end of the string. This message changes the value of the string. It will have the trimmed string.',
52
+ 'sub ({from} {to}) — Substitute the first occurrence of {from} with {to}. Both parameters are required. This message changes the value of the string. It will have the result.',
53
+ 'gsub ({from} {to}) — Substitute all occurrences of {from} with {to}. Both parameters are required. This message changes the value of the string. It will have the result.',
54
+ 'split ({from} {to}) — Get the substring from index {from} up to (not including) index {to}. Indexes are 0-based; out-of-range indexes are clamped to the start or end of the string. Both parameters are required. Does not change the value of the string. It will have the substring.',
55
+ 'splitl ({index}) — Get the substring to the left of index {index} (same as split (0, {index})). A parameter is required. Does not change the value of the string. It will have the substring.',
56
+ 'splitr ({index}) — Get the substring from index {index} to the end of the string (same as split ({index}, size)). A parameter is required. Does not change the value of the string. It will have the substring.',
57
+ 'split_list ({delim} {dst.path}) — Split the string by {delim} and put the parts into children of the container at {dst.path} (or an alias that points to one), one part per child, in order. Existing children are matched by position and have their values set; extra parts get new (untyped) children, numbered from 1; extra existing children are left alone. Both parameters are required. Does not change the value of the string. It will have the number of parts.',
58
+ 'page — Show the value in a pager (less), for viewing long content a screen at a time.'
59
+ ]
60
+ end
24
61
 
25
- #
62
+
63
+ #
26
64
  # Strip whitespace from the beginning and end of the string.
27
65
  #
28
66
  def msg_trim
@@ -120,7 +158,115 @@ module Gloo
120
158
  end
121
159
  end
122
160
 
123
- #
161
+ #
162
+ # Get the substring from index {from} up to (not including) index {to}.
163
+ # Indexes are 0-based. Out-of-range indexes are clamped to the
164
+ # beginning or end of the string. Does not change the string's value.
165
+ #
166
+ def msg_split
167
+ return '' unless value
168
+
169
+ if @params&.token_count&.positive?
170
+ expr = Gloo::Expr::Expression.new( @engine, [ @params.tokens.first ] )
171
+ from = expr.evaluate.to_i
172
+ expr = Gloo::Expr::Expression.new( @engine, [ @params.tokens.last ] )
173
+ to = expr.evaluate.to_i
174
+
175
+ result = clamped_substring( from, to )
176
+ @engine.heap.it.set_to result
177
+ return result
178
+ else
179
+ # Error
180
+ @engine.log.error MISSING_PARAM_MSG
181
+ @engine.heap.it.set_to false
182
+ return false
183
+ end
184
+ end
185
+
186
+ #
187
+ # Get the substring to the left of (not including) index {index}.
188
+ # Same as split( 0, index ). Does not change the string's value.
189
+ #
190
+ def msg_splitl
191
+ return '' unless value
192
+
193
+ if @params&.token_count&.positive?
194
+ expr = Gloo::Expr::Expression.new( @engine, @params.tokens )
195
+ index = expr.evaluate.to_i
196
+
197
+ result = clamped_substring( 0, index )
198
+ @engine.heap.it.set_to result
199
+ return result
200
+ else
201
+ # Error
202
+ @engine.log.error MISSING_PARAM_MSG
203
+ @engine.heap.it.set_to false
204
+ return false
205
+ end
206
+ end
207
+
208
+ #
209
+ # Get the substring from index {index} to the end of the string.
210
+ # Same as split( index, size ). Does not change the string's value.
211
+ #
212
+ def msg_splitr
213
+ return '' unless value
214
+
215
+ if @params&.token_count&.positive?
216
+ expr = Gloo::Expr::Expression.new( @engine, @params.tokens )
217
+ index = expr.evaluate.to_i
218
+
219
+ result = clamped_substring( index, value.length )
220
+ @engine.heap.it.set_to result
221
+ return result
222
+ else
223
+ # Error
224
+ @engine.log.error MISSING_PARAM_MSG
225
+ @engine.heap.it.set_to false
226
+ return false
227
+ end
228
+ end
229
+
230
+ #
231
+ # Split the string by the given delimiter and put the parts into
232
+ # children of the target container, one part per child, in order.
233
+ # The target is a path to a container, or to an alias that points
234
+ # to one. Existing children are matched by position (not name) and
235
+ # have their values set; if there are more parts than children,
236
+ # new (untyped) children are created for the extras, numbered
237
+ # from 1. Existing children beyond the part count are left alone.
238
+ # The string's own value is unchanged; the number of parts is put
239
+ # into 'it'.
240
+ #
241
+ def msg_split_list
242
+ return unless value
243
+
244
+ if @params&.token_count.to_i < 2
245
+ @engine.log.error MISSING_PARAM_MSG
246
+ @engine.heap.it.set_to false
247
+ return false
248
+ end
249
+
250
+ expr = Gloo::Expr::Expression.new( @engine, [ @params.tokens.first ] )
251
+ delim = expr.evaluate
252
+
253
+ target = split_list_target( @params.tokens.last )
254
+ return false unless target
255
+
256
+ parts = value.split( delim )
257
+ existing = target.children
258
+ parts.each_with_index do |part, index|
259
+ child = existing[ index ]
260
+ child ||= target.find_add_child( ( index + 1 ).to_s, 'untyped' )
261
+ child.set_value part
262
+ end
263
+
264
+ count = parts.count
265
+ @engine.heap.it.set_to count
266
+ return count
267
+ end
268
+
269
+ #
124
270
  # Does the string contain the given string?
125
271
  #
126
272
  # This was formerly an overload of obj.contains?
@@ -344,6 +490,50 @@ module Gloo
344
490
  @engine.platform.page( value )
345
491
  end
346
492
 
493
+ private
494
+
495
+ #
496
+ # Resolve the target container path for split_list. The path may
497
+ # point directly at a container, or at an alias that points to
498
+ # one. Returns nil (and logs an error, setting 'it' to false)
499
+ # if the path doesn't exist or doesn't resolve to a container.
500
+ #
501
+ def split_list_target( token )
502
+ pn = Gloo::Core::Pn.new( @engine, token )
503
+ unless pn&.exists?
504
+ @engine.log.error 'Target container path does not exist!'
505
+ @engine.heap.it.set_to false
506
+ return nil
507
+ end
508
+
509
+ target = pn.resolve
510
+ target = Gloo::Objs::Alias.resolve_alias( @engine, target )
511
+ unless target&.is_container?
512
+ @engine.log.error 'Target for split_list must be a container!'
513
+ @engine.heap.it.set_to false
514
+ return nil
515
+ end
516
+
517
+ return target
518
+ end
519
+
520
+ #
521
+ # Get the substring from index {from} up to (not including) index {to}.
522
+ # Out-of-range indexes are clamped to the string's own bounds (0 and
523
+ # its length), rather than raising an error. A degenerate range
524
+ # (from at or past to) returns an empty string.
525
+ #
526
+ def clamped_substring( from, to )
527
+ len = value.length
528
+ from = 0 if from.negative?
529
+ from = len if from > len
530
+ to = 0 if to.negative?
531
+ to = len if to > len
532
+ return '' if from >= to
533
+
534
+ return value[ from...to ]
535
+ end
536
+
347
537
  end
348
538
  end
349
539
  end
@@ -73,32 +73,11 @@ module Gloo
73
73
  :name => KEYWORD,
74
74
  :shortcut => KEYWORD_SHORT,
75
75
  :description => 'A longer, multi-line text string. Use BEGIN ' \
76
- 'and END to mark the text range.',
77
- :messages => [
78
- 'Same messages as the string object type:',
79
- 'up Convert the string to uppercase. This message changes the value of the string.',
80
- 'down Convert the string to lowercase. This message changes the value of the string.',
81
- 'size — Get the size of the string. It will have the string size.',
82
- 'count_chars — Count the number of characters in the string. It will have the character count.',
83
- 'count_words — Count the number of words in the string. It will have the word count.',
84
- 'count_lines — Count the number of lines in the string. It will have the line count.',
85
- 'starts_with? ({str}) — Check if the string starts with the given string. A parameter is required: the string to look for at the beginning of this string. It will have a boolean.',
86
- 'ends_with? ({str}) — Check if the string ends with the given string. A parameter is required: the string to look for at the end of this string. It will have a boolean.',
87
- 'substring? ({str}) — Check if the string includes the given sub-string. A parameter is required: the string to look for in this string. It will have a boolean.',
88
- 'format_for_html — Format this string for HTML output. Tabs, spaces and returns are converted to HTML elements. The value of the string is changed.',
89
- 'encode64 — Base64 encode the string. This message changes the value of the string. It will have the encoded string.',
90
- 'decode64 — Decode the string from Base64. This message changes the value of the string. It will have the decoded string.',
91
- 'escape — Escape the string to make it URL safe. This message changes the value of the string. It will have the escaped string.',
92
- 'unescape — Unescape the string (from URL safe format). This message changes the value of the string. It will have the unescaped string.',
93
- 'gen_uuid — Set the value of the string to a newly generated, random UUID. This message changes the value of the string.',
94
- 'gen_alphanumeric ({len}) — Set the value of the string to a newly generated, random alphanumeric string. The {len} parameter is optional; the length is 10 if not specified. This message changes the value of the string.',
95
- 'gen_hex ({len}) — Set the value of the string to a newly generated, random hex string. The {len} parameter is optional; the length is 10 if not specified. This message changes the value of the string.',
96
- 'gen_base64 ({len}) — Set the value of the string to a newly generated, random base64 string. The {len} parameter is optional; the length is 12 if not specified. This message changes the value of the string.',
97
- 'trim — Strip whitespace from the beginning and end of the string. This message changes the value of the string. It will have the trimmed string.',
98
- 'sub ({from}, {to}) — Substitute the first occurrence of {from} with {to}. Both parameters are required. This message changes the value of the string. It will have the result.',
99
- 'gsub ({from}, {to}) — Substitute all occurrences of {from} with {to}. Both parameters are required. This message changes the value of the string. It will have the result.',
100
- 'page — Show the value in a pager (less), for viewing long content a screen at a time.'
101
- ],
76
+ 'and END to mark the text range. Shares the same messages ' \
77
+ 'as the string object type; the two differ mainly by ' \
78
+ 'convention text for longer, multi-line blocks, string ' \
79
+ 'for a single word or line.',
80
+ :messages => StringMsgs.message_docs,
102
81
  :examples => <<~EXAMPLES.strip
103
82
  t [container] :
104
83
  msg [txt] : BEGIN
@@ -161,23 +161,36 @@ module Gloo
161
161
  # Messages
162
162
  # ---------------------------------------------------------------------
163
163
 
164
- #
164
+ #
165
165
  # Invoke the function, run the script and return the result.
166
- #
166
+ #
167
+ # If on_invoke itself hits an error, it is left alone rather
168
+ # than being clobbered with an unreliable result - callers can
169
+ # tell this happened because the engine is left in an error
170
+ # state (@engine.heap.error), same as any other failed verb.
171
+ #
167
172
  def invoke args
168
173
  @engine.log.debug "Invoking function: #{name}"
169
174
 
170
175
  set_params args if args
176
+
177
+ @engine.heap.error.start_tracking
171
178
  run_on_invoke
179
+ failed = @engine.heap.error.error_count.positive?
180
+
181
+ if failed
182
+ run_after_invoke
183
+ return nil
184
+ end
172
185
 
173
- if @engine.running_app&.obj&.embedded_renderer
186
+ if @engine.running_app&.obj&.embedded_renderer
174
187
  return_value = @engine.running_app.obj.embedded_renderer.render result, params_hash
175
188
  else
176
189
  return_value = result
177
190
  end
178
191
  @engine.heap.it.set_to return_value
179
192
  run_after_invoke
180
-
193
+
181
194
  return return_value
182
195
  end
183
196
 
@@ -12,7 +12,7 @@ module Gloo
12
12
  KEYWORD_SHORT = '?'.freeze
13
13
 
14
14
  BANNER = "Entering the gloo help shell. Type 'quit' to exit.\n" \
15
- "Try: verbs, objects, settings, extensions, libraries, docs, " \
15
+ "Try: verbs, objects, settings, theme, extensions, libraries, docs, " \
16
16
  "verb {name}, object {name}, doc {name}, library {name}, extension {name}\n".freeze
17
17
 
18
18
  #
@@ -50,12 +50,14 @@ module Gloo
50
50
  :name => KEYWORD,
51
51
  :shortcut => KEYWORD_SHORT,
52
52
  :description => 'Enter the interactive help shell. From there, ' \
53
- 'look up verbs, object types, settings, extensions, libraries, ' \
54
- 'and narrative doc pages, or get detailed help for a specific ' \
55
- 'verb, object, doc page, loaded library, or loaded extension.',
53
+ 'look up verbs, object types, settings, the current color ' \
54
+ 'theme, extensions, libraries, and narrative doc pages, or ' \
55
+ 'get detailed help for a specific verb, object, doc page, ' \
56
+ 'loaded library, or loaded extension.',
56
57
  :syntax => [ 'help' ],
57
58
  :result => "Enters the help shell, prompt \"help> \". Commands: " \
58
- 'verbs, objects, settings, extensions, libraries, docs (lists), ' \
59
+ 'verbs, objects, settings, theme, extensions, libraries, docs ' \
60
+ '(lists — theme also shows a color preview of both palettes), ' \
59
61
  'verb {name}, object {name}, doc {name}, library {name}, ' \
60
62
  'extension {name} (detail for one, tab-completable — library ' \
61
63
  '{name} / extension {name} show the README for a loaded core ' \
@@ -65,6 +67,7 @@ module Gloo
65
67
  help> verbs
66
68
  help> verb put
67
69
  help> object container
70
+ help> theme
68
71
  help> docs
69
72
  help> doc getting_started
70
73
  help> library db
@@ -3,6 +3,10 @@
3
3
  #
4
4
  # Invoke a function from a script.
5
5
  #
6
+ # Resolution, validation and the actual invoke are all handled by
7
+ # Gloo::Core::Invoker, shared with inline calls inside expressions
8
+ # (see Gloo::Expr::Call) so both go through the same error handling.
9
+ #
6
10
 
7
11
  module Gloo
8
12
  module Verbs
@@ -15,24 +19,10 @@ module Gloo
15
19
  # Run the verb.
16
20
  #
17
21
  def run
18
- if @tokens.token_count > 1
19
- ob = @tokens.first
20
-
21
- # Get the function object
22
- pn = Gloo::Core::Pn.new( @engine, @tokens.second )
23
- func = pn.resolve
24
-
25
- # Is the object a function?
26
- if func&.is_function?
27
- params = get_params_arr
28
-
29
- @engine.log.debug "invoking function: #{func.pn}"
30
- result = func.invoke( params )
31
- @engine.log.debug "function returned: #{result}"
32
- @engine.heap.it.set_to result
33
- return result
34
- end
35
- end
22
+ target = @tokens.token_count > 1 ? @tokens.second : nil
23
+ arg_tokens = @tokens.token_count > 1 ? @tokens.params[ 1..-1 ] : []
24
+
25
+ return Gloo::Core::Invoker.invoke( @engine, target, arg_tokens )
36
26
  end
37
27
 
38
28
  #
@@ -49,32 +39,6 @@ module Gloo
49
39
  return KEYWORD_SHORT
50
40
  end
51
41
 
52
- # ---------------------------------------------------------------------
53
- # Private functions
54
- # ---------------------------------------------------------------------
55
-
56
- private
57
-
58
- #
59
- # Get params array.
60
- #
61
- def get_params_arr
62
- @engine.log.debug "token params: #{@tokens.params}"
63
- params = @tokens.params[1..-1]
64
-
65
- @engine.log.info "params: #{params}"
66
- evaluated_params = []
67
-
68
- params.each do |p|
69
- expr = Gloo::Expr::Expression.new( @engine, [ p ] )
70
- evaluated_params << expr.evaluate
71
- end
72
-
73
- @engine.log.debug "evaluated_params: #{evaluated_params}"
74
-
75
- return evaluated_params
76
- end
77
-
78
42
  # ---------------------------------------------------------------------
79
43
  # Verb Documentation
80
44
  # ---------------------------------------------------------------------
@@ -87,12 +51,36 @@ module Gloo
87
51
  :name => KEYWORD,
88
52
  :shortcut => KEYWORD_SHORT,
89
53
  :description => 'Invoke a function. Set it to the result of the function.',
90
- :syntax => [ 'invoke {path.to.function} {params}' ],
54
+ :syntax => [
55
+ 'invoke {path.to.function} {params}',
56
+ 'invoke( {path.to.function} {params} ) — inline, usable inside any expression',
57
+ '~>( {path.to.function} {params} ) — inline, shortcut spelling'
58
+ ],
91
59
  :parameters => [
92
60
  '{path.to.function} — The function we want to invoke.',
93
61
  '{params} — The list of parameters to the function.'
94
62
  ],
95
- :result => 'The result of the function is put into it.',
63
+ :result => 'The result of the function is put into it. The ' \
64
+ 'inline forms (invoke(...), ~>(...)) can be used anywhere ' \
65
+ 'an expression is evaluated - show, put ... into, if, ' \
66
+ 'unless, eval, and more - and evaluate to the result ' \
67
+ 'directly rather than going through it.',
68
+ :errors => [
69
+ "#{Gloo::Core::Invoker::NO_TARGET_ERR} — No function reference was given.",
70
+ "#{Gloo::Core::Invoker::NOT_FOUND_ERR}{path.to.function} — The path doesn't resolve to any object.",
71
+ "#{Gloo::Core::Invoker::NOT_FUNCTION_ERR}{path.to.function} — The path resolves to an object that isn't a function.",
72
+ "#{Gloo::Core::Invoker::PARAM_COUNT_ERR}{path.to.function} (expected N, got N) — The number of params given doesn't match what the function declares."
73
+ ],
74
+ :notes => 'If the function itself fails during invocation ' \
75
+ '(its on_invoke script hits an error), it is left ' \
76
+ 'unchanged rather than being set to an unreliable result. ' \
77
+ 'The underlying error is whatever was reported by the ' \
78
+ 'failure inside the function. ' \
79
+ 'Inline call params are space-separated, same as the ' \
80
+ 'standalone verb - each one is evaluated as a single ' \
81
+ 'token (a literal or object reference), not a multi-token ' \
82
+ "sub-expression, so invoke( f 3+4 ) won't parse 3+4 as " \
83
+ 'one arg.',
96
84
  :examples => <<~EXAMPLES.strip
97
85
  #
98
86
  # Function examples
@@ -111,6 +99,11 @@ module Gloo
111
99
  invoke functions.add 3 4
112
100
  show it
113
101
 
102
+ # Inline, anywhere an expression is evaluated:
103
+ show invoke( functions.add 3 4 )
104
+ put ~>( functions.add 3 4 ) into total
105
+ show "Total: " + invoke( functions.add 3 4 )
106
+
114
107
  show 'done' (white)
115
108
 
116
109
  #
@@ -73,16 +73,17 @@ module Gloo
73
73
  # Show object in standard format.
74
74
  #
75
75
  def show_obj( obj, indent = ' ' )
76
+ theme = @engine.theme
76
77
  if obj.multiline_value? && obj.value_is_array?
77
- str = "#{indent}#{obj.name}".white
78
- str << " [#{obj.type_display}] : ".yellow
78
+ str = theme.emphasis( "#{indent}#{obj.name}" )
79
+ str << theme.accent( " [#{obj.type_display}] : " )
79
80
  @engine.log.show str
80
81
  obj.value.each do |line|
81
82
  @engine.log.show "#{indent} #{line}"
82
83
  end
83
84
  else
84
- str = "#{indent}#{obj.name}".white
85
- str << " [#{obj.type_display}] : ".yellow
85
+ str = theme.emphasis( "#{indent}#{obj.name}" )
86
+ str << theme.accent( " [#{obj.type_display}] : " )
86
87
  str << "#{obj.value}"
87
88
  @engine.log.show str
88
89
  end
@@ -7,6 +7,7 @@ tests [can] :
7
7
  string [can] :
8
8
 
9
9
  s [string] :
10
+ dst [can] :
10
11
 
11
12
  up_down [test] :
12
13
  description [string] : Convert string case
@@ -42,3 +43,56 @@ tests [can] :
42
43
  tell ^^.s to count_chars
43
44
  eval it = 5
44
45
  assert "expected 5 characters"
46
+
47
+ split [test] :
48
+ description [string] : Get a substring between two indexes
49
+ on_test [script] :
50
+ put 'one two three' into ^^.s
51
+ tell ^^.s to split (4 7)
52
+ eval it = 'two'
53
+ assert "expected split (4 7) to equal 'two'"
54
+ eval ^^.s = 'one two three'
55
+ assert "expected split to leave the string unchanged"
56
+
57
+ splitl [test] :
58
+ description [string] : Get the substring to the left of an index
59
+ on_test [script] :
60
+ put 'one two three' into ^^.s
61
+ tell ^^.s to splitl (7)
62
+ eval it = 'one two'
63
+ assert "expected splitl (7) to equal 'one two'"
64
+
65
+ splitr [test] :
66
+ description [string] : Get the substring from an index to the end
67
+ on_test [script] :
68
+ put 'one two three' into ^^.s
69
+ tell ^^.s to splitr (4)
70
+ eval it = 'two three'
71
+ assert "expected splitr (4) to equal 'two three'"
72
+
73
+ split_out_of_range [test] :
74
+ description [string] : Out-of-range split indexes clamp to the string's bounds
75
+ on_test [script] :
76
+ put 'one two three' into ^^.s
77
+ tell ^^.s to split (-5 4)
78
+ eval it = 'one '
79
+ assert "expected split (-5 4) to clamp to 'one '"
80
+ tell ^^.s to split (8 100)
81
+ eval it = 'three'
82
+ assert "expected split (8 100) to clamp to 'three'"
83
+
84
+ split_list [test] :
85
+ description [string] : Split a string into children of a target container
86
+ on_test [script] :
87
+ put 'one,two,three' into ^^.s
88
+ tell ^^.s to split_list (',' ^^.dst)
89
+ eval it = 3
90
+ assert "expected split_list to put the part count into it"
91
+ eval ^^.dst.1 = 'one'
92
+ assert "expected dst.1 to equal 'one'"
93
+ eval ^^.dst.2 = 'two'
94
+ assert "expected dst.2 to equal 'two'"
95
+ eval ^^.dst.3 = 'three'
96
+ assert "expected dst.3 to equal 'three'"
97
+ eval ^^.s = 'one,two,three'
98
+ assert "expected split_list to leave the string unchanged"
@@ -18,3 +18,76 @@ tests [can] :
18
18
  invoke tests.verbs.invoke.f
19
19
  eval it = 42
20
20
  assert "expected it to be 42"
21
+
22
+ add [ƒ] :
23
+ on_invoke [script] :
24
+ put ^.params.x + ^.params.y into ^.result
25
+ params [can] :
26
+ x [int] :
27
+ y [int] :
28
+ result [int] :
29
+
30
+ total [int] :
31
+
32
+ inline_invoke_in_show_test [test] :
33
+ description [string] : Inline invoke( ... ) works inside show.
34
+ on_test [script] :
35
+ show invoke( tests.verbs.invoke.add 3 4 )
36
+ eval it = 7
37
+ assert "expected it to be 7"
38
+
39
+ inline_shortcut_in_show_test [test] :
40
+ description [string] : Inline ~>( ... ) works inside show, same as invoke( ... ).
41
+ on_test [script] :
42
+ show ~>( tests.verbs.invoke.add 3 4 )
43
+ eval it = 7
44
+ assert "expected it to be 7"
45
+
46
+ inline_invoke_with_operator_test [test] :
47
+ description [string] : Inline invoke( ... ) composes with an operator.
48
+ on_test [script] :
49
+ show "Total: " + invoke( tests.verbs.invoke.add 3 4 )
50
+ eval it = "Total: 7"
51
+ assert "expected it to be 'Total: 7'"
52
+
53
+ inline_invoke_in_put_test [test] :
54
+ description [string] : Inline invoke( ... ) works inside put ... into.
55
+ on_test [script] :
56
+ put 0 into ^^.total
57
+ put invoke( tests.verbs.invoke.add 3 4 ) into ^^.total
58
+ eval ^^.total = 7
59
+ assert "expected total to be 7"
60
+
61
+ inline_invoke_in_if_test [test] :
62
+ description [string] : Inline invoke( ... ) works inside if.
63
+ on_test [script] :
64
+ eval false
65
+ if invoke( tests.verbs.invoke.add 3 4 ) = 7 then eval true
66
+ assert "expected the if branch to have run"
67
+
68
+ err_fired [bool] : false
69
+
70
+ on_error [script] :
71
+ put true into ^.err_fired
72
+
73
+ inline_invoke_error_test [test] :
74
+ description [string] : Inline invoke( ... ) reports an error for an unresolved target, same as the standalone verb.
75
+ on_test [script] :
76
+ put false into ^^.err_fired
77
+ show invoke( tests.verbs.invoke.no_such_function )
78
+ eval ^^.err_fired = true
79
+ assert "expected on_error to have fired for an unresolved inline call target"
80
+
81
+ greet [ƒ] :
82
+ on_invoke [script] :
83
+ put 'Hi, ' + ^.params.name into ^.result
84
+ params [can] :
85
+ name [string] :
86
+ result [string] :
87
+
88
+ inline_invoke_with_quoted_arg_test [test] :
89
+ description [string] : A quoted string arg inside invoke( ... ) is passed through as one arg, not split on its internal space.
90
+ on_test [script] :
91
+ show invoke( tests.verbs.invoke.greet "Bob Smith" )
92
+ eval it = "Hi, Bob Smith"
93
+ assert "expected it to be 'Hi, Bob Smith'"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gloo
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.1.0
4
+ version: 6.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eric Crane
@@ -250,12 +250,10 @@ executables:
250
250
  extensions: []
251
251
  extra_rdoc_files: []
252
252
  files:
253
- - ".DS_Store"
254
253
  - ".gitignore"
255
254
  - ".rubocop.yml"
256
255
  - ".ruby-gemset"
257
256
  - ".ruby-version"
258
- - ".travis.yml"
259
257
  - CLAUDE.md
260
258
  - CODE_OF_CONDUCT.md
261
259
  - Gemfile
@@ -275,6 +273,7 @@ files:
275
273
  - docs/operators.md
276
274
  - docs/plugins.md
277
275
  - docs/verbs.md
276
+ - docs/web_app.md
278
277
  - exe/gloo
279
278
  - exe/o
280
279
  - gloo.gemspec
@@ -293,6 +292,7 @@ files:
293
292
  - lib/gloo/app/running_app.rb
294
293
  - lib/gloo/app/settings.rb
295
294
  - lib/gloo/app/table.rb
295
+ - lib/gloo/app/theme.rb
296
296
  - lib/gloo/convert/converter.rb
297
297
  - lib/gloo/convert/falseclass_to_integer.rb
298
298
  - lib/gloo/convert/nilclass_to_date.rb
@@ -314,6 +314,7 @@ files:
314
314
  - lib/gloo/core/gloo_system.rb
315
315
  - lib/gloo/core/heap.rb
316
316
  - lib/gloo/core/here.rb
317
+ - lib/gloo/core/invoker.rb
317
318
  - lib/gloo/core/it.rb
318
319
  - lib/gloo/core/literal.rb
319
320
  - lib/gloo/core/obj.rb
@@ -332,6 +333,7 @@ files:
332
333
  - lib/gloo/exec/runner.rb
333
334
  - lib/gloo/exec/script.rb
334
335
  - lib/gloo/exec/stack.rb
336
+ - lib/gloo/expr/call.rb
335
337
  - lib/gloo/expr/expression.rb
336
338
  - lib/gloo/expr/l_boolean.rb
337
339
  - lib/gloo/expr/l_decimal.rb
data/.DS_Store DELETED
Binary file