gloo 2.5.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2a7a9a2289b2ecb245cf9c689bfc693acc1f45c183ab4569e42d290436d88600
4
- data.tar.gz: 2b8ba9e7c0e89c84d6cf129c6dc549c3655af88f0e140bf18a082b0fe94d4392
3
+ metadata.gz: 85917a19626e03193559e9e779a77f9a50e42083729824d27f8651d629af9b8d
4
+ data.tar.gz: 5d1cdc8947f63a756dcaee08c59751a104c6c202771a7de6edbb5fcfbebb9fcb
5
5
  SHA512:
6
- metadata.gz: 9d6364f481d93ae3f4d2434eb3fc13f611ddb567caf071743a17a0e10e5afb3bbf4091d8c7ee4bb37566e9a77bc61dac88f81076706bd20460e3ecdda9f3c445
7
- data.tar.gz: 95bd30fc3ba446f660b178fc756642070deca1d6d035d1576f6faea3788bf568bfbb1e37065191158ab4086d06c29437659e3eeaffaa0338740c1ad1d11d4150
6
+ metadata.gz: 991ab79d39d1c9606f4a72b18ac99cc6ab32b6924f7af9e17bd707ad6d32970d7c6f0a994b33152905cfe460c9035fbd19c10a0b522e35ffecc38625a663ca50
7
+ data.tar.gz: 725741071414ff857311f243e930bb393a3c04e46017bb154c500e96831bead87d7ee5f750ed830291d0657a9f1a5a4e877879fa3705adea28bc93f549e2b4db
data/README.md CHANGED
@@ -1,43 +1,24 @@
1
1
  # Gloo
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/gloo`. To experiment with that code, run `bin/console` for an interactive prompt.
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
- Add this line to your application's Gemfile:
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
- TODO: Write usage instructions here
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
- ## Contributing
15
+ Run gloo:
34
16
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/gloo. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
17
+ $ gloo
36
18
 
37
- ## License
38
19
 
39
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
20
+ ## Documentation
40
21
 
41
- ## Code of Conduct
22
+ See documentation here:
42
23
 
43
- Everyone interacting in the OutlineScript project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/gloo/blob/master/CODE_OF_CONDUCT.md).
24
+ https://gloo.ecrane.us/doc
data/bin/run ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # Run Gloo (this gem) but not as a gem (app), just referencing source code.
4
+ #
5
+ # From the root of the project, run Gloo with:
6
+ #
7
+ # > bin/run
8
+ #
9
+
10
+ ruby ./lib/run.rb
data/gloo.gemspec CHANGED
@@ -41,4 +41,5 @@ Gem::Specification.new do |spec|
41
41
  spec.add_dependency 'mysql2', '~> 0.5', '>= 0.5.3'
42
42
  spec.add_dependency 'sqlite3', '~> 1.4', '>= 1.4.2'
43
43
  spec.add_dependency 'os', '~> 1.1', '>= 1.1.4'
44
+ spec.add_dependency 'pg', '~> 1.5.4'
44
45
  end
data/lib/VERSION CHANGED
@@ -1 +1 @@
1
- 2.5.0
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
@@ -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
- create_logger
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 create_logger
40
- f = File.join( @engine.settings.log_path, 'gloo.log' )
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
- @logger.error ex.message
98
- @logger.error ex.backtrace
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
- create_logger
164
+ create_loggers
124
165
  end
125
166
 
126
167
  end
data/lib/gloo/app/mode.rb CHANGED
@@ -9,6 +9,7 @@ module Gloo
9
9
  class Mode
10
10
 
11
11
  EMBED = :embed # Run as embedded script processor
12
+ APP = :app # Running in APP mode.
12
13
  CLI = :cli # Run in interactive (CLI) mode
13
14
  SCRIPT = :script # Run a script
14
15
  VERSION = :version # Show version information
@@ -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
@@ -284,8 +284,6 @@ module Gloo
284
284
  return
285
285
  end
286
286
 
287
- @engine.event_manager.on_unload self
288
- @engine.heap.unload self
289
287
  @engine.persist_man.unload self
290
288
  end
291
289
 
@@ -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
- unless obj
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
- puts "#{cmd} is not a valid option"
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
@@ -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
- pretty = JSON.pretty_generate( self.value )
67
- puts pretty
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
- h = JSON.parse( self.value )
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.handle_json( json, parent )
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 handle_json( json, parent )
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
- handle_json( v, o )
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
- handle_json( o, child )
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
@@ -17,8 +17,7 @@ module Gloo
17
17
  def run
18
18
  return unless @engine.persist_man.maps
19
19
 
20
- objs = @engine.persist_man.maps.map { |fs| fs.obj }
21
- objs.each { |o| o.msg_unload }
20
+ @engine.persist_man.unload_all
22
21
  end
23
22
 
24
23
  #
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: 2.5.0
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-06-28 00:00:00.000000000 Z
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