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 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