Thread Tools Display Modes
10-16-11, 12:24 PM   #1
Wurstmann
A Murloc Raider
Join Date: Sep 2011
Posts: 5
Setting nested table keys dynamically (don't know how to call it)

Hello!

What i'm trying to do is, create different options for my addon for many different elements and AceDB should store those options in a variable looking something like this:
Code:
options = {
  showInCombat = true,
  icons = {
    width = 20,
    height = 20,
  },
  bars = {
    width = 200,
    height = 30,
    bar1 = {
      color = "green",
    },
    bar2 = {
      color = "red",
    },
  },
}
but currently it still looks like this:
Code:
options = {
  showInCombat = true,
  iconWidth = 20,
  iconHeight = 20,
  barWidth = 200,
  barHeight = 30,
  bar1Color = "green",
  bar2Color = "red",
}
Right now i have following 'set' (AceConfig) function:
Code:
function addon:SetSliderValue(info, value)
	local key = info[#info];

	db[key] = value;
end
"key" would be something like bar1Color, barWidth and so on, the variable name that will be filled with the value that got changed.
But i think it would look better and be more organized if all the options for the specific elements would be grouped together in nested tables.
My problem is, i don't know how to rewrite the 'set' function to do that.
I need something like this:
Code:
function addon:SetSliderValue(info, value)
	local rootNode = info[1]; -- "bar"
	local secondNode = info[2]; -- "bar1";
	local thirdNode = info[3]; -- "color";

	-- db[rootNode][secondNode][thirdNode] = value;
	-- db.rootNode.secondNode.thirdNode = value;

end
And this part is where i don't know how to do it.
I searched on google but didn't really know what to search for, so came up with nothing related to my problem.
Is this somehow possible? Is this even a good idea?
Or should i create a new function for every "layer", db.bars[key] = value, db.bars.bar1[key] = value and so on?
But one function would be so much simpler to maintain... :O
  Reply With Quote
10-16-11, 12:44 PM   #2
Xrystal
nUI Maintainer
 
Xrystal's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Feb 2006
Posts: 5,935
I'm pretty sure I have that type of thing in one of my addons on my desktop. When I get back home after the weekend I'll take a look if no one has replied by then.
__________________


Characters:
Gwynedda - 70 - Demon Warlock
Galaviel - 65 - Resto Druid
Gamaliel - 61 - Disc Priest
Gwynytha - 60 - Survival Hunter
Lienae - 60 - Resto Shaman
Plus several others below level 60

Info Panel IDs : http://www.wowinterface.com/forums/s...818#post136818
  Reply With Quote
10-16-11, 02:12 PM   #3
Wurstmann
A Murloc Raider
Join Date: Sep 2011
Posts: 5
Ok after some more testing and trying i think i figured it out
Code:
if(#info > 1) then                         -- if it has 'child nodes'
	local writeTo = db[info[1]];    -- set it to the root node
	
	for i=2, #info-1 do                    -- for every child node
		writeTo = writeTo[info[i]];   -- go one step deeper into the 'tree'
	end
	
	writeTo[info[#info]] = value;       -- set the last node to the value
else                                           -- it doesn't have child nodes
	db[info[1]] = value;             -- just set it normally
end
I guess it works because by assigning an existing table (in this case the database with all the options) to 'writeTo' the variable doesn't get a copy of the table, but a reference to it, something similar to a pointer in C with the memory adress like {ff0e0394} (i'm not a c programmer so correct me if im wrong). And when we assign a value to a key in writeTo, the ACTUAL table gets modified.
Something like that...
But maybe theres something simpler than that, so if you know it, let me know

Edit: now cleaner simpler code!
Code:
local writeTo = db;

for i=1, #info-1 do
	writeTo = writeTo[info[i]];
end

writeTo[info[#info]] = value;

Last edited by Wurstmann : 10-16-11 at 02:48 PM.
  Reply With Quote
10-17-11, 08:13 PM   #4
SDPhantom
A Pyroguard Emberseer
 
SDPhantom's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 2,327
It would be an easy thing to do with metatables.

Code:
local table=setmetatable({},{__index=function(t,k)
	t[k]=setmetatable({},getmetatable(t));
	return t[k];
end});
- or -
Code:
local table={};
setmetatable(table,{__index=function(t,k)
	t[k]=setmetatable({},getmetatable(t));
	return t[k];
end});

Here's how it works. The __index metamethod is called/used when the index doesn't exist. This can be a function to deal with it or another table to grab values from. The value returned from the function is passed back as the value for the associated key. When a table is provided, it looks up the key in the table and returns its value.

In this case, we have a function to create a new table and propagate itself to it. The first line creates the table and sets it to the key provided. The second line returns the table after it has been set. The return is still required even though the value is now set.



If the table is not empty when the metatable is set, it will not apply to any existing table values. To do this, I'll post some experimental code that'll handle this. Just put this somewhere and call CreateDynamicStructure() on the table. It works recursively without increasing the call stack any further than needed.

lua Code:
  1. do
  2.     local meta;--   This value prototype will allow propagation
  3.     meta={__index=function(t,k)
  4.         t[k]=setmetatable({},meta);
  5.         return t[k];
  6.     end};
  7.  
  8.     local buffer={};
  9.     function CreateDynamicStructure(tbl)
  10.         table.insert(buffer,tbl);
  11.         while #buffer>0 do
  12.             local val=buffer[1];
  13.             for i,j in pairs(val) do
  14.                 if type(j)=="table" then
  15.                     table.insert(buffer,j);
  16.                 end
  17.             end
  18.             setmetatable(val,meta);
  19.             table.remove(buffer,1);
  20.         end
  21.         return tbl;
  22.     end
  23. end
__________________
WoWInterface AddOns
"All I want is a pretty girl, a decent meal, and the right to shoot lightning at fools."
-Anders (Dragon Age: Origins - Awakening)

Last edited by SDPhantom : 10-17-11 at 08:42 PM.
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » Setting nested table keys dynamically (don't know how to call it)


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off