hypersonicplus 0.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 +7 -0
- data/lib/hdatastructures/hfieldtable.rb +285 -0
- data/lib/hdatastructures/hhash.rb +9 -0
- data/lib/hdatastructures/hlist.rb +100 -0
- data/lib/hdatastructures/hrecord.rb +75 -0
- data/lib/hdatastructures/hspreadfieldtable.rb +129 -0
- data/lib/hdb/hdataloader.rb +75 -0
- data/lib/hdb/hdb.rb +357 -0
- data/lib/hdb/hdb_test.rb +248 -0
- data/lib/hdb/hdbgenerator.rb +211 -0
- data/lib/hdb/hdbi.rb +63 -0
- data/lib/hdb/hdbi_test.rb +133 -0
- data/lib/hdb/hfield.rb +180 -0
- data/lib/hdb/hmysql.rb +99 -0
- data/lib/hdb/hmysql2.rb +96 -0
- data/lib/hdb/hodb.rb +948 -0
- data/lib/hdb/hpgsql.rb +54 -0
- data/lib/hengine/application_controller.rb +204 -0
- data/lib/hengine/hconfiguration.rb +40 -0
- data/lib/hengine/hhotlogger.rb +13 -0
- data/lib/hengine/hlogger.rb +119 -0
- data/lib/hengine/hmalloc.rb +275 -0
- data/lib/hengine/hmoduleloader.rb +15 -0
- data/lib/hengine/hsessiondata.rb +79 -0
- data/lib/hengine/hshareddata.rb +60 -0
- data/lib/hengine/htranslate.rb +40 -0
- data/lib/hengine/hviewloader.rb +99 -0
- data/lib/hinit/hinit.rb +3 -0
- data/lib/hmisc/hcolorize.rb +100 -0
- data/lib/hmisc/hdecoratorfunctions.rb +15 -0
- data/lib/hmisc/hdir.rb +19 -0
- data/lib/hmisc/hhtmlnode.rb +27 -0
- data/lib/hmisc/hinputvalidator.rb +95 -0
- data/lib/hmisc/hio.rb +142 -0
- data/lib/hmisc/hjson.rb +16 -0
- data/lib/hsqlmanager/hpgsqldatabasemanager.rb +76 -0
- data/lib/hsqlmanager/hsqldatabasemanager.rb +349 -0
- data/lib/hsqlmanager/hsqltable.rb +16 -0
- data/lib/husermanager/husermanager.rb +122 -0
- data/lib/hwidgets/haccordionmenu.rb +117 -0
- data/lib/hwidgets/hcheckboxtag.rb +33 -0
- data/lib/hwidgets/hdbactionbuttons.rb +26 -0
- data/lib/hwidgets/hdbcombobox.rb +71 -0
- data/lib/hwidgets/hdbdialogview.rb +190 -0
- data/lib/hwidgets/hdbfilterview.rb +28 -0
- data/lib/hwidgets/hdbtableview.rb +213 -0
- data/lib/hwidgets/hdbview.rb +63 -0
- data/lib/hwidgets/hdivtag.rb +9 -0
- data/lib/hwidgets/hdropdown.rb +44 -0
- data/lib/hwidgets/hformfield.rb +91 -0
- data/lib/hwidgets/hgrouptag.rb +65 -0
- data/lib/hwidgets/hhiddeninputtag.rb +12 -0
- data/lib/hwidgets/hinputtag.rb +55 -0
- data/lib/hwidgets/hlabeltag.rb +30 -0
- data/lib/hwidgets/hmainview.rb +37 -0
- data/lib/hwidgets/hpagination.rb +65 -0
- data/lib/hwidgets/hradiobuttontag.rb +30 -0
- data/lib/hwidgets/hselecttag.rb +32 -0
- data/lib/hwidgets/htableview.rb +262 -0
- data/lib/hwidgets/htabview.rb +84 -0
- data/lib/hwidgets/htextareatag.rb +20 -0
- data/lib/hwidgets/htopnav.rb +85 -0
- data/lib/hwidgets/hwidget.rb +423 -0
- data/lib/hypersonic.rb +9 -0
- metadata +276 -0
data/lib/hdb/hpgsql.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'hdb/hdb'
|
2
|
+
|
3
|
+
class HPgSql < HDB
|
4
|
+
|
5
|
+
def initialize(host, port, dbname, user, password, timezone, connectionName)
|
6
|
+
|
7
|
+
super(host, port, dbname, user, password, timezone, connectionName, "hpgsql")
|
8
|
+
@result = nil
|
9
|
+
|
10
|
+
end
|
11
|
+
|
12
|
+
def connect()
|
13
|
+
|
14
|
+
@connection = PGconn.new(@host, @port, "", "", @dbname, @user, @password)
|
15
|
+
hl << "Server version: #{self.execute("SHOW server_version").firstData.to_s}"
|
16
|
+
self.execute("SET TIME ZONE '#{@timezone}'") if @timezone
|
17
|
+
return @connection
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
def disconnect()
|
22
|
+
|
23
|
+
@connection.close()
|
24
|
+
@connection = nil
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
def _execute(queryStr = self.queryStr)
|
29
|
+
|
30
|
+
@table = []
|
31
|
+
@result = @connection.query(queryStr)
|
32
|
+
@result.each do |row|
|
33
|
+
@table << row
|
34
|
+
end
|
35
|
+
return self
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
def fieldNameList()
|
40
|
+
|
41
|
+
fieldList = {}
|
42
|
+
|
43
|
+
@result.fields.each { |fieldName| fieldList[fieldName] = nil }
|
44
|
+
|
45
|
+
return fieldList
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
def rowsAffected
|
50
|
+
return @result.cmd_tuples()
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
@@ -0,0 +1,204 @@
|
|
1
|
+
require 'bcrypt'
|
2
|
+
require 'jbuilder'
|
3
|
+
require 'json'
|
4
|
+
require 'ostruct'
|
5
|
+
require 'pg'
|
6
|
+
require 'erb'
|
7
|
+
require 'erubis'
|
8
|
+
|
9
|
+
class ApplicationController
|
10
|
+
|
11
|
+
attr_accessor :isRenderized
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@layouts = {}
|
15
|
+
@layout = "application"
|
16
|
+
end
|
17
|
+
|
18
|
+
def _hInit(controllerName, actionName)
|
19
|
+
@controllerName = controllerName
|
20
|
+
@actionName = actionName
|
21
|
+
end
|
22
|
+
|
23
|
+
def _readFile(filename)
|
24
|
+
file = File.open(filename,'r')
|
25
|
+
content = self._localVariable(@locals) + file.read
|
26
|
+
file.close()
|
27
|
+
hl << content
|
28
|
+
return content
|
29
|
+
end
|
30
|
+
|
31
|
+
def heval(jsonStr)
|
32
|
+
# Quando converto un oggetto OpenStruct in json usando l'ambiente IRB ottengo il formato:
|
33
|
+
# "\"#<OpenStruct name=\\\"_herbert_\\\", bonaffini=\\\"_bonaffini_\\\">\""
|
34
|
+
if(jsonStr.index("#<OpenStruct"))
|
35
|
+
hl << "[application_controllet::heval]#: =========> first case".red
|
36
|
+
osn = eval(jsonStr).gsub(/#<OpenStruct.*>/) { |token| "{#{token.gsub('"', "'").gsub("=", ":").gsub("#<OpenStruct", "")[0..-2]}}" }
|
37
|
+
hash = eval(osn)
|
38
|
+
return OpenStruct.new hash
|
39
|
+
end
|
40
|
+
# Quando converto un oggetto OpenStruct in json usando l'ambiente rails ottengo il formato:
|
41
|
+
# '{"table":{"name":"_herbert_","bonaffini":"_bonaffini_"},"modifiable":true}'
|
42
|
+
if(jsonStr.index('},"modifiable":true}'))
|
43
|
+
hl << "[application_controllet::heval]#: =========> second case".red
|
44
|
+
hash = eval(jsonStr)[:table]
|
45
|
+
return OpenStruct.new hash
|
46
|
+
end
|
47
|
+
return eval(jsonStr)
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
# Questo metodo permette di avere le variabili locali di locals disponibili nel file erb
|
52
|
+
# file .rb
|
53
|
+
# - es. render(template: "test/index", layout: 'application', locals: {name: 'herbert', surname: 'bonaffini'})
|
54
|
+
# file .html.erb
|
55
|
+
# - es. <%= "Name: #{name}, Surname: #{@locals[:surname]}" %
|
56
|
+
def _localVariable(args)
|
57
|
+
|
58
|
+
return "" unless args
|
59
|
+
str = ""
|
60
|
+
args.each { |key, value| str += "#{key}=heval('#{value.to_json}');"; }
|
61
|
+
hl << "ApplicationController::_localVariable: #{str}"
|
62
|
+
return "<% #{str} %>"
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
def content_for(layoutName, &block)
|
67
|
+
|
68
|
+
@layouts[layoutName] = block
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
def herb(filename)
|
73
|
+
content = self._readFile(filename)
|
74
|
+
erb = ERB.new(content)
|
75
|
+
#erb = Erubis::Eruby.new(content)
|
76
|
+
return erb.result(binding())
|
77
|
+
end
|
78
|
+
|
79
|
+
def execLayout(filename)
|
80
|
+
|
81
|
+
content = self._readFile(filename).gsub(/content_for.*(do|{)/) { |token| "#{token} _herbout=''" }
|
82
|
+
# To more information http://apidock.com/ruby/v1_9_3_392/ERB/Compiler
|
83
|
+
compiler = ERB::Compiler.new("<>")
|
84
|
+
compiler.pre_cmd = ["_herbout=''"]
|
85
|
+
compiler.put_cmd = "_herbout.concat"
|
86
|
+
compiler.insert_cmd = "_herbout.concat"
|
87
|
+
compiler.post_cmd = [""]
|
88
|
+
code, enc = compiler.compile(content)
|
89
|
+
hl << code
|
90
|
+
eval(code)
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
def _setDefaultLayout(filename)
|
95
|
+
|
96
|
+
result = self.herb(filename)
|
97
|
+
self.content_for(:default) do
|
98
|
+
result
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
# by this method you can set another layout as on rails. It is enough to call layout in your controller
|
104
|
+
# example1: layout("layout_name") # static
|
105
|
+
# example2: layout :determine_layout # dynamic where determine_layout is a method name
|
106
|
+
def layout(layout = nil)
|
107
|
+
@layout = layout if(layout) # it is required to work as a getter and setter
|
108
|
+
return @layout if(@layout.class == String)
|
109
|
+
return eval(@layout.to_s)
|
110
|
+
end
|
111
|
+
|
112
|
+
def templateFileName (controllerName, actionName)
|
113
|
+
return @file if(@file)
|
114
|
+
return "./app/views/#{controllerName}/#{actionName}_view.html.erb"
|
115
|
+
end
|
116
|
+
|
117
|
+
# il nome dei parziale deve inziare con _ e non deve contenere _view
|
118
|
+
def partialFileName (controllerName, actionName)
|
119
|
+
return "./app/views/#{controllerName}/#{actionName}.html.erb"
|
120
|
+
end
|
121
|
+
|
122
|
+
def __render(controllerName, actionName, &block)
|
123
|
+
templateFileName = self.templateFileName(controllerName, actionName)
|
124
|
+
layoutFileName = "./app/views/layouts/#{self.layout}.html.erb"
|
125
|
+
self._setDefaultLayout(templateFileName)
|
126
|
+
self.execLayout(templateFileName)
|
127
|
+
hl << @layouts[:default].call
|
128
|
+
return self.herb(layoutFileName, &block)
|
129
|
+
end
|
130
|
+
|
131
|
+
|
132
|
+
def _render(controllerName, actionName)
|
133
|
+
|
134
|
+
return self.__render(controllerName, actionName) do |layoutName|
|
135
|
+
if(layoutName)
|
136
|
+
@layouts[layoutName].call
|
137
|
+
else
|
138
|
+
@layouts[:default].call
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
143
|
+
|
144
|
+
# examples:
|
145
|
+
# render(template: "test/index") # can i use an other template
|
146
|
+
# render(layout: 'application') # can i use an other layout
|
147
|
+
# render(action: 'hello') # can i use an ./views/xxx/hello_view.html.erb
|
148
|
+
# render(text: 'ciao') # return only the text 'ciao'
|
149
|
+
# render(json: {name: 'herbert', surname: 'von carean'}) # return an hash with json format
|
150
|
+
# render(file: "app/views/test/index_view.html.erb")
|
151
|
+
|
152
|
+
# file .rb
|
153
|
+
# - es. render(template: "test/index", layout: 'application', locals: {name: 'herbert', surname: 'bonaffini'})
|
154
|
+
# file .html.erb
|
155
|
+
# - es. <%= "Name: #{name}, Surname: #{@locals[:surname]}" %
|
156
|
+
|
157
|
+
def render(template: nil, action: nil, file: nil, text: nil, json: nil, layout: false, status: "200 OK", nothing: false, partial: nil, object: nil, locals: nil, collection: nil, spacer_template: nil)
|
158
|
+
|
159
|
+
hl << "isRenderized: #{@isRenderized}"
|
160
|
+
@isRenderized = true
|
161
|
+
|
162
|
+
# <%= render(partial: "article", collection: %w{ ant bee cat dog elk }, spacer_template: 'spacer') %>
|
163
|
+
if partial
|
164
|
+
@locals[partial] = object if object
|
165
|
+
return self.herb(self.partialFileName(@controllerName, "_#{partial}")) unless collection
|
166
|
+
result = ""
|
167
|
+
collection.each do |value|
|
168
|
+
@locals = {}
|
169
|
+
@locals[partial] = value
|
170
|
+
result += self.herb(self.partialFileName(@controllerName, "_#{partial}"))
|
171
|
+
result += self.herb(self.partialFileName(@controllerName, "_#{spacer_template}")) if spacer_template
|
172
|
+
end
|
173
|
+
return result
|
174
|
+
end
|
175
|
+
|
176
|
+
@locals = locals
|
177
|
+
|
178
|
+
return "" if nothing
|
179
|
+
|
180
|
+
@layout = layout if layout.class == String
|
181
|
+
|
182
|
+
if(file)
|
183
|
+
@file = file
|
184
|
+
return self.render if layout
|
185
|
+
return self.herb(file)
|
186
|
+
end
|
187
|
+
|
188
|
+
return text if text
|
189
|
+
|
190
|
+
return json.to_json if json
|
191
|
+
|
192
|
+
return self._render(template.split('/')[0], template.split('/')[1]) if template
|
193
|
+
|
194
|
+
return self._render(@controllerName, action) if action
|
195
|
+
|
196
|
+
return self._render(@controllerName, @actionName)
|
197
|
+
|
198
|
+
end
|
199
|
+
|
200
|
+
|
201
|
+
end
|
202
|
+
|
203
|
+
|
204
|
+
Dir.glob("app/controllers/**/*.rb").each { |filename| require "./#{filename}" }
|
@@ -0,0 +1,40 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "singleton"
|
4
|
+
require "yaml"
|
5
|
+
|
6
|
+
class HConfiguration
|
7
|
+
|
8
|
+
include Singleton
|
9
|
+
|
10
|
+
def initialize()
|
11
|
+
@configurations = Hash.new
|
12
|
+
@configurations["CONFIGURATION"] = YAML.load_file('config/configuration.yml')
|
13
|
+
# eventuali altri configuration da caricare all'avvio
|
14
|
+
end
|
15
|
+
|
16
|
+
def configuration(configurationName)
|
17
|
+
|
18
|
+
return @configurations[configurationName]
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
def setValue(fieldValue, fieldName, configurationName = "CONFIGURATION")
|
23
|
+
self.configuration(configurationName)[fieldName] = fieldValue
|
24
|
+
end
|
25
|
+
|
26
|
+
def value(fieldName, configurationName = "CONFIGURATION")
|
27
|
+
|
28
|
+
return self.configuration(configurationName)[fieldName]
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
def hc()
|
36
|
+
|
37
|
+
return HConfiguration.instance()
|
38
|
+
|
39
|
+
end
|
40
|
+
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class HHotLogger
|
2
|
+
|
3
|
+
def self.append(str, logName)
|
4
|
+
log = hsd.value(logName)
|
5
|
+
return unless log
|
6
|
+
hsd.set(logName, log = {}) if log.class != Hash
|
7
|
+
timestamp = Time.now.to_s
|
8
|
+
log[timestamp] = [] unless log[timestamp]
|
9
|
+
log[timestamp] << str
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
|
@@ -0,0 +1,119 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
class HLogger
|
4
|
+
|
5
|
+
# log on screen if filename is stdout
|
6
|
+
HLOG_MAXSIZE = 10 # 10MB
|
7
|
+
def initialize(filename, level: 'DEBUG')
|
8
|
+
@levels = self._levels
|
9
|
+
@levelToNum = self._toNum
|
10
|
+
@level = @levelToNum[level]
|
11
|
+
return if(filename == "stdout")
|
12
|
+
filename = "logger.txt" if(filename == nil)
|
13
|
+
if (File.exist?(filename) and File.size(filename).to_f / 1000000 >= HLOG_MAXSIZE)
|
14
|
+
timestamp = DateTime.now.strftime "%d-%m-%Y-%H.%M.%S"
|
15
|
+
File.rename(filename, "#{filename}.#{timestamp}")
|
16
|
+
end
|
17
|
+
@file = File.new(filename, "a+")
|
18
|
+
end
|
19
|
+
|
20
|
+
def _levels
|
21
|
+
levels = []
|
22
|
+
levels << "OFF"
|
23
|
+
levels << "FATAL"
|
24
|
+
levels << "ERROR"
|
25
|
+
levels << "WARNING"
|
26
|
+
levels << "INFO"
|
27
|
+
levels << "DEBUG"
|
28
|
+
levels << "DEBUG2"
|
29
|
+
levels << "DEBUG3"
|
30
|
+
levels << "DEBUG4"
|
31
|
+
levels << "ALL"
|
32
|
+
|
33
|
+
return levels
|
34
|
+
end
|
35
|
+
|
36
|
+
def _toNum
|
37
|
+
|
38
|
+
levelToNum = {}
|
39
|
+
self._levels.each_with_index do |level, i|
|
40
|
+
levelToNum[level] = i
|
41
|
+
end
|
42
|
+
|
43
|
+
return levelToNum
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
def toNum(strLevel)
|
48
|
+
return @levelToNum[strLevel]
|
49
|
+
end
|
50
|
+
|
51
|
+
def level(value)
|
52
|
+
|
53
|
+
return @levels[value]
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
def close
|
58
|
+
@file.close if(@file)
|
59
|
+
end
|
60
|
+
|
61
|
+
def timestamp
|
62
|
+
return DateTime.now.strftime "%d-%m-%Y %H:%M:%S"
|
63
|
+
end
|
64
|
+
|
65
|
+
# hlogger << "hello world"
|
66
|
+
# hlogger.<<("hello world", "DEBUG") # warning: if i put some space doesn't work
|
67
|
+
|
68
|
+
def << (str, level = 'DEBUG')
|
69
|
+
|
70
|
+
level = self.toNum(level) if(level.class == String)
|
71
|
+
|
72
|
+
return if(level > @level)
|
73
|
+
|
74
|
+
t = self.timestamp
|
75
|
+
strLevel = self.level(level)
|
76
|
+
if(@file)
|
77
|
+
@file << "[#{strLevel} #{t}]$ #{str}\n"
|
78
|
+
else
|
79
|
+
case self.level(level)
|
80
|
+
when "ERROR"
|
81
|
+
puts "[#{strLevel} hypersonic]$ #{str}".red
|
82
|
+
when "FATAL"
|
83
|
+
puts "[#{strLevel} hypersonic]$ #{str}".red
|
84
|
+
when "DEBUG"
|
85
|
+
puts "[#{strLevel} hypersonic]$ #{str}".green
|
86
|
+
when "WARNING"
|
87
|
+
puts "[#{strLevel} hypersonic]$ #{str}".hight_cyan
|
88
|
+
when "INFO"
|
89
|
+
puts "[#{strLevel} hypersonic]$ #{str}".hight_purple
|
90
|
+
else
|
91
|
+
puts "[#{strLevel} hypersonic]$ #{str}".white
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
return self
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
# You can use this function more beautiful than .<<(...)
|
100
|
+
|
101
|
+
def write(str, level)
|
102
|
+
self.<<(str, level)
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
|
108
|
+
|
109
|
+
def hlogger
|
110
|
+
|
111
|
+
return hsd.value("hlogger")
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
def hl
|
116
|
+
|
117
|
+
return hlogger
|
118
|
+
|
119
|
+
end
|
@@ -0,0 +1,275 @@
|
|
1
|
+
require "singleton"
|
2
|
+
|
3
|
+
class HNode
|
4
|
+
|
5
|
+
attr_reader :obj, :parentNode, :childNodes, :createTimestamp
|
6
|
+
attr_accessor :updateTimestamp
|
7
|
+
|
8
|
+
def initialize(obj, parentNode = nil, timestamp = Time.now.to_i)
|
9
|
+
@obj = obj
|
10
|
+
@createTimestamp = timestamp
|
11
|
+
@updateTimestamp = timestamp
|
12
|
+
@parentNode = parentNode
|
13
|
+
@childNodes = []
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.showObj(obj: nil, margin: 0)
|
17
|
+
if obj.class == Hash
|
18
|
+
hl.<< ' ' * margin + " => by connect: receiver: #{obj[:receiver].class} - method: #{obj[:method]}(#{obj[:args]})".green, "DEBUG2"
|
19
|
+
elsif
|
20
|
+
hl.<< ' ' * margin + " => by hm().malloc: #{obj}".green, "DEBUG2"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def showObj(margin: 0)
|
25
|
+
HNode.showObj(obj: @obj, margin: margin)
|
26
|
+
end
|
27
|
+
|
28
|
+
def show(oid: nil, margin: 0)
|
29
|
+
|
30
|
+
parentObj = @parentNode.obj if @parentNode
|
31
|
+
poid = parentObj.object_id if parentObj
|
32
|
+
str = "oid: #{oid} - #{@obj.class} - parent: #{parentObj.class} => poid: #{poid} - time: #{Time.at(@updateTimestamp).to_time.strftime("%H:%M:%S")}"
|
33
|
+
|
34
|
+
if poid
|
35
|
+
hl.<< ' ' * margin + str.yellow, "DEBUG2"
|
36
|
+
else
|
37
|
+
hl.<< ' ' * margin + str.red, "DEBUG2"
|
38
|
+
end
|
39
|
+
|
40
|
+
self.showObj(margin: margin)
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
def showTree(oid: nil, margin: 0)
|
45
|
+
self.show(oid: oid, margin: margin)
|
46
|
+
@childNodes.each do |node|
|
47
|
+
node.showTree(margin: margin + 3)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
class HMalloc
|
54
|
+
|
55
|
+
include Singleton
|
56
|
+
|
57
|
+
attr_reader :memory, :deallocated
|
58
|
+
|
59
|
+
def initialize
|
60
|
+
hl << "============== NEW HMALLOC ==============".red
|
61
|
+
@expiration = 15 * 60 # seconds
|
62
|
+
@memory = {}
|
63
|
+
@deallocated = {}
|
64
|
+
end
|
65
|
+
|
66
|
+
# poid: parent object id
|
67
|
+
def malloc(obj, poid = nil)
|
68
|
+
|
69
|
+
oid = obj.object_id
|
70
|
+
poid = poid.to_i
|
71
|
+
parentNode = @memory[poid] if poid != 0
|
72
|
+
hl.<< "WARNING malloc: poid #{poid} not found", "ERROR" if poid != 0 and !parentNode
|
73
|
+
|
74
|
+
node = HNode.new(obj, parentNode)
|
75
|
+
# Se abilita la seguente istruzione non viene deallocata la memoria
|
76
|
+
#ObjectSpace.define_finalizer(obj, proc {|objectId| hl << "Finalizer of the #{objectId}" })
|
77
|
+
|
78
|
+
hl.<< "WARNING: #{oid} already exist".red, "ERROR" if @memory.include?(oid)
|
79
|
+
@memory[oid] = node
|
80
|
+
parentNode.childNodes << node if parentNode
|
81
|
+
hl.<< "[HMalloc.malloc]#: ".yellow, "DEBUG2"
|
82
|
+
hl.<< "WARNING: No parent".red, "ERROR" if poid == 0
|
83
|
+
node.show(oid: oid, margin: 3)
|
84
|
+
|
85
|
+
return node
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
def malloc2(obj, parent = nil)
|
90
|
+
|
91
|
+
return self.malloc(obj, parent.object_id)
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
def parentOf(oid)
|
96
|
+
return @memory[oid.to_i].parentNode.obj.object_id if oid
|
97
|
+
end
|
98
|
+
|
99
|
+
def getNode(oid)
|
100
|
+
oid = oid.to_i
|
101
|
+
node = @memory[oid]
|
102
|
+
self.hotLog("ERROR: HMalloc::getNode(#{oid}): #{oid} deallocated".red) if @deallocated[oid]
|
103
|
+
return nil unless node
|
104
|
+
node.updateTimestamp = Time.now.to_i
|
105
|
+
self.getNode(node.parentNode.obj.object_id) if node.parentNode # Aggiorna updateTimestamp dei genitori
|
106
|
+
return node
|
107
|
+
end
|
108
|
+
|
109
|
+
def get(oid)
|
110
|
+
return self.getNode(oid).obj
|
111
|
+
end
|
112
|
+
|
113
|
+
def dealloc(oid, deleteFromParent = true)
|
114
|
+
return unless oid
|
115
|
+
oid = oid.to_i
|
116
|
+
node = @memory[oid]
|
117
|
+
hl << "WARNING: #{oid} not found".red unless node
|
118
|
+
self.hotLog("ERROR: HMalloc::dealloc(#{oid}): already deallocated") if @deallocated[oid]
|
119
|
+
return unless node
|
120
|
+
hl << "[HMalloc.dealloc]#:".green
|
121
|
+
node.show(oid: oid, margin: 3)
|
122
|
+
node.childNodes.clone.each do |childNode|
|
123
|
+
self.dealloc2(childNode.obj, false)
|
124
|
+
end
|
125
|
+
node.parentNode.childNodes.delete(node) if node.parentNode and deleteFromParent
|
126
|
+
@memory.delete(oid)
|
127
|
+
@deallocated[oid] = true if hsd.value("log4memory")
|
128
|
+
|
129
|
+
end
|
130
|
+
|
131
|
+
def dealloc2(obj, deleteFromParent = true)
|
132
|
+
return unless obj
|
133
|
+
return self.dealloc(obj.object_id, deleteFromParent)
|
134
|
+
end
|
135
|
+
|
136
|
+
def resetMemory()
|
137
|
+
hl << "Reset Memory ... 100%".hight_cyan
|
138
|
+
@memory = {}
|
139
|
+
end
|
140
|
+
|
141
|
+
def hotLog(str)
|
142
|
+
HHotLogger.append(str, "log4memory")
|
143
|
+
end
|
144
|
+
|
145
|
+
def clean()
|
146
|
+
|
147
|
+
#GC.start(full_mark: true, immediate_sweep: true) # Start Gargabe Collection immediately and deletes every unused memory block
|
148
|
+
#Senza l'istruzione sopra la memoria viene liberata gradualmente ad es.
|
149
|
+
# - se ho 100 blocchi di memoria non usati ne vengolo liberati solo 40 per poi liberare la restante parte in un momento successivo
|
150
|
+
# - se invece eseguo GC.start sopra con immediate_sweep: true viene liberata tutta la memoria non usata con effetto immediato
|
151
|
+
|
152
|
+
to_delete = nil
|
153
|
+
to_delete = @memory.select do |oid, node|
|
154
|
+
node.parentNode == nil and node.updateTimestamp + @expiration <= Time.now.to_i
|
155
|
+
end
|
156
|
+
hl << "[start cleaning]#: ...".hight_cyan
|
157
|
+
to_delete.each do |oid, node|
|
158
|
+
self.dealloc(oid)
|
159
|
+
end
|
160
|
+
|
161
|
+
end
|
162
|
+
|
163
|
+
def show
|
164
|
+
|
165
|
+
hl.<< "################################################################################################".hight_white, "DEBUG2"
|
166
|
+
hl.<< "# #".hight_white, "DEBUG2"
|
167
|
+
hl.<< "# Tree Hypersonic Memory Leak #".hight_white, "DEBUG2"
|
168
|
+
hl.<< "# #".hight_white, "DEBUG2"
|
169
|
+
hl.<< "################################################################################################".hight_white, "DEBUG2"
|
170
|
+
hl.<< "# #".hight_white, "DEBUG2"
|
171
|
+
hl.<< "# Visualizzazione della memoria ad albero (non compare l'oid dei figli) #".hight_white, "DEBUG2"
|
172
|
+
hl.<< "# #".hight_white, "DEBUG2"
|
173
|
+
hl.<< "# Le seguenti allocazioni di memoria possono essere generate in due modi: #".hight_white, "DEBUG2"
|
174
|
+
hl.<< "# #".hight_white, "DEBUG2"
|
175
|
+
hl.<< "# - By connect: in questo caso la tabella sotto mostra il receiver, il metodo e i parametri #".hight_white, "DEBUG2"
|
176
|
+
hl.<< "# es. tr.connect(:ondblclick, self, 'doubleClick', id: @oid, ...) #".hight_white, "DEBUG2"
|
177
|
+
hl.<< "# #".hight_white, "DEBUG2"
|
178
|
+
hl.<< "# - By malloc: in questo caso la tabella sotto mostra l'oggetto usato #".hight_white, "DEBUG2"
|
179
|
+
hl.<< "# es. @oid = hm().malloc(@modelName.clone, poid).obj.object_id.to_s #".hight_white, "DEBUG2"
|
180
|
+
hl.<< "# #".hight_white, "DEBUG2"
|
181
|
+
hl.<< "# - Le righe in rosso sono quelle senza parent (vericare che ce ne sia solo una) #".hight_white, "DEBUG2"
|
182
|
+
hl.<< "# Se ce sono piu' di una e si vuole capire da dove proviene il metodo alloc genera #".hight_white, "DEBUG2"
|
183
|
+
hl.<< "# un Warning rosso quando si esegue una malloc senza poid #".hight_white, "DEBUG2"
|
184
|
+
hl.<< "# #".hight_white, "DEBUG2"
|
185
|
+
hl.<< "################################################################################################".hight_white, "DEBUG2"
|
186
|
+
|
187
|
+
memory = @memory.sort_by { |oid, node| node.updateTimestamp }
|
188
|
+
memory.each do |oid, node|
|
189
|
+
node.showTree(oid: oid) unless node.parentNode
|
190
|
+
end
|
191
|
+
|
192
|
+
return memory
|
193
|
+
|
194
|
+
end
|
195
|
+
|
196
|
+
def showAll(sorted: false)
|
197
|
+
|
198
|
+
hl.<< "################################################################################################".hight_white, "DEBUG2"
|
199
|
+
hl.<< "# #".hight_white, "DEBUG2"
|
200
|
+
hl.<< "# Hypersonic Memory Leak #".hight_white, "DEBUG2"
|
201
|
+
hl.<< "# #".hight_white, "DEBUG2"
|
202
|
+
hl.<< "################################################################################################".hight_white, "DEBUG2"
|
203
|
+
hl.<< "# #".hight_white, "DEBUG2"
|
204
|
+
hl.<< "# Le seguenti allocazioni di memoria possono essere generate in due modi: #".hight_white, "DEBUG2"
|
205
|
+
hl.<< "# #".hight_white, "DEBUG2"
|
206
|
+
hl.<< "# - By connect: in questo caso la tabella sotto mostra il receiver, il metodo e i parametri #".hight_white, "DEBUG2"
|
207
|
+
hl.<< "# es. tr.connect(:ondblclick, self, 'doubleClick', id: @oid, ...) #".hight_white, "DEBUG2"
|
208
|
+
hl.<< "# #".hight_white, "DEBUG2"
|
209
|
+
hl.<< "# - By malloc: in questo caso la tabella sotto mostra l'oggetto usato #".hight_white, "DEBUG2"
|
210
|
+
hl.<< "# es. @oid = hm().malloc(@modelName.clone, poid).obj.object_id.to_s #".hight_white, "DEBUG2"
|
211
|
+
hl.<< "# #".hight_white, "DEBUG2"
|
212
|
+
hl.<< "# - Le righe in rosso sono quelle senza parent (vericare che ce ne sia solo una) #".hight_white, "DEBUG2"
|
213
|
+
hl.<< "# Se ce sono piu' di una e si vuole capire da dove proviene il metodo alloc genera #".hight_white, "DEBUG2"
|
214
|
+
hl.<< "# un Warning rosso quando si esegue una malloc senza poid #".hight_white, "DEBUG2"
|
215
|
+
hl.<< "# #".hight_white, "DEBUG2"
|
216
|
+
hl.<< "################################################################################################".hight_white, "DEBUG2"
|
217
|
+
usedMemory = "[Used Memory]#: #{@memory.length} blocks".hight_cyan
|
218
|
+
hl.<< "# #{usedMemory} ".hight_white, "DEBUG2"
|
219
|
+
hl.<< "################################################################################################".hight_white, "DEBUG2"
|
220
|
+
|
221
|
+
memory = (sorted) ? @memory.sort_by { |oid, node| node.updateTimestamp } : @memory
|
222
|
+
memory.each do |oid, node|
|
223
|
+
node.show(oid: oid)
|
224
|
+
end
|
225
|
+
|
226
|
+
return memory
|
227
|
+
|
228
|
+
end
|
229
|
+
|
230
|
+
def test
|
231
|
+
|
232
|
+
m = hm()
|
233
|
+
a1 = "LevelA-1"
|
234
|
+
l1 = "Level 1"
|
235
|
+
l2a = "Level 2-a"
|
236
|
+
l2b = "Level 2-b"
|
237
|
+
l2c = "Level 2-c"
|
238
|
+
l3a = "Level 3-a"
|
239
|
+
l3b = "Level 3-b"
|
240
|
+
l3c = "Level 3-c"
|
241
|
+
|
242
|
+
node = m.malloc2(l1)
|
243
|
+
m.malloc2(a1)
|
244
|
+
m.malloc2(l2a, l1)
|
245
|
+
m.malloc2(l2b, l1)
|
246
|
+
m.malloc2(l2c, l1)
|
247
|
+
m.malloc2(l3a, l2a)
|
248
|
+
m.malloc2(l3b, l2a)
|
249
|
+
m.malloc2(l3c, l2a)
|
250
|
+
|
251
|
+
m.show
|
252
|
+
sleep(3)
|
253
|
+
p m.get(l3c.object_id)
|
254
|
+
m.clean # La cancellazione avviene solo impostazione @expiration = 3 in quanto sleep = 3
|
255
|
+
m.show
|
256
|
+
|
257
|
+
end
|
258
|
+
|
259
|
+
end
|
260
|
+
|
261
|
+
def hm()
|
262
|
+
|
263
|
+
return HMalloc.instance()
|
264
|
+
|
265
|
+
end
|
266
|
+
|
267
|
+
#hm().test
|
268
|
+
|
269
|
+
#a = "herbert"
|
270
|
+
#b = "bonaffini"
|
271
|
+
#hm().malloc(a)
|
272
|
+
#hm().malloc(b)
|
273
|
+
#hm.show
|
274
|
+
|
275
|
+
|