gloo 3.0.1 → 3.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.
- checksums.yaml +4 -4
- data/gloo.gemspec +1 -0
- data/lib/VERSION +1 -1
- data/lib/VERSION_NOTES +6 -0
- data/lib/gloo/app/engine.rb +37 -4
- data/lib/gloo/app/log.rb +1 -2
- data/lib/gloo/app/running_app.rb +41 -0
- data/lib/gloo/core/factory.rb +1 -2
- data/lib/gloo/core/gloo_system.rb +5 -0
- data/lib/gloo/objs/basic/function.rb +169 -0
- data/lib/gloo/objs/basic/untyped.rb +1 -1
- data/lib/gloo/objs/web/json.rb +14 -1
- data/lib/gloo/objs/web/uri.rb +13 -1
- data/lib/gloo/objs/web_svr/element.rb +244 -0
- data/lib/gloo/objs/web_svr/page.rb +389 -0
- data/lib/gloo/objs/web_svr/partial.rb +204 -0
- data/lib/gloo/objs/web_svr/svr.rb +299 -0
- data/lib/gloo/verbs/cls.rb +1 -1
- data/lib/gloo/verbs/redirect.rb +56 -0
- data/lib/gloo/web_svr/asset.rb +194 -0
- data/lib/gloo/web_svr/config.rb +56 -0
- data/lib/gloo/web_svr/embedded_renderer.rb +91 -0
- data/lib/gloo/web_svr/handler.rb +120 -0
- data/lib/gloo/web_svr/request.rb +107 -0
- data/lib/gloo/web_svr/response.rb +118 -0
- data/lib/gloo/web_svr/response_code.rb +69 -0
- data/lib/gloo/web_svr/router.rb +179 -0
- data/lib/gloo/web_svr/server.rb +97 -0
- metadata +32 -2
@@ -0,0 +1,389 @@
|
|
1
|
+
# Author:: Eric Crane (mailto:eric.crane@mac.com)
|
2
|
+
# Copyright:: Copyright (c) 2024 Eric Crane. All rights reserved.
|
3
|
+
#
|
4
|
+
# A web page hosted in a gloo web server.
|
5
|
+
#
|
6
|
+
|
7
|
+
module Gloo
|
8
|
+
module Objs
|
9
|
+
class Page < Gloo::Core::Obj
|
10
|
+
|
11
|
+
KEYWORD = 'page'.freeze
|
12
|
+
KEYWORD_SHORT = 'page'.freeze
|
13
|
+
|
14
|
+
# Events
|
15
|
+
ON_RENDER = 'on_render'.freeze
|
16
|
+
ON_RENDERED = 'on_rendered'.freeze
|
17
|
+
|
18
|
+
# Parameters used during render.
|
19
|
+
PARAMS = 'params'.freeze
|
20
|
+
|
21
|
+
# Content
|
22
|
+
HEAD = 'head'.freeze
|
23
|
+
BODY = 'body'.freeze
|
24
|
+
CONTENT = 'content'.freeze
|
25
|
+
TITLE = 'title'.freeze
|
26
|
+
|
27
|
+
# Layout for this page.
|
28
|
+
# If not specified, use the layout for the app.
|
29
|
+
LAYOUT = 'layout'.freeze
|
30
|
+
|
31
|
+
# Return Content type and HTML Code
|
32
|
+
CONTENT_TYPE = 'content_type'.freeze
|
33
|
+
HTML_CONTENT = 'html'.freeze
|
34
|
+
TEXT_CONTENT = 'text'.freeze
|
35
|
+
JSON_CONTENT = 'json'.freeze
|
36
|
+
RETURN_CODE = 'return_code'.freeze
|
37
|
+
|
38
|
+
#
|
39
|
+
# The name of the object type.
|
40
|
+
#
|
41
|
+
def self.typename
|
42
|
+
return KEYWORD
|
43
|
+
end
|
44
|
+
|
45
|
+
#
|
46
|
+
# The short name of the object type.
|
47
|
+
#
|
48
|
+
def self.short_typename
|
49
|
+
return KEYWORD_SHORT
|
50
|
+
end
|
51
|
+
|
52
|
+
#
|
53
|
+
# Set the value with any necessary type conversions.
|
54
|
+
#
|
55
|
+
def set_value( new_value )
|
56
|
+
self.value = new_value.to_s
|
57
|
+
end
|
58
|
+
|
59
|
+
#
|
60
|
+
# Does this object support multi-line values?
|
61
|
+
# Initially only true for scripts.
|
62
|
+
#
|
63
|
+
def multiline_value?
|
64
|
+
return false
|
65
|
+
end
|
66
|
+
|
67
|
+
#
|
68
|
+
# Get the head element.
|
69
|
+
#
|
70
|
+
def head
|
71
|
+
return find_child HEAD
|
72
|
+
end
|
73
|
+
|
74
|
+
#
|
75
|
+
# Get the header content.
|
76
|
+
# This might be in a content child, or it might be
|
77
|
+
# the head object itself.
|
78
|
+
#
|
79
|
+
def head_content
|
80
|
+
head_obj = head
|
81
|
+
return nil unless head_obj
|
82
|
+
|
83
|
+
content_obj = head_obj.find_child CONTENT
|
84
|
+
return content_obj ? content_obj : head_obj
|
85
|
+
end
|
86
|
+
|
87
|
+
#
|
88
|
+
# Get the body element.
|
89
|
+
#
|
90
|
+
def body
|
91
|
+
return find_child BODY
|
92
|
+
end
|
93
|
+
|
94
|
+
#
|
95
|
+
# Get the body content.
|
96
|
+
# This might be in a content child, or it might be
|
97
|
+
# the body object itself.
|
98
|
+
#
|
99
|
+
def body_content
|
100
|
+
body_obj = body
|
101
|
+
return nil unless body_obj
|
102
|
+
|
103
|
+
content_obj = body_obj.find_child CONTENT
|
104
|
+
return content_obj ? content_obj : body_obj
|
105
|
+
end
|
106
|
+
|
107
|
+
#
|
108
|
+
# Get the params hash from the child object.
|
109
|
+
# Returns nil if there is none.
|
110
|
+
#
|
111
|
+
def params_hash
|
112
|
+
params_can = find_child PARAMS
|
113
|
+
return nil unless params_can
|
114
|
+
|
115
|
+
h = {}
|
116
|
+
params_can.children.each do |o|
|
117
|
+
h[ o.name ] = o.value
|
118
|
+
end
|
119
|
+
|
120
|
+
return h
|
121
|
+
end
|
122
|
+
|
123
|
+
#
|
124
|
+
# Get the return code.
|
125
|
+
# SUCCESS is the default if none is set.
|
126
|
+
#
|
127
|
+
def return_code
|
128
|
+
code = find_child RETURN_CODE
|
129
|
+
return code ? code.value : Gloo::WebSvr::ResponseCode::SUCCESS
|
130
|
+
end
|
131
|
+
|
132
|
+
#
|
133
|
+
# Get the content type.
|
134
|
+
#
|
135
|
+
def content_type
|
136
|
+
type = find_child CONTENT_TYPE
|
137
|
+
return type ? type.value : nil
|
138
|
+
end
|
139
|
+
|
140
|
+
#
|
141
|
+
# Get the layout for this page.
|
142
|
+
#
|
143
|
+
def page_layout
|
144
|
+
o = find_child LAYOUT
|
145
|
+
return nil unless o
|
146
|
+
|
147
|
+
o = Gloo::Objs::Alias.resolve_alias( @engine, o )
|
148
|
+
return o
|
149
|
+
end
|
150
|
+
|
151
|
+
#
|
152
|
+
# Is the return type HTML?
|
153
|
+
#
|
154
|
+
def is_html?
|
155
|
+
return true if content_type.nil?
|
156
|
+
return content_type == HTML_CONTENT
|
157
|
+
end
|
158
|
+
|
159
|
+
#
|
160
|
+
# Is the return type TEXT?
|
161
|
+
#
|
162
|
+
def is_text?
|
163
|
+
return content_type == TEXT_CONTENT
|
164
|
+
end
|
165
|
+
|
166
|
+
#
|
167
|
+
# Is the return type JSON?
|
168
|
+
#
|
169
|
+
def is_json?
|
170
|
+
return content_type == JSON_CONTENT
|
171
|
+
end
|
172
|
+
|
173
|
+
|
174
|
+
# ---------------------------------------------------------------------
|
175
|
+
# Events
|
176
|
+
# ---------------------------------------------------------------------
|
177
|
+
|
178
|
+
#
|
179
|
+
# Run the on render script if there is one.
|
180
|
+
#
|
181
|
+
def run_on_render
|
182
|
+
o = find_child ON_RENDER
|
183
|
+
return unless o
|
184
|
+
|
185
|
+
Gloo::Exec::Dispatch.message( @engine, 'run', o )
|
186
|
+
end
|
187
|
+
|
188
|
+
#
|
189
|
+
# Run the on rendered script if there is one.
|
190
|
+
#
|
191
|
+
def run_on_rendered
|
192
|
+
o = find_child ON_RENDERED
|
193
|
+
return unless o
|
194
|
+
|
195
|
+
Gloo::Exec::Dispatch.message( @engine, 'run', o )
|
196
|
+
end
|
197
|
+
|
198
|
+
|
199
|
+
# ---------------------------------------------------------------------
|
200
|
+
# Children
|
201
|
+
# ---------------------------------------------------------------------
|
202
|
+
|
203
|
+
#
|
204
|
+
# Does this object have children to add when an object
|
205
|
+
# is created in interactive mode?
|
206
|
+
# This does not apply during obj load, etc.
|
207
|
+
#
|
208
|
+
def add_children_on_create?
|
209
|
+
return true
|
210
|
+
end
|
211
|
+
|
212
|
+
#
|
213
|
+
# Add children to this object.
|
214
|
+
# This is used by containers to add children needed
|
215
|
+
# for default configurations.
|
216
|
+
#
|
217
|
+
def add_default_children
|
218
|
+
fac = @engine.factory
|
219
|
+
|
220
|
+
fac.create_script ON_RENDER, '', self
|
221
|
+
fac.create_script ON_RENDERED, '', self
|
222
|
+
fac.create_can PARAMS, self
|
223
|
+
|
224
|
+
params = { :name => HEAD,
|
225
|
+
:type => Gloo::Objs::Element.typename,
|
226
|
+
:value => nil,
|
227
|
+
:parent => self }
|
228
|
+
head = fac.create params
|
229
|
+
content = fac.create_can CONTENT, head
|
230
|
+
params = { :name => TITLE,
|
231
|
+
:type => Gloo::Objs::Element.typename,
|
232
|
+
:value => nil,
|
233
|
+
:parent => content }
|
234
|
+
title = fac.create params
|
235
|
+
|
236
|
+
params = { :name => BODY,
|
237
|
+
:type => Gloo::Objs::Element.typename,
|
238
|
+
:value => nil,
|
239
|
+
:parent => self }
|
240
|
+
body = fac.create params
|
241
|
+
content = fac.create_can CONTENT, body
|
242
|
+
end
|
243
|
+
|
244
|
+
|
245
|
+
# ---------------------------------------------------------------------
|
246
|
+
# Messages
|
247
|
+
# ---------------------------------------------------------------------
|
248
|
+
|
249
|
+
#
|
250
|
+
# Get a list of message names that this object receives.
|
251
|
+
#
|
252
|
+
def self.messages
|
253
|
+
return super + [ 'render' ]
|
254
|
+
end
|
255
|
+
|
256
|
+
#
|
257
|
+
# Get the expiration date for the certificate.
|
258
|
+
#
|
259
|
+
def msg_render
|
260
|
+
content = self.render
|
261
|
+
@engine.heap.it.set_to content
|
262
|
+
return content
|
263
|
+
end
|
264
|
+
|
265
|
+
# ---------------------------------------------------------------------
|
266
|
+
# Render
|
267
|
+
# ---------------------------------------------------------------------
|
268
|
+
|
269
|
+
#
|
270
|
+
# Wrap the content in the tag with id and class.
|
271
|
+
#
|
272
|
+
def wrap( tag, content, id=nil, classes=nil )
|
273
|
+
return "<#{tag}>#{content}</#{tag}>"
|
274
|
+
end
|
275
|
+
|
276
|
+
#
|
277
|
+
# Is there a redirect page set in the running app?
|
278
|
+
#
|
279
|
+
def redirect_set?
|
280
|
+
return false unless @engine.app_running?
|
281
|
+
return @engine.running_app.obj.redirect
|
282
|
+
end
|
283
|
+
|
284
|
+
#
|
285
|
+
# Render the page.
|
286
|
+
#
|
287
|
+
def render
|
288
|
+
run_on_render
|
289
|
+
return nil if redirect_set?
|
290
|
+
|
291
|
+
params = params_hash
|
292
|
+
|
293
|
+
if is_html?
|
294
|
+
contents = render_html params
|
295
|
+
elsif is_json?
|
296
|
+
contents = render_json
|
297
|
+
elsif is_text?
|
298
|
+
contents = render_text params
|
299
|
+
else
|
300
|
+
@engine.log.error "Unknown content type: #{content_type}"
|
301
|
+
return nil
|
302
|
+
end
|
303
|
+
|
304
|
+
run_on_rendered
|
305
|
+
return nil if redirect_set?
|
306
|
+
|
307
|
+
return contents
|
308
|
+
end
|
309
|
+
|
310
|
+
#
|
311
|
+
# Render the page as HTML.
|
312
|
+
#
|
313
|
+
def render_html params
|
314
|
+
head_obj = render_with_params head_content, :render_html, params
|
315
|
+
body_obj = render_with_params body_content, :render_html, params
|
316
|
+
|
317
|
+
layout = page_layout_or_app_layout
|
318
|
+
if layout
|
319
|
+
@engine.log.debug "Using Page Layout: #{layout.pn}"
|
320
|
+
contents = layout.render_layout( head_obj, body_obj )
|
321
|
+
else
|
322
|
+
@engine.log.debug "No layout for page."
|
323
|
+
contents = wrap( 'html', head_obj + body_obj )
|
324
|
+
end
|
325
|
+
|
326
|
+
return Gloo::WebSvr::Response.html_response(
|
327
|
+
@engine, contents, return_code )
|
328
|
+
end
|
329
|
+
|
330
|
+
#
|
331
|
+
# Get the layout for this page or if none for the app.
|
332
|
+
#
|
333
|
+
def page_layout_or_app_layout
|
334
|
+
layout = page_layout
|
335
|
+
return layout if layout
|
336
|
+
|
337
|
+
return nil unless @engine.app_running?
|
338
|
+
return @engine.running_app.obj.default_page_layout
|
339
|
+
end
|
340
|
+
|
341
|
+
#
|
342
|
+
# Render the page as JSON.
|
343
|
+
#
|
344
|
+
def render_json
|
345
|
+
json_content = Gloo::Objs::Json.convert_obj_to_json( body )
|
346
|
+
|
347
|
+
return Gloo::WebSvr::Response.json_response( @engine, json_content, return_code )
|
348
|
+
end
|
349
|
+
|
350
|
+
#
|
351
|
+
# Render the page as TEXT.
|
352
|
+
#
|
353
|
+
def render_text params
|
354
|
+
text_content = render_with_params body_content, :render_text, params
|
355
|
+
return Gloo::WebSvr::Response.text_response( @engine, text_content, return_code )
|
356
|
+
end
|
357
|
+
|
358
|
+
#
|
359
|
+
# Given an object and a render message, render the object.
|
360
|
+
# If the obj is nil, return an empty string.
|
361
|
+
# If the params are nil, no param rendering is done.
|
362
|
+
#
|
363
|
+
def render_with_params obj, render_ƒ, params
|
364
|
+
return '' unless obj
|
365
|
+
|
366
|
+
content = Element.render_obj( obj, render_ƒ, @engine )
|
367
|
+
# content = Page.render_params( content, params ) if params
|
368
|
+
content = @engine.running_app.obj.embedded_renderer.render content, params
|
369
|
+
|
370
|
+
return content
|
371
|
+
end
|
372
|
+
|
373
|
+
#
|
374
|
+
# Render content with the given params.
|
375
|
+
# Params might be nil, in which case the content
|
376
|
+
# is returned with no changes.
|
377
|
+
#
|
378
|
+
def self.render_params content, params
|
379
|
+
return content unless params
|
380
|
+
|
381
|
+
renderer = ERB.new( content )
|
382
|
+
content = renderer.result_with_hash( params )
|
383
|
+
|
384
|
+
return content
|
385
|
+
end
|
386
|
+
|
387
|
+
end
|
388
|
+
end
|
389
|
+
end
|
@@ -0,0 +1,204 @@
|
|
1
|
+
# Author:: Eric Crane (mailto:eric.crane@mac.com)
|
2
|
+
# Copyright:: Copyright (c) 2024 Eric Crane. All rights reserved.
|
3
|
+
#
|
4
|
+
# A partial page.
|
5
|
+
#
|
6
|
+
|
7
|
+
module Gloo
|
8
|
+
module Objs
|
9
|
+
class Partial < Gloo::Core::Obj
|
10
|
+
|
11
|
+
KEYWORD = 'partial'.freeze
|
12
|
+
KEYWORD_SHORT = 'part'.freeze
|
13
|
+
|
14
|
+
# Events
|
15
|
+
ON_RENDER = 'on_render'.freeze
|
16
|
+
ON_RENDERED = 'on_rendered'.freeze
|
17
|
+
|
18
|
+
# Parameters used during render.
|
19
|
+
PARAMS = 'params'.freeze
|
20
|
+
|
21
|
+
# Content
|
22
|
+
CONTENT = 'content'.freeze
|
23
|
+
|
24
|
+
|
25
|
+
#
|
26
|
+
# The name of the object type.
|
27
|
+
#
|
28
|
+
def self.typename
|
29
|
+
return KEYWORD
|
30
|
+
end
|
31
|
+
|
32
|
+
#
|
33
|
+
# The short name of the object type.
|
34
|
+
#
|
35
|
+
def self.short_typename
|
36
|
+
return KEYWORD_SHORT
|
37
|
+
end
|
38
|
+
|
39
|
+
#
|
40
|
+
# Set the value with any necessary type conversions.
|
41
|
+
#
|
42
|
+
def set_value( new_value )
|
43
|
+
self.value = new_value.to_s
|
44
|
+
end
|
45
|
+
|
46
|
+
#
|
47
|
+
# Does this object support multi-line values?
|
48
|
+
# Initially only true for scripts.
|
49
|
+
#
|
50
|
+
def multiline_value?
|
51
|
+
return false
|
52
|
+
end
|
53
|
+
|
54
|
+
#
|
55
|
+
# Get the content obj.
|
56
|
+
#
|
57
|
+
def content
|
58
|
+
return find_child CONTENT
|
59
|
+
end
|
60
|
+
|
61
|
+
#
|
62
|
+
# Get the params hash from the child object.
|
63
|
+
# Returns nil if there is none.
|
64
|
+
#
|
65
|
+
def params_hash
|
66
|
+
params_can = find_child PARAMS
|
67
|
+
return nil unless params_can
|
68
|
+
|
69
|
+
h = {}
|
70
|
+
params_can.children.each do |o|
|
71
|
+
h[ o.name ] = o.value
|
72
|
+
end
|
73
|
+
|
74
|
+
return h
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
# ---------------------------------------------------------------------
|
79
|
+
# Events
|
80
|
+
# ---------------------------------------------------------------------
|
81
|
+
|
82
|
+
#
|
83
|
+
# Run the on render script if there is one.
|
84
|
+
#
|
85
|
+
def run_on_render
|
86
|
+
o = find_child ON_RENDER
|
87
|
+
return unless o
|
88
|
+
|
89
|
+
Gloo::Exec::Dispatch.message( @engine, 'run', o )
|
90
|
+
end
|
91
|
+
|
92
|
+
#
|
93
|
+
# Run the on rendered script if there is one.
|
94
|
+
#
|
95
|
+
def run_on_rendered
|
96
|
+
o = find_child ON_RENDERED
|
97
|
+
return unless o
|
98
|
+
|
99
|
+
Gloo::Exec::Dispatch.message( @engine, 'run', o )
|
100
|
+
end
|
101
|
+
|
102
|
+
|
103
|
+
# ---------------------------------------------------------------------
|
104
|
+
# Children
|
105
|
+
# ---------------------------------------------------------------------
|
106
|
+
|
107
|
+
#
|
108
|
+
# Does this object have children to add when an object
|
109
|
+
# is created in interactive mode?
|
110
|
+
# This does not apply during obj load, etc.
|
111
|
+
#
|
112
|
+
def add_children_on_create?
|
113
|
+
return true
|
114
|
+
end
|
115
|
+
|
116
|
+
#
|
117
|
+
# Add children to this object.
|
118
|
+
# This is used by containers to add children needed
|
119
|
+
# for default configurations.
|
120
|
+
#
|
121
|
+
def add_default_children
|
122
|
+
fac = @engine.factory
|
123
|
+
|
124
|
+
fac.create_script ON_RENDER, '', self
|
125
|
+
fac.create_script ON_RENDERED, '', self
|
126
|
+
|
127
|
+
fac.create_can PARAMS, self
|
128
|
+
fac.create_can CONTENT, self
|
129
|
+
end
|
130
|
+
|
131
|
+
|
132
|
+
# ---------------------------------------------------------------------
|
133
|
+
# Messages
|
134
|
+
# ---------------------------------------------------------------------
|
135
|
+
|
136
|
+
#
|
137
|
+
# Get a list of message names that this object receives.
|
138
|
+
#
|
139
|
+
def self.messages
|
140
|
+
return super + [ 'render' ]
|
141
|
+
end
|
142
|
+
|
143
|
+
#
|
144
|
+
# Get the expiration date for the certificate.
|
145
|
+
#
|
146
|
+
def msg_render
|
147
|
+
part_content = self.render
|
148
|
+
@engine.heap.it.set_to part_content
|
149
|
+
return part_content
|
150
|
+
end
|
151
|
+
|
152
|
+
# ---------------------------------------------------------------------
|
153
|
+
# Render
|
154
|
+
# ---------------------------------------------------------------------
|
155
|
+
|
156
|
+
#
|
157
|
+
# Render the page.
|
158
|
+
# Use the specified render function or HTML by default.
|
159
|
+
#
|
160
|
+
def render( render_ƒ = :render_html )
|
161
|
+
run_on_render
|
162
|
+
|
163
|
+
part_content = ''
|
164
|
+
content.children.each do |e|
|
165
|
+
part_content << e.send( render_ƒ )
|
166
|
+
end
|
167
|
+
|
168
|
+
# part_content = Page.render_params part_content, params_hash
|
169
|
+
part_content = @engine.running_app.obj.embedded_renderer.render part_content, params_hash
|
170
|
+
|
171
|
+
run_on_rendered
|
172
|
+
return part_content
|
173
|
+
end
|
174
|
+
|
175
|
+
#
|
176
|
+
# Render the layout with the body and head params.
|
177
|
+
#
|
178
|
+
def render_layout( head, body )
|
179
|
+
run_on_render
|
180
|
+
|
181
|
+
part_content = ''
|
182
|
+
content.children.each do |e|
|
183
|
+
e = Gloo::Objs::Alias.resolve_alias( @engine, e )
|
184
|
+
|
185
|
+
obj = e.find_child CONTENT
|
186
|
+
e = obj if obj
|
187
|
+
|
188
|
+
part_content << Element.render_obj( e, :render_html, @engine )
|
189
|
+
end
|
190
|
+
|
191
|
+
params = params_hash || {}
|
192
|
+
params[ 'head' ] = head
|
193
|
+
params[ 'body' ] = body
|
194
|
+
|
195
|
+
# part_content = Page.render_params part_content, params
|
196
|
+
part_content = @engine.running_app.obj.embedded_renderer.render part_content, params
|
197
|
+
|
198
|
+
run_on_rendered
|
199
|
+
return part_content
|
200
|
+
end
|
201
|
+
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|