gloo 3.1.1 → 3.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/gloo.gemspec +1 -0
  3. data/lib/VERSION +1 -1
  4. data/lib/VERSION_NOTES +13 -0
  5. data/lib/gloo/app/log.rb +46 -6
  6. data/lib/gloo/app/platform.rb +7 -1
  7. data/lib/gloo/app/running_app.rb +42 -1
  8. data/lib/gloo/convert/falseclass_to_integer.rb +20 -0
  9. data/lib/gloo/convert/nilclass_to_date.rb +21 -0
  10. data/lib/gloo/convert/nilclass_to_datetime.rb +21 -0
  11. data/lib/gloo/convert/nilclass_to_integer.rb +21 -0
  12. data/lib/gloo/convert/nilclass_to_string.rb +21 -0
  13. data/lib/gloo/convert/nilclass_to_time.rb +21 -0
  14. data/lib/gloo/convert/trueclass_to_integer.rb +20 -0
  15. data/lib/gloo/core/error.rb +7 -0
  16. data/lib/gloo/core/it.rb +7 -0
  17. data/lib/gloo/core/obj.rb +41 -1
  18. data/lib/gloo/core/parser.rb +6 -3
  19. data/lib/gloo/exec/exec_env.rb +4 -0
  20. data/lib/gloo/exec/script.rb +9 -1
  21. data/lib/gloo/objs/basic/container.rb +18 -2
  22. data/lib/gloo/objs/basic/integer.rb +1 -0
  23. data/lib/gloo/objs/cli/menu.rb +9 -3
  24. data/lib/gloo/objs/{basic → ctrl}/function.rb +12 -0
  25. data/lib/gloo/objs/data/markdown.rb +60 -2
  26. data/lib/gloo/objs/data/mysql.rb +35 -7
  27. data/lib/gloo/objs/data/pg.rb +8 -0
  28. data/lib/gloo/objs/data/query.rb +66 -11
  29. data/lib/gloo/objs/data/query_result.rb +22 -1
  30. data/lib/gloo/objs/data/sqlite.rb +17 -2
  31. data/lib/gloo/objs/data/table.rb +143 -4
  32. data/lib/gloo/objs/web/json.rb +2 -0
  33. data/lib/gloo/objs/web_svr/element.rb +13 -5
  34. data/lib/gloo/objs/web_svr/page.rb +44 -2
  35. data/lib/gloo/objs/web_svr/partial.rb +7 -2
  36. data/lib/gloo/objs/web_svr/svr.rb +71 -4
  37. data/lib/gloo/verbs/break.rb +44 -0
  38. data/lib/gloo/verbs/create.rb +6 -0
  39. data/lib/gloo/verbs/invoke.rb +80 -0
  40. data/lib/gloo/verbs/log.rb +26 -5
  41. data/lib/gloo/verbs/redirect.rb +54 -6
  42. data/lib/gloo/web_svr/asset.rb +51 -23
  43. data/lib/gloo/web_svr/handler.rb +4 -2
  44. data/lib/gloo/web_svr/request.rb +35 -2
  45. data/lib/gloo/web_svr/routing/resource_router.rb +47 -0
  46. data/lib/gloo/web_svr/routing/router.rb +218 -0
  47. data/lib/gloo/web_svr/routing/show_routes.rb +98 -0
  48. data/lib/gloo/web_svr/server.rb +10 -2
  49. data/lib/gloo/web_svr/table_renderer.rb +147 -0
  50. data/lib/gloo/web_svr/web_method.rb +54 -0
  51. metadata +31 -4
  52. data/lib/gloo/web_svr/router.rb +0 -179
@@ -3,6 +3,7 @@
3
3
  #
4
4
  # Markdown data.
5
5
  #
6
+ require 'redcarpet'
6
7
 
7
8
  module Gloo
8
9
  module Objs
@@ -55,7 +56,7 @@ module Gloo
55
56
  # Get a list of message names that this object receives.
56
57
  #
57
58
  def self.messages
58
- return super + %w[show page]
59
+ return super + %w[show page render]
59
60
  end
60
61
 
61
62
  #
@@ -71,9 +72,66 @@ module Gloo
71
72
  def msg_page
72
73
  return unless self.value
73
74
 
74
- @engine.platform.show( md, true, true )
75
+ @engine.platform.show( self.value, true, true )
75
76
  end
76
77
 
78
+ #
79
+ # Render the markdown as HTML.
80
+ # Needs an optional parameter of where to put the rendered html.
81
+ # The html will be in 'it' as well.
82
+ #
83
+ def msg_render
84
+ html = Gloo::Objs::Markdown.md_2_html( value )
85
+
86
+ # Put the HTML in the optional parameter if one is given.
87
+ if @params&.token_count&.positive?
88
+ pn = Gloo::Core::Pn.new( @engine, @params.first )
89
+ o = pn.resolve
90
+ o.set_value html
91
+ end
92
+
93
+ # Put the HTML in it, in any case.
94
+ @engine.heap.it.set_to html
95
+ end
96
+
97
+ # ---------------------------------------------------------------------
98
+ # Static Helpers
99
+ # ---------------------------------------------------------------------
100
+
101
+ #
102
+ # Convert markdown to HTML using the
103
+ # Redcarpet markdown processor.
104
+ #
105
+ def self.md_2_html( md )
106
+ markdown = Redcarpet::Markdown.new(
107
+ Redcarpet::Render::HTML,
108
+ autolink: true,
109
+ fenced_code_blocks: true,
110
+ tables: true,
111
+ strikethrough: true )
112
+
113
+ return markdown.render( md )
114
+ end
115
+
116
+ #
117
+ # Does not work.
118
+ # See note in the platform.rb file.
119
+ #
120
+ # #
121
+ # # Convert markdown to manpage using the
122
+ # # Redcarpet markdown processor.
123
+ # #
124
+ # def self.md_2_manpage( md )
125
+ # markdown = Redcarpet::Markdown.new(
126
+ # Redcarpet::Render::ManPage,
127
+ # autolink: true,
128
+ # fenced_code_blocks: true,
129
+ # tables: true,
130
+ # strikethrough: true )
131
+
132
+ # return markdown.render( md )
133
+ # end
134
+
77
135
  end
78
136
  end
79
137
  end
@@ -90,22 +90,42 @@ module Gloo
90
90
  @engine.heap.it.set_to true
91
91
  end
92
92
 
93
+
93
94
  # ---------------------------------------------------------------------
94
95
  # DB functions (all database connections)
95
96
  # ---------------------------------------------------------------------
96
97
 
98
+ #
99
+ # Get the client object.
100
+ # It might be cached, so check first.
101
+ # If it is not cached, create a new one.
102
+ #
103
+ def get_client
104
+ app = @engine.running_app
105
+
106
+ client = app.db_client_for_obj( self ) if app
107
+
108
+ unless client
109
+ h = {
110
+ host: host_value,
111
+ database: db_value,
112
+ username: user_value,
113
+ password: passwd_value
114
+ }
115
+ client = Mysql2::Client.new( h )
116
+
117
+ app.cache_db_client( self, client ) if app
118
+ end
119
+
120
+ return client
121
+ end
122
+
97
123
  #
98
124
  # Open a connection and execute the SQL statement.
99
125
  # Return the resulting data.
100
126
  #
101
127
  def query( sql, params = nil )
102
- h = {
103
- host: host_value,
104
- database: db_value,
105
- username: user_value,
106
- password: passwd_value
107
- }
108
- client = Mysql2::Client.new( h )
128
+ client = get_client
109
129
 
110
130
  heads = []
111
131
  data = []
@@ -134,6 +154,14 @@ module Gloo
134
154
  return [ heads, data ]
135
155
  end
136
156
 
157
+ #
158
+ # Based on the result set, build a QueryResult object.
159
+ #
160
+ def get_query_result( result )
161
+ return QueryResult.new result[0], result[1]
162
+ end
163
+
164
+
137
165
  # ---------------------------------------------------------------------
138
166
  # Private functions
139
167
  # ---------------------------------------------------------------------
@@ -119,6 +119,14 @@ module Gloo
119
119
  return [ heads, data ]
120
120
  end
121
121
 
122
+ #
123
+ # Based on the result set, build a QueryResult object.
124
+ #
125
+ def get_query_result( result )
126
+ return QueryResult.new result[0], result[1]
127
+ end
128
+
129
+
122
130
  # ---------------------------------------------------------------------
123
131
  # Private functions
124
132
  # ---------------------------------------------------------------------
@@ -16,6 +16,7 @@ module Gloo
16
16
  SQL = 'sql'.freeze
17
17
  RESULT = 'result'.freeze
18
18
  PARAMS = 'params'.freeze
19
+ SIMPLE_LIST = 'simple_list'.freeze
19
20
 
20
21
  DB_MISSING_ERR = 'The database connection is missing!'.freeze
21
22
 
@@ -70,24 +71,69 @@ module Gloo
70
71
  end
71
72
 
72
73
  #
73
- # SSH to the host and execute the command, then update result.
74
+ # Run the query and process the results.
74
75
  #
75
76
  def msg_run
76
77
  db = db_obj
77
- unless db
78
- @engine.err DB_MISSING_ERR
78
+ return unless db
79
+
80
+ begin
81
+ result = db.query( sql_value, param_array )
82
+ process_result( result, db )
83
+ rescue => e
84
+ @engine.err e.message
79
85
  return
80
86
  end
87
+ end
88
+
89
+ #
90
+ # Run the query and return the results.
91
+ #
92
+ def run_query
93
+ db = db_obj
94
+ return unless db
81
95
 
82
96
  begin
97
+ log_query sql_value, param_array
98
+
99
+ db_start = ::Time.now
83
100
  result = db.query( sql_value, param_array )
84
- process_result result
101
+ db_done = ::Time.now
102
+ elapsed = ( ( db_done - db_start ) * 1000.0 ).round(2)
103
+
104
+ app = @engine.running_app
105
+ app.add_db_time elapsed if app
106
+ return result
85
107
  rescue => e
86
108
  @engine.err e.message
87
109
  return
88
110
  end
89
111
  end
90
112
 
113
+ #
114
+ # Write the query to the log.
115
+ #
116
+ def log_query sql, params
117
+ @engine.log.info "QUERY PARAMS: #{params}" if params
118
+ @engine.log.info "QUERY: #{sql}"
119
+ end
120
+
121
+
122
+ # ---------------------------------------------------------------------
123
+ # Output as simple list
124
+ # ---------------------------------------------------------------------
125
+
126
+ #
127
+ # Should the output be put in a simple list?
128
+ #
129
+ def simple_list?
130
+ o = find_child SIMPLE_LIST
131
+ return false unless o
132
+
133
+ return o.value
134
+ end
135
+
136
+
91
137
  # ---------------------------------------------------------------------
92
138
  # Private functions
93
139
  # ---------------------------------------------------------------------
@@ -99,6 +145,12 @@ module Gloo
99
145
  #
100
146
  def db_obj
101
147
  o = find_child DB
148
+
149
+ unless o
150
+ @engine.err DB_MISSING_ERR
151
+ return nil
152
+ end
153
+
102
154
  return Gloo::Objs::Alias.resolve_alias( @engine, o )
103
155
  end
104
156
 
@@ -118,21 +170,24 @@ module Gloo
118
170
  # If there's a result container, we'll create objects in it.
119
171
  # If not, we'll just show the output in the console.
120
172
  #
121
- def process_result( result )
173
+ def process_result( result, db )
122
174
  return if result.nil?
123
175
 
124
- heads = result[0]
125
- data = result[1]
126
- qr = QueryResult.new heads, data
127
- return unless qr.has_data_to_show?
176
+ query_result = db.get_query_result( result )
177
+ return unless query_result
178
+ return unless query_result.has_data_to_show?
128
179
 
129
180
  result_can = find_child RESULT
130
181
  result_can = Gloo::Objs::Alias.resolve_alias( @engine, result_can )
131
182
 
132
183
  if result_can
133
- qr.update_result_container result_can
184
+ if simple_list?
185
+ query_result.update_result_container_simple result_can
186
+ else
187
+ query_result.update_result_container result_can
188
+ end
134
189
  else
135
- qr.show
190
+ query_result.show
136
191
  end
137
192
  end
138
193
 
@@ -98,6 +98,14 @@ module Gloo
98
98
  single_row_result? ? update_single_row : update_rows
99
99
  end
100
100
 
101
+ #
102
+ # Update the result container with the data from the query.
103
+ #
104
+ def update_result_container_simple( in_can )
105
+ @result_can = in_can
106
+ single_row_result? ? update_single_row : update_rows_simple
107
+ end
108
+
101
109
  #
102
110
  # The result has a single row.
103
111
  # Map values from the result set to objects that are present.
@@ -122,7 +130,20 @@ module Gloo
122
130
  end
123
131
  end
124
132
  end
125
-
133
+
134
+ #
135
+ # Put all rows in the result object.
136
+ #
137
+ def update_rows_simple
138
+ @data.each do |row|
139
+ row.each do |val|
140
+ o = @result_can.find_add_child( val, 'untyped' )
141
+ o.set_value val
142
+ end
143
+ end
144
+ end
145
+
146
+
126
147
  # ---------------------------------------------------------------------
127
148
  # Private functions
128
149
  # ---------------------------------------------------------------------
@@ -116,10 +116,25 @@ module Gloo
116
116
  end
117
117
 
118
118
  db = SQLite3::Database.open name
119
- db.results_as_hash = true
120
- return db.query( sql, params )
119
+ # db.results_as_hash = true
120
+ results = db.query( sql, params )
121
+
122
+ return results
123
+ end
124
+
125
+ #
126
+ # Based on the result set, build a QueryResult object.
127
+ #
128
+ def get_query_result( result )
129
+ rows = []
130
+ while ( row = result.next ) do
131
+ rows << row
132
+ end
133
+
134
+ return QueryResult.new( result.columns, rows )
121
135
  end
122
136
 
137
+
123
138
  # ---------------------------------------------------------------------
124
139
  # Private functions
125
140
  # ---------------------------------------------------------------------
@@ -13,6 +13,8 @@ module Gloo
13
13
  KEYWORD_SHORT = 'tbl'.freeze
14
14
  HEADERS = 'headers'.freeze
15
15
  DATA = 'data'.freeze
16
+ CELLS = 'cells'.freeze
17
+ STYLES = 'styles'.freeze
16
18
 
17
19
  #
18
20
  # The name of the object type.
@@ -58,12 +60,64 @@ module Gloo
58
60
  return [] unless o
59
61
 
60
62
  o = Gloo::Objs::Alias.resolve_alias( @engine, o )
61
- cols = self.columns
62
- return o.children.map do |e|
63
- cols.map { |h| e.find_child( h ).value }
63
+
64
+ if o.is_a? Gloo::Objs::Query
65
+ @engine.log.debug "Table getting data from query."
66
+ begin
67
+ result = o.run_query
68
+ return result
69
+ rescue => e
70
+ @engine.err e.message
71
+ return nil
72
+ end
73
+ else
74
+ cols = self.columns
75
+
76
+ if o.children&.first.children.empty?
77
+ # It is a simgle row table.
78
+ rows = [ cols.map { |h| o.find_child( h )&.value } ]
79
+ else
80
+ rows = o.children.map do |e|
81
+ cols.map { |h| e.find_child( h )&.value }
82
+ end
83
+ end
84
+
85
+ return [ cols, rows ]
64
86
  end
65
87
  end
66
88
 
89
+ #
90
+ # Get the styles for the table, if any.
91
+ #
92
+ def styles
93
+ style_h = {}
94
+ o = find_child STYLES
95
+ return style_h unless o
96
+ o = Gloo::Objs::Alias.resolve_alias( @engine, o )
97
+
98
+ o.children.each do |c|
99
+ style_h[ c.name ] = c.value
100
+ end
101
+
102
+ return style_h
103
+ end
104
+
105
+ #
106
+ # Get cell renderer hash keyed by column name.
107
+ #
108
+ def cell_renderers
109
+ h = {}
110
+ o = find_child CELLS
111
+ return h unless o
112
+
113
+ o.children.each do |c|
114
+ h[ c.name ] = c.value
115
+ end
116
+
117
+ return h
118
+ end
119
+
120
+
67
121
  # ---------------------------------------------------------------------
68
122
  # Children
69
123
  # ---------------------------------------------------------------------
@@ -88,6 +142,7 @@ module Gloo
88
142
  fac.create_can DATA, self
89
143
  end
90
144
 
145
+
91
146
  # ---------------------------------------------------------------------
92
147
  # Messages
93
148
  # ---------------------------------------------------------------------
@@ -96,7 +151,7 @@ module Gloo
96
151
  # Get a list of message names that this object receives.
97
152
  #
98
153
  def self.messages
99
- return super + %w[show]
154
+ return super + %w[show render]
100
155
  end
101
156
 
102
157
  #
@@ -107,6 +162,90 @@ module Gloo
107
162
  @engine.platform.show_table headers, data, title
108
163
  end
109
164
 
165
+ def msg_render
166
+ return render
167
+ end
168
+
169
+
170
+ # ---------------------------------------------------------------------
171
+ # Render
172
+ # ---------------------------------------------------------------------
173
+
174
+ #
175
+ # Render the table.
176
+ # The render_ƒ is 'render_html', 'render_text', 'render_json', etc.
177
+ #
178
+ def render render_ƒ
179
+ begin
180
+ result = self.data
181
+ head = self.headers
182
+ head = result[0] if head.empty?
183
+ rows = result[1]
184
+
185
+ columns = build_columns result[0]
186
+
187
+ params = {
188
+ head: head,
189
+ cols: result[0],
190
+ columns: columns,
191
+ rows: rows,
192
+ styles: self.styles,
193
+ cell_renderers: self.cell_renderers
194
+ }
195
+
196
+ helper = Gloo::WebSvr::TableRenderer.new( @engine )
197
+ return helper.data_to_table params
198
+ rescue => e
199
+ @engine.err e.message
200
+ return nil
201
+ end
202
+ end
203
+
204
+ #
205
+ # Build the column list based on the result data and
206
+ # the headers defined in the table object.
207
+ #
208
+ def build_columns result_data
209
+ head_children = find_child HEADERS
210
+ cell_renderers = find_child CELLS
211
+
212
+ columns = []
213
+ return columns unless result_data
214
+
215
+ result_data.each_with_index do |c,index|
216
+ visible = true
217
+ name = c
218
+ title = c
219
+ display_index = index
220
+
221
+ if head_children
222
+ child = head_children.find_child c
223
+ if child
224
+ title = child.value
225
+ display_index = head_children.child_index( c )
226
+ else
227
+ visible = false
228
+ end
229
+ end
230
+
231
+ cell_renderer = nil
232
+ if cell_renderers
233
+ this_cr = cell_renderers.find_child( c )
234
+ cell_renderer = this_cr.value if this_cr
235
+ end
236
+
237
+ columns << {
238
+ name: name,
239
+ title: title,
240
+ visible: visible,
241
+ data_index: index,
242
+ display_index: display_index,
243
+ cell_renderer: cell_renderer
244
+ }
245
+ end
246
+ return columns.sort_by { |hsh| hsh[ :display_index ] }
247
+ end
248
+
110
249
  end
111
250
  end
112
251
  end
@@ -63,6 +63,8 @@ module Gloo
63
63
  # Make the JSON pretty.
64
64
  #
65
65
  def msg_pretty
66
+ return unless self.value
67
+
66
68
  json = JSON.parse( self.value )
67
69
  pretty = JSON.pretty_generate( json )
68
70
  set_value pretty
@@ -173,7 +173,7 @@ module Gloo
173
173
  # Get the expiration date for the certificate.
174
174
  #
175
175
  def msg_render
176
- content = self.render
176
+ content = self.render_html
177
177
  @engine.heap.it.set_to content
178
178
  return content
179
179
  end
@@ -226,10 +226,9 @@ module Gloo
226
226
  e = Gloo::Objs::Alias.resolve_alias( engine, e )
227
227
  if e.class == Element
228
228
  rendered_obj_content << e.send( render_ƒ )
229
- elsif e.class == Partial
230
- rendered_obj_content << e.render( render_ƒ )
231
229
  else
232
- rendered_obj_content << e.value.to_s
230
+ data = render_thing e, render_ƒ, engine
231
+ ( rendered_obj_content << data ) if data # e.render( render_ƒ )
233
232
  end
234
233
  end
235
234
  else
@@ -238,7 +237,16 @@ module Gloo
238
237
 
239
238
  return rendered_obj_content
240
239
  end
241
-
240
+
241
+ def self.render_thing e, render_ƒ, engine
242
+ begin
243
+ return e.render( render_ƒ )
244
+ rescue => e
245
+ engine.err e.message
246
+ return ''
247
+ end
248
+ end
249
+
242
250
  end
243
251
  end
244
252
  end
@@ -17,6 +17,7 @@ module Gloo
17
17
 
18
18
  # Parameters used during render.
19
19
  PARAMS = 'params'.freeze
20
+ ID = 'id'.freeze
20
21
 
21
22
  # Content
22
23
  HEAD = 'head'.freeze
@@ -112,6 +113,19 @@ module Gloo
112
113
  params_can = find_child PARAMS
113
114
  return nil unless params_can
114
115
 
116
+ if @request
117
+ url_params = @request.query_params
118
+ url_params.each do |k,v|
119
+ o = params_can.find_child k
120
+ o.set_value( v ) if o
121
+ end
122
+
123
+ @request.body_params.each do |k,v|
124
+ o = params_can.find_child k
125
+ o.set_value( v ) if o
126
+ end
127
+ end
128
+
115
129
  h = {}
116
130
  params_can.children.each do |o|
117
131
  h[ o.name ] = o.value
@@ -182,6 +196,8 @@ module Gloo
182
196
  o = find_child ON_RENDER
183
197
  return unless o
184
198
 
199
+ @engine.log.debug "running on_render for page"
200
+
185
201
  Gloo::Exec::Dispatch.message( @engine, 'run', o )
186
202
  end
187
203
 
@@ -192,6 +208,8 @@ module Gloo
192
208
  o = find_child ON_RENDERED
193
209
  return unless o
194
210
 
211
+ @engine.log.debug "running on_rendered for page"
212
+
195
213
  Gloo::Exec::Dispatch.message( @engine, 'run', o )
196
214
  end
197
215
 
@@ -281,13 +299,36 @@ module Gloo
281
299
  return @engine.running_app.obj.redirect
282
300
  end
283
301
 
302
+ #
303
+ # Set the ID parameter if there is one.
304
+ #
305
+ def set_id
306
+ return unless @request.id
307
+ @engine.log.info "Setting ID: #{@request.id}"
308
+
309
+ params_can = find_child PARAMS
310
+ return nil unless params_can
311
+
312
+ id_obj = params_can.find_child( ID )
313
+ return unless id_obj
314
+
315
+ id_obj.set_value( @request.id )
316
+ end
317
+
284
318
  #
285
319
  # Render the page.
320
+ # If this is being called from the web server,
321
+ # the request will be passed in and will include
322
+ # request context such as params.
286
323
  #
287
- def render
324
+ def render request=nil
325
+ @request = request
326
+ set_id if @request
327
+
288
328
  run_on_render
289
329
  return nil if redirect_set?
290
330
 
331
+ # Set Params before running on render
291
332
  params = params_hash
292
333
 
293
334
  if is_html?
@@ -300,8 +341,9 @@ module Gloo
300
341
  @engine.log.error "Unknown content type: #{content_type}"
301
342
  return nil
302
343
  end
303
-
344
+
304
345
  run_on_rendered
346
+ @request = nil
305
347
  return nil if redirect_set?
306
348
 
307
349
  return contents
@@ -161,8 +161,13 @@ module Gloo
161
161
  run_on_render
162
162
 
163
163
  part_content = ''
164
- content.children.each do |e|
165
- part_content << e.send( render_ƒ )
164
+ data = content
165
+ if data.children.empty?
166
+ part_content = data.value
167
+ else
168
+ data.children.each do |e|
169
+ part_content << e.send( render_ƒ )
170
+ end
166
171
  end
167
172
 
168
173
  # part_content = Page.render_params part_content, params_hash