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/lib/gloo/expr/expression.rb
CHANGED
|
@@ -47,6 +47,7 @@ module Gloo
|
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
return @left.value if @left.is_a? Gloo::Core::Literal
|
|
50
|
+
return @left.value if @left.is_a? Gloo::Expr::Call
|
|
50
51
|
return resolve_ref @left if @left.is_a? Gloo::Core::Pn
|
|
51
52
|
|
|
52
53
|
return @left
|
|
@@ -75,6 +76,7 @@ module Gloo
|
|
|
75
76
|
#
|
|
76
77
|
def evaluate_sym( sym )
|
|
77
78
|
return sym.value if sym.is_a? Gloo::Core::Literal
|
|
79
|
+
return sym.value if sym.is_a? Gloo::Expr::Call
|
|
78
80
|
return resolve_ref sym if sym.is_a? Gloo::Core::Pn
|
|
79
81
|
|
|
80
82
|
return sym
|
|
@@ -109,6 +111,7 @@ module Gloo
|
|
|
109
111
|
return LInteger.new( token ) if LInteger.integer?( token )
|
|
110
112
|
return LString.new( token ) if LString.string?( token )
|
|
111
113
|
return LDecimal.new( token ) if LDecimal.decimal?( token )
|
|
114
|
+
return Gloo::Expr::Call.new( @engine, token ) if Gloo::Expr::Call.call?( token )
|
|
112
115
|
|
|
113
116
|
# last chance: an Object reference
|
|
114
117
|
return Gloo::Core::Pn.new( @engine, token )
|
|
@@ -73,6 +73,59 @@ module Gloo
|
|
|
73
73
|
return ln.resolve
|
|
74
74
|
end
|
|
75
75
|
|
|
76
|
+
# ---------------------------------------------------------------------
|
|
77
|
+
# Object Documentation
|
|
78
|
+
# ---------------------------------------------------------------------
|
|
79
|
+
|
|
80
|
+
#
|
|
81
|
+
# Get the object's documentation data.
|
|
82
|
+
#
|
|
83
|
+
def self.doc_data
|
|
84
|
+
{
|
|
85
|
+
:name => KEYWORD,
|
|
86
|
+
:shortcut => KEYWORD_SHORT,
|
|
87
|
+
:description => 'A pointer to another object. Normal ' \
|
|
88
|
+
'path-name references will refer to the aliased object. To ' \
|
|
89
|
+
'refer to the alias itself, add an * at the end of the ' \
|
|
90
|
+
'path-name — needed, for example, to set the value of the ' \
|
|
91
|
+
'alias. The value of the alias is merely the path-name of ' \
|
|
92
|
+
'the referenced object. Well constructed aliases will ' \
|
|
93
|
+
'redirect to the referenced object through any number of ' \
|
|
94
|
+
'steps, and relative references will also work in an alias.',
|
|
95
|
+
:messages => [
|
|
96
|
+
'resolve — Check to see if the object referenced exists. Sets it to true or false.'
|
|
97
|
+
],
|
|
98
|
+
:notes => 'The alias also reflects (forwards) the messages of the object it points to.',
|
|
99
|
+
:examples => <<~EXAMPLES.strip
|
|
100
|
+
#
|
|
101
|
+
# Alias object.
|
|
102
|
+
#
|
|
103
|
+
|
|
104
|
+
a [can] :
|
|
105
|
+
s [string] : a string
|
|
106
|
+
i [integer] : 13
|
|
107
|
+
ln [alias] : a.s
|
|
108
|
+
|
|
109
|
+
on_load [script] :
|
|
110
|
+
show a.ln
|
|
111
|
+
show a.ln*
|
|
112
|
+
put 'a.i' into a.ln*
|
|
113
|
+
put 7 into a.ln
|
|
114
|
+
show a.ln
|
|
115
|
+
run a.add
|
|
116
|
+
|
|
117
|
+
#
|
|
118
|
+
# Example of creating an object using an alias.
|
|
119
|
+
#
|
|
120
|
+
add [script] :
|
|
121
|
+
put 'x' into a.ln*
|
|
122
|
+
create a.ln* as string
|
|
123
|
+
put 'test' into x
|
|
124
|
+
show a.ln
|
|
125
|
+
EXAMPLES
|
|
126
|
+
}
|
|
127
|
+
end
|
|
128
|
+
|
|
76
129
|
end
|
|
77
130
|
end
|
|
78
131
|
end
|
|
@@ -115,6 +115,36 @@ module Gloo
|
|
|
115
115
|
return false
|
|
116
116
|
end
|
|
117
117
|
|
|
118
|
+
# ---------------------------------------------------------------------
|
|
119
|
+
# Object Documentation
|
|
120
|
+
# ---------------------------------------------------------------------
|
|
121
|
+
|
|
122
|
+
#
|
|
123
|
+
# Get the object's documentation data.
|
|
124
|
+
#
|
|
125
|
+
def self.doc_data
|
|
126
|
+
{
|
|
127
|
+
:name => KEYWORD,
|
|
128
|
+
:shortcut => KEYWORD_SHORT,
|
|
129
|
+
:description => 'A boolean value. Value will be either true or false.',
|
|
130
|
+
:messages => [
|
|
131
|
+
'not — Set the boolean to the opposite of what it is now.',
|
|
132
|
+
'true — Set the boolean to true.',
|
|
133
|
+
'false — Set the boolean to false.'
|
|
134
|
+
],
|
|
135
|
+
:examples => <<~EXAMPLES.strip
|
|
136
|
+
b [can] :
|
|
137
|
+
flag [boolean] : true
|
|
138
|
+
on_load [script] :
|
|
139
|
+
show b.flag
|
|
140
|
+
put false into b.flag
|
|
141
|
+
show b.flag
|
|
142
|
+
tell b.flag to not
|
|
143
|
+
show b.flag
|
|
144
|
+
EXAMPLES
|
|
145
|
+
}
|
|
146
|
+
end
|
|
147
|
+
|
|
118
148
|
end
|
|
119
149
|
end
|
|
120
150
|
end
|
|
@@ -75,6 +75,44 @@ module Gloo
|
|
|
75
75
|
@engine.heap.it.set_to val
|
|
76
76
|
return val
|
|
77
77
|
end
|
|
78
|
+
|
|
79
|
+
# ---------------------------------------------------------------------
|
|
80
|
+
# Object Documentation
|
|
81
|
+
# ---------------------------------------------------------------------
|
|
82
|
+
|
|
83
|
+
#
|
|
84
|
+
# Get the object's documentation data.
|
|
85
|
+
#
|
|
86
|
+
def self.doc_data
|
|
87
|
+
{
|
|
88
|
+
:name => KEYWORD,
|
|
89
|
+
:shortcut => KEYWORD_SHORT,
|
|
90
|
+
:description => 'A container of other objects. A container is ' \
|
|
91
|
+
'similar to a folder in a file system. It can contain any ' \
|
|
92
|
+
'number of objects including other containers. The ' \
|
|
93
|
+
'container structure provides direct access to any object ' \
|
|
94
|
+
'within it through the object.object.object path-name structure.',
|
|
95
|
+
:children => [
|
|
96
|
+
'None by default — but any container can have any number of objects added to it, at runtime.'
|
|
97
|
+
],
|
|
98
|
+
:messages => [
|
|
99
|
+
'count — Count the number of children objects in the container. The result is put in it.',
|
|
100
|
+
'delete_children — Delete all children objects from the container.',
|
|
101
|
+
'show_key_value_table — Show a table with key (name) and values for all children in the container.',
|
|
102
|
+
'child_exists ({name}) — Check to see if there is a child with the given name. A parameter is required. It will have a boolean.'
|
|
103
|
+
],
|
|
104
|
+
:examples => <<~EXAMPLES.strip
|
|
105
|
+
can [can] :
|
|
106
|
+
data [can] :
|
|
107
|
+
1 : one
|
|
108
|
+
2 : two
|
|
109
|
+
3 : three
|
|
110
|
+
on_load [script] :
|
|
111
|
+
tell can.data to show_key_value_table
|
|
112
|
+
EXAMPLES
|
|
113
|
+
}
|
|
114
|
+
end
|
|
115
|
+
|
|
78
116
|
end
|
|
79
117
|
end
|
|
80
118
|
end
|
|
@@ -92,6 +92,36 @@ module Gloo
|
|
|
92
92
|
@engine.heap.it.set_to formatted
|
|
93
93
|
end
|
|
94
94
|
|
|
95
|
+
# ---------------------------------------------------------------------
|
|
96
|
+
# Object Documentation
|
|
97
|
+
# ---------------------------------------------------------------------
|
|
98
|
+
|
|
99
|
+
#
|
|
100
|
+
# Get the object's documentation data.
|
|
101
|
+
#
|
|
102
|
+
def self.doc_data
|
|
103
|
+
{
|
|
104
|
+
:name => KEYWORD,
|
|
105
|
+
:shortcut => KEYWORD_SHORT,
|
|
106
|
+
:description => 'A decimal (numeric) value.',
|
|
107
|
+
:messages => [
|
|
108
|
+
'round ({precision}) — Round to the nearest whole value. If ' \
|
|
109
|
+
'an optional parameter is included, round to the precision specified.',
|
|
110
|
+
'format ({fmt}) — With no parameter, adds comma separators to the whole part (e.g. 1000.5 -> 1,000.5). With a parameter, uses it as a sprintf-style format string (e.g. \'%.2f\'). It will have the formatted string.'
|
|
111
|
+
],
|
|
112
|
+
:examples => <<~EXAMPLES.strip
|
|
113
|
+
d [can] :
|
|
114
|
+
x [decimal] : 100
|
|
115
|
+
on_load [script] :
|
|
116
|
+
show d.x
|
|
117
|
+
put d.x / 3 into d.x
|
|
118
|
+
show d.x
|
|
119
|
+
tell d.x to round (1)
|
|
120
|
+
show d.x
|
|
121
|
+
EXAMPLES
|
|
122
|
+
}
|
|
123
|
+
end
|
|
124
|
+
|
|
95
125
|
end
|
|
96
126
|
end
|
|
97
127
|
end
|
|
@@ -118,6 +118,64 @@ module Gloo
|
|
|
118
118
|
@engine.heap.it.set_to formatted
|
|
119
119
|
end
|
|
120
120
|
|
|
121
|
+
# ---------------------------------------------------------------------
|
|
122
|
+
# Object Documentation
|
|
123
|
+
# ---------------------------------------------------------------------
|
|
124
|
+
|
|
125
|
+
#
|
|
126
|
+
# Get the object's documentation data.
|
|
127
|
+
#
|
|
128
|
+
def self.doc_data
|
|
129
|
+
{
|
|
130
|
+
:name => KEYWORD,
|
|
131
|
+
:shortcut => KEYWORD_SHORT,
|
|
132
|
+
:description => 'An integer (numeric) value.',
|
|
133
|
+
:messages => [
|
|
134
|
+
'inc — Increment the integer value by 1.',
|
|
135
|
+
'dec — Decrement the integer value by 1.',
|
|
136
|
+
'randomize ({max}) — Set the value of the integer to a random ' \
|
|
137
|
+
'number. By default the range is 0..99 inclusive. Use an ' \
|
|
138
|
+
'optional parameter to set the maximum of the range; the ' \
|
|
139
|
+
'range always starts at 0. To model a 6-sided die, set the ' \
|
|
140
|
+
'range to 6 and add 1 to the result.',
|
|
141
|
+
'format ({fmt}) — With no parameter, adds comma separators (e.g. 1000 -> 1,000). With a parameter, uses it as a sprintf-style format string (e.g. \'%05d\'). It will have the formatted string.'
|
|
142
|
+
],
|
|
143
|
+
:examples => <<~EXAMPLES.strip
|
|
144
|
+
#
|
|
145
|
+
# Integer object.
|
|
146
|
+
#
|
|
147
|
+
|
|
148
|
+
i [can] :
|
|
149
|
+
|
|
150
|
+
#
|
|
151
|
+
# The integer value.
|
|
152
|
+
#
|
|
153
|
+
x [integer] : 0
|
|
154
|
+
|
|
155
|
+
#
|
|
156
|
+
# Do some basic tests with it
|
|
157
|
+
#
|
|
158
|
+
on_load [script] :
|
|
159
|
+
show i.x
|
|
160
|
+
tell i.x to inc
|
|
161
|
+
show i.x
|
|
162
|
+
put i.x * 10 into i.x
|
|
163
|
+
show i.x
|
|
164
|
+
|
|
165
|
+
# Show a random number
|
|
166
|
+
tell ^.x to randomize
|
|
167
|
+
show 'Random number (up to 100 by default): ' + ^.x
|
|
168
|
+
|
|
169
|
+
tell ^.x to randomize(6)
|
|
170
|
+
tell ^.x to inc
|
|
171
|
+
show '6-sided dice: ' + ^.x
|
|
172
|
+
|
|
173
|
+
# An uninitialized integer.
|
|
174
|
+
y [integer] :
|
|
175
|
+
EXAMPLES
|
|
176
|
+
}
|
|
177
|
+
end
|
|
178
|
+
|
|
121
179
|
end
|
|
122
180
|
end
|
|
123
181
|
end
|
|
@@ -94,6 +94,37 @@ module Gloo
|
|
|
94
94
|
s.run
|
|
95
95
|
end
|
|
96
96
|
|
|
97
|
+
# ---------------------------------------------------------------------
|
|
98
|
+
# Object Documentation
|
|
99
|
+
# ---------------------------------------------------------------------
|
|
100
|
+
|
|
101
|
+
#
|
|
102
|
+
# Get the object's documentation data.
|
|
103
|
+
#
|
|
104
|
+
def self.doc_data
|
|
105
|
+
{
|
|
106
|
+
:name => KEYWORD,
|
|
107
|
+
:shortcut => KEYWORD_SHORT,
|
|
108
|
+
:description => 'An executable script — a set of commands to be run.',
|
|
109
|
+
:messages => [
|
|
110
|
+
'run — Run the script. The script can be run by telling the ' \
|
|
111
|
+
'object to run, or via the run verb.'
|
|
112
|
+
],
|
|
113
|
+
:examples => <<~EXAMPLES.strip
|
|
114
|
+
script [can] :
|
|
115
|
+
on_load [script] :
|
|
116
|
+
show "Showing multiple lines..."
|
|
117
|
+
show script.msg1
|
|
118
|
+
show script.msg2
|
|
119
|
+
show script.msg3
|
|
120
|
+
show "Done."
|
|
121
|
+
msg1 [string] : one
|
|
122
|
+
msg2 [string] : two
|
|
123
|
+
msg3 [string] : three
|
|
124
|
+
EXAMPLES
|
|
125
|
+
}
|
|
126
|
+
end
|
|
127
|
+
|
|
97
128
|
end
|
|
98
129
|
end
|
|
99
130
|
end
|
|
@@ -44,10 +44,37 @@ module Gloo
|
|
|
44
44
|
# Get a list of message names that this object receives.
|
|
45
45
|
#
|
|
46
46
|
def self.messages
|
|
47
|
-
return super +
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
return super + StringMsgs.messages
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# ---------------------------------------------------------------------
|
|
51
|
+
# Object Documentation
|
|
52
|
+
# ---------------------------------------------------------------------
|
|
53
|
+
|
|
54
|
+
#
|
|
55
|
+
# Get the object's documentation data.
|
|
56
|
+
#
|
|
57
|
+
def self.doc_data
|
|
58
|
+
{
|
|
59
|
+
:name => KEYWORD,
|
|
60
|
+
:shortcut => KEYWORD_SHORT,
|
|
61
|
+
:description => 'A string value. For string interpolation, ' \
|
|
62
|
+
'see the erb object type. Shares the same messages as the ' \
|
|
63
|
+
'text object type; the two differ mainly by convention — ' \
|
|
64
|
+
'string for a single word or line, text for longer, ' \
|
|
65
|
+
'multi-line blocks.',
|
|
66
|
+
:messages => StringMsgs.message_docs,
|
|
67
|
+
:examples => <<~EXAMPLES.strip
|
|
68
|
+
s [can] :
|
|
69
|
+
msg [string] : Hello World!
|
|
70
|
+
on_load [script] :
|
|
71
|
+
show s.msg
|
|
72
|
+
tell s.msg to up
|
|
73
|
+
show s.msg
|
|
74
|
+
tell s.msg to size
|
|
75
|
+
show it
|
|
76
|
+
EXAMPLES
|
|
77
|
+
}
|
|
51
78
|
end
|
|
52
79
|
|
|
53
80
|
end
|
|
@@ -10,8 +10,57 @@ module Gloo
|
|
|
10
10
|
module Objs
|
|
11
11
|
module StringMsgs
|
|
12
12
|
|
|
13
|
+
#
|
|
14
|
+
# Get the list of message names this mixin implements, derived
|
|
15
|
+
# from its own msg_* methods so String/Text don't have to
|
|
16
|
+
# hand-duplicate the list (and can't drift out of sync with it).
|
|
17
|
+
#
|
|
18
|
+
def self.messages
|
|
19
|
+
return instance_methods( false )
|
|
20
|
+
.select { |m| m.to_s.start_with?( 'msg_' ) }
|
|
21
|
+
.map { |m| m.to_s.sub( /\Amsg_/, '' ) }
|
|
22
|
+
end
|
|
13
23
|
|
|
14
|
-
#
|
|
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
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
#
|
|
15
64
|
# Strip whitespace from the beginning and end of the string.
|
|
16
65
|
#
|
|
17
66
|
def msg_trim
|
|
@@ -109,7 +158,115 @@ module Gloo
|
|
|
109
158
|
end
|
|
110
159
|
end
|
|
111
160
|
|
|
112
|
-
#
|
|
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
|
+
#
|
|
113
270
|
# Does the string contain the given string?
|
|
114
271
|
#
|
|
115
272
|
# This was formerly an overload of obj.contains?
|
|
@@ -324,6 +481,59 @@ module Gloo
|
|
|
324
481
|
return s
|
|
325
482
|
end
|
|
326
483
|
|
|
484
|
+
#
|
|
485
|
+
# Show the value in a pager, for long content.
|
|
486
|
+
#
|
|
487
|
+
def msg_page
|
|
488
|
+
return unless value
|
|
489
|
+
|
|
490
|
+
@engine.platform.page( value )
|
|
491
|
+
end
|
|
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
|
+
|
|
327
537
|
end
|
|
328
538
|
end
|
|
329
539
|
end
|
data/lib/gloo/objs/basic/text.rb
CHANGED
|
@@ -58,10 +58,36 @@ module Gloo
|
|
|
58
58
|
# Get a list of message names that this object receives.
|
|
59
59
|
#
|
|
60
60
|
def self.messages
|
|
61
|
-
return super +
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
61
|
+
return super + StringMsgs.messages
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# ---------------------------------------------------------------------
|
|
65
|
+
# Object Documentation
|
|
66
|
+
# ---------------------------------------------------------------------
|
|
67
|
+
|
|
68
|
+
#
|
|
69
|
+
# Get the object's documentation data.
|
|
70
|
+
#
|
|
71
|
+
def self.doc_data
|
|
72
|
+
{
|
|
73
|
+
:name => KEYWORD,
|
|
74
|
+
:shortcut => KEYWORD_SHORT,
|
|
75
|
+
:description => 'A longer, multi-line text string. Use BEGIN ' \
|
|
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,
|
|
81
|
+
:examples => <<~EXAMPLES.strip
|
|
82
|
+
t [container] :
|
|
83
|
+
msg [txt] : BEGIN
|
|
84
|
+
I will now write a poem
|
|
85
|
+
of two lines or less
|
|
86
|
+
END
|
|
87
|
+
on_load [script] :
|
|
88
|
+
show t.msg
|
|
89
|
+
EXAMPLES
|
|
90
|
+
}
|
|
65
91
|
end
|
|
66
92
|
|
|
67
93
|
end
|
|
@@ -36,6 +36,27 @@ module Gloo
|
|
|
36
36
|
return super
|
|
37
37
|
end
|
|
38
38
|
|
|
39
|
+
# ---------------------------------------------------------------------
|
|
40
|
+
# Object Documentation
|
|
41
|
+
# ---------------------------------------------------------------------
|
|
42
|
+
|
|
43
|
+
#
|
|
44
|
+
# Get the object's documentation data.
|
|
45
|
+
#
|
|
46
|
+
def self.doc_data
|
|
47
|
+
{
|
|
48
|
+
:name => KEYWORD,
|
|
49
|
+
:shortcut => KEYWORD_SHORT,
|
|
50
|
+
:description => 'An untyped object. If no type is specified ' \
|
|
51
|
+
'when an object is created it will be of this type.',
|
|
52
|
+
:examples => <<~EXAMPLES.strip
|
|
53
|
+
> create x
|
|
54
|
+
> put 1 into x
|
|
55
|
+
> put 'string' into x
|
|
56
|
+
EXAMPLES
|
|
57
|
+
}
|
|
58
|
+
end
|
|
59
|
+
|
|
39
60
|
end
|
|
40
61
|
end
|
|
41
62
|
end
|