gloo 2.4.3 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +8 -27
- data/bin/run +10 -0
- data/gloo.gemspec +1 -0
- data/lib/VERSION +1 -1
- data/lib/VERSION_NOTES +19 -0
- data/lib/gloo/app/args.rb +36 -1
- data/lib/gloo/app/engine.rb +14 -2
- data/lib/gloo/app/log.rb +48 -7
- data/lib/gloo/app/mode.rb +1 -0
- data/lib/gloo/app/settings.rb +13 -0
- data/lib/gloo/core/event_manager.rb +32 -0
- data/lib/gloo/core/obj.rb +0 -2
- data/lib/gloo/objs/cli/menu.rb +101 -9
- data/lib/gloo/objs/data/pg.rb +208 -0
- data/lib/gloo/objs/web/json.rb +67 -10
- data/lib/gloo/persist/persist_man.rb +15 -0
- data/lib/gloo/verbs/log.rb +69 -0
- data/lib/gloo/verbs/unload.rb +1 -2
- metadata +19 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 85917a19626e03193559e9e779a77f9a50e42083729824d27f8651d629af9b8d
|
4
|
+
data.tar.gz: 5d1cdc8947f63a756dcaee08c59751a104c6c202771a7de6edbb5fcfbebb9fcb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 991ab79d39d1c9606f4a72b18ac99cc6ab32b6924f7af9e17bd707ad6d32970d7c6f0a994b33152905cfe460c9035fbd19c10a0b522e35ffecc38625a663ca50
|
7
|
+
data.tar.gz: 725741071414ff857311f243e930bb393a3c04e46017bb154c500e96831bead87d7ee5f750ed830291d0657a9f1a5a4e877879fa3705adea28bc93f549e2b4db
|
data/README.md
CHANGED
@@ -1,43 +1,24 @@
|
|
1
1
|
# Gloo
|
2
2
|
|
3
|
-
|
3
|
+
Gloo is a scripting language built on ruby.
|
4
4
|
|
5
|
-
TODO: Delete this and the text above, and describe your gem
|
6
5
|
|
7
6
|
## Installation
|
8
7
|
|
9
|
-
|
10
|
-
|
11
|
-
```ruby
|
12
|
-
gem 'gloo'
|
13
|
-
```
|
14
|
-
|
15
|
-
And then execute:
|
16
|
-
|
17
|
-
$ bundle
|
18
|
-
|
19
|
-
Or install it yourself as:
|
8
|
+
Install gloo like this:
|
20
9
|
|
21
10
|
$ gem install gloo
|
22
11
|
|
23
|
-
## Usage
|
24
12
|
|
25
|
-
|
26
|
-
|
27
|
-
## Development
|
28
|
-
|
29
|
-
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
30
|
-
|
31
|
-
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
13
|
+
## Usage
|
32
14
|
|
33
|
-
|
15
|
+
Run gloo:
|
34
16
|
|
35
|
-
|
17
|
+
$ gloo
|
36
18
|
|
37
|
-
## License
|
38
19
|
|
39
|
-
|
20
|
+
## Documentation
|
40
21
|
|
41
|
-
|
22
|
+
See documentation here:
|
42
23
|
|
43
|
-
|
24
|
+
https://gloo.ecrane.us/doc
|
data/bin/run
ADDED
data/gloo.gemspec
CHANGED
data/lib/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
3.0.0
|
data/lib/VERSION_NOTES
CHANGED
@@ -1,3 +1,22 @@
|
|
1
|
+
3.0.0 - 2023.12.27
|
2
|
+
- Adds events: on_quit, on_save, on_unload, on_reload
|
3
|
+
- More robust JSON object
|
4
|
+
- Adds Postgres connectivity
|
5
|
+
- Adds log verb and error log file
|
6
|
+
- More options in gloo CLI menus
|
7
|
+
- q! - quit app (and gloo)
|
8
|
+
- update so a quit cmd from gloo script works in menu
|
9
|
+
- show breadcrumb of menu hierarchy
|
10
|
+
- : cmd - use colon or some other symbol to run a gloo command from a menu
|
11
|
+
- Maybe : with no command to drop out of menus to gloo?
|
12
|
+
- qq - Quit to top menu
|
13
|
+
- Option to run in --app mode
|
14
|
+
|
15
|
+
|
16
|
+
2.5.0 - 2023.06.28
|
17
|
+
- Catch run time exceptions and show in error log.
|
18
|
+
|
19
|
+
|
1
20
|
2.4.3 - 2023.06.27
|
2
21
|
- One more attempt to get URI open to work.
|
3
22
|
|
data/lib/gloo/app/args.rb
CHANGED
@@ -14,7 +14,7 @@ module Gloo
|
|
14
14
|
QUIET = 'quiet'.freeze
|
15
15
|
GLOO_ENV = 'GLOO_ENV'.freeze
|
16
16
|
|
17
|
-
attr_reader :switches, :files
|
17
|
+
attr_reader :switches, :files, :app_path
|
18
18
|
|
19
19
|
#
|
20
20
|
# Create arguments and setup.
|
@@ -23,6 +23,7 @@ module Gloo
|
|
23
23
|
@engine = engine
|
24
24
|
@switches = []
|
25
25
|
@files = []
|
26
|
+
@app_path = nil
|
26
27
|
|
27
28
|
params.each { |o| process_one_arg( o ) }
|
28
29
|
ARGV.each { |o| process_one_arg( o ) }
|
@@ -35,6 +36,34 @@ module Gloo
|
|
35
36
|
return @switches.include?( QUIET )
|
36
37
|
end
|
37
38
|
|
39
|
+
#
|
40
|
+
# Is the app switch set?
|
41
|
+
#
|
42
|
+
def app?
|
43
|
+
@switches.include?( Gloo::App::Mode::APP.to_s )
|
44
|
+
end
|
45
|
+
|
46
|
+
#
|
47
|
+
# Make sure that if we are running in App mode
|
48
|
+
# that the app path has been set and is a valid path.
|
49
|
+
#
|
50
|
+
def verify_app_mode
|
51
|
+
return true unless app?
|
52
|
+
|
53
|
+
if @app_path.nil?
|
54
|
+
@engine.log.error "App Path required to run in App mode."
|
55
|
+
return false
|
56
|
+
end
|
57
|
+
|
58
|
+
unless File.directory? @app_path
|
59
|
+
@engine.log.error "'#{@app_path}' is not a valid directory."
|
60
|
+
return false
|
61
|
+
end
|
62
|
+
|
63
|
+
@engine.log.info "App root directory: '#{@app_path}'."
|
64
|
+
return true
|
65
|
+
end
|
66
|
+
|
38
67
|
#
|
39
68
|
# Is the version switch set?
|
40
69
|
#
|
@@ -72,6 +101,8 @@ module Gloo
|
|
72
101
|
def detect_mode
|
73
102
|
mode = if ENV[ GLOO_ENV ] == Gloo::App::Mode::TEST.to_s
|
74
103
|
Mode::TEST
|
104
|
+
elsif app?
|
105
|
+
Mode::APP
|
75
106
|
elsif version?
|
76
107
|
Mode::VERSION
|
77
108
|
elsif help?
|
@@ -85,6 +116,8 @@ module Gloo
|
|
85
116
|
else
|
86
117
|
Mode.default_mode
|
87
118
|
end
|
119
|
+
|
120
|
+
mode = Mode::CLI unless verify_app_mode
|
88
121
|
@engine.log.debug "running in #{mode} mode"
|
89
122
|
|
90
123
|
return mode
|
@@ -102,6 +135,8 @@ module Gloo
|
|
102
135
|
def process_one_arg( arg )
|
103
136
|
if arg.start_with? '--'
|
104
137
|
switches << arg[ 2..-1 ]
|
138
|
+
elsif app? && ( @app_path.nil? )
|
139
|
+
@app_path = arg
|
105
140
|
else
|
106
141
|
files << arg
|
107
142
|
end
|
data/lib/gloo/app/engine.rb
CHANGED
@@ -110,6 +110,9 @@ module Gloo
|
|
110
110
|
run_files
|
111
111
|
elsif @mode == Mode::EMBED
|
112
112
|
run_keep_alive
|
113
|
+
elsif @mode == Mode::APP
|
114
|
+
@settings.override_project_path @args.app_path
|
115
|
+
run
|
113
116
|
else
|
114
117
|
run
|
115
118
|
end
|
@@ -187,13 +190,19 @@ module Gloo
|
|
187
190
|
#
|
188
191
|
# Process the command.
|
189
192
|
#
|
190
|
-
def process_cmd
|
193
|
+
def process_cmd cmd=nil
|
194
|
+
@last_cmd = cmd if cmd
|
195
|
+
|
191
196
|
if last_cmd_blank?
|
192
197
|
@platform.clear_screen
|
193
198
|
return
|
194
199
|
end
|
195
200
|
|
196
|
-
|
201
|
+
begin
|
202
|
+
@parser.run @last_cmd
|
203
|
+
rescue => e
|
204
|
+
err e.message
|
205
|
+
end
|
197
206
|
end
|
198
207
|
|
199
208
|
#
|
@@ -207,6 +216,9 @@ module Gloo
|
|
207
216
|
# Do any clean up and quit.
|
208
217
|
#
|
209
218
|
def quit
|
219
|
+
@log.debug 'triggering on_quit events...'
|
220
|
+
@event_manager.on_quit
|
221
|
+
|
210
222
|
@log.debug 'quitting...'
|
211
223
|
end
|
212
224
|
|
data/lib/gloo/app/log.rb
CHANGED
@@ -11,6 +11,15 @@ module Gloo
|
|
11
11
|
module App
|
12
12
|
class Log
|
13
13
|
|
14
|
+
DEBUG = 'debug'.freeze
|
15
|
+
INFO = 'info'.freeze
|
16
|
+
WARN = 'warn'.freeze
|
17
|
+
ERROR = 'error'.freeze
|
18
|
+
LEVELS = [ DEBUG, INFO, WARN, ERROR ].freeze
|
19
|
+
|
20
|
+
LOG_FILE = 'gloo.log'.freeze
|
21
|
+
ERROR_FILE = 'error.log'.freeze
|
22
|
+
|
14
23
|
attr_accessor :quiet
|
15
24
|
attr_reader :logger
|
16
25
|
|
@@ -28,7 +37,7 @@ module Gloo
|
|
28
37
|
@quite = quiet
|
29
38
|
@debug = engine.settings.debug
|
30
39
|
|
31
|
-
|
40
|
+
create_loggers
|
32
41
|
|
33
42
|
debug 'log intialized...'
|
34
43
|
end
|
@@ -36,10 +45,26 @@ module Gloo
|
|
36
45
|
#
|
37
46
|
# Create the default [file] logger.
|
38
47
|
#
|
39
|
-
def
|
40
|
-
f = File.join( @engine.settings.log_path,
|
48
|
+
def create_loggers
|
49
|
+
f = File.join( @engine.settings.log_path, LOG_FILE )
|
41
50
|
@logger = Logger.new( f )
|
42
51
|
@logger.level = Logger::DEBUG
|
52
|
+
|
53
|
+
err = File.join( @engine.settings.log_path, ERROR_FILE )
|
54
|
+
@error = Logger.new( err )
|
55
|
+
@error.level = Logger::WARN
|
56
|
+
end
|
57
|
+
|
58
|
+
# ---------------------------------------------------------------------
|
59
|
+
# Static Helpers
|
60
|
+
# ---------------------------------------------------------------------
|
61
|
+
|
62
|
+
#
|
63
|
+
# Does the given str represent a logging level?
|
64
|
+
#
|
65
|
+
def self.is_level? str
|
66
|
+
return false unless str.is_a? String
|
67
|
+
return LEVELS.include? str.strip.downcase
|
43
68
|
end
|
44
69
|
|
45
70
|
# ---------------------------------------------------------------------
|
@@ -57,6 +82,21 @@ module Gloo
|
|
57
82
|
# Logging functions
|
58
83
|
# ---------------------------------------------------------------------
|
59
84
|
|
85
|
+
#
|
86
|
+
# Write to the specified level.
|
87
|
+
#
|
88
|
+
def write( msg, level )
|
89
|
+
if level == DEBUG
|
90
|
+
debug msg
|
91
|
+
elsif level == INFO
|
92
|
+
info msg
|
93
|
+
elsif level == WARN
|
94
|
+
warn msg
|
95
|
+
elsif level == ERROR
|
96
|
+
error msg
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
60
100
|
#
|
61
101
|
# Write a debug message to the log.
|
62
102
|
#
|
@@ -66,7 +106,6 @@ module Gloo
|
|
66
106
|
@logger.debug msg
|
67
107
|
end
|
68
108
|
|
69
|
-
|
70
109
|
#
|
71
110
|
# Write an information message to the log.
|
72
111
|
# Also write to the console unless quiet.
|
@@ -82,6 +121,7 @@ module Gloo
|
|
82
121
|
#
|
83
122
|
def warn( msg )
|
84
123
|
@logger.warn msg
|
124
|
+
@error.warn msg
|
85
125
|
puts msg.yellow unless @quiet
|
86
126
|
end
|
87
127
|
|
@@ -93,9 +133,10 @@ module Gloo
|
|
93
133
|
def error( msg, ex = nil, engine = nil )
|
94
134
|
engine&.heap&.error&.set_to msg
|
95
135
|
@logger.error msg
|
136
|
+
@error.error msg
|
96
137
|
if ex
|
97
|
-
@
|
98
|
-
@
|
138
|
+
@error.error ex.message
|
139
|
+
@error.error ex.backtrace
|
99
140
|
puts msg.red unless @quiet
|
100
141
|
puts ex.message.red unless @quiet
|
101
142
|
puts ex.backtrace unless @quiet
|
@@ -120,7 +161,7 @@ module Gloo
|
|
120
161
|
# Restore the logger after deserialization.
|
121
162
|
#
|
122
163
|
def restore_after_deserialization
|
123
|
-
|
164
|
+
create_loggers
|
124
165
|
end
|
125
166
|
|
126
167
|
end
|
data/lib/gloo/app/mode.rb
CHANGED
data/lib/gloo/app/settings.rb
CHANGED
@@ -84,6 +84,19 @@ module Gloo
|
|
84
84
|
return 7
|
85
85
|
end
|
86
86
|
|
87
|
+
# ---------------------------------------------------------------------
|
88
|
+
# Functions
|
89
|
+
# ---------------------------------------------------------------------
|
90
|
+
|
91
|
+
#
|
92
|
+
# Running in app mode, so overriding the root project path.
|
93
|
+
#
|
94
|
+
def override_project_path path
|
95
|
+
@engine.log.debug "Root project path is #{path}"
|
96
|
+
|
97
|
+
@project_path = path
|
98
|
+
end
|
99
|
+
|
87
100
|
# ---------------------------------------------------------------------
|
88
101
|
# Private
|
89
102
|
# ---------------------------------------------------------------------
|
@@ -40,6 +40,38 @@ module Gloo
|
|
40
40
|
arr.each { |o| Gloo::Exec::Dispatch.message( @engine, 'run', o ) }
|
41
41
|
end
|
42
42
|
|
43
|
+
#
|
44
|
+
# Run on_reload scripts in the object that will be reloaded.
|
45
|
+
#
|
46
|
+
def on_reload( obj )
|
47
|
+
return unless obj
|
48
|
+
|
49
|
+
@engine.log.debug 'on_reload event'
|
50
|
+
arr = Gloo::Core::ObjFinder.by_name( @engine, 'on_reload', obj )
|
51
|
+
arr.each { |o| Gloo::Exec::Dispatch.message( @engine, 'run', o ) }
|
52
|
+
end
|
53
|
+
|
54
|
+
#
|
55
|
+
# Run on_save scripts in the object that is being saved.
|
56
|
+
#
|
57
|
+
def on_save( obj )
|
58
|
+
return unless obj
|
59
|
+
|
60
|
+
@engine.log.debug 'on_save event'
|
61
|
+
arr = Gloo::Core::ObjFinder.by_name( @engine, 'on_save', obj )
|
62
|
+
arr.each { |o| Gloo::Exec::Dispatch.message( @engine, 'run', o ) }
|
63
|
+
end
|
64
|
+
|
65
|
+
#
|
66
|
+
# Run on_quit scripts in any open objets.
|
67
|
+
# If no obj is given the script will be run in root.
|
68
|
+
#
|
69
|
+
def on_quit
|
70
|
+
@engine.log.debug 'on_quit event'
|
71
|
+
arr = Gloo::Core::ObjFinder.by_name( @engine, 'on_quit' )
|
72
|
+
arr.each { |o| Gloo::Exec::Dispatch.message( @engine, 'run', o ) }
|
73
|
+
end
|
74
|
+
|
43
75
|
end
|
44
76
|
end
|
45
77
|
end
|
data/lib/gloo/core/obj.rb
CHANGED
data/lib/gloo/objs/cli/menu.rb
CHANGED
@@ -23,6 +23,8 @@ module Gloo
|
|
23
23
|
TITLE_COLOR = 'bright_cyan'.freeze
|
24
24
|
QUIT_ITEM_NAME = 'q'.freeze
|
25
25
|
|
26
|
+
@@menu_stack = []
|
27
|
+
|
26
28
|
#
|
27
29
|
# The name of the object type.
|
28
30
|
#
|
@@ -53,6 +55,8 @@ module Gloo
|
|
53
55
|
# Should we keep looping or should we stop?
|
54
56
|
#
|
55
57
|
def loop?
|
58
|
+
return false unless @engine.running
|
59
|
+
|
56
60
|
o = find_child LOOP
|
57
61
|
return false unless o
|
58
62
|
|
@@ -106,6 +110,14 @@ module Gloo
|
|
106
110
|
return o ? true : false
|
107
111
|
end
|
108
112
|
|
113
|
+
#
|
114
|
+
# Get the Menu's Title.
|
115
|
+
#
|
116
|
+
def title
|
117
|
+
obj = find_child TITLE
|
118
|
+
return obj.value
|
119
|
+
end
|
120
|
+
|
109
121
|
# ---------------------------------------------------------------------
|
110
122
|
# Children
|
111
123
|
# ---------------------------------------------------------------------
|
@@ -132,6 +144,69 @@ module Gloo
|
|
132
144
|
fac.create_script DEFAULT, '', self
|
133
145
|
end
|
134
146
|
|
147
|
+
# ---------------------------------------------------------------------
|
148
|
+
# Menu Stack
|
149
|
+
# ---------------------------------------------------------------------
|
150
|
+
|
151
|
+
#
|
152
|
+
# Show the bread-crumbs for the menu stack.
|
153
|
+
#
|
154
|
+
def show_menu_stack
|
155
|
+
if @@menu_stack.count < 2
|
156
|
+
puts '...'
|
157
|
+
else
|
158
|
+
msg = ''
|
159
|
+
@@menu_stack[0..-2].each do |menu|
|
160
|
+
msg << ' | ' unless msg.blank?
|
161
|
+
msg << menu.title
|
162
|
+
end
|
163
|
+
msg << ' | ... '
|
164
|
+
puts msg
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
#
|
169
|
+
# Add a menu to the stack.
|
170
|
+
#
|
171
|
+
def push_menu obj
|
172
|
+
@@menu_stack << obj
|
173
|
+
end
|
174
|
+
|
175
|
+
#
|
176
|
+
# Pop a menu from the stack.
|
177
|
+
# If the last item isn't the given menu,
|
178
|
+
# it won't be popped.
|
179
|
+
#
|
180
|
+
def pop_menu menu
|
181
|
+
if @@menu_stack[-1] == menu
|
182
|
+
@@menu_stack.pop
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
#
|
187
|
+
# Quit all menus and drop into gloo.
|
188
|
+
#
|
189
|
+
def pop_to_top_level_menu
|
190
|
+
@engine.log.debug 'Quitting to top level menu'
|
191
|
+
while @@menu_stack.count > 1
|
192
|
+
menu = @@menu_stack.pop
|
193
|
+
o = menu.find_child LOOP
|
194
|
+
o.set_value( false ) if o
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
#
|
199
|
+
# Quit all menus and drop into gloo.
|
200
|
+
#
|
201
|
+
def quit_all_menus
|
202
|
+
@engine.log.debug 'Dropping into Gloo'
|
203
|
+
@@menu_stack.each do |menu|
|
204
|
+
o = menu.find_child LOOP
|
205
|
+
o.set_value( false ) if o
|
206
|
+
end
|
207
|
+
@engine.loop
|
208
|
+
end
|
209
|
+
|
135
210
|
# ---------------------------------------------------------------------
|
136
211
|
# Messages
|
137
212
|
# ---------------------------------------------------------------------
|
@@ -148,6 +223,7 @@ module Gloo
|
|
148
223
|
#
|
149
224
|
def msg_run
|
150
225
|
lazy_add_children
|
226
|
+
push_menu self
|
151
227
|
run_default
|
152
228
|
loop do
|
153
229
|
begin_menu
|
@@ -162,6 +238,7 @@ module Gloo
|
|
162
238
|
cmd ? run_command( cmd ) : run_default
|
163
239
|
break unless loop?
|
164
240
|
end
|
241
|
+
pop_menu self
|
165
242
|
end
|
166
243
|
|
167
244
|
# ---------------------------------------------------------------------
|
@@ -238,9 +315,8 @@ module Gloo
|
|
238
315
|
# There is a title, so show it.
|
239
316
|
#
|
240
317
|
def run_default_title
|
241
|
-
obj = find_child TITLE
|
242
|
-
title = obj.value
|
243
318
|
@engine.platform&.clear_screen
|
319
|
+
show_menu_stack
|
244
320
|
Banner.show_banner( title, TITLE_STYLE, TITLE_COLOR )
|
245
321
|
end
|
246
322
|
|
@@ -248,22 +324,38 @@ module Gloo
|
|
248
324
|
# Run the selected command.
|
249
325
|
#
|
250
326
|
def run_command( cmd )
|
327
|
+
@engine.log.debug "Menu Command: #{cmd}"
|
251
328
|
obj = find_cmd cmd
|
252
329
|
|
253
|
-
|
330
|
+
if obj
|
331
|
+
script = obj.do_script
|
332
|
+
return unless script
|
333
|
+
|
334
|
+
s = Gloo::Exec::Script.new( @engine, script )
|
335
|
+
s.run
|
336
|
+
else
|
254
337
|
if cmd == '?'
|
255
338
|
show_options
|
339
|
+
elsif cmd == 'q!'
|
340
|
+
@engine.log.info 'Quitting Gloo'
|
341
|
+
@engine.stop_running
|
342
|
+
elsif cmd == 'qq'
|
343
|
+
pop_to_top_level_menu
|
344
|
+
elsif cmd.starts_with? ':'
|
345
|
+
gloo_cmd = cmd[1..-1].strip
|
346
|
+
if gloo_cmd.blank?
|
347
|
+
quit_all_menus
|
348
|
+
else
|
349
|
+
@engine.log.debug "Running Gloo command: #{gloo_cmd}"
|
350
|
+
@engine.process_cmd gloo_cmd
|
351
|
+
end
|
256
352
|
else
|
257
|
-
|
353
|
+
msg = "#{cmd} is not a valid option"
|
354
|
+
@engine.log.warn msg
|
258
355
|
end
|
259
356
|
return
|
260
357
|
end
|
261
358
|
|
262
|
-
script = obj.do_script
|
263
|
-
return unless script
|
264
|
-
|
265
|
-
s = Gloo::Exec::Script.new( @engine, script )
|
266
|
-
s.run
|
267
359
|
end
|
268
360
|
|
269
361
|
end
|
@@ -0,0 +1,208 @@
|
|
1
|
+
# Author:: Eric Crane (mailto:eric.crane@mac.com)
|
2
|
+
# Copyright:: Copyright (c) 2023 Eric Crane. All rights reserved.
|
3
|
+
#
|
4
|
+
# A Postgres database connection.
|
5
|
+
#
|
6
|
+
# https://rubygems.org/gems/pg/versions/0.18.4
|
7
|
+
# https://github.com/ged/ruby-pg
|
8
|
+
#
|
9
|
+
require 'pg'
|
10
|
+
|
11
|
+
module Gloo
|
12
|
+
module Objs
|
13
|
+
class Pg < Gloo::Core::Obj
|
14
|
+
|
15
|
+
KEYWORD = 'postgres'.freeze
|
16
|
+
KEYWORD_SHORT = 'pg'.freeze
|
17
|
+
|
18
|
+
HOST = 'host'.freeze
|
19
|
+
DB = 'database'.freeze
|
20
|
+
USER = 'username'.freeze
|
21
|
+
PASSWD = 'password'.freeze
|
22
|
+
|
23
|
+
#
|
24
|
+
# The name of the object type.
|
25
|
+
#
|
26
|
+
def self.typename
|
27
|
+
return KEYWORD
|
28
|
+
end
|
29
|
+
|
30
|
+
#
|
31
|
+
# The short name of the object type.
|
32
|
+
#
|
33
|
+
def self.short_typename
|
34
|
+
return KEYWORD_SHORT
|
35
|
+
end
|
36
|
+
|
37
|
+
# ---------------------------------------------------------------------
|
38
|
+
# Children
|
39
|
+
# ---------------------------------------------------------------------
|
40
|
+
|
41
|
+
#
|
42
|
+
# Does this object have children to add when an object
|
43
|
+
# is created in interactive mode?
|
44
|
+
# This does not apply during obj load, etc.
|
45
|
+
#
|
46
|
+
def add_children_on_create?
|
47
|
+
return true
|
48
|
+
end
|
49
|
+
|
50
|
+
#
|
51
|
+
# Add children to this object.
|
52
|
+
# This is used by containers to add children needed
|
53
|
+
# for default configurations.
|
54
|
+
#
|
55
|
+
def add_default_children
|
56
|
+
fac = @engine.factory
|
57
|
+
fac.create_string HOST, nil, self
|
58
|
+
fac.create_string DB, nil, self
|
59
|
+
fac.create_string USER, nil, self
|
60
|
+
fac.create_string PASSWD, nil, self
|
61
|
+
end
|
62
|
+
|
63
|
+
# ---------------------------------------------------------------------
|
64
|
+
# Messages
|
65
|
+
# ---------------------------------------------------------------------
|
66
|
+
|
67
|
+
#
|
68
|
+
# Get a list of message names that this object receives.
|
69
|
+
#
|
70
|
+
def self.messages
|
71
|
+
return super + [ 'verify' ]
|
72
|
+
end
|
73
|
+
|
74
|
+
#
|
75
|
+
# SSH to the host and execute the command, then update result.
|
76
|
+
#
|
77
|
+
def msg_verify
|
78
|
+
return unless connects?
|
79
|
+
|
80
|
+
@engine.heap.it.set_to true
|
81
|
+
end
|
82
|
+
|
83
|
+
# ---------------------------------------------------------------------
|
84
|
+
# DB functions (all database connections)
|
85
|
+
# ---------------------------------------------------------------------
|
86
|
+
|
87
|
+
#
|
88
|
+
# Open a connection and execute the SQL statement.
|
89
|
+
# Return the resulting data.
|
90
|
+
#
|
91
|
+
def query( sql, params = nil )
|
92
|
+
heads = []
|
93
|
+
data = []
|
94
|
+
client = pg_conn
|
95
|
+
|
96
|
+
if params
|
97
|
+
param_arr = []
|
98
|
+
params.each do |p|
|
99
|
+
param_arr << { :value => p, :type => 0, :format => 0 }
|
100
|
+
end
|
101
|
+
rs = client.exec_params( sql, params )
|
102
|
+
else
|
103
|
+
rs = client.exec( sql )
|
104
|
+
end
|
105
|
+
|
106
|
+
if rs && ( rs.count > 0 )
|
107
|
+
rs[0].each do |name, val|
|
108
|
+
heads << name
|
109
|
+
end
|
110
|
+
rs.each_with_index do |row, index|
|
111
|
+
arr = []
|
112
|
+
row.each do |name, val|
|
113
|
+
arr << val
|
114
|
+
end
|
115
|
+
data << arr
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
return [ heads, data ]
|
120
|
+
end
|
121
|
+
|
122
|
+
# ---------------------------------------------------------------------
|
123
|
+
# Private functions
|
124
|
+
# ---------------------------------------------------------------------
|
125
|
+
|
126
|
+
private
|
127
|
+
|
128
|
+
#
|
129
|
+
# Get the host from the child object.
|
130
|
+
# Returns nil if there is none.
|
131
|
+
#
|
132
|
+
def host_value
|
133
|
+
o = find_child HOST
|
134
|
+
return nil unless o
|
135
|
+
|
136
|
+
o = Gloo::Objs::Alias.resolve_alias( @engine, o )
|
137
|
+
return o.value
|
138
|
+
end
|
139
|
+
|
140
|
+
#
|
141
|
+
# Get the Database name from the child object.
|
142
|
+
# Returns nil if there is none.
|
143
|
+
#
|
144
|
+
def db_value
|
145
|
+
o = find_child DB
|
146
|
+
return nil unless o
|
147
|
+
|
148
|
+
o = Gloo::Objs::Alias.resolve_alias( @engine, o )
|
149
|
+
return o.value
|
150
|
+
end
|
151
|
+
|
152
|
+
#
|
153
|
+
# Get the Username from the child object.
|
154
|
+
# Returns nil if there is none.
|
155
|
+
#
|
156
|
+
def user_value
|
157
|
+
o = find_child USER
|
158
|
+
return nil unless o
|
159
|
+
|
160
|
+
o = Gloo::Objs::Alias.resolve_alias( @engine, o )
|
161
|
+
return o.value
|
162
|
+
end
|
163
|
+
|
164
|
+
#
|
165
|
+
# Get the Password name from the child object.
|
166
|
+
# Returns nil if there is none.
|
167
|
+
#
|
168
|
+
def passwd_value
|
169
|
+
o = find_child PASSWD
|
170
|
+
return nil unless o
|
171
|
+
|
172
|
+
o = Gloo::Objs::Alias.resolve_alias( @engine, o )
|
173
|
+
return o.value
|
174
|
+
end
|
175
|
+
|
176
|
+
#
|
177
|
+
# Try the connection and make sure it works.
|
178
|
+
# Returns true if we can establish a connection.
|
179
|
+
#
|
180
|
+
def connects?
|
181
|
+
begin
|
182
|
+
result = pg_conn.exec( "SELECT NOW()" )
|
183
|
+
rescue => e
|
184
|
+
@engine.err e.message
|
185
|
+
@engine.heap.it.set_to false
|
186
|
+
return false
|
187
|
+
end
|
188
|
+
return true
|
189
|
+
end
|
190
|
+
|
191
|
+
#
|
192
|
+
# Get the PG connection.
|
193
|
+
#
|
194
|
+
def pg_conn
|
195
|
+
if host_value
|
196
|
+
conn = PG.connect(
|
197
|
+
host_value, 5432, '', '',
|
198
|
+
db_value,
|
199
|
+
user_value,
|
200
|
+
passwd_value )
|
201
|
+
else
|
202
|
+
conn = PG.connect( dbname: db_value )
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
data/lib/gloo/objs/web/json.rb
CHANGED
@@ -56,15 +56,15 @@ module Gloo
|
|
56
56
|
# Get a list of message names that this object receives.
|
57
57
|
#
|
58
58
|
def self.messages
|
59
|
-
return super + %w[get parse pretty]
|
59
|
+
return super + %w[get set parse pretty]
|
60
60
|
end
|
61
61
|
|
62
62
|
#
|
63
63
|
# Make the JSON pretty.
|
64
64
|
#
|
65
65
|
def msg_pretty
|
66
|
-
|
67
|
-
|
66
|
+
json = JSON.parse( self.value )
|
67
|
+
pretty = JSON.pretty_generate( json )
|
68
68
|
set_value pretty
|
69
69
|
end
|
70
70
|
|
@@ -79,12 +79,37 @@ module Gloo
|
|
79
79
|
end
|
80
80
|
return unless data
|
81
81
|
|
82
|
-
|
83
|
-
field = h[ data ]
|
82
|
+
field = Gloo::Objs::Json.get_value_in_json self.value, data
|
84
83
|
@engine.heap.it.set_to field
|
85
84
|
return field
|
86
85
|
end
|
87
86
|
|
87
|
+
#
|
88
|
+
# Convert the target object to JSON and set the value of
|
89
|
+
# this JSON to that value.
|
90
|
+
#
|
91
|
+
def msg_set
|
92
|
+
if @params&.token_count&.positive?
|
93
|
+
pn = Gloo::Core::Pn.new( @engine, @params.tokens.first )
|
94
|
+
unless pn&.exists?
|
95
|
+
@engine.err 'Source path for objects does not exist'
|
96
|
+
return
|
97
|
+
end
|
98
|
+
else
|
99
|
+
@engine.err 'Source path for objects is required'
|
100
|
+
return
|
101
|
+
end
|
102
|
+
parent = pn.resolve
|
103
|
+
|
104
|
+
h = convert_obj_to_hash( parent )
|
105
|
+
json = JSON.parse( h.to_json )
|
106
|
+
json = JSON.pretty_generate( json )
|
107
|
+
|
108
|
+
set_value json
|
109
|
+
@engine.heap.it.set_to json
|
110
|
+
return json
|
111
|
+
end
|
112
|
+
|
88
113
|
#
|
89
114
|
# Parse the JSON data and put it in objects.
|
90
115
|
# The additional parameter is the path to the destination
|
@@ -104,19 +129,40 @@ module Gloo
|
|
104
129
|
parent = pn.resolve
|
105
130
|
|
106
131
|
json = JSON.parse( self.value )
|
107
|
-
self.
|
132
|
+
self.handle_json_to_obj( json, parent )
|
133
|
+
end
|
134
|
+
|
135
|
+
# ---------------------------------------------------------------------
|
136
|
+
# JSON Helper functions
|
137
|
+
# ---------------------------------------------------------------------
|
138
|
+
|
139
|
+
#
|
140
|
+
# Convert the object to a hash of name and values.
|
141
|
+
#
|
142
|
+
def convert_obj_to_hash( obj )
|
143
|
+
h = {}
|
144
|
+
|
145
|
+
if obj.child_count > 0
|
146
|
+
obj.children.each do |child|
|
147
|
+
h = h.merge( convert_obj_to_hash( child ) )
|
148
|
+
end
|
149
|
+
else
|
150
|
+
h[ obj.name ] = obj.value
|
151
|
+
end
|
152
|
+
|
153
|
+
return h
|
108
154
|
end
|
109
155
|
|
110
156
|
#
|
111
157
|
# Handle JSON, creating objects and setting values.
|
112
158
|
# Note that this is a recursive function.
|
113
159
|
#
|
114
|
-
def
|
160
|
+
def handle_json_to_obj( json, parent )
|
115
161
|
if json.class == Hash
|
116
162
|
json.each do |k, v|
|
117
|
-
if v.class == Array
|
163
|
+
if ( v.class == Array ) || ( v.class == Hash )
|
118
164
|
o = parent.find_add_child( k, 'can' )
|
119
|
-
|
165
|
+
handle_json_to_obj( v, o )
|
120
166
|
else
|
121
167
|
o = parent.find_add_child( k, 'untyped' )
|
122
168
|
o.set_value v
|
@@ -125,11 +171,22 @@ module Gloo
|
|
125
171
|
elsif json.class == Array
|
126
172
|
json.each_with_index do |o, index|
|
127
173
|
child = parent.find_add_child( index.to_s, 'can' )
|
128
|
-
|
174
|
+
handle_json_to_obj( o, child )
|
129
175
|
end
|
130
176
|
end
|
131
177
|
end
|
132
178
|
|
179
|
+
#
|
180
|
+
# Parse the JSON data and look for the value within it.
|
181
|
+
#
|
182
|
+
def self.get_value_in_json( json, path_to_value )
|
183
|
+
data = JSON.parse( json )
|
184
|
+
path_to_value.split( '.' ).each do |segment|
|
185
|
+
data = data[ segment ]
|
186
|
+
end
|
187
|
+
return data
|
188
|
+
end
|
189
|
+
|
133
190
|
end
|
134
191
|
end
|
135
192
|
end
|
@@ -42,6 +42,9 @@ module Gloo
|
|
42
42
|
ref = Gloo::Core::Pn.new( @engine, name )
|
43
43
|
obj = ref.resolve
|
44
44
|
|
45
|
+
# Send an on_save event
|
46
|
+
@engine.event_manager.on_save obj
|
47
|
+
|
45
48
|
fs = find_file_storage( obj )
|
46
49
|
fs.save
|
47
50
|
end
|
@@ -62,11 +65,21 @@ module Gloo
|
|
62
65
|
end
|
63
66
|
end
|
64
67
|
|
68
|
+
#
|
69
|
+
# Unload all loaded objects.
|
70
|
+
#
|
71
|
+
def unload_all
|
72
|
+
objs = self.maps.map { |fs| fs.obj }
|
73
|
+
objs.each { |o| o.msg_unload }
|
74
|
+
end
|
75
|
+
|
65
76
|
#
|
66
77
|
# The given object is unloading.
|
67
78
|
# Do any necessary clean up here.
|
68
79
|
#
|
69
80
|
def unload( obj )
|
81
|
+
@engine.event_manager.on_unload obj
|
82
|
+
@engine.heap.unload obj
|
70
83
|
@maps.each_with_index do |o, i|
|
71
84
|
if o.obj.pn === obj.pn
|
72
85
|
@maps.delete_at( i )
|
@@ -82,6 +95,7 @@ module Gloo
|
|
82
95
|
return unless @maps
|
83
96
|
|
84
97
|
@maps.each do |fs|
|
98
|
+
@engine.event_manager.on_reload fs.obj
|
85
99
|
@engine.heap.unload fs.obj
|
86
100
|
fs.load
|
87
101
|
end
|
@@ -94,6 +108,7 @@ module Gloo
|
|
94
108
|
fs = find_file_storage( obj )
|
95
109
|
return unless fs
|
96
110
|
|
111
|
+
@engine.event_manager.on_reload obj
|
97
112
|
@engine.heap.unload obj
|
98
113
|
fs.load
|
99
114
|
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# Author:: Eric Crane (mailto:eric.crane@mac.com)
|
2
|
+
# Copyright:: Copyright (c) 2023 Eric Crane. All rights reserved.
|
3
|
+
#
|
4
|
+
# Write to the standard (or error) gloo log.
|
5
|
+
#
|
6
|
+
|
7
|
+
module Gloo
|
8
|
+
module Verbs
|
9
|
+
class Log < Gloo::Core::Verb
|
10
|
+
|
11
|
+
KEYWORD = 'log'.freeze
|
12
|
+
KEYWORD_SHORT = 'log'.freeze
|
13
|
+
|
14
|
+
#
|
15
|
+
# Run the verb.
|
16
|
+
#
|
17
|
+
def run
|
18
|
+
if @tokens.token_count > 1
|
19
|
+
expr = Gloo::Expr::Expression.new( @engine, @tokens.params )
|
20
|
+
result = expr.evaluate
|
21
|
+
level = log_level_specified( result )
|
22
|
+
@engine.log.write result, level
|
23
|
+
@engine.heap.it.set_to result
|
24
|
+
else
|
25
|
+
@engine.log.debug ''
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
#
|
30
|
+
# Get the Verb's keyword.
|
31
|
+
#
|
32
|
+
def self.keyword
|
33
|
+
return KEYWORD
|
34
|
+
end
|
35
|
+
|
36
|
+
#
|
37
|
+
# Get the Verb's keyword shortcut.
|
38
|
+
#
|
39
|
+
def self.keyword_shortcut
|
40
|
+
return KEYWORD_SHORT
|
41
|
+
end
|
42
|
+
|
43
|
+
# ---------------------------------------------------------------------
|
44
|
+
# Private functions
|
45
|
+
# ---------------------------------------------------------------------
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
#
|
50
|
+
# Get the formatted string.
|
51
|
+
#
|
52
|
+
def log_level_specified( str )
|
53
|
+
if @params&.token_count&.positive?
|
54
|
+
if Gloo::App::Log.is_level? @params.tokens.first
|
55
|
+
return @params.tokens.first
|
56
|
+
end
|
57
|
+
|
58
|
+
expr = Gloo::Expr::Expression.new( @engine, @params.tokens )
|
59
|
+
level = expr.evaluate
|
60
|
+
return level if Gloo::App::Log.is_level? level
|
61
|
+
end
|
62
|
+
|
63
|
+
# Lastly, it's just debug
|
64
|
+
return Gloo::App::Log::LEVELS[0]
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/lib/gloo/verbs/unload.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gloo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eric Crane
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-12-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -264,6 +264,20 @@ dependencies:
|
|
264
264
|
- - ">="
|
265
265
|
- !ruby/object:Gem::Version
|
266
266
|
version: 1.1.4
|
267
|
+
- !ruby/object:Gem::Dependency
|
268
|
+
name: pg
|
269
|
+
requirement: !ruby/object:Gem::Requirement
|
270
|
+
requirements:
|
271
|
+
- - "~>"
|
272
|
+
- !ruby/object:Gem::Version
|
273
|
+
version: 1.5.4
|
274
|
+
type: :runtime
|
275
|
+
prerelease: false
|
276
|
+
version_requirements: !ruby/object:Gem::Requirement
|
277
|
+
requirements:
|
278
|
+
- - "~>"
|
279
|
+
- !ruby/object:Gem::Version
|
280
|
+
version: 1.5.4
|
267
281
|
description: A scripting languge to keep it all together.
|
268
282
|
email:
|
269
283
|
- eric.crane@mac.com
|
@@ -285,6 +299,7 @@ files:
|
|
285
299
|
- README.md
|
286
300
|
- Rakefile
|
287
301
|
- bin/console
|
302
|
+
- bin/run
|
288
303
|
- bin/setup
|
289
304
|
- exe/gloo
|
290
305
|
- exe/o
|
@@ -361,6 +376,7 @@ files:
|
|
361
376
|
- lib/gloo/objs/ctrl/repeat.rb
|
362
377
|
- lib/gloo/objs/data/markdown.rb
|
363
378
|
- lib/gloo/objs/data/mysql.rb
|
379
|
+
- lib/gloo/objs/data/pg.rb
|
364
380
|
- lib/gloo/objs/data/query.rb
|
365
381
|
- lib/gloo/objs/data/query_result.rb
|
366
382
|
- lib/gloo/objs/data/sqlite.rb
|
@@ -404,6 +420,7 @@ files:
|
|
404
420
|
- lib/gloo/verbs/if.rb
|
405
421
|
- lib/gloo/verbs/list.rb
|
406
422
|
- lib/gloo/verbs/load.rb
|
423
|
+
- lib/gloo/verbs/log.rb
|
407
424
|
- lib/gloo/verbs/move.rb
|
408
425
|
- lib/gloo/verbs/put.rb
|
409
426
|
- lib/gloo/verbs/quit.rb
|