Thread Tools Display Modes
07/08/14, 09:11 AM   #1
zgrssd
AddOn Author - Click to view addons
Join Date: May 2014
Posts: 280
LibConstantMapper

While trying to figure out wich unambigious Chat Category Constant name relates to wich category I ran into the issue that the Constant Names are the keys in the global table. They can be identified via Pattern Matching, but they are not a subtable that you can easily itterate over.

Doing excessive pattern matching is bad for performance. Also there are other similary organised groups of values (like the Chat_Channels or all the Event ID's) you might want to find an easy match for.
So I started development on this library. It consists of two files:
mappings.lua
Lua Code:
  1. ConstantMapperMappings = {
  2.     { mapping = "ChatCategories", pattern = "^CHAT_CATEGORY_", exclude = "^CHAT_CATEGORY_HEADER" }
  3. }
Just a table. It contains the mapping (wich Key the table will be saved under and will be requestable), the pattern to match (in this case for chat categories) and a pattern to not include (in this case I want all the entries starting with "CHAT_CATEGORY_", except the ones starting wiht "CHAT_CATEGORY_HEADER").
If I also want the chat channels using this library, I just have to modify it like this:
Lua Code:
  1. ConstantMapperMappings = {
  2.     { mapping = "ChatCategories", pattern = "^CHAT_CATEGORY_", exclude = "^CHAT_CATEGORY_HEADER" },
  3.     { mapping = "ChatChannels", pattern = "^CHAT_CHANNEL_"}
  4. }

main.lua
Lua Code:
  1. local Mappings = ConstantMapperMappings
  2. local data = { }
  3.  
  4. --Make certain data contains a table for each mapping
  5. for i=1, #Mappings, 1 do
  6.     local currentMap = Mappings[i]
  7.    
  8.     if(data[currentMap.mapping] == nil) then
  9.         data[currentMap.mapping] = {}
  10.     end
  11. end
  12.  
  13. --For every entry in the Global table
  14. for key, value in zo_insecurePairs(_G) do
  15.     --Compare it to every mapping
  16.     for i=1, #Mappings, 1 do
  17.         local currentMap = Mappings[i]
  18.        
  19.         if (key):find(currentMap.pattern) and (currentMap.exclude == nil or not(key):find(currentMap.exclude)) then
  20.             --found a Value for this mapping, so store it in the table
  21.             local newentry = { key = key, value = value}
  22.            
  23.             table.insert(data[currentMap.mapping], newentry)
  24.         end
  25.     end
  26. end
I go over all entries in the global table. Compare each entry to each mapping. And if it matches, I store the value as a subtable in Data.
That way I get a easy to itterate over table containing wich ConstantName matches wich Category.

Going over the whoel global table is a lot faster then I anticipated so maybe I switch to a "retreive on demand, but cache" approach instead.

Of course the whole thing will use libStub to avoid multiple execution in the final version. I just wanted to ask if there are any mistakes in this code I have to look out for.
  Reply With Quote
07/08/14, 10:37 AM   #2
merlight
AddOn Author - Click to view addons
Join Date: Jul 2014
Posts: 671
Some suggestions.

a) either allow more exludes (make it a table) to make things like this work (because Lua's regular expressions are so weak they can't accomplish this in one go):
Lua Code:
  1. { mapping = "Stats", pattern = "^STAT_", exclude = {"^STAT_BONUS_OPTION_", "^STAT_SOFT_CAP_OPTION", "^STAT_VALUE_COLOR"} }
b) or replace excludes with a non-mapping...
Lua Code:
  1. { mapping = false, pattern = "^CHAT_CATEGORY_HEADER_" }, -- non-mapping
  2. { mapping = "ChatCategories", pattern = "^CHAT_CATEGORY_" },
  3. { mapping = "StatBonusOptions", pattern = "^STAT_BONUS_OPTION_" },
  4. { mapping = "StatSoftCapOptions", pattern = "^STAT_SOFT_CAP_OPTION_" },
  5. { mapping = false, pattern = "^STAT_VALUE_COLOR" }, -- non-mapping
  6. { mapping = "Stats", pattern = "^STAT_" },
...and stop after the first match
Lua Code:
  1. --For every entry in the Global table
  2. for key, value in zo_insecurePairs(_G) do
  3.     --Compare it to every mapping
  4.     local foundMap = nil
  5.     for _, currentMap in ipairs(Mappings) do
  6.         if key:find(currentMap.pattern) then
  7.             foundMap = currentMap
  8.             break -- stop at the first match
  9.         end
  10.     end
  11.     if foundMap and foundMap.mapping then
  12.             --found a Value for this mapping, so store it in the table
  13.             local newentry = { key = key, value = value}
  14.             table.insert(data[foundMap.mapping], newentry)
  15.     end
  16. end

Also it would be nice to have direct [value] => "key" mapping in addition to the table of pairs (I'm aware there might be collisions and the library would have to deal somehow, that's why wrote in addition to )

Last edited by merlight : 07/08/14 at 10:40 AM.
  Reply With Quote
07/08/14, 12:15 PM   #3
Garkin
 
Garkin's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2014
Posts: 832
Some more suggestions:

Lua Code:
  1. local MAJOR, MINOR = "LibConstantMapper-1.0", 1
  2.  
  3. local lib, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
  4. if not lib then return end
  5.  
  6. local mappingsTable = {
  7.    ["ACTION_TYPE"] = { exclude = "DEPRECATED" },
  8.    ["ATTRIBUTE"] ={ exclude = "ATTRIBUTE_.+_" },
  9.    ["CHAT_CATEGORY"] = { exclude = "^CHAT_CATEGORY_HEADER" },
  10.    ["CURRENCY_CHANGE_REASON"] = {},
  11.    ["DAMAGE_TYPE" = {},
  12.    ["ITEM_QUALITY"] = {},
  13.    ["ITEM_TRAIT_TYPE"] = {},
  14.    ["ITEMSTYLE"] = { exclude = "DEPRECATED" },
  15.    ["ITEMTYPE"] = {},
  16.    ["LINK_TYPE"] = { pattern = "_LINK_TYPE$" }
  17.    ["STAT"] = { exclude = {"^STAT_BONUS_OPTION_", "^STAT_SOFT_CAP_OPTION", "^STAT_VALUE_COLOR"} }
  18. }
  19.  
  20. --do not overwrite existing data
  21. lib.data = lib.data or {}
  22.  
  23. --internal functions
  24. function lib:AddData(mapping, pattern, exclude)
  25.    for name, value in zo_insecurePairs(_G) do
  26.       if type(mapping) == "table" then
  27.          for mappingName, mappingTable in pairs(mapping) do
  28.             lib:SaveDataEntry(name, value, mappingName, mappingTable.pattern, mappingTable.exclude)
  29.          end
  30.       elseif type(mapping) == "string" then
  31.          lib:SaveDataEntry(name, value, mapping, pattern, exclude)
  32.       end
  33.    end
  34. end
  35.  
  36. function lib:SaveDataEntry(name, value, mapping, pattern, exclude)
  37.    if (name):find(pattern or "^"..mapping.."_") == nil then return end
  38.  
  39.    local skip = false
  40.    if exclude then
  41.       if type(exclude) == "table" then
  42.          for i,v in ipairs(exclude) do
  43.             if (name):find(v) then
  44.                skip = true
  45.                break
  46.             end
  47.          end
  48.       else
  49.          skip = (name):find(exclude) ~= nil
  50.       end
  51.    end
  52.    
  53.    if not skip then
  54.       lib.data[mapping] = data[mapping] or {}
  55.       lib.data[mapping][name] = value
  56.    end
  57. end
  58.  
  59. if oldminor then
  60.    --library update, add only new/changed items?
  61.    local newItems = {}
  62.    for name, value in pairs(mappingsTable) do
  63.       if value ~= lib.mappings[name] then
  64.          newItems[name] = value
  65.          lib.mappings = value
  66.       end
  67.    end
  68.    lib:AddData(newItems)
  69. else
  70.    lib.mappings = mappingsTable
  71.    lib:AddData(mappingsTable)
  72. end
  73.  
  74.  
  75. --external functions
  76. function lib:AddMapping(mapping, pattern, exclude)
  77.    --add or replace enxisting entry
  78.    if type(mapping) == "table" then
  79.       for name, value in pairs(mapping) do
  80.          lib.mappings[name] = value
  81.       end
  82.    else  
  83.       lib.mappings[mapping] = { ["pattern"] = pattern, ["exclude"] = exclude }
  84.    end
  85.  
  86.    lib:AddData(mapping, pattern, exclude)  
  87. end
  88.  
  89. function lib:GetConstants(mapping)
  90.    return lib.data[mapping]
  91. end

1) Mapping can be part of the name and pattern is defined only in special cases
2) Do not create a new global table ConstantMapperMappings, just make it accessible using the library reference
3) As merlight said, it would be nice to have direct [value] => "key" mapping, so I changed it that way
  Reply With Quote
07/09/14, 04:25 AM   #4
zgrssd
AddOn Author - Click to view addons
Join Date: May 2014
Posts: 280
Originally Posted by merlight View Post
Some suggestions.

a) either allow more exludes (make it a table) to make things like this work (because Lua's regular expressions are so weak they can't accomplish this in one go):
Lua Code:
  1. { mapping = "Stats", pattern = "^STAT_", exclude = {"^STAT_BONUS_OPTION_", "^STAT_SOFT_CAP_OPTION", "^STAT_VALUE_COLOR"} }
b) or replace excludes with a non-mapping...
[highlight="Lua"]
[...]
Also it would be nice to have direct [value] => "key" mapping in addition to the table of pairs (I'm aware there might be collisions and the library would have to deal somehow, that's why wrote in addition to )
I want the same Key to be able to pop up in multiple mappings (i.e. Events appareing ina big "all events" mapping as well as sublist for each class like guild), so non-mapping is out of the question.

The final structure for mappings might looks something like this:
1 Mapping (the mapping name)
-> with 1...N patterns to match
-> each pattern with 0...M exclusions

But that is pretty far in the future. First things first.

Originally Posted by Garkin View Post
1) Mapping can be part of the name and pattern is defined only in special cases
2) Do not create a new global table ConstantMapperMappings, just make it accessible using the library reference
3) As merlight said, it would be nice to have direct [value] => "key" mapping, so I changed it that way
1) Due to the long term plans, a mapping might be able to have multiple patterns. Combinign them would just make the code mroe complex
2) The global table was only a temporary solution for my first trials. Currently I actually tend towards mappings being registered at runtime the same way you register media with LibMedia or libaries with LibStub. And only being processed on demand. if so the mappings.lua file will propably run after the actuall library and just call the register function in a loop.
3) My original idea was a [value] => "key" mapping. But that would cause issues if I ever end up with the same value more then once (the whole Chat Cat header issues pointed me at that).
The output tables are designed to be itterable via # operator, no use of "pairs" needed. But taht is only personal preference of int indexes over string indexes.
Not using the value as key also means I can accomodate non-key worthy values. For example, afaik "" is a valid value. But not a valid index. BugEaters inability to deal with nil and "" values pointed me towards that issue.
A simple int indexed array of key&value allows a lot more ways to process the data.

Edit (too 3):
The more I think about it, the better my idea sounds. The global table is full of values that would never make a valid index for a table: empty stings, functions, other tables - non of that could ever make a proper index. Plus sometimes the same function/table might be used as value multiple keys (so I had the same index used multiple times).
Clear index-worthy int and string values seem to be a odd thing in the global table, rather then a common one.

Last edited by zgrssd : 07/09/14 at 04:38 AM.
  Reply With Quote
07/09/14, 08:31 AM   #5
merlight
AddOn Author - Click to view addons
Join Date: Jul 2014
Posts: 671
Originally Posted by zgrssd View Post
For example, afaik "" is a valid value. But not a valid index. BugEaters inability to deal with nil and "" values pointed me towards that issue.
Anything but nil is a valid index (you can even use another table as key). In SavedVars only int/string/boolean keys are allowed, but that is SavedVars limitation, not Lua limitation. Empty string is a valid key in both.

Skip down to *CONSTRUCTIVE* if you only want something constructive, this below is just rant

Originally Posted by zgrssd View Post
A simple int indexed array of key&value allows a lot more ways to process the data.
But not the one way I find most convenient - quickly answering the question "what's the symbolic name of this value?".

Originally Posted by zgrssd View Post
Edit (too 3):
The more I think about it, the better my idea sounds. The global table is full of values that would never make a valid index for a table: empty stings, functions, other tables - non of that could ever make a proper index.
I don't think I would ask the name of anything but integer constants (except when I was writing a function to dump _G, I used some heuristics to give names to metatables, and that was when I used [{table}] => "string" mapping; but that's something completely out of scope of this library, I guess).

Originally Posted by zgrssd View Post
Plus sometimes the same function/table might be used as value multiple keys (so I had the same index used multiple times).
Clear index-worthy int and string values seem to be a odd thing in the global table, rather then a common one.
Look at it this way. You give me an array of pairs. I want to know the name of a thing. So I'll write this function:
Lua Code:
  1. local function nameIt1(value, mapping)
  2.     for i, m in ipairs(mapping) do
  3.         if value == m.value then
  4.             return m.key
  5.         end
  6.     end
  7. end

Someone else might instead do it this way:
Lua Code:
  1. local function nameIt2(mapping, value)
  2.     local name = nil
  3.     for i, m in ipairs(mapping) do
  4.         if value == m.value then
  5.             name = m.key
  6.         end
  7.     end
  8.     return name
  9. end

nameIt1 returns the first key with matching value, nameIt2 returns the last. Not to mention that the order of values in mapping depends on the order in which you get them from zo_insecurePairs! Which may be different every time you /reloadui, so addons using any nameIt function might behave strangely sometimes. I know it's hard do deal with conflicts properly, but if it's done in a library, at least it can be done consistently.


*CONSTRUCTIVE*

You could:
1) Add type requirement to your mapping spec. For example, "only int values allowed", everything else thrown away.
2) Sort your data={{value=5,key="foo"}, {value=5,key="bar"}} pairs table on value and key (sorting elements with equal values on key is important if you want consistent search results). Or zo_binaryinsert right away, instead of table.insert's and table.sort afterwards.
3) Provide a lookup function which would zo_binarysearch for given value in the sorted data.

Last edited by merlight : 07/09/14 at 08:34 AM.
  Reply With Quote
07/09/14, 11:21 AM   #6
zgrssd
AddOn Author - Click to view addons
Join Date: May 2014
Posts: 280
Originally Posted by merlight View Post
But not the one way I find most convenient - quickly answering the question "what's the symbolic name of this value?".
If you want it done differently, you can always do it differently.

My experience tells me that a int-indexed, properly formed array consisting of key/value tables offers the best overall usage while still having acceptable looping performance.
Looping over the array with # and comparing a string to "something" is going to have the same performance as asking the system for the value to key "something". Because all those tables are "under the hood" are one List without allowed duplicates and one with allowed duplicates.

Also I cannot guarantee that any value will be there only once. That is simply a matter of how the data looks and the patterns/exclusiong are set.
Better ending up with the same key twice in the array (easy to diagnose) then having sometimes the one key in use, sometimes the other (hard to diagnose).
  Reply With Quote
07/09/14, 04:01 PM   #7
zgrssd
AddOn Author - Click to view addons
Join Date: May 2014
Posts: 280
After another set of pondering I reduced it to the following KISS case and even added some sanity checks on the input data:
Lua Code:
  1. --Use lib stub to figure out if the same or higher version was already used
  2. local major, minor = "LibConstantMapper", 1
  3. local lib = LibStub:NewLibrary(major, minor)
  4.  
  5. if not lib then
  6.     return
  7. end
  8.  
  9. function lib:getMappedData(pattern, exclude)
  10.     --Sanity check on values
  11.     assert(pattern ~= nil and type(pattern) == "string", "pattern must not be nil and of type string")
  12.     assert(exlcude == nil or type(exclude) == "string", "exclude must be nil or of type string")
  13.    
  14.     local result = {}
  15.  
  16.     --For every entry in the Global table
  17.     for key, value in zo_insecurePairs(_G) do
  18.         --Compare it to the given mapping
  19.         if (key):find(pattern) and (exclude == nil or not(key):find(exclude)) then
  20.             --found a Value for this mapping, so store it in the result table
  21.             local newentry = { key = key, value = value}
  22.            
  23.             table.insert(result, newentry)
  24.         end
  25.     end
  26.  
  27.     return result
  28. end
I will also work on giving you some default pattern/exclusion pairs to work with (propably a "getMaps" and "addMap" function, similar to LibMediaProvider:List()).

Last edited by zgrssd : 07/09/14 at 04:03 PM. Reason: Had forgotten to throw out some debug messages
  Reply With Quote
07/09/14, 06:13 PM   #8
merlight
AddOn Author - Click to view addons
Join Date: Jul 2014
Posts: 671
Originally Posted by zgrssd View Post
Because all those tables are "under the hood" are one List without allowed duplicates and one with allowed duplicates.
Absolutely not. Non-integer keys are hashed. Look at _G. If Lua were to go through the whole table everytime it needs to resolve a symbol, it would be unusable for almost anything, even simple scripts would take forever.
I'm not sure how tables with non-contiguous integer-only keys are implemented in Lua; I guess they're simply ordered binary-searched arrays.

Originally Posted by zgrssd View Post
Also I cannot guarantee that any value will be there only once. That is simply a matter of how the data looks and the patterns/exclusiong are set.
Better ending up with the same key twice in the array (easy to diagnose) then having sometimes the one key in use, sometimes the other (hard to diagnose).
That's why I proposed to make it sorted, and binary-searchable.
  Reply With Quote
07/10/14, 04:58 AM   #9
zgrssd
AddOn Author - Click to view addons
Join Date: May 2014
Posts: 280
Uploaded a first version:
http://www.esoui.com/downloads/info6...antMapper.html

I am propably going to make this a dual-Library:
One with the :getMappedData function and others that go over the global table
One to store all the maps.
That way I could do proper versioning on the maps too.

Originally Posted by merlight View Post
That's why I proposed to make it sorted, and binary-searchable.
Maybe later.
Without caching it would cost resources everytime the value is requested. But it would only be usefull in a rare amount of cases (debugging). Personally I can work with a simple for loop and the data it gives me.
Once I get a function with chaching up and running I will propably include it.
  Reply With Quote
07/11/14, 06:20 AM   #10
zgrssd
AddOn Author - Click to view addons
Join Date: May 2014
Posts: 280
I ultimatively decided against making the mapping and the actuall working library seperate.
I added a function that allows you to get the data based on the name of a map. This function will also be expanded to include caching later.
List Maps only gives the names of maps, not the entire map table

I have also expanded the mappings a bit so it now includes all events, as well as several event subgroups. But that part is still WIP.

I was not able to run this on my client yet and it is not an actuall release, so there are propably still some errors in there:
Lua Code:
  1. --Use lib stub to figure out if the same or higher version was already used
  2. local major, minor = "LibConstantMapper", 0.2
  3. local lib = LibStub:NewLibrary(major, minor)
  4.  
  5. if not lib then
  6.     return
  7. end
  8.  
  9. function lib:getMappedData(pattern, exclude)
  10.     --Sanity check on values
  11.     assert(pattern ~= nil and type(pattern) == "string", "pattern must not be nil and of type string")
  12.     assert(exlcude == nil or type(exclude) == "string", "exclude must be nil or of type string")
  13.    
  14.     local result = {}
  15.  
  16.     --For every entry in the Global table
  17.     for key, value in zo_insecurePairs(_G) do
  18.         --Compare it to the given mapping
  19.         if (key):find(pattern) and (exclude == nil or not(key):find(exclude)) then
  20.             --found a Value for this mapping, so store it in the result table
  21.             local newentry = { key = key, value = value}
  22.            
  23.             table.insert(result, newentry)
  24.         end
  25.     end
  26.  
  27.     return result
  28. end
  29.  
  30. function lib:getDataByMapping(map_name)
  31.     local map = self:getMap(map_name)
  32.     assert (map ~= nil and map ~= {}, "A mapping named '" .. map_name .. "' could not be found")
  33.    
  34.     --If all worked out so far, let getMappedData do it's job
  35.     return self:getMappedData(map.pattern, map.exclude)
  36. end
  37.  
  38. --Functions and Data related to the maps
  39. function lib:listMaps()
  40.     local result = {}
  41.  
  42.     for key, value in pairs(self.__maps) do
  43.         table.insert(result, key)
  44.     end
  45.    
  46.     return result
  47. end
  48.  
  49. function lib:addMap(map, pattern, exclude)
  50.     if(self.__maps == nil) then
  51.         self.__maps = {}
  52.     end
  53.  
  54.     assert(map ~= nil or type(map) == "string", "map must not be nil and of type string")
  55.     assert(pattern ~= nil and type(pattern) == "string", "pattern must not be nil and of type string")
  56.     assert(exlcude == nil or type(exclude) == "string", "exclude must be nil or of type string")
  57.    
  58.     self.__maps[map] = { pattern = pattern, exclude = exclude }
  59. end
  60.  
  61. function lib:getMap(map)
  62.     assert(map ~= nil or type(map) == "string", "map must not be nil and of type string")
  63.    
  64.     return self.__maps[map]
  65. end
  66.  
  67. --Predefined mappings
  68. local ConstantMapperMappings = {
  69.     { mapping = "ChatCategories", pattern = "^CHAT_CATEGORY_", exclude = "^CHAT_CATEGORY_HEADER" },
  70.     { mapping = "ChatChannels", pattern = "^CHAT_CHANNEL_"},
  71.     { mapping = "Events", pattern = "^EVENT_"},
  72.     { mapping = "EventsAbility", pattern = "^EVENT_ABILITY_" },
  73.     { mapping = "EventsAchievement", pattern = "^EVENT_ACHIEVEMENT_"},
  74.     { mapping = "EventsAction", pattern = "^EVENT_ACTION_"},
  75.     { mapping = "EventsActive", pattern = "^EVENT_ACTIVE_"},
  76.     { mapping = "EventsAddOn", pattern "^EVENT_ADD_ON_" },
  77.     { mapping = "EventsAgentChat", pattern "^EVENT_AGENT_CHAT_" },
  78.     { mapping = "EventsAlliancePoint", pattern "^EVENT_ALLIANCE_POINT_" },
  79.     { mapping = "EventsArtifact", pattern "^EVENT_ARTIFACT_" },
  80.     { mapping = "EventsAssignedCampaign", pattern "^EVENT_ASSIGNED_CAMPAIGN_" },
  81.     { mapping = "EventsAttribute", pattern "^EVENT_ATTRIBUTE_" },
  82.     { mapping = "EventsAvenge", pattern "^EVENT_AVENGE_" },
  83.     { mapping = "EventsBankIs", pattern "^EVENT_BANK_IS_" },
  84.     { mapping = "EventsBankedMoney", pattern "^EVENT_BANKED_MONEY_" },
  85.     { mapping = "EventsBattleStandards", pattern "^EVENT_BATTLE_STANDARDS_" },
  86.     { mapping = "EventsBegin", pattern "^EVENT_BEGIN_" },
  87.     { mapping = "EventsBosses", pattern "^EVENT_BOSSES_" },
  88.     { mapping = "EventsBroadcast", pattern "^EVENT_BROADCAST" },
  89.     { mapping = "EventsBuy", pattern "^EVENT_BUY_" },
  90.     { mapping = "EventsBuyback", pattern "^EVENT_BUYBACK_" },
  91.     { mapping = "EventsCampaign", pattern "^EVENT_CAMPAIGN_" },
  92.     { mapping = "EventsCancel", pattern "^EVENT_CANCEL_" },
  93.     { mapping = "EventsCannot", pattern "^EVENT_CANNOT_" },
  94.     { mapping = "EventsCapsLock", pattern "^EVENT_CAPS_LOCK_STATE_" },
  95.     { mapping = "EventsCaptureArea", pattern "^EVENT_CAPTURE_AREA_" },
  96.     { mapping = "EventsChatChannel", pattern "^EVENT_CHAT_CHANNEL_" },
  97.     { mapping = "EventsChatLog", pattern "^EVENT_CHAT_LOG_" },
  98.     { mapping = "EventsChatMessage", pattern "^EVENT_CHAT_MESSAGE_" },
  99.     { mapping = "EventsChatter", pattern "^EVENT_CHATTER_" },
  100.     { mapping = "EventsClose", pattern "^EVENT_CLOSE_" },
  101.     { mapping = "EventsCombat", pattern "^EVENT_COMBAT_" },
  102.     { mapping = "EventsConfirm", pattern "^EVENT_CONFIRM_" },
  103.     { mapping = "EventsConversation", pattern "^EVENT_CONVERSATION_" }
  104. }
  105.  
  106. for i=1, #ConstantMapperMappings, 1 do
  107.     local currentMap = ConstantMapperMappings[i]
  108.     lib:addMap(currentMap.mapping, currentMap.pattern, currentMap.exclude)
  109. end
  Reply With Quote
07/12/14, 04:36 AM   #11
zgrssd
AddOn Author - Click to view addons
Join Date: May 2014
Posts: 280
The above code (after adding some missing = in the table assignment at the botom) has been uploaded as version 0.2.
I also started work on a function that gives you a value indexed array of the keys. This is my code so far (not done any testruns):
Lua Code:
  1. function lib:getValIndexedKeyList(input)
  2.     --assert that input is remotely valid
  3.     assert (input ~= nil and type(input) == "table", "input must be not nil and a table")
  4.    
  5.     local result = {}
  6.    
  7.     for outerkey, outervalue in input do
  8.         --assert that this index of input has the right contained elements
  9.         assert (type(outervalue) == "table" and outervalue.key ~= nil and outervalue.value ~= nil, "Key: '" .. outerkey .. "' is not a table or does not contain a pair of key/value indexes")
  10.        
  11.         --Some local variables to shorten the syntax
  12.         local innerkey, innervalue = outervalue.key, outervalue.value
  13.        
  14.         --Check if this value has already been used as key
  15.         assert(result[innervalue] == nil, "Key: '" .. outerkey .. "' contains the duplicate value '" .. innervalue .. "'")
  16.         result[innervalue] = innerkey
  17.     end
  18.    
  19.     return result
  20. end

Last edited by zgrssd : 07/12/14 at 04:38 AM.
  Reply With Quote
07/13/14, 05:57 AM   #12
zgrssd
AddOn Author - Click to view addons
Join Date: May 2014
Posts: 280
Just uploaded version 0.3
Aside from some changes to the description, this also include the new function:
getValIndexedKeyList()
Wich gives you a array of the keys, indexed by their values. By default it will throw an assertion exception if it runs into the same value a second time. But this behavior can be disabeled via an optional bool switch (but I highly advise against it. Duplicate values is something you really have to look at. Wich is why I made this case an exception in the first place).
  Reply With Quote
07/18/14, 02:22 AM   #13
zgrssd
AddOn Author - Click to view addons
Join Date: May 2014
Posts: 280
And now I uploaded v0.4
I added some basic sorting to "getDataByMapping". Not added buffering yet, so it might be slightly slower then before.
Embedded the new version fo LibStub.
I added a new default mapping for the "BIND_TYPE" enumeration that is currently on the PTS server.

The 1.3 patchnoites also gives me a better name for the next major release:
"Enumeration Harvester"
Apparently those "groups of Cosntants named by a pattern" are thier way of exposing enumerations to our LUA code. It would have been a bit better if they put them into subtables (one per Enum) instead of adding a prefix (so we can quickly itterate over each enum group). But this way I get to programm something for it.
  Reply With Quote

ESOUI » AddOns » Released AddOns » LibConstantMapper

Thread Tools
Display Modes

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