gloo 2.5.0 → 3.0.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/README.md +8 -27
- data/bin/run +10 -0
- data/gloo.gemspec +1 -0
- data/lib/VERSION +1 -1
- data/lib/VERSION_NOTES +15 -0
- data/lib/gloo/app/args.rb +36 -1
- data/lib/gloo/app/engine.rb +9 -1
- 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,18 @@
|
|
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
|
+
|
1
16
|
2.5.0 - 2023.06.28
|
2
17
|
- Catch run time exceptions and show in error log.
|
3
18
|
|
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,7 +190,9 @@ 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
|
@@ -211,6 +216,9 @@ module Gloo
|
|
211
216
|
# Do any clean up and quit.
|
212
217
|
#
|
213
218
|
def quit
|
219
|
+
@log.debug 'triggering on_quit events...'
|
220
|
+
@event_manager.on_quit
|
221
|
+
|
214
222
|
@log.debug 'quitting...'
|
215
223
|
end
|
216
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
|