Thread Tools Display Modes
01-31-11, 11:43 AM   #1
Zista
A Murloc Raider
 
Zista's Avatar
AddOn Author - Click to view addons
Join Date: May 2010
Posts: 5
[SOLVED] Auto-updating table

Are there any metamethods you can add to a table that will make it automatically update?

I have a table with all of the values being set to values from my SavedVariables. Is there any way to update the table automatically when the one of the SavedVariables gets changed?

I am looking for something similar to the way AceDB manages the db variables for each file in the addon (even though you are updating the local variable "db" it still updates the SavedVariables).
__________________

Last edited by Zista : 02-04-11 at 12:35 AM.
  Reply With Quote
01-31-11, 12:22 PM   #2
ravagernl
Proceritate Corporis
Premium Member
AddOn Author - Click to view addons
Join Date: Feb 2006
Posts: 1,176
You could use the metamethod __newindex, iirc
  Reply With Quote
01-31-11, 02:38 PM   #3
Zista
A Murloc Raider
 
Zista's Avatar
AddOn Author - Click to view addons
Join Date: May 2010
Posts: 5
Would that work if you had a table like:
Code:
local myTable = {
	a = db.a
	b = db.b
	c = db.c
}
where if you changed the value of db.a, myTable.a would change as well?
__________________
  Reply With Quote
02-01-11, 05:52 PM   #4
Akkorian
A Flamescale Wyrmkin
 
Akkorian's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2010
Posts: 111
Post

Hi Zista,

Unless you’re doing something really weird, why don’t you read directly from your saved variables table?

If you really want to keep two separate tables, you could set a metatable with a “__newindex” method on your saved variables table:

Lua Code:
  1. setmetatable( MySavedVar, {
  2.     __newindex = function( tbl, key, value )
  3.         MySavedVar[ key ] = value
  4.         myTable[ key ] = value
  5.     end
  6. } )
  7.  
  8. MySavedVar[ "foo" ] = "bar"
  9.  
  10. print( myTable[ "foo" ] )
  11. ==> "bar"

Or, you could write the value in both tables instead of only in one:

Lua Code:
  1. function SetNewValue( key, value )
  2.     MySavedVar[ key ] = value
  3.     myTable[ key ] = value
  4. end
  5.  
  6. SetNewValue( "foo", "bar" )
  7.  
  8. print( myTable[ "foo" ] )
  9. ==> "bar"

Or, you could set up your second table like this, storing just the key name:

Lua Code:
  1. local myTable = {
  2.     a = "foo",
  3. }
  4.  
  5. print( MySavedVar[ myTable.a ] )
  6. ==> "bar"
__________________
“Be humble, for you are made of earth. Be noble, for you are made of stars.”
  Reply With Quote
02-01-11, 08:01 PM   #5
SDPhantom
A Pyroguard Emberseer
 
SDPhantom's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 2,336
Some added information, the __newindex metamethod is only run if the table key doesn't exist already (or is nil). Also it's a good practice to avoid the standard value set "table[key]=value" on the same table the metamethod is running from. This may cause the metamethod to trigger recursively and send the scripting engine into an endless loop. To prevent this, use the rawset() function. This function exists specifically to bypass the triggering of metamethods.

Bad code:
Code:
local table=setmetatable({},{
	__newindex=function(t,k,v)
		t[k]=v;--	Causes recursive calling
	end;
});
Good code:
Code:
local table=setmetatable({},{
	__newindex=function(t,k,v)
		rawset(t,k,v);--	Bypasses metamethods and sets v directly in k of table t
	end;
});
Note: These are just examples, Lua already does this by default only if the metamethod doesn't exist. You still need to set the value yourself if you want to define this metamethod.
__________________
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 : 02-01-11 at 08:05 PM.
  Reply With Quote
02-02-11, 12:57 AM   #6
Ailae
A Rage Talon Dragon Guard
 
Ailae's Avatar
AddOn Author - Click to view addons
Join Date: Dec 2007
Posts: 318
What's the difference between __index and __newindex? On a quick glance they seem to do the same thing, run when a requested table key is nil.
__________________
Oh, the simulated horror!
  Reply With Quote
02-02-11, 06:01 AM   #7
ravagernl
Proceritate Corporis
Premium Member
AddOn Author - Click to view addons
Join Date: Feb 2006
Posts: 1,176
Originally Posted by Ailae View Post
What's the difference between __index and __newindex? On a quick glance they seem to do the same thing, run when a requested table key is nil.
__index is called when you are trying to get a table index that doesn't exist. (http://www.lua.org/pil/13.4.1.html)
__newindex is called when you are setting a table index that didn't previously exist.(http://www.lua.org/pil/13.4.2.html)

So if you want to track when a table is updated, you can view a solution for that here: http://www.lua.org/pil/13.4.4.html.

May I suggest you look at tekkub's AddOnTemplate Zista, since I'm not sure if you really need this advanced stuff. He has an elegant soltuion imho.

Last edited by ravagernl : 02-02-11 at 06:05 AM.
  Reply With Quote
02-03-11, 12:01 PM   #8
Zista
A Murloc Raider
 
Zista's Avatar
AddOn Author - Click to view addons
Join Date: May 2010
Posts: 5
I'm using oUF and have 2 separate addons. In the oUF style addon, I have a table of colors that is made up of values from the SavedVariables from the main addon. I am trying to make it so when one the the colors is changed in the options menu of the main addon, the color table gets updated in the oUF style addon. I have about 60 colors and would like to keep the code condensed as much as possible so I don't want to have each option in the main addon update both the SavedVariable and the oUF color table. I would rather have the oUF color table update automatically so that when the color table is called from it returns the current value of the SavedVariable instead of the value that the SavedVariable was when the color table was initialized.

My table currently looks like this:
Code:
local db = MyAddon.db.profile
local colors = setmetatable({
	power = setmetatable({
		["MANA"] = {tonumber(db.oUF.Colors.Power.Mana.r), tonumber(db.oUF.Colors.Power.Mana.g), tonumber(db.oUF.Colors.Power.Mana.b)},
		["RAGE"] = {tonumber(db.oUF.Colors.Power.Rage.r), tonumber(db.oUF.Colors.Power.Rage.g), tonumber(db.oUF.Colors.Power.Rage.b)},
		["FOCUS"] = {tonumber(db.oUF.Colors.Power.Focus.r), tonumber(db.oUF.Colors.Power.Focus.g), tonumber(db.oUF.Colors.Power.Focus.b)},
		["ENERGY"] = {tonumber(db.oUF.Colors.Power.Energy.r), tonumber(db.oUF.Colors.Power.Energy.g), tonumber(db.oUF.Colors.Power.Energy.b)},
		["RUNES"] = {tonumber(db.oUF.Colors.Power.Runes.r), tonumber(db.oUF.Colors.Power.Runes.g), tonumber(db.oUF.Colors.Power.Runes.b)},
		["RUNIC_POWER"] = {tonumber(db.oUF.Colors.Power.RunicPower.r), tonumber(db.oUF.Colors.Power.RunicPower.g), tonumber(db.oUF.Colors.Power.RunicPower.b)},
		["AMMOSLOT"] = {tonumber(db.oUF.Colors.Power.AmmoSlot.r), tonumber(db.oUF.Colors.Power.AmmoSlot.g), tonumber(db.oUF.Colors.Power.AmmoSlot.b)},
		["FUEL"] = {tonumber(db.oUF.Colors.Power.Fuel.r), tonumber(db.oUF.Colors.Power.Fuel.g), tonumber(db.oUF.Colors.Power.Fuel.b)},
		["POWER_TYPE_STEAM"] = {0.55, 0.57, 0.61},
		["POWER_TYPE_PYRITE"] = {0.60, 0.09, 0.17},
	}, {__index = oUF.colors.power}),
	class = setmetatable({
		["WARRIOR"] = {tonumber(db.oUF.Colors.Class.Warrior.r), tonumber(db.oUF.Colors.Class.Warrior.g), tonumber(db.oUF.Colors.Class.Warrior.b)},
		["PRIEST"] = {tonumber(db.oUF.Colors.Class.Priest.r), tonumber(db.oUF.Colors.Class.Priest.g), tonumber(db.oUF.Colors.Class.Priest.b)},
		["DRUID"] = {tonumber(db.oUF.Colors.Class.Druid.r), tonumber(db.oUF.Colors.Class.Druid.g), tonumber(db.oUF.Colors.Class.Druid.b)},
		["HUNTER"] = {tonumber(db.oUF.Colors.Class.Hunter.r), tonumber(db.oUF.Colors.Class.Hunter.g), tonumber(db.oUF.Colors.Class.Hunter.b)},
		["MAGE"] = {tonumber(db.oUF.Colors.Class.Mage.r), tonumber(db.oUF.Colors.Class.Mage.g), tonumber(db.oUF.Colors.Class.Mage.b)},
		["PALADIN"] = {tonumber(db.oUF.Colors.Class.Paladin.r), tonumber(db.oUF.Colors.Class.Paladin.g), tonumber(db.oUF.Colors.Class.Paladin.b)},
		["SHAMAN"] = {tonumber(db.oUF.Colors.Class.Shaman.r), tonumber(db.oUF.Colors.Class.Shaman.g), tonumber(db.oUF.Colors.Class.Shaman.b)},
		["WARLOCK"] = {tonumber(db.oUF.Colors.Class.Warlock.r), tonumber(db.oUF.Colors.Class.Warlock.g), tonumber(db.oUF.Colors.Class.Warlock.b)},
		["ROGUE"] = {tonumber(db.oUF.Colors.Class.Rogue.r), tonumber(db.oUF.Colors.Class.Rogue.g), tonumber(db.oUF.Colors.Class.Rogue.b)},
		["DEATHKNIGHT"] = {tonumber(db.oUF.Colors.Class.DeathKnight.r), tonumber(db.oUF.Colors.Class.DeathKnight.g), tonumber(db.oUF.Colors.Class.DeathKnight.b)},
	}, {__index = oUF.colors.class}),
	happiness = setmetatable({
		[1] = {tonumber(db.oUF.Colors.Happiness.Happiness1.r), tonumber(db.oUF.Colors.Happiness.Happiness1.g), tonumber(db.oUF.Colors.Happiness.Happiness1.b)},
		[2] = {tonumber(db.oUF.Colors.Happiness.Happiness2.r), tonumber(db.oUF.Colors.Happiness.Happiness2.g), tonumber(db.oUF.Colors.Happiness.Happiness2.b)},
		[3] = {tonumber(db.oUF.Colors.Happiness.Happiness3.r), tonumber(db.oUF.Colors.Happiness.Happiness3.g), tonumber(db.oUF.Colors.Happiness.Happiness3.b)},
	}, {__index = oUF.colors.happiness}),
	runes = setmetatable({
		[1] = {tonumber(db.oUF.Colors.Runes.Rune1.r), tonumber(db.oUF.Colors.Runes.Rune1.g), tonumber(db.oUF.Colors.Runes.Rune1.b)},
		[2] = {tonumber(db.oUF.Colors.Runes.Rune2.r), tonumber(db.oUF.Colors.Runes.Rune2.g), tonumber(db.oUF.Colors.Runes.Rune2.b)},
		[3] = {tonumber(db.oUF.Colors.Runes.Rune3.r), tonumber(db.oUF.Colors.Runes.Rune3.g), tonumber(db.oUF.Colors.Runes.Rune3.b)},
		[4] = {tonumber(db.oUF.Colors.Runes.Rune4.r), tonumber(db.oUF.Colors.Runes.Rune4.g), tonumber(db.oUF.Colors.Runes.Rune4.b)},
	}, {__index = oUF.colors.runes}),
	totembar = setmetatable({
		[1] = {tonumber(db.oUF.Colors.Totems.Fire.r), tonumber(db.oUF.Colors.Totems.Fire.g), tonumber(db.oUF.Colors.Totems.Fire.b)},
		[2] = {tonumber(db.oUF.Colors.Totems.Earth.r), tonumber(db.oUF.Colors.Totems.Earth.g), tonumber(db.oUF.Colors.Totems.Earth.b)},		
		[3] = {tonumber(db.oUF.Colors.Totems.Water.r), tonumber(db.oUF.Colors.Totems.Water.g), tonumber(db.oUF.Colors.Totems.Water.b)},
		[4] = {tonumber(db.oUF.Colors.Totems.Air.r), tonumber(db.oUF.Colors.Totems.Air.g), tonumber(db.oUF.Colors.Totems.Air.b)},	
	}, {__index = oUF.colors.totembar}),
}, {__index = oUF.colors})
At some point I will go back through and change the colors to be unpackable instead of having separate r, g, and b values
__________________

Last edited by Zista : 02-03-11 at 12:59 PM.
  Reply With Quote
02-03-11, 01:44 PM   #9
Zista
A Murloc Raider
 
Zista's Avatar
AddOn Author - Click to view addons
Join Date: May 2010
Posts: 5
Solved it.

I used the __index metamethod to return the value from the SavedVariables and just left the table more or less blank.

EX:
Code:
local db = MyAddon.db.profile
local colors = setmetatable({
	power = setmetatable({
	}, {
		__index = function(t, k)
			local color = db.oUF.Colors.Power[k]
			return color and {tonumber(color.r), tonumber(color.g), tonumber(color.b)} or oUF.colors.power[k]
		end
	})
}, {__index = db.oUF.Colors or oUF.colors})
__________________
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » Auto-updating table


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