gloo 1.4.2 → 2.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/.DS_Store +0 -0
- data/.gitignore +1 -0
- data/gloo.gemspec +0 -2
- data/lib/VERSION +1 -1
- data/lib/dependencies.rb +4 -4
- data/lib/gloo/app/args.rb +112 -0
- data/lib/gloo/app/engine.rb +247 -0
- data/lib/gloo/app/engine_context.rb +25 -0
- data/lib/gloo/app/info.rb +20 -3
- data/lib/gloo/app/log.rb +73 -1
- data/lib/gloo/app/mode.rb +27 -0
- data/lib/gloo/app/platform.rb +8 -1
- data/lib/gloo/app/settings.rb +202 -0
- data/lib/gloo/convert/converter.rb +42 -0
- data/lib/gloo/convert/string_to_date.rb +21 -0
- data/lib/gloo/convert/string_to_datetime.rb +21 -0
- data/lib/gloo/convert/string_to_decimal.rb +20 -0
- data/lib/gloo/convert/string_to_integer.rb +20 -0
- data/lib/gloo/convert/string_to_time.rb +21 -0
- data/lib/gloo/core/baseo.rb +31 -0
- data/lib/gloo/core/dictionary.rb +245 -0
- data/lib/gloo/core/error.rb +61 -0
- data/lib/gloo/core/event_manager.rb +45 -0
- data/lib/gloo/core/factory.rb +211 -0
- data/lib/gloo/core/gloo_system.rb +267 -0
- data/lib/gloo/core/heap.rb +53 -0
- data/lib/gloo/core/here.rb +36 -0
- data/lib/gloo/core/it.rb +36 -0
- data/lib/gloo/core/literal.rb +30 -0
- data/lib/gloo/core/obj.rb +318 -0
- data/lib/gloo/core/obj_finder.rb +30 -0
- data/lib/gloo/core/op.rb +40 -0
- data/lib/gloo/core/parser.rb +60 -0
- data/lib/gloo/core/pn.rb +212 -0
- data/lib/gloo/core/tokens.rb +165 -0
- data/lib/gloo/core/verb.rb +87 -0
- data/lib/gloo/exec/action.rb +48 -0
- data/lib/gloo/exec/dispatch.rb +40 -0
- data/lib/gloo/exec/exec_env.rb +75 -0
- data/lib/gloo/exec/runner.rb +45 -0
- data/lib/gloo/exec/script.rb +50 -0
- data/lib/gloo/exec/stack.rb +79 -0
- data/lib/gloo/expr/expression.rb +119 -0
- data/lib/gloo/expr/l_boolean.rb +36 -0
- data/lib/gloo/expr/l_decimal.rb +39 -0
- data/lib/gloo/expr/l_integer.rb +37 -0
- data/lib/gloo/expr/l_string.rb +58 -0
- data/lib/gloo/expr/op_div.rb +22 -0
- data/lib/gloo/expr/op_minus.rb +22 -0
- data/lib/gloo/expr/op_mult.rb +22 -0
- data/lib/gloo/expr/op_plus.rb +24 -0
- data/lib/gloo/objs/basic/alias.rb +78 -0
- data/lib/gloo/objs/basic/boolean.rb +120 -0
- data/lib/gloo/objs/basic/container.rb +65 -0
- data/lib/gloo/objs/basic/decimal.rb +76 -0
- data/lib/gloo/objs/basic/integer.rb +73 -0
- data/lib/gloo/objs/basic/script.rb +99 -0
- data/lib/gloo/objs/basic/string.rb +77 -0
- data/lib/gloo/objs/basic/text.rb +79 -0
- data/lib/gloo/objs/basic/untyped.rb +41 -0
- data/lib/gloo/objs/cli/banner.rb +1 -1
- data/lib/gloo/objs/cli/bar.rb +3 -3
- data/lib/gloo/objs/cli/colorize.rb +1 -1
- data/lib/gloo/objs/cli/confirm.rb +1 -1
- data/lib/gloo/objs/cli/menu.rb +6 -6
- data/lib/gloo/objs/cli/menu_item.rb +1 -1
- data/lib/gloo/objs/cli/pastel.rb +1 -1
- data/lib/gloo/objs/cli/prompt.rb +1 -1
- data/lib/gloo/objs/cli/select.rb +2 -2
- data/lib/gloo/objs/ctrl/each.rb +279 -0
- data/lib/gloo/objs/ctrl/repeat.rb +108 -0
- data/lib/gloo/objs/data/markdown.rb +79 -0
- data/lib/gloo/objs/data/mysql.rb +5 -5
- data/lib/gloo/objs/data/query.rb +4 -4
- data/lib/gloo/objs/data/sqlite.rb +1 -1
- data/lib/gloo/objs/data/table.rb +112 -0
- data/lib/gloo/objs/dev/git.rb +2 -2
- data/lib/gloo/objs/dev/stats.rb +4 -4
- data/lib/gloo/objs/dt/date.rb +65 -0
- data/lib/gloo/objs/dt/datetime.rb +120 -0
- data/lib/gloo/objs/dt/dt_tools.rb +100 -0
- data/lib/gloo/objs/dt/time.rb +65 -0
- data/lib/gloo/objs/ror/erb.rb +116 -0
- data/lib/gloo/objs/ror/eval.rb +107 -0
- data/lib/gloo/objs/snd/play.rb +1 -1
- data/lib/gloo/objs/snd/say.rb +1 -1
- data/lib/gloo/objs/system/file_handle.rb +4 -4
- data/lib/gloo/objs/system/ssh_exec.rb +1 -1
- data/lib/gloo/objs/system/system.rb +1 -1
- data/lib/gloo/objs/web/http_get.rb +159 -0
- data/lib/gloo/objs/web/http_post.rb +183 -0
- data/lib/gloo/objs/web/json.rb +135 -0
- data/lib/gloo/objs/web/slack.rb +130 -0
- data/lib/gloo/objs/web/teams.rb +117 -0
- data/lib/gloo/objs/web/uri.rb +148 -0
- data/lib/gloo/persist/disc_mech.rb +87 -0
- data/lib/gloo/persist/file_loader.rb +193 -0
- data/lib/gloo/persist/file_saver.rb +51 -0
- data/lib/gloo/persist/file_storage.rb +46 -0
- data/lib/gloo/persist/line_splitter.rb +81 -0
- data/lib/gloo/persist/persist_man.rb +153 -0
- data/lib/gloo/utils/format.rb +21 -0
- data/lib/gloo/utils/stats.rb +206 -0
- data/lib/gloo/utils/words.rb +19 -0
- data/lib/gloo/verbs/alert.rb +2 -2
- data/lib/gloo/verbs/beep.rb +1 -1
- data/lib/gloo/verbs/cls.rb +1 -1
- data/lib/gloo/verbs/context.rb +62 -0
- data/lib/gloo/verbs/create.rb +68 -0
- data/lib/gloo/verbs/execute.rb +56 -0
- data/lib/gloo/verbs/files.rb +49 -0
- data/lib/gloo/verbs/help.rb +1 -1
- data/lib/gloo/verbs/if.rb +92 -0
- data/lib/gloo/verbs/list.rb +98 -0
- data/lib/gloo/verbs/load.rb +45 -0
- data/lib/gloo/verbs/move.rb +89 -0
- data/lib/gloo/verbs/put.rb +94 -0
- data/lib/gloo/verbs/quit.rb +40 -0
- data/lib/gloo/verbs/reload.rb +43 -0
- data/lib/gloo/verbs/run.rb +75 -0
- data/lib/gloo/verbs/save.rb +39 -0
- data/lib/gloo/verbs/show.rb +63 -0
- data/lib/gloo/verbs/tell.rb +80 -0
- data/lib/gloo/verbs/unless.rb +92 -0
- data/lib/gloo/verbs/unload.rb +46 -0
- data/lib/gloo/verbs/version.rb +3 -3
- data/lib/gloo/verbs/wait.rb +42 -0
- data/lib/gloo.rb +2 -2
- data/lib/run.rb +2 -2
- metadata +97 -22
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# Author:: Eric Crane (mailto:eric.crane@mac.com)
|
|
2
|
+
# Copyright:: Copyright (c) 2020 Eric Crane. All rights reserved.
|
|
3
|
+
#
|
|
4
|
+
# A URI (URL).
|
|
5
|
+
#
|
|
6
|
+
require 'uri'
|
|
7
|
+
require 'net/http'
|
|
8
|
+
require 'openssl'
|
|
9
|
+
|
|
10
|
+
module Gloo
|
|
11
|
+
module Objs
|
|
12
|
+
class Uri < Gloo::Core::Obj
|
|
13
|
+
|
|
14
|
+
KEYWORD = 'uri'.freeze
|
|
15
|
+
KEYWORD_SHORT = 'url'.freeze
|
|
16
|
+
|
|
17
|
+
#
|
|
18
|
+
# The name of the object type.
|
|
19
|
+
#
|
|
20
|
+
def self.typename
|
|
21
|
+
return KEYWORD
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
#
|
|
25
|
+
# The short name of the object type.
|
|
26
|
+
#
|
|
27
|
+
def self.short_typename
|
|
28
|
+
return KEYWORD_SHORT
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
#
|
|
32
|
+
# Set the value with any necessary type conversions.
|
|
33
|
+
#
|
|
34
|
+
def set_value( new_value )
|
|
35
|
+
self.value = new_value.to_s
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
#
|
|
39
|
+
# Does this object support multi-line values?
|
|
40
|
+
# Initially only true for scripts.
|
|
41
|
+
#
|
|
42
|
+
def multiline_value?
|
|
43
|
+
return false
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# ---------------------------------------------------------------------
|
|
47
|
+
# Messages
|
|
48
|
+
# ---------------------------------------------------------------------
|
|
49
|
+
|
|
50
|
+
#
|
|
51
|
+
# Get a list of message names that this object receives.
|
|
52
|
+
#
|
|
53
|
+
def self.messages
|
|
54
|
+
basic = %w[open]
|
|
55
|
+
gets = %w[get_scheme get_host get_path]
|
|
56
|
+
more = %w[get_query get_fragment get_cert_expires]
|
|
57
|
+
return super + basic + gets + more
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
#
|
|
61
|
+
# Get the expiration date for the certificate.
|
|
62
|
+
#
|
|
63
|
+
def msg_get_cert_expires
|
|
64
|
+
return unless value
|
|
65
|
+
o = value
|
|
66
|
+
uri = URI( value )
|
|
67
|
+
response = Net::HTTP.start( uri.host, uri.port, :use_ssl => true )
|
|
68
|
+
cert = response.peer_cert
|
|
69
|
+
o = cert.not_after
|
|
70
|
+
|
|
71
|
+
@engine.heap.it.set_to o
|
|
72
|
+
return o
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
#
|
|
76
|
+
# Get the URI fragment that comes after the '#'
|
|
77
|
+
# in the URL. Might be used to scroll down in the page.
|
|
78
|
+
#
|
|
79
|
+
def msg_get_fragment
|
|
80
|
+
return unless value
|
|
81
|
+
|
|
82
|
+
o = URI( value ).fragment
|
|
83
|
+
@engine.heap.it.set_to o
|
|
84
|
+
return o
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
#
|
|
88
|
+
# Get the URI query parameters.
|
|
89
|
+
# Example: id=121
|
|
90
|
+
#
|
|
91
|
+
def msg_get_query
|
|
92
|
+
return unless value
|
|
93
|
+
|
|
94
|
+
o = URI( value ).query
|
|
95
|
+
@engine.heap.it.set_to o
|
|
96
|
+
return o
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
#
|
|
100
|
+
# Get the URI path.
|
|
101
|
+
# Example: /posts
|
|
102
|
+
#
|
|
103
|
+
def msg_get_path
|
|
104
|
+
return unless value
|
|
105
|
+
|
|
106
|
+
o = URI( value ).path
|
|
107
|
+
@engine.heap.it.set_to o
|
|
108
|
+
return o
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
#
|
|
112
|
+
# Get the URI host.
|
|
113
|
+
# Example: google.com
|
|
114
|
+
#
|
|
115
|
+
def msg_get_host
|
|
116
|
+
return unless value
|
|
117
|
+
|
|
118
|
+
o = URI( value ).host
|
|
119
|
+
@engine.heap.it.set_to o
|
|
120
|
+
return o
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
#
|
|
124
|
+
# Get the URI Scheme.
|
|
125
|
+
# Example: http
|
|
126
|
+
#
|
|
127
|
+
def msg_get_scheme
|
|
128
|
+
return unless value
|
|
129
|
+
|
|
130
|
+
o = URI( value ).scheme
|
|
131
|
+
@engine.heap.it.set_to o
|
|
132
|
+
return o
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
#
|
|
136
|
+
# Open the URI in the default browser.
|
|
137
|
+
#
|
|
138
|
+
def msg_open
|
|
139
|
+
return unless value
|
|
140
|
+
|
|
141
|
+
cmd = Gloo::Core::GlooSystem.open_for_platform
|
|
142
|
+
cmd_with_param = "#{cmd} \"#{value}\""
|
|
143
|
+
`#{cmd_with_param}`
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Author:: Eric Crane (mailto:eric.crane@mac.com)
|
|
2
|
+
# Copyright:: Copyright (c) 2022 Eric Crane. All rights reserved.
|
|
3
|
+
#
|
|
4
|
+
# Disc based mechanism for files.
|
|
5
|
+
# Provides interaction between the persistance classes and the OS
|
|
6
|
+
# file and folder system.
|
|
7
|
+
# This class might be overiden elsewhere to provide other mechanism.
|
|
8
|
+
# For example, in gloo-web, there will be a db based mechanism.
|
|
9
|
+
#
|
|
10
|
+
|
|
11
|
+
module Gloo
|
|
12
|
+
module Persist
|
|
13
|
+
class DiscMech
|
|
14
|
+
|
|
15
|
+
#
|
|
16
|
+
# Set up a disc based file mechanism.
|
|
17
|
+
#
|
|
18
|
+
def initialize( engine )
|
|
19
|
+
@engine = engine
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
#
|
|
23
|
+
# Get the default file extention.
|
|
24
|
+
#
|
|
25
|
+
def file_ext
|
|
26
|
+
return '.gloo'
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
#
|
|
30
|
+
# Get all the gloo files in the folder (partial path).
|
|
31
|
+
#
|
|
32
|
+
def get_all_files_in( folder )
|
|
33
|
+
pns = []
|
|
34
|
+
dir = File.join( @engine.settings.project_path, folder )
|
|
35
|
+
Dir.glob( "#{dir}*.gloo" ).each do |f|
|
|
36
|
+
pns << f
|
|
37
|
+
end
|
|
38
|
+
return pns
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
#
|
|
42
|
+
# Check if a file exists.
|
|
43
|
+
#
|
|
44
|
+
def exist?( file )
|
|
45
|
+
File.exist?( file )
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
#
|
|
49
|
+
# Check to see if the file is valid.
|
|
50
|
+
#
|
|
51
|
+
def valid?( file )
|
|
52
|
+
return false unless file
|
|
53
|
+
return false unless File.exist?( file )
|
|
54
|
+
return false unless File.file?( file )
|
|
55
|
+
return false unless file.end_with?( self.file_ext )
|
|
56
|
+
|
|
57
|
+
return true
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
#
|
|
61
|
+
# Expand a single file path.
|
|
62
|
+
#
|
|
63
|
+
def expand( name )
|
|
64
|
+
ext_path = File.expand_path( name )
|
|
65
|
+
return [ ext_path ] if self.valid?( ext_path )
|
|
66
|
+
|
|
67
|
+
full_name = "#{name}#{file_ext}"
|
|
68
|
+
return [ File.join( @engine.settings.project_path, full_name ) ]
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
#
|
|
72
|
+
# Read in the contents of a single file.
|
|
73
|
+
#
|
|
74
|
+
def read( file )
|
|
75
|
+
return File.read( file )
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
#
|
|
79
|
+
# Write data to the file.
|
|
80
|
+
#
|
|
81
|
+
def write( pn, data )
|
|
82
|
+
File.write( pn, data )
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# Author:: Eric Crane (mailto:eric.crane@mac.com)
|
|
2
|
+
# Copyright:: Copyright (c) 2019 Eric Crane. All rights reserved.
|
|
3
|
+
#
|
|
4
|
+
# Helper class used to load a file and create objects in the heap.
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
module Gloo
|
|
8
|
+
module Persist
|
|
9
|
+
class FileLoader
|
|
10
|
+
|
|
11
|
+
BEGIN_BLOCK = 'BEGIN'.freeze
|
|
12
|
+
END_BLOCK = 'END'.freeze
|
|
13
|
+
SPACE_CNT = 2
|
|
14
|
+
|
|
15
|
+
attr_reader :obj
|
|
16
|
+
|
|
17
|
+
#
|
|
18
|
+
# Set up a file storage for an object.
|
|
19
|
+
#
|
|
20
|
+
def initialize( engine, pn )
|
|
21
|
+
@engine = engine
|
|
22
|
+
@mech = @engine.platform.getFileMech( @engine )
|
|
23
|
+
@pn = pn
|
|
24
|
+
@tabs = 0
|
|
25
|
+
@obj = nil
|
|
26
|
+
@in_multiline = false
|
|
27
|
+
@exiting_multiline = false
|
|
28
|
+
@in_block = false
|
|
29
|
+
@block_value = ''
|
|
30
|
+
@debug = false
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
#
|
|
34
|
+
# Load the objects from the file.
|
|
35
|
+
#
|
|
36
|
+
def load
|
|
37
|
+
unless @mech.exist?( @pn )
|
|
38
|
+
@engine.log.error "File '#{@pn}' does not exist."
|
|
39
|
+
return
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
@engine.log.debug "Loading file '#{@pn}'"
|
|
43
|
+
@tabs = 0
|
|
44
|
+
@parent_stack = []
|
|
45
|
+
@parent = @engine.heap.root
|
|
46
|
+
@parent_stack.push @parent
|
|
47
|
+
f = @mech.read( @pn )
|
|
48
|
+
f.each_line do |line|
|
|
49
|
+
next if skip_line? line
|
|
50
|
+
|
|
51
|
+
handle_one_line line
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
#
|
|
56
|
+
# Process one one of the file we're loading.
|
|
57
|
+
#
|
|
58
|
+
def handle_one_line( line )
|
|
59
|
+
if line.strip.end_with? BEGIN_BLOCK
|
|
60
|
+
@in_block = true
|
|
61
|
+
@save_line = line
|
|
62
|
+
elsif @in_block
|
|
63
|
+
if line.strip == END_BLOCK
|
|
64
|
+
@in_block = false
|
|
65
|
+
determine_indent @save_line
|
|
66
|
+
process_line @save_line
|
|
67
|
+
else
|
|
68
|
+
@block_value << line
|
|
69
|
+
end
|
|
70
|
+
else
|
|
71
|
+
determine_indent line
|
|
72
|
+
process_line line
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
#
|
|
77
|
+
# Is this line a comment or a blank line?
|
|
78
|
+
# If so we'll skip it.
|
|
79
|
+
#
|
|
80
|
+
def skip_line?( line )
|
|
81
|
+
line = line.strip
|
|
82
|
+
return true if line.empty?
|
|
83
|
+
return true if line[ 0 ] == '#'
|
|
84
|
+
|
|
85
|
+
return false
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
#
|
|
89
|
+
# Determine the relative indent level for the line.
|
|
90
|
+
#
|
|
91
|
+
def determine_indent( line )
|
|
92
|
+
tabs = tab_count( line )
|
|
93
|
+
@indent = 0 # same level as prior line
|
|
94
|
+
if tabs > @tabs # indent
|
|
95
|
+
# TODO: What if indent is more than one more level?
|
|
96
|
+
@tabs = tabs
|
|
97
|
+
@indent = 1
|
|
98
|
+
elsif tabs < @tabs # outdent
|
|
99
|
+
diff = @tabs - tabs
|
|
100
|
+
@tabs -= diff
|
|
101
|
+
@indent -= diff
|
|
102
|
+
end
|
|
103
|
+
puts "tabs: #{@tabs}, indent: #{@indent}, line: #{line}" if @debug
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
#
|
|
107
|
+
# Process one line and add objects.
|
|
108
|
+
#
|
|
109
|
+
def process_line( line )
|
|
110
|
+
# reset multiline unless we're actually indented
|
|
111
|
+
if @in_multiline && @multi_indent > @indent
|
|
112
|
+
puts "Done multiline mi: #{@multi_indent}, i: #{@indent}" if @debug
|
|
113
|
+
@in_multiline = false
|
|
114
|
+
@exiting_multiline = true
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
if @in_multiline
|
|
118
|
+
@last.add_line line
|
|
119
|
+
else
|
|
120
|
+
setup_process_obj_line
|
|
121
|
+
process_obj_line line
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
#
|
|
126
|
+
# Setup and get ready to process an object line.
|
|
127
|
+
#
|
|
128
|
+
def setup_process_obj_line
|
|
129
|
+
if @exiting_multiline
|
|
130
|
+
@exiting_multiline = false
|
|
131
|
+
@indent += 1
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
if @indent.positive?
|
|
135
|
+
@parent = @last
|
|
136
|
+
@parent_stack.push @parent
|
|
137
|
+
elsif @indent.negative?
|
|
138
|
+
@indent.abs.times do
|
|
139
|
+
@parent_stack.pop
|
|
140
|
+
@parent = @parent_stack.last
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
#
|
|
146
|
+
# Process one line and add objects.
|
|
147
|
+
#
|
|
148
|
+
def process_obj_line( line )
|
|
149
|
+
name, type, value = split_line( line )
|
|
150
|
+
unless @block_value == ''
|
|
151
|
+
value = @block_value
|
|
152
|
+
@block_value = ''
|
|
153
|
+
end
|
|
154
|
+
params = { name: name, type: type, value: value, parent: @parent }
|
|
155
|
+
@last = @engine.factory.create( params )
|
|
156
|
+
|
|
157
|
+
if value.empty? && @last&.multiline_value?
|
|
158
|
+
@multi_indent = 0
|
|
159
|
+
@in_multiline = true
|
|
160
|
+
puts "*** Start multiline. multi_indent: #{@multi_indent}" if @debug
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
@obj = @last if @obj.nil?
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
#
|
|
167
|
+
# Get the number of leading tabs.
|
|
168
|
+
#
|
|
169
|
+
def tab_count( line )
|
|
170
|
+
i = 0
|
|
171
|
+
|
|
172
|
+
if line[ i ] == ' '
|
|
173
|
+
i += 1 while line[ i ] == ' '
|
|
174
|
+
tab_equiv = ( i / SPACE_CNT ).to_i
|
|
175
|
+
puts "Found #{i} spaces => #{tab_equiv}" if @debug
|
|
176
|
+
return tab_equiv
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
i += 1 while line[ i ] == "\t"
|
|
180
|
+
return i
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
#
|
|
184
|
+
# Split the line into 3 parts.
|
|
185
|
+
#
|
|
186
|
+
def split_line( line )
|
|
187
|
+
o = LineSplitter.new( line, @tabs )
|
|
188
|
+
return o.split
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Author:: Eric Crane (mailto:eric.crane@mac.com)
|
|
2
|
+
# Copyright:: Copyright (c) 2019 Eric Crane. All rights reserved.
|
|
3
|
+
#
|
|
4
|
+
# Helper class used to save an object to a file..
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
module Gloo
|
|
8
|
+
module Persist
|
|
9
|
+
class FileSaver
|
|
10
|
+
|
|
11
|
+
#
|
|
12
|
+
# Set up a file storage for an object.
|
|
13
|
+
#
|
|
14
|
+
def initialize( engine, pn, obj )
|
|
15
|
+
@engine = engine
|
|
16
|
+
@mech = @engine.platform.getFileMech( @engine )
|
|
17
|
+
@pn = pn
|
|
18
|
+
@obj = obj
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
#
|
|
22
|
+
# Save the object to the file.
|
|
23
|
+
#
|
|
24
|
+
def save
|
|
25
|
+
data = get_obj( @obj )
|
|
26
|
+
@mech.write( @pn, data )
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
#
|
|
30
|
+
# Get string of tabs for indentation.
|
|
31
|
+
#
|
|
32
|
+
def tabs( indent = 0 )
|
|
33
|
+
return "\t" * indent
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
#
|
|
37
|
+
# Convert an object to textual representation.
|
|
38
|
+
# This is a recursive function.
|
|
39
|
+
#
|
|
40
|
+
def get_obj( obj, indent = 0 )
|
|
41
|
+
t = tabs( indent )
|
|
42
|
+
str = "#{t}#{obj.name} [#{obj.type_display}] : #{obj.value_display}\n"
|
|
43
|
+
obj.children.each do |child|
|
|
44
|
+
str << get_obj( child, indent + 1 )
|
|
45
|
+
end
|
|
46
|
+
return str
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Author:: Eric Crane (mailto:eric.crane@mac.com)
|
|
2
|
+
# Copyright:: Copyright (c) 2019 Eric Crane. All rights reserved.
|
|
3
|
+
#
|
|
4
|
+
# Helper class takes an object and writes it to a file.
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
module Gloo
|
|
8
|
+
module Persist
|
|
9
|
+
class FileStorage
|
|
10
|
+
|
|
11
|
+
attr_reader :obj, :pn
|
|
12
|
+
|
|
13
|
+
#
|
|
14
|
+
# Set up a file storage for an object.
|
|
15
|
+
#
|
|
16
|
+
def initialize( engine, pn, obj = nil )
|
|
17
|
+
@engine = engine
|
|
18
|
+
@obj = obj
|
|
19
|
+
@pn = pn
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
#
|
|
23
|
+
# Save the object to the file.
|
|
24
|
+
#
|
|
25
|
+
def save
|
|
26
|
+
fs = FileSaver.new( @engine, @pn, @obj )
|
|
27
|
+
fs.save
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
#
|
|
31
|
+
# Load the object from the file.
|
|
32
|
+
#
|
|
33
|
+
def load
|
|
34
|
+
fl = FileLoader.new( @engine, @pn )
|
|
35
|
+
fl.load
|
|
36
|
+
@obj = fl.obj
|
|
37
|
+
if @obj
|
|
38
|
+
@engine.log.debug "Loaded object: #{@obj.name}"
|
|
39
|
+
else
|
|
40
|
+
@engine.log.error "Error loading file at #{@pn}"
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Author:: Eric Crane (mailto:eric.crane@mac.com)
|
|
2
|
+
# Copyright:: Copyright (c) 2020 Eric Crane. All rights reserved.
|
|
3
|
+
#
|
|
4
|
+
# Helper class used as part of file loading.
|
|
5
|
+
# It is responsible for splitting a line into components.
|
|
6
|
+
#
|
|
7
|
+
|
|
8
|
+
module Gloo
|
|
9
|
+
module Persist
|
|
10
|
+
class LineSplitter
|
|
11
|
+
|
|
12
|
+
BEGIN_BLOCK = 'BEGIN'.freeze
|
|
13
|
+
END_BLOCK = 'END'.freeze
|
|
14
|
+
|
|
15
|
+
attr_reader :obj
|
|
16
|
+
|
|
17
|
+
#
|
|
18
|
+
# Set up a line splitter
|
|
19
|
+
#
|
|
20
|
+
def initialize( line, tabs )
|
|
21
|
+
@line = line
|
|
22
|
+
@tabs = tabs
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
#
|
|
26
|
+
# Split the line into 3 parts.
|
|
27
|
+
#
|
|
28
|
+
def split
|
|
29
|
+
detect_name
|
|
30
|
+
detect_type
|
|
31
|
+
detect_value
|
|
32
|
+
|
|
33
|
+
return @name, @type, @value
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
#
|
|
37
|
+
# Detect the object name.
|
|
38
|
+
#
|
|
39
|
+
def detect_name
|
|
40
|
+
@line = @line.strip
|
|
41
|
+
@idx = @line.index( ' ' )
|
|
42
|
+
@name = @line[ 0..@idx - 1 ]
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
#
|
|
46
|
+
# Detect the object type.
|
|
47
|
+
#
|
|
48
|
+
def detect_type
|
|
49
|
+
@line = @line[ @idx + 1..-1 ]
|
|
50
|
+
@idx = @line.index( ' ' )
|
|
51
|
+
|
|
52
|
+
if @line[ 0 ] == ':'
|
|
53
|
+
@type = 'untyped'
|
|
54
|
+
return
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
@type = @line[ 0..( @idx ? @idx - 1 : -1 ) ]
|
|
58
|
+
@type = @type[ 1..-1 ] if @type[ 0 ] == '['
|
|
59
|
+
@type = @type[ 0..-2 ] if @type[ -1 ] == ']'
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
#
|
|
63
|
+
# Detect the object value.
|
|
64
|
+
# Use nil if there is no value specified.
|
|
65
|
+
#
|
|
66
|
+
def detect_value
|
|
67
|
+
if @idx
|
|
68
|
+
@value = @line[ @idx + 1..-1 ]
|
|
69
|
+
if @value[ 0..1 ] == ': '
|
|
70
|
+
@value = @value[ 2..-1 ]
|
|
71
|
+
elsif @value[ 0 ] == ':'
|
|
72
|
+
@value = @value[ 1..-1 ]
|
|
73
|
+
end
|
|
74
|
+
else
|
|
75
|
+
@value = nil
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|