Ruby - Array value is stored with a different Unicode character - ruby-on-rails

Ruby is storing array value as ["118\u001F119"] as a result I'm unable to get the first index value.
Any idea how I can retrieve the value properly?
prov = $evm.root['miq_provision_request'] || \
$evm.root['miq_provision'] || \
$evm.root['miq_provision_request_template']
job_template_array = prov.get_option_array(:job_template_id)
job_template_array = job_template_array[0]
#handle.log(:info, "job_template_by_id is #{job_template_array}")
Here is the output when I try to get the first index.
[----] I, [2022-07-06T09:05:14.492607 #314:2aad21d5b6fc] INFO -- automation: Q-task_id([r745_miq_provision_1962]) <AEMethod launch_ansible_job> job_template_by_id is 118▼119
Here is what the function looks like.
def self.get_option_array(key, value, from)
# Return value - Support array and non-array types
data = value || from[key]
Array.wrap(data)
end

Related

Table is both nil and not nil at the same time

For some reason, when I access only my main table, it's fine, but when I try to access it using a variable, it's somehow nil?
Here's the function that's giving the error:
function parseMtl(mtlFilePath, mtlTbl) -- Parses the mtl file at mtlFIlePath
local step1 = {} -- Table to store the split lines
local mtlID = 0 -- The ID of the material
local mtlList = {} -- The list of materials
local faceColors = {} -- The returned colors of the polygons
local fC -- A test variable
contents, size = love.filesystem.read(mtlFilePath, all) -- Read the .mtl file at mtlFilePath
step1 = split(contents, "\n") -- Split the contents into step1 by the newline character
for i=1,#step1 do
if (starts(step1[i], "newmtl")) -- Create a new material
then
mtlID = mtlID + 1
mtlName = split(step1[i], "%s")[2]
table.insert(mtlList, {mtlName, mtlID})
end
if (starts(step1[i], "Kd")) -- If it's a color value, put value into the list of materials
then
R = split(step1[i], "%s")[2] * 255
G = split(step1[i], "%s")[3] * 255
B = split(step1[i], "%s")[4] * 255
table.insert(mtlList[mtlID], {R, G, B})
end
for i=1,#mtlTbl do -- Convert the mtlTbl values into 'Vertex ID, Color' format
fC = mtlList[mtlTbl[i][2]]
table.insert(faceColors, {i, fC})
end
end
return faceColors
end
The part that's doing weird stuff is the table.insert(faceColors, {i, fC}), it's somehow returning nil when I put fC in a table, when I print the fC value directly it's not nil. I have no idea why it's doing this..
Were you trying to use the return value of table.insert?
table.insert is void, so it always returns nil.
How are you accessing your color data?
The way you set up your data, you would access it with:
local faceColors = parseMtl(...)
for i = 1, #faceColors do
print(faceColors[i][2])
end

Append elements to a Lua table from variables / Clearing a Lua table

I make a function to parsing path name and file name from a computer directory using Lua Cheat Engine, next I want store the results in to a Lua table.
My function :
function addSongList()
load_dialog = createOpenDialog(self)
load_dialog.InitalDir = os.getenv('%USERPROFILE%')
load_dialog.Filter = 'MP3 files|*.mp3|*'
load_dialog.execute()
file = load_dialog.FileName
if file then
--- parsing path and filename
local pathN = file:match("(.*[\\/])")
local path, name = file:match('(.*\\)(.*)%.mp3')
--- test to open E:\MyMP3\mysong.mp3
print(pathN) --- result : E:\MyMP3\
print(name) --- result : mysong.mp3
end
end
local mp3Table = {}
table.insert(mp3Table,{pathN,name})
Is this correct way and correct syntax using table.insert(mp3Table,{pathN,name})
How to check if elements already added to the table by print out them?
How to clearing / empty the table ?
Thank you
1 - Inserting to the table:
table.insert(tb, value) inserts the value to de table tb. Using table.insert(mp3Table,{pathN,name}) you are dynamically creating a (sub)table and then appending to the main one.
2 - Printing the table.
As already pointed out you can just traverse the table using pairs or ipairs in order to get the elements.
I prefer ipairs in this case because the table is numerically indexed and order is guaranteed in accordance to table.insert.
The inner table must be indexed by numbers because you created it usign numeric indices.
for k, v in ipairs(mp3Table) do
print(v[1], v[2])
end
But you can also opt for a metatable which will also give you the possibility to generate a string representation for the table:
mp3Table_mt =
{
__tostring = function(self)
local ret = {}
for k, v in ipairs(self) do
table.insert(ret, v[1] .. "\t" .. v[2])
end
return table.concat(ret, "\n")
end
}
When initializing mp3Table you have to assign the metatable
local mp3Table = setmetatable({}, mp3Table_mt)
Then you can just tell Lua to print the table:
print(mp3Table)
3 - Empty/Delete the table:
Well there are two different things here. One is empty another is delete.
Lua uses garbage collection so actual deleting only occurs when there are no more references to a particular table. What you can do to tell Lua you no longer need a variable is assing nil to it. If there is no other reference to the value your variable was pointing to, the GC will clean it when it runs.
But you can empty the table without deleting it.
It may be tempting to say that mp3Table = {} "empties the table". But it does not.
What you are doing in this case is assigning a fresh new table to mp3Table variable. And if any other variable is still pointing to the old table it will no get collected and the inner values will remain untouched. If there's no such other variable, the table will be garbage collected just as if you assigned nil to mp3Table variable.
So to effectivelly empty a table you have to traverse it and set all its variables to nil.
function clearTable(tb)
for i, v in pairs(tb) do
tb[i] = nil
end
end
Specifically in the case asked, just assigning a new table to mp3Table may be enough because there are no more references to the same table. Assign nil afterwards is not necessary. What matters is if there are variables pointing to the same value. If you know what you are doing and the consequenses then no problem go ahead.
Putting it all together:
mp3Table_mt =
{
__tostring = function(self)
local ret = {}
for k, v in ipairs(self) do
table.insert(ret, v[1] .. "\t" .. v[2])
end
return table.concat(ret, "\n")
end
}
function addSongList(mp3Table)
local load_dialog = createOpenDialog(self)
load_dialog.InitalDir = os.getenv('%USERPROFILE%')
load_dialog.Filter = 'MP3 files|*.mp3|*'
load_dialog.execute()
file = load_dialog.FileName
if file then
--- parsing path and filename
local pathN = file:match("(.*[\\/])")
local path, name = file:match('(.*\\)(.*)%.mp3')
--- test to open E:\MyMP3\mysong.mp3
print(pathN) --- result : E:\MyMP3\
print(name) --- result : mysong.mp3
table.insert(mp3Table,{pathN,name})
end
return mp3Table
end
function clearTable(tb)
for i, v in pairs(tb) do
tb[i] = nil
end
end
local mp3Table = setmetatable({}, mp3Table_mt)
print(addSongList(mp3Table))
clearTable(mp3Table) -- I'm not assigning a new one. Just clearing the fields.
print(mp3Table) -- Must print nothing
1)yes
2)printing table in cycle:
for k,v in pairs(mp3Table) do
print( v.pathN, v.name)
end
3)empty table
mp3Table = {} -- clean
mp3Table = nil -- delete

Slplit IPv4 address to minimum and maximum range

Using Lua how do I split a given IP address to get the minimum and maximum range for example:
94.19.21.119
I have a csv like this:
18087936,18153471,"AU"
18153472,18219007,"JP"
18219008,18350079,"IN"
18350080,18874367,"CN"
thats read to 3 tables and the csv is min,max,country code:
IPfrom = {}
IPto = {}
IPCountry = {}
they get populated like this:
IPfrom[18087936] = L
IPto[L] = 18153471
IPCountry[L] = "AU"
with L being the line number of the io.read, what Im then trying to do is get the minimum range so I can without looping check if it exists then if it does that key holds the index of the maximum range and if the ip is within the min/max I get the country code. Probably a different way of doing things but the tables are over 100000 entries so looping is taking some time.
Perhaps something like the following will work for you:
--
-- Converts an IPv4 address into its integer value
--
function iptoint(ip)
local ipint = 0
local iter = string.gmatch(ip, "%d+")
for i = 3, 0, -1 do
local piece = tonumber(iter())
if piece == nil or piece < 0 or piece > 255 then
return nil
end
ipint = bit32.bor(ipint, bit32.lshift(piece, 8 * i))
end
return ipint
end
--
-- Looks up an IPv4 address in a multidimensional table, with the entries:
-- {start_address, end_address, country}
-- and returns the matching country
--
function iptocountry(ip, tbl)
local ipint = iptoint(ip)
if ipint == nil then
return nil
end
for _,v in pairs(tbl) do
if ipint >= v[1] and ipint <= v[2] then
return v[3]
end
end
return nil
end
Example usage:
local countries = {
{16777216, 17367039, "US"},
{1578300000, 1678300000, "CAN"}
-- ... rest of entries loaded from CSV file
}
local ip = "94.19.21.119"
print (iptocountry(ip, countries)) -- prints CAN
A hash table (the basic type in Lua) will give you O(N). An array (a table with no holes with indices from someMinAddr to someMaxAddr) will give you O(1), but use a significant amount of memory. A binary search through a properly sorted structured table could give you O(log N), which for 100000 addresses is probably worth the effort. I imagine you could have a structure like this:
IPfrom = {
{line=L1, addFrom=from1, addrTo=to1, c=country1},
{line=L2, addFrom=from2, addrTo=to2, c=country2},
{line=L3, addFrom=from3, addrTo=to3, c=country3},
{line=L4, addFrom=from4, addrTo=to4, c=country4},
...
}
because I don't see the point of separating the to and country fields from the other info, just means more table lookup. Anyways if you really do want to separate them the following is not affected:
-- init:
create table from CSV file
sort IPFrom on addFrom field
-- as many times as required:
function findIP(addr)
is addr smaller than IPfrom[middle].addrTo3?
if yes, is addr smaller than IPfrom[middle of middle]?
etc
end
This is recursive so if you structure it properly you can use tail calls and not worry about stack overflow (;), something like
function findIPRecurs(addr, ipTbl, indxMin, indxMax)
local middle = (indxMin + indxMax )/2
local midAddr = ipTbl[middle].addrFrom
if addr < midAddr then
return findIPRecurs(addr, ipTbl, indxMin, middle)
else if addr > midAddr then
return findIPRecurs(addr, ipTbl, middle, indxMax)
else -- have entry:
return middle
end
end
function findIP(addr)
return findIPRecurs(addr, ipTbl, 1, #ipTbl)
end
I have not tested this so there might be some fixing up to do but you get the idea. This will use the same memory as O(N) method but for large arrays will be considerably faster; much less memory than O(1) method, and probably acceptably slower.

lua Hashtables, table index is nil?

What I'm currently trying to do is make a table of email addresses (as keys) that hold person_records (as values). Where the person_record holds 6 or so things in it. The problem I'm getting is that when I try to assign the email address as a key to a table it complains and says table index is nil... This is what I have so far:
random_record = split(line, ",")
person_record = {first_name = random_record[1], last_name = random_record[2], email_address = random_record[3], street_address = random_record[4], city = random_record[5], state = random_record[6]}
email_table[person_record.email_address] = person_record
I wrote my own split function that basically takes a line of input and pulls out the 6 comma seperated values and stores them in a table (random_record)
I get an error when I try to say email_table[person_record.email_address] = person_record.
But when I print out person_record.email_address it's NOT nil, it prints out the string I stored in it.. I'm so confused.
function split(str, pat)
local t = {} -- NOTE: use {n = 0} in Lua-5.0
local fpat = "(.-)" .. pat
local last_end = 1
local s, e, cap = str:find(fpat, 1)
while s do
if s ~= 1 or cap ~= "" then
table.insert(t,cap)
end
last_end = e+1
s, e, cap = str:find(fpat, last_end)
end
if last_end <= #str then
cap = str:sub(last_end)
table.insert(t, cap)
end
return t
end
The following code is copy and pasted from your example and runs just fine:
email_table = {}
random_record = {"first", "second", "third"}
person_record = {first_name = random_record[1], last_name = random_record[1], email_address = random_record[1]}
email_table[person_record.email_address] = person_record
So your problem is in your split function.
BTW, Lua doesn't have "hashtables". It simply has "tables" which store key/value pairs. Whether these happen to use hashes or not is an implementation detail.
It looks like you iterating over some lines that have comma-separated data.
Looking at your split function, it stops as soon as there's no more separator (,) symbols in particular line to find. So feeding it anything with less than 3 ,-separated fields (for very common example: an empty line at end of file) will produce a table that doesn't go up to [3]. Addressing any empty table value will return you a nil, so person_record.email_address will be set to nil as well on the 2nd line of your code. Then, when you attempt to use this nil stored in person_record.email_address as an index to email_table in 3rd line, you will get the exact error you've mentioned.

Lua: Is there a way to concatenate "nil" values?

I have the following function in Lua:
function iffunc(k,str,str1)
if k ~= 0 then
return str .. k .. (str1 or "")
end
end
This function allows me to check if value k is populated or not. I'm actually using it to determine if I want to display something that has zero value. My problem is this: I'm trying to concatenate a string of iffunc(), but since some of the values are 0, it returns an error of trying to concatenate a nil value. For instance:
levellbon = iffunc(levellrep["BonusStr"],"#wStr#r{#x111","#r}") .. iffunc(levellrep["BonusInt"],"#wInt#r{#x111","#r}") .. iffunc(levellrep["BonusWis"],"#wWis#r{#x111","#r}")
If any of the table values are 0, it'll return the error. I could easily put 'return 0' in the iffunc itself; however, I don't want a string of 000, either. So how can I work it where no matter which values are nil, I won't get that error? Ultimately, I'm going to do an iffunc on the levellbon variable to see if that's populated or not, but I've got that part figured out. I just need to get past this little hurdle right now. Thanks!
I'd do this:
function iffunc(k,str,str1)
if k == 0 then return "" end
return str .. k .. (str1 or "")
end
You should add an else statement in the function, where you return an empty string ("").

Resources