Download
(4 Kb)
Download
Updated: 08/11/14 09:17 AM
Compatibility:
Update 3 (1.3.3)
Updated:08/11/14 09:17 AM
Created:07/10/14 04:51 AM
Monthly downloads:31
Total downloads:3,681
Favorites:0
MD5:
LibConstantMapper
Version: 0.7
by: zgrssd [More]
It is easy to figure out wich value a known constant has at runtime - you use it, you get the value.
However it is not easy to figure out wich value corresponds to wich Constant (Global Table Key)
This library deals with the plumbing: It goes over the entire global table and does string pattern matching. It then returns those Constant names and thier values in a easy to itterate over, int indexed table.
For added convinience it can also create you a value-indexed table from those results.

LibConstantMapper API
:getDataByMapping(map_name, rebuildCache)
Returns
If a map of this name exists it will do 1-2 things:
If no cache exists or rebuidChache is true, it will build the cache from scratch by itterating over the global table, sort the result by value first and then store it in the cache.
In any case it will return a deep copy of whatever the cache contains now.
Arguments
map_name
Name of the mapping. As defined durign registering and retrieved by listMaps
(optional)rebuildCache
If this parameter is true an existing cache for this mapping will be discarded and the data will be read in from the global table again.
Note: The prefered way of getting data since implemented in 0.2.


:getMappedData(pattern [, exclude])
Returns
A well formed array containing all the Keys and thier values that match pattern, but do not match exclude. Due to the nature of the source and extraction, no guarantees over the order of the key/value pairs or thier uniqueness of each value can be given (that is entirely up to the data, what order pairs uses today and the two patterns given).
Arguments
pattern
The string pattern that has to match for the key/value to land in the output
exclude
(Optional) another string pattern. If an global table entry matches the pattern and the exclude pattern, it is not included in the output (see the example case below)
:getValIndexedKeyList(input [, noDuplicateAssertion])
Returns
A table that uses the Values's as indexes and the keys as values. Thus allows quick value->key mapping. The input table is itterated via ipairs, so the result should be deterministic (if you should be using the noDuplicateAssertion override).
No guarantee that the keys are consecutive can be made (this depends entirly on the input).
Throws
An assertion error if the same a value has already been used as index. This error implies that something in the input is wrong - usually that the pattern/exclude combo is somehow not excluding everything it should. Thus resulting in the same value being more then once in the input table.
Arguments
input
The return values of a getDataByMapping() or getMappedData() should be given here.
But every table that can be itterated over with ipairs and contains nested tables with key&value indexes should be just as valid.
noDuplicateAssertion
Normally the function will throw an exception if it finds the same value a second time (and thus tries to write the same index again). If this is set to true, it will instead ignore the problem and overwrite the old value of the index.
Use at own risk: Duplicate values mean either you should not use this function on the data in the first place, or that something with the retrieval patterns is wrong. Supressing the assertion could lead to unforseen consequences down the road.


Maps
Having the right pattern/exclude pair to feed to getMappedData can be an issue. So I provided several pre-written patterns to feed it. Each of those is called a "map". The maps are provided as part of the addons main file.
Additional maps can be registered at runtime.

:listMaps()
Returns
The names of all the currently registered maps, wheter they are defined with the library or registered by other code.
:addMap(map, pattern [, exclude])
Arguments
map
A unique string that identifies this mapping. If a map with this value already exists, it is overwritten and it's cached values are discared.
pattern
The pattern associated with this map
exlcude
(Optional)The exclude pattern associated with this map

:getMap(map)
Returns
A table containing the pattern and exlucde entires under correspondingly named keys.
Arguments
map
The string that identifies the map, as given under addMap


Example Case (Chat Categories)
Unified Chat Tabs has been using the int ID of the categoreis during storage, but I realised this was flawed: If the order of categories changed after a update it would assign the wrong color data to the categories and enable/disable the wrong categories on each tab.
I needed to know wich Constant Name/Global Table Key related to wich Chat Category Number as I intended to use the Constants Name/Key during storage. And I needed that data at runtime, not compile time (after all I expected them to change with updates and the code had to react instantly).
The data looked like this at the time:
CHAT_CATEGORY_COMBAT_ALLIANCE_POINTS = 48
CHAT_CATEGORY_COMBAT_BATTLE_TOKENS = 46
CHAT_CATEGORY_COMBAT_BLOCK_ABSORBED_DEFEND = 58
CHAT_CATEGORY_COMBAT_DEATH = 61
CHAT_CATEGORY_COMBAT_DIRECT_DAMAGE = 51
CHAT_CATEGORY_COMBAT_DIRECT_HEAL = 53
...
CHAT_CATEGORY_HEADER_CHANNELS = 1
CHAT_CATEGORY_HEADER_COMBAT = 45
CHAT_CATEGORY_HEADER_GUILDS = 10

...
CHAT_CATEGORY_ZONE = 6
CHAT_CATEGORY_ZONE_ENGLISH = 20
CHAT_CATEGORY_ZONE_FRENCH = 21
CHAT_CATEGORY_ZONE_GERMAN = 22

Wich added the issue that it contained 3 entries I did not want - CHAT_CATEGORY_HEADER - because they were duplicate values and unrelated to my case.
Garkin pointed me out that if I find all that match "^CHAT_CATEGORY_" but exclude all that match "^CHAT_CATEGORY_HEADER" I would get exactly the data I wanted.

thus calling
:getMappedData("^CHAT_CATEGORY_", "^CHAT_CATEGORY_HEADER")
get's you an array looking like this (order is not guaranteed):
[1]
["key"] = "CHAT_CATEGORY_COMBAT_ALLIANCE_POINTS"
["value"] = 48
[2]
["key"] = "CHAT_CATEGORY_COMBAT_BATTLE_TOKENS"
["value"] = 46
[3]
["key"] = "CHAT_CATEGORY_COMBAT_BLOCK_ABSORBED_DEFEND"
["value"] = 58
[4]
["key"] = "CHAT_CATEGORY_COMBAT_DEATH"
["value"] = 61
[5]
["key"] = "CHAT_CATEGORY_COMBAT_DIRECT_DAMAGE"
["value"] = 51
[6]
["key"] = "CHAT_CATEGORY_COMBAT_DIRECT_HEAL"
["value"] = 53
...
[38]
["key"] = "CHAT_CATEGORY_ZONE"
["value"] = 6
[39]
["key"] = "CHAT_CATEGORY_ZONE_ENGLISH"
["value"] = 20
[40]
["key"] = "CHAT_CATEGORY_ZONE_FRENCH"
["value"] = 21
[41]
["key"] = "CHAT_CATEGORY_ZONE_GERMAN"
["value"] = 22
Feeding it to getMappedData would get you a table looking like this (keys will not be continous, as there are only 41 Constants/Keys that map to channel ID's. But there are 61 Channel ID's (so 20 remain unused)):
[1] = "CHAT_CATEGORY_SAY"
[2] = "CHAT_CATEGORY_YELL"
[3] = "CHAT_CATEGORY_WHISPER_INCOMING"
[4] = "CHAT_CATEGORY_WHISPER_OUTGOING"
...
[58] = "CHAT_CATEGORY_COMBAT_BLOCK_ABSORBED_DEFEND"
[59] = "CHAT_CATEGORY_COMBAT_RESIST"
[60] = "CHAT_CATEGORY_COMBAT_OTHER"
[61] = "CHAT_CATEGORY_COMBAT_DEATH"
v0.7:
Fixed an issue with the no Duplicate Assertion in "getValIndexedKeyList". The error message will now be created with help of the tostring() function to always get valid strings from the input.
The cache table now only keeps weak references to it's data, so the entire cache can now be garbage collected if the memory is needed.
Fixed an issue with the Events Mapping: It was accidently including the EVENT_MANAGER. Still having unwanted entries among the events however. It is not reliable until I implement multiple-exclusion patterns.
Removed all subevent mappings as they were incomplete anyway.
Added TradingHouseFilterTypes to the pre-made mappings
Bumped API version for Stand Alone installations

v0.6:
Added the two new mappings for ^Zo and ^ZoFont
Rewrote the compare function so it no longer tries to compare the type userdata (it will order by key in case at least one value is of this type).

v0.5:
Added Caching:
getDataByMapping will now use caching. The cache can be forced to be rebuild using a boolean argument
addMap will delete the cache on regsitering a map, in case previous cached results exist.
Bumped the version number transmitted to LibStub to 0.5
Added Slash Command /libCM to quickly run getDataByMapping from chat. So far only the mapping name can be specified.

v0.4:
Embedded updated version of LibStub
Added sorting to the output of "getDataByMapping"
Added a mapping for the new bind type enumeration that is on the PTS right now.
Note: I was stupid again and forgot to bump the LibStub version with this release too. It is still 0.2

v0.3:
added "getValIndexedKeyList" function. This will get you a list of the keys indexed by thier values, to quickly map a key to any given value.
Note: Apparently I was beign stupid and forgot to bump the LibStub version with this release

v0.2:
Rolled the pre-defined mappings fully into the primary file
Added "getDataByMapping" to directly get data via the name of it's mapping. This will be the new default way to get data if a mapping exists.
ListMaps now only returns the mapping names in an array, not the full array of mappings.

v0.1:
First test release.
If you still have it, please delete it. Due to some mistakes from me when using LibStub it would overwrite every version short of a 1.1 (if there ever is one).
Also the ...mappings.lua no longer exists after this version, making the file useless.
Optional Files (0)


Archived Files (6)
File Name
Version
Size
Uploader
Date
0.6
4kB
zgrssd
07/19/14 01:56 AM
0.5
4kB
zgrssd
07/18/14 09:34 AM
0.4
4kB
zgrssd
07/18/14 02:15 AM
0.3
3kB
zgrssd
07/13/14 05:54 AM
0.2
3kB
zgrssd
07/11/14 12:13 PM
0.1
3kB
07/10/14 04:51 AM


Post A Reply Comment Options
Unread 04/27/16, 05:05 PM  
calia1120
 
calia1120's Avatar
AddOn Author - Click to view AddOns

Forum posts: 62
File comments: 232
Uploads: 5
Re: Unified chat tabs error

Originally Posted by MK32
Unified chat tabs addon has an error that seems to point to this lib. Is this a fault of this lib or the addon?

2016-03-07T14:06:36.436-06:00 |cff0000Lua Error: Key: '2' contains the duplicate value '1'
stack traceback:
[C]: in function 'assert'
user:/AddOns/UnifiedChatTabs/libs/LibConstantMapper.lua:47: in function 'lib:getValIndexedKeyList'
user:/AddOns/UnifiedChatTabs/UCT_main.lua:272: in function 'OnAddOnLoaded'|r

Edit: It looks like the TG patch changed the key structure. Is there a fix?
The issue lies with the library. I commented out lines 47 & 48 of LibConstantMapper.lua, and it doesn't appear to impact the functionality. I'm still able to add new tabs and they're showing up properly across all characters.
Report comment to moderator  
Reply With Quote
Unread 04/05/16, 12:59 PM  
MK32

Forum posts: 0
File comments: 120
Uploads: 0
Unified chat tabs error

Unified chat tabs addon has an error that seems to point to this lib. Is this a fault of this lib or the addon?

2016-03-07T14:06:36.436-06:00 |cff0000Lua Error: Key: '2' contains the duplicate value '1'
stack traceback:
[C]: in function 'assert'
user:/AddOns/UnifiedChatTabs/libs/LibConstantMapper.lua:47: in function 'lib:getValIndexedKeyList'
user:/AddOns/UnifiedChatTabs/UCT_main.lua:272: in function 'OnAddOnLoaded'|r

Edit: It looks like the TG patch changed the key structure. Is there a fix?
Last edited by MK32 : 04/05/16 at 01:04 PM.
Report comment to moderator  
Reply With Quote
Unread 07/17/14, 03:18 AM  
zgrssd
AddOn Author - Click to view AddOns

Forum posts: 280
File comments: 26
Uploads: 3
A wonderfull example as to why this library is usefull just poppoed up in the PTS Changenotes 1.3:
Added BIND_TYPE Enumeration

Returned by GetItemLinkBindType.

Values for all enumerations are listed in the full API documentation. Search for the enumeration prefix (for example, BIND_TYPE).
So apparently those "groups of similary named Constants" are thier way to make enumerations.

All I have to do now is add a pattern that matches for "BIND_TYPE_".

This also gives me a better name for a later version:
EnumHarvester perhaps?
Report comment to moderator  
Reply With Quote
Unread 07/14/14, 06:58 AM  
zgrssd
AddOn Author - Click to view AddOns

Forum posts: 280
File comments: 26
Uploads: 3
Re: Re: Re: That's kind of why symbols exist in the first place

Originally Posted by LoquaciousAndroid
Code:
if(mysteriousValue == CHAT_CATEGORY_SAY) then
    DoWhatYouNeedForSay(...)
end
That's what I am talking about...you already know that mysteriousValue MUST be some kind of chat category, otherwise you wouldn't have registered for that event or stored that value off.

So, I must be missing something here, I'm just trying to make sure you're not solving a problem that these symbols were specifically invented to solve. Why else would there be so many globals?
This is hardcoding it.
It would fail if they ever renamed that constant, till I rework the code.
It would also fail if they ever added a category.
There are 41* of those constants as it is now. I would hate it to even have to write an array containing all those constant names (could itterate over it via a for loop then).
Most importantly they might add more with later API releases.
All reason I much prefer to have code make this array for me, then making it myself.

As the programming is now, I would have to look at the Global table every time the API version changes. And risk making something wrong in the time between the API update and my code update.
With this library my code adopts automatically. I can write code that can easily survive changes to those constants (be it value changes, minor renames, removals or additions).


*And that is one of the smaller amounts. There are currently 469 Event ID's in the global table.
With my library you get a nice, int indexed list of those. You can simply figure out in wich event your code is running by looking it up in the list.
Without it - you would hate to be the one who has to write that array.
Last edited by zgrssd : 07/14/14 at 07:05 AM.
Report comment to moderator  
Reply With Quote
Unread 07/13/14, 06:04 PM  
LoquaciousAndroid

Forum posts: 1
File comments: 3
Uploads: 0
Re: Re: That's kind of why symbols exist in the first place

Code:
if(mysteriousValue == CHAT_CATEGORY_SAY) then
    DoWhatYouNeedForSay(...)
end
That's what I am talking about...you already know that mysteriousValue MUST be some kind of chat category, otherwise you wouldn't have registered for that event or stored that value off.

So, I must be missing something here, I'm just trying to make sure you're not solving a problem that these symbols were specifically invented to solve. Why else would there be so many globals?
Report comment to moderator  
Reply With Quote
Unread 07/12/14, 11:21 AM  
zgrssd
AddOn Author - Click to view AddOns

Forum posts: 280
File comments: 26
Uploads: 3
Re: That's kind of why symbols exist in the first place

Originally Posted by LoquaciousAndroid
ESO actually makes those global symbols so that addons don't have to depend on magic numbers. If addons used the constants the the configuration problem you mentioned wouldn't exist.

Or maybe I am missing something here...
It is easy to figure out the value of CHAT_CATEGORY_SAY. You just use the constant, you get the value.
It is hard to figure out that Chat Category ID 1 equates to SAY. Much less figuring that out at runtime in a non-localised fashion - when my code needs that data.
I can't just hardcode that 1 is CHAT_CATEGORY_SAY, because it might not be this way in future revision of the API.

I needed an unambigious name for each named chat category. So that even in the case that the order changed between runs of my addon (like a API update) I would still assign the right values to the right category.
During saving I figure out wich Chat Category that number equates too. And just store it under that chat categories name.
During application I can just use the respective constant from the global table.
Report comment to moderator  
Reply With Quote
Unread 07/11/14, 02:53 PM  
LoquaciousAndroid

Forum posts: 1
File comments: 3
Uploads: 0
That's kind of why symbols exist in the first place

ESO actually makes those global symbols so that addons don't have to depend on magic numbers. If addons used the constants the the configuration problem you mentioned wouldn't exist.

Or maybe I am missing something here...
Report comment to moderator  
Reply With Quote
Post A Reply



Category Jump: