flickerstreak@30: --[[ flickerstreak@30: Name: LibRock-1.0 flickerstreak@30: Revision: $Rev: 63317 $ flickerstreak@30: Developed by: ckknight (ckknight@gmail.com) flickerstreak@30: Website: http://www.wowace.com/ flickerstreak@30: Description: Library to allow for library and addon creation and easy table recycling functions. flickerstreak@30: License: LGPL v2.1 flickerstreak@30: ]] flickerstreak@30: flickerstreak@30: local MAJOR_VERSION = "LibRock-1.0" flickerstreak@30: local MINOR_VERSION = tonumber(("$Revision: 63317 $"):match("(%d+)")) - 60000 flickerstreak@30: flickerstreak@30: local _G = _G flickerstreak@30: local GetLocale = _G.GetLocale flickerstreak@30: local CATEGORIES flickerstreak@30: if GetLocale() == "deDE" then flickerstreak@30: CATEGORIES = { flickerstreak@30: ["Action Bars"] = "Aktionsleisten", flickerstreak@30: ["Auction"] = "Auktion", flickerstreak@30: ["Audio"] = "Audio", flickerstreak@30: ["Battlegrounds/PvP"] = "Schlachtfeld/PvP", flickerstreak@30: ["Buffs"] = "Stärkungszauber", flickerstreak@30: ["Chat/Communication"] = "Chat/Kommunikation", flickerstreak@30: ["Druid"] = "Druide", flickerstreak@30: ["Hunter"] = "Jäger", flickerstreak@30: ["Mage"] = "Magier", flickerstreak@30: ["Paladin"] = "Paladin", flickerstreak@30: ["Priest"] = "Priester", flickerstreak@30: ["Rogue"] = "Schurke", flickerstreak@30: ["Shaman"] = "Schamane", flickerstreak@30: ["Warlock"] = "Hexenmeister", flickerstreak@30: ["Warrior"] = "Krieger", flickerstreak@30: ["Healer"] = "Heiler", flickerstreak@30: ["Tank"] = "Tank", flickerstreak@30: ["Caster"] = "Zauberer", flickerstreak@30: ["Combat"] = "Kampf", flickerstreak@30: ["Compilations"] = "Zusammenstellungen", flickerstreak@30: ["Data Export"] = "Datenexport", flickerstreak@30: ["Development Tools"] = "Entwicklungstools", flickerstreak@30: ["Guild"] = "Gilde", flickerstreak@30: ["Frame Modification"] = "Frameveränderungen", flickerstreak@30: ["Interface Enhancements"] = "Interfaceverbesserungen", flickerstreak@30: ["Inventory"] = "Inventar", flickerstreak@30: ["Library"] = "Bibliotheken", flickerstreak@30: ["Map"] = "Karte", flickerstreak@30: ["Mail"] = "Post", flickerstreak@30: ["Miscellaneous"] = "Diverses", flickerstreak@30: ["Quest"] = "Quest", flickerstreak@30: ["Raid"] = "Schlachtzug", flickerstreak@30: ["Tradeskill"] = "Beruf", flickerstreak@30: ["UnitFrame"] = "Einheiten-Fenster", flickerstreak@30: } flickerstreak@30: elseif GetLocale() == "frFR" then flickerstreak@30: CATEGORIES = { flickerstreak@30: ["Action Bars"] = "Barres d'action", flickerstreak@30: ["Auction"] = "Hôtel des ventes", flickerstreak@30: ["Audio"] = "Audio", flickerstreak@30: ["Battlegrounds/PvP"] = "Champs de bataille/JcJ", flickerstreak@30: ["Buffs"] = "Buffs", flickerstreak@30: ["Chat/Communication"] = "Chat/Communication", flickerstreak@30: ["Druid"] = "Druide", flickerstreak@30: ["Hunter"] = "Chasseur", flickerstreak@30: ["Mage"] = "Mage", flickerstreak@30: ["Paladin"] = "Paladin", flickerstreak@30: ["Priest"] = "Prêtre", flickerstreak@30: ["Rogue"] = "Voleur", flickerstreak@30: ["Shaman"] = "Chaman", flickerstreak@30: ["Warlock"] = "Démoniste", flickerstreak@30: ["Warrior"] = "Guerrier", flickerstreak@30: ["Healer"] = "Soigneur", flickerstreak@30: ["Tank"] = "Tank", flickerstreak@30: ["Caster"] = "Casteur", flickerstreak@30: ["Combat"] = "Combat", flickerstreak@30: ["Compilations"] = "Compilations", flickerstreak@30: ["Data Export"] = "Exportation de données", flickerstreak@30: ["Development Tools"] = "Outils de développement", flickerstreak@30: ["Guild"] = "Guilde", flickerstreak@30: ["Frame Modification"] = "Modification des fenêtres", flickerstreak@30: ["Interface Enhancements"] = "Améliorations de l'interface", flickerstreak@30: ["Inventory"] = "Inventaire", flickerstreak@30: ["Library"] = "Bibliothèques", flickerstreak@30: ["Map"] = "Carte", flickerstreak@30: ["Mail"] = "Courrier", flickerstreak@30: ["Miscellaneous"] = "Divers", flickerstreak@30: ["Quest"] = "Quêtes", flickerstreak@30: ["Raid"] = "Raid", flickerstreak@30: ["Tradeskill"] = "Métiers", flickerstreak@30: ["UnitFrame"] = "Fenêtres d'unité", flickerstreak@30: } flickerstreak@30: elseif GetLocale() == "koKR" then flickerstreak@30: CATEGORIES = { flickerstreak@30: ["Action Bars"] = "액션바", flickerstreak@30: ["Auction"] = "경매", flickerstreak@30: ["Audio"] = "음향", flickerstreak@30: ["Battlegrounds/PvP"] = "전장/PvP", flickerstreak@30: ["Buffs"] = "버프", flickerstreak@30: ["Chat/Communication"] = "대화/의사소통", flickerstreak@30: ["Druid"] = "드루이드", flickerstreak@30: ["Hunter"] = "사냥꾼", flickerstreak@30: ["Mage"] = "마법사", flickerstreak@30: ["Paladin"] = "성기사", flickerstreak@30: ["Priest"] = "사제", flickerstreak@30: ["Rogue"] = "도적", flickerstreak@30: ["Shaman"] = "주술사", flickerstreak@30: ["Warlock"] = "흑마법사", flickerstreak@30: ["Warrior"] = "전사", flickerstreak@30: ["Healer"] = "힐러", flickerstreak@30: ["Tank"] = "탱커", flickerstreak@30: ["Caster"] = "캐스터", flickerstreak@30: ["Combat"] = "전투", flickerstreak@30: ["Compilations"] = "복합", flickerstreak@30: ["Data Export"] = "자료 출력", flickerstreak@30: ["Development Tools"] = "개발 도구", flickerstreak@30: ["Guild"] = "길드", flickerstreak@30: ["Frame Modification"] = "구조 변경", flickerstreak@30: ["Interface Enhancements"] = "인터페이스 강화", flickerstreak@30: ["Inventory"] = "인벤토리", flickerstreak@30: ["Library"] = "라이브러리", flickerstreak@30: ["Map"] = "지도", flickerstreak@30: ["Mail"] = "우편", flickerstreak@30: ["Miscellaneous"] = "기타", flickerstreak@30: ["Quest"] = "퀘스트", flickerstreak@30: ["Raid"] = "공격대", flickerstreak@30: ["Tradeskill"] = "전문기술", flickerstreak@30: ["UnitFrame"] = "유닛 프레임", flickerstreak@30: } flickerstreak@30: elseif GetLocale() == "zhTW" then flickerstreak@30: CATEGORIES = { flickerstreak@30: ["Action Bars"] = "動作列", flickerstreak@30: ["Auction"] = "拍賣", flickerstreak@30: ["Audio"] = "音效", flickerstreak@30: ["Battlegrounds/PvP"] = "戰場/PvP", flickerstreak@30: ["Buffs"] = "增益", flickerstreak@30: ["Chat/Communication"] = "聊天/通訊", flickerstreak@30: ["Druid"] = "德魯伊", flickerstreak@30: ["Hunter"] = "獵人", flickerstreak@30: ["Mage"] = "法師", flickerstreak@30: ["Paladin"] = "聖騎士", flickerstreak@30: ["Priest"] = "牧師", flickerstreak@30: ["Rogue"] = "盜賊", flickerstreak@30: ["Shaman"] = "薩滿", flickerstreak@30: ["Warlock"] = "術士", flickerstreak@30: ["Warrior"] = "戰士", flickerstreak@30: ["Healer"] = "治療者", flickerstreak@30: ["Tank"] = "坦克", flickerstreak@30: ["Caster"] = "施法者", flickerstreak@30: ["Combat"] = "戰鬥", flickerstreak@30: ["Compilations"] = "整合", flickerstreak@30: ["Data Export"] = "資料匯出", flickerstreak@30: ["Development Tools"] = "開發工具", flickerstreak@30: ["Guild"] = "公會", flickerstreak@30: ["Frame Modification"] = "框架修改", flickerstreak@30: ["Interface Enhancements"] = "介面增強", flickerstreak@30: ["Inventory"] = "庫存", flickerstreak@30: ["Library"] = "程式庫", flickerstreak@30: ["Map"] = "地圖", flickerstreak@30: ["Mail"] = "郵件", flickerstreak@30: ["Miscellaneous"] = "雜項", flickerstreak@30: ["Quest"] = "任務", flickerstreak@30: ["Raid"] = "團隊", flickerstreak@30: ["Tradeskill"] = "交易技能", flickerstreak@30: ["UnitFrame"] = "頭像框架", flickerstreak@30: } flickerstreak@30: elseif GetLocale() == "zhCN" then flickerstreak@30: CATEGORIES = { flickerstreak@30: ["Action Bars"] = "动作条", flickerstreak@30: ["Auction"] = "拍卖", flickerstreak@30: ["Audio"] = "音频", flickerstreak@30: ["Battlegrounds/PvP"] = "战场/PvP", flickerstreak@30: ["Buffs"] = "增益魔法", flickerstreak@30: ["Chat/Communication"] = "聊天/交流", flickerstreak@30: ["Druid"] = "德鲁伊", flickerstreak@30: ["Hunter"] = "猎人", flickerstreak@30: ["Mage"] = "法师", flickerstreak@30: ["Paladin"] = "圣骑士", flickerstreak@30: ["Priest"] = "牧师", flickerstreak@30: ["Rogue"] = "潜行者", flickerstreak@30: ["Shaman"] = "萨满祭司", flickerstreak@30: ["Warlock"] = "术士", flickerstreak@30: ["Warrior"] = "战士", flickerstreak@30: ["Healer"] = "治疗", flickerstreak@30: ["Tank"] = "坦克", flickerstreak@30: ["Caster"] = "远程输出", flickerstreak@30: ["Combat"] = "战斗", flickerstreak@30: ["Compilations"] = "编译", flickerstreak@30: ["Data Export"] = "数据导出", flickerstreak@30: ["Development Tools"] = "开发工具", flickerstreak@30: ["Guild"] = "公会", flickerstreak@30: ["Frame Modification"] = "框架修改", flickerstreak@30: ["Interface Enhancements"] = "界面增强", flickerstreak@30: ["Inventory"] = "背包", flickerstreak@30: ["Library"] = "库", flickerstreak@30: ["Map"] = "地图", flickerstreak@30: ["Mail"] = "邮件", flickerstreak@30: ["Miscellaneous"] = "杂项", flickerstreak@30: ["Quest"] = "任务", flickerstreak@30: ["Raid"] = "团队", flickerstreak@30: ["Tradeskill"] = "商业技能", flickerstreak@30: ["UnitFrame"] = "头像框架", flickerstreak@30: } flickerstreak@30: elseif GetLocale() == "esES" then flickerstreak@30: CATEGORIES = { flickerstreak@30: ["Action Bars"] = "Barras de Acción", flickerstreak@30: ["Auction"] = "Subasta", flickerstreak@30: ["Audio"] = "Audio", flickerstreak@30: ["Battlegrounds/PvP"] = "Campos de Batalla/JcJ", flickerstreak@30: ["Buffs"] = "Buffs", flickerstreak@30: ["Chat/Communication"] = "Chat/Comunicación", flickerstreak@30: ["Druid"] = "Druida", flickerstreak@30: ["Hunter"] = "Cazador", flickerstreak@30: ["Mage"] = "Mago", flickerstreak@30: ["Paladin"] = "Paladín", flickerstreak@30: ["Priest"] = "Sacerdote", flickerstreak@30: ["Rogue"] = "Pícaro", flickerstreak@30: ["Shaman"] = "Chamán", flickerstreak@30: ["Warlock"] = "Brujo", flickerstreak@30: ["Warrior"] = "Guerrero", flickerstreak@30: ["Healer"] = "Sanador", flickerstreak@30: ["Tank"] = "Tanque", flickerstreak@30: ["Caster"] = "Conjurador", flickerstreak@30: ["Combat"] = "Combate", flickerstreak@30: ["Compilations"] = "Compilaciones", flickerstreak@30: ["Data Export"] = "Exportar Datos", flickerstreak@30: ["Development Tools"] = "Herramientas de Desarrollo", flickerstreak@30: ["Guild"] = "Hermandad", flickerstreak@30: ["Frame Modification"] = "Modificación de Marcos", flickerstreak@30: ["Interface Enhancements"] = "Mejoras de la Interfaz", flickerstreak@30: ["Inventory"] = "Inventario", flickerstreak@30: ["Library"] = "Biblioteca", flickerstreak@30: ["Map"] = "Mapa", flickerstreak@30: ["Mail"] = "Correo", flickerstreak@30: ["Miscellaneous"] = "Misceláneo", flickerstreak@30: ["Quest"] = "Misión", flickerstreak@30: ["Raid"] = "Banda", flickerstreak@30: ["Tradeskill"] = "Habilidad de Comercio", flickerstreak@30: ["UnitFrame"] = "Marco de Unidades", flickerstreak@30: } flickerstreak@30: else -- enUS flickerstreak@30: CATEGORIES = { flickerstreak@30: ["Action Bars"] = "Action Bars", flickerstreak@30: ["Auction"] = "Auction", flickerstreak@30: ["Audio"] = "Audio", flickerstreak@30: ["Battlegrounds/PvP"] = "Battlegrounds/PvP", flickerstreak@30: ["Buffs"] = "Buffs", flickerstreak@30: ["Chat/Communication"] = "Chat/Communication", flickerstreak@30: ["Druid"] = "Druid", flickerstreak@30: ["Hunter"] = "Hunter", flickerstreak@30: ["Mage"] = "Mage", flickerstreak@30: ["Paladin"] = "Paladin", flickerstreak@30: ["Priest"] = "Priest", flickerstreak@30: ["Rogue"] = "Rogue", flickerstreak@30: ["Shaman"] = "Shaman", flickerstreak@30: ["Warlock"] = "Warlock", flickerstreak@30: ["Warrior"] = "Warrior", flickerstreak@30: ["Healer"] = "Healer", flickerstreak@30: ["Tank"] = "Tank", flickerstreak@30: ["Caster"] = "Caster", flickerstreak@30: ["Combat"] = "Combat", flickerstreak@30: ["Compilations"] = "Compilations", flickerstreak@30: ["Data Export"] = "Data Export", flickerstreak@30: ["Development Tools"] = "Development Tools", flickerstreak@30: ["Guild"] = "Guild", flickerstreak@30: ["Frame Modification"] = "Frame Modification", flickerstreak@30: ["Interface Enhancements"] = "Interface Enhancements", flickerstreak@30: ["Inventory"] = "Inventory", flickerstreak@30: ["Library"] = "Library", flickerstreak@30: ["Map"] = "Map", flickerstreak@30: ["Mail"] = "Mail", flickerstreak@30: ["Miscellaneous"] = "Miscellaneous", flickerstreak@30: ["Quest"] = "Quest", flickerstreak@30: ["Raid"] = "Raid", flickerstreak@30: ["Tradeskill"] = "Tradeskill", flickerstreak@30: ["UnitFrame"] = "UnitFrame", flickerstreak@30: } flickerstreak@30: end flickerstreak@30: flickerstreak@30: local select = _G.select flickerstreak@30: local tostring = _G.tostring flickerstreak@30: local pairs = _G.pairs flickerstreak@30: local ipairs = _G.ipairs flickerstreak@30: local error = _G.error flickerstreak@30: local setmetatable = _G.setmetatable flickerstreak@30: local getmetatable = _G.getmetatable flickerstreak@30: local type = _G.type flickerstreak@30: local pcall = _G.pcall flickerstreak@30: local next = _G.next flickerstreak@30: local tonumber = _G.tonumber flickerstreak@30: local strmatch = _G.strmatch flickerstreak@30: local table_remove = _G.table.remove flickerstreak@30: local debugstack = _G.debugstack flickerstreak@30: local LoadAddOn = _G.LoadAddOn flickerstreak@30: local GetAddOnInfo = _G.GetAddOnInfo flickerstreak@30: local GetAddOnMetadata = _G.GetAddOnMetadata flickerstreak@30: local GetNumAddOns = _G.GetNumAddOns flickerstreak@30: local DisableAddOn = _G.DisableAddOn flickerstreak@30: local EnableAddOn = _G.EnableAddOn flickerstreak@30: local IsAddOnLoadOnDemand = _G.IsAddOnLoadOnDemand flickerstreak@30: local IsLoggedIn = _G.IsLoggedIn flickerstreak@30: local geterrorhandler = _G.geterrorhandler flickerstreak@30: local assert = _G.assert flickerstreak@30: local collectgarbage = _G.collectgarbage flickerstreak@30: local table_sort = _G.table.sort flickerstreak@30: local table_concat = _G.table.concat flickerstreak@30: flickerstreak@30: -- #AUTODOC_NAMESPACE Rock flickerstreak@30: flickerstreak@30: flickerstreak@30: local LibStub = _G.LibStub flickerstreak@30: flickerstreak@30: local Rock = LibStub:GetLibrary(MAJOR_VERSION, true) or _G.Rock flickerstreak@30: local oldRock flickerstreak@30: if not Rock then flickerstreak@30: Rock = LibStub:NewLibrary(MAJOR_VERSION, MINOR_VERSION) flickerstreak@30: if not Rock then flickerstreak@30: return flickerstreak@30: end flickerstreak@30: Rock.name = MAJOR_VERSION flickerstreak@30: else flickerstreak@30: Rock, oldRock = Rock:NewLibrary(MAJOR_VERSION, MINOR_VERSION) flickerstreak@30: if not Rock then flickerstreak@30: return flickerstreak@30: end flickerstreak@30: end flickerstreak@30: _G.Rock = Rock flickerstreak@30: flickerstreak@30: local L = setmetatable({}, {__index=function(self,key) self[key] = key; return key end}) flickerstreak@30: if GetLocale() == "zhCN" then flickerstreak@30: L["Advanced options"] = "高级选项" flickerstreak@30: L["Advanced options for developers and power users."] = "开发者与高级用户的高级选项" flickerstreak@30: L["Unit tests"] = "框体测试" flickerstreak@30: L["Enable unit tests to be run. This is for developers only.\n\nYou must ReloadUI for changes to take effect."] = "开启框体测试,仅供开发者使用。\n\n需要重载用户界面。" flickerstreak@30: L["Contracts"] = "侦错协定" flickerstreak@30: L["Enable contracts to be run. This is for developers and anyone wanting to file a bug. Do not file a bug unless contracts are enabled. This will slightly slow down your addons if enabled."] = "启用侦错协定,这是给插件作者用来通报错误所使用。" flickerstreak@30: L["Reload UI"] = "重载UI" flickerstreak@30: L["Reload the User Interface for some changes to take effect."] = "部分功能更改需要重载用户界面才会生效。" flickerstreak@30: L["Reload"] = "重载" flickerstreak@30: L["Give donation"] = "捐赠" flickerstreak@30: L["Donate"] = "捐赠" flickerstreak@30: L["Give a much-needed donation to the author of this addon."] = "给插件作者捐赠支持插件开发。" flickerstreak@30: L["File issue"] = "通报错误" flickerstreak@30: L["Report"] = "报告" flickerstreak@30: L["File a bug or request a new feature or an improvement to this addon."] = "发送错误报告或请求新功能及要改进的部分。" flickerstreak@30: L["Press Ctrl-C to copy, then Alt-Tab out of the game, open your favorite web browser, and paste the link into the address bar."] = "Ctrl-C复制网址,Alt-Tab切换到桌面,打开浏览器,在地址栏贴上网址。" flickerstreak@30: L["Press Cmd-C to copy, then Cmd-Tab out of the game, open your favorite web browser, and paste the link into the address bar."] = "Cmd-C复制网址,Cmd-Tab切换到电脑桌面,打开浏览器,在地址栏贴上网址。" flickerstreak@30: L["Enabled"] = "开启" flickerstreak@30: L["Enable or disable this addon."] = "启用这个插件。" flickerstreak@30: flickerstreak@30: elseif GetLocale() == "zhTW" then flickerstreak@30: L["Advanced options"] = "進階選項" flickerstreak@30: L["Advanced options for developers and power users."] = "插件作者、進階用戶選項" flickerstreak@30: L["Unit tests"] = "單元測試" flickerstreak@30: L["Enable unit tests to be run. This is for developers only.\n\nYou must ReloadUI for changes to take effect."] = "啟用單元測試,這是給插件作者使用的功能。\n\n需要重載介面才能使用。" flickerstreak@30: L["Contracts"] = "偵錯協定" flickerstreak@30: L["Enable contracts to be run. This is for developers and anyone wanting to file a bug. Do not file a bug unless contracts are enabled. This will slightly slow down your addons if enabled."] = "啟用偵錯協定,這是給插件作者用來通報錯誤所使用。" flickerstreak@30: L["Reload UI"] = "重載介面" flickerstreak@30: L["Reload the User Interface for some changes to take effect."] = "重新載入使用者介面,部分功能才會生效。" flickerstreak@30: L["Reload"] = "重載" flickerstreak@30: L["Give donation"] = "捐贈" flickerstreak@30: L["Donate"] = "捐贈" flickerstreak@30: L["Give a much-needed donation to the author of this addon."] = "捐贈金錢給插件作者。" flickerstreak@30: L["File issue"] = "通報錯誤" flickerstreak@30: L["Report"] = "報告" flickerstreak@30: L["File a bug or request a new feature or an improvement to this addon."] = "發出錯誤報告或請求新功能及要改進的部分。" flickerstreak@30: L["Press Ctrl-C to copy, then Alt-Tab out of the game, open your favorite web browser, and paste the link into the address bar."] = "Ctrl-C複製網址,Alt-Tab切換到電腦桌面,打開瀏覽器,在網址列貼上網址。" flickerstreak@30: L["Press Cmd-C to copy, then Cmd-Tab out of the game, open your favorite web browser, and paste the link into the address bar."] = "Cmd-C複製網址,Cmd-Tab切換到電腦桌面,打開瀏覽器,在網址列貼上網址。" flickerstreak@30: L["Enabled"] = "啟用" flickerstreak@30: L["Enable or disable this addon."] = "啟用這個插件。" flickerstreak@30: elseif GetLocale() == "koKR" then flickerstreak@30: L["Advanced options"] = "상세 옵션" flickerstreak@30: L["Advanced options for developers and power users."] = "개발자와 파워 사용자를 위한 상세 옵션입니다." flickerstreak@30: L["Unit tests"] = "유닛 테스트" flickerstreak@30: L["Enable unit tests to be run. This is for developers only.\n\nYou must ReloadUI for changes to take effect."] = "유닛 테스트를 사용합니다. 이것은 개발자만을 위한 옵션입니다.\n\n변경된 결과를 적용하기 위해 당신의 UI를 재실행 합니다." flickerstreak@30: L["Contracts"] = "계약" flickerstreak@30: L["Enable contracts to be run. This is for developers and anyone wanting to file a bug. Do not file a bug unless contracts are enabled. This will slightly slow down your addons if enabled."] = "계약을 사용합니다. 이것은 개발자와 버그 파일을 알릴 분이면 누구나 사용 가능합니다. 계약이 가능하지 않으면 버그 파일을 보내지 마십시오. 이것은 당신의 애드온 속도를 약간 떨어뜨립니다." flickerstreak@30: L["Reload UI"] = "UI 재실행" flickerstreak@30: L["Reload the User Interface for some changes to take effect."] = "변경된 결과를 적용하기 위해 사용자 인터페이스를 재실행합니다." flickerstreak@30: L["Reload"] = "재실행" flickerstreak@30: L["Give donation"] = "기부" flickerstreak@30: L["Donate"] = "기부" flickerstreak@30: L["Give a much-needed donation to the author of this addon."] = "이 애드온의 제작자에게 필요한 기부를 합니다." flickerstreak@30: L["File issue"] = "파일 이슈" flickerstreak@30: L["Report"] = "보고" flickerstreak@30: L["File a bug or request a new feature or an improvement to this addon."] = "버그 파일을 알리거나 새로운 기능 또는 이 애드온에 대한 개선을 부탁합니다." flickerstreak@30: L["Press Ctrl-C to copy, then Alt-Tab out of the game, open your favorite web browser, and paste the link into the address bar."] = "Ctrl-C로 복사합니다. Alt-Tab 눌려 게임으로 부터 나간후 웹 브라우저를 엽니다. 복사된 링크를 주소 창에 붙여넣기 합니다." flickerstreak@30: L["Press Cmd-C to copy, then Cmd-Tab out of the game, open your favorite web browser, and paste the link into the address bar."] = "Cmd-C로 복사합니다. Cmd-Tab 눌려 게임으로 부터 나간후 웹 브라우저를 엽니다. 복사된 링크를 주소 창에 붙여넣기 합니다." flickerstreak@30: L["Enabled"] = "사용" flickerstreak@30: L["Enable or disable this addon."] = "이 애드온을 사용하거나 사용하지 않습니다." flickerstreak@30: elseif GetLocale() == "frFR" then flickerstreak@30: L["Advanced options"] = "Options avancées" flickerstreak@30: L["Advanced options for developers and power users."] = "Options avancées à l'attention des développeurs et des utilisateurs expérimentés." flickerstreak@30: L["Reload UI"] = "Recharger IU" flickerstreak@30: L["Reload the User Interface for some changes to take effect."] = "Recharge l'interface utilisateur afin que certains changements prennent effet." flickerstreak@30: L["Reload"] = "Recharger" flickerstreak@30: L["Give donation"] = "Faire un don" flickerstreak@30: L["Donate"] = "Don" flickerstreak@30: L["Give a much-needed donation to the author of this addon."] = "Permet de faire un don bien mérité à l'auteur de cet addon." flickerstreak@30: L["File issue"] = "Problème" flickerstreak@30: L["Report"] = "Signaler" flickerstreak@30: L["File a bug or request a new feature or an improvement to this addon."] = "Permet de signaler un bogue ou de demander une amélioration à cet addon." flickerstreak@30: L["Press Ctrl-C to copy, then Alt-Tab out of the game, open your favorite web browser, and paste the link into the address bar."] = "Ctrl-C pour copier, puis Alt-Tab pour sortir du jeu. Ouvrez votre navigateur internet et collez le lien dans la barre d'adresse." flickerstreak@30: L["Press Cmd-C to copy, then Cmd-Tab out of the game, open your favorite web browser, and paste the link into the address bar."] = "Cmd-C pour copier, puis Alt-Tab pour sortir du jeu. Ouvrez votre navigateur internet et collez le lien dans la barre d'adresse." flickerstreak@30: L["Enabled"] = "Activé" flickerstreak@30: L["Enable or disable this addon."] = "Active ou désactive cet addon." flickerstreak@30: end flickerstreak@30: flickerstreak@30: local isStandalone = debugstack():match("[Oo%.][Nn%.][Ss%.]\\([^\\]+)\\") == MAJOR_VERSION or nil flickerstreak@30: local unitTestDB, enableContracts flickerstreak@30: flickerstreak@30: local weakKey = { __mode = 'k' } flickerstreak@30: flickerstreak@30: -- frame to manage events from flickerstreak@30: Rock.frame = oldRock and oldRock.frame or _G.CreateFrame("Frame") flickerstreak@30: local frame = Rock.frame flickerstreak@30: -- dict of libraries in { ["major"] = object } form flickerstreak@30: Rock.libraries = oldRock and oldRock.libraries or { [MAJOR_VERSION] = Rock } flickerstreak@30: local libraries = Rock.libraries flickerstreak@30: -- set of libraries which have gone through the finalization process in { [object] = true } form flickerstreak@30: Rock.finalizedLibraries = setmetatable(oldRock and oldRock.finalizedLibraries or { }, weakKey) flickerstreak@30: local finalizedLibraries = Rock.finalizedLibraries flickerstreak@30: -- set of libraries which have been tried to be loaded. flickerstreak@30: Rock.scannedLibraries = oldRock and oldRock.scannedLibraries or {} flickerstreak@30: local scannedLibraries = Rock.scannedLibraries flickerstreak@30: -- exportedMethods[library] = { "method1", "method2" } flickerstreak@30: Rock.exportedMethods = setmetatable(oldRock and oldRock.exportedMethods or {}, weakKey) flickerstreak@30: local exportedMethods = Rock.exportedMethods flickerstreak@30: -- mixinToObject[mixin][object] = true flickerstreak@30: Rock.mixinToObject = setmetatable(oldRock and oldRock.mixinToObject or {}, weakKey) flickerstreak@30: local mixinToObject = Rock.mixinToObject flickerstreak@30: -- dict of addons in { ["name"] = object } form flickerstreak@30: Rock.addons = oldRock and oldRock.addons or {} flickerstreak@30: local addons = Rock.addons flickerstreak@30: -- set of libraries that should be finalized before ADDON_LOADED. flickerstreak@30: Rock.pendingLibraries = setmetatable(oldRock and oldRock.pendingLibraries or { }, weakKey) flickerstreak@30: local pendingLibraries = Rock.pendingLibraries flickerstreak@30: -- list of addons in order of created that need to be initialized by ADDON_LOADED. flickerstreak@30: Rock.pendingAddons = oldRock and oldRock.pendingAddons or {} flickerstreak@30: local pendingAddons = Rock.pendingAddons flickerstreak@30: -- dictionary of addons to their folder names flickerstreak@30: Rock.addonToFolder = oldRock and oldRock.addonToFolder or {} flickerstreak@30: local addonToFolder = Rock.addonToFolder flickerstreak@30: -- set of folders which have been loaded flickerstreak@30: Rock.foldersLoaded = oldRock and oldRock.foldersLoaded or {} flickerstreak@30: local foldersLoaded = Rock.foldersLoaded flickerstreak@30: -- list of addons in order of created that need to be enabled by PLAYER_LOGIN. flickerstreak@30: Rock.pendingAddonsEnable = oldRock and oldRock.pendingAddonsEnable or {} flickerstreak@30: local pendingAddonsEnable = Rock.pendingAddonsEnable flickerstreak@30: -- set of addons which have been enabled at least once. flickerstreak@30: Rock.addonsAlreadyEnabled = oldRock and oldRock.addonsAlreadyEnabled or {} flickerstreak@30: local addonsAlreadyEnabled = Rock.addonsAlreadyEnabled flickerstreak@30: -- set of addons which have no database and are set to be inactive. flickerstreak@30: Rock.inactiveAddons = oldRock and oldRock.inactiveAddons or {} flickerstreak@30: local inactiveAddons = Rock.inactiveAddons flickerstreak@30: -- set of addons which are currently enabled (not necessarily should be) flickerstreak@30: Rock.currentlyEnabledAddons = oldRock and oldRock.currentlyEnabledAddons or {} flickerstreak@30: local currentlyEnabledAddons = Rock.currentlyEnabledAddons flickerstreak@30: -- dictionary of namespace to list of functions which will be run. flickerstreak@30: Rock.unitTests = oldRock and oldRock.unitTests or {} flickerstreak@30: local unitTests = Rock.unitTests flickerstreak@30: -- metatable for addons flickerstreak@30: Rock.addon_mt = oldRock and oldRock.addon_mt or {} flickerstreak@30: local addon_mt = Rock.addon_mt flickerstreak@30: for k in pairs(addon_mt) do flickerstreak@30: addon_mt[k] = nil flickerstreak@30: end flickerstreak@30: function addon_mt:__tostring() flickerstreak@30: return tostring(self.name) flickerstreak@30: end flickerstreak@30: flickerstreak@30: local function better_tostring(self) flickerstreak@30: if type(self) == "table" and self.name then flickerstreak@30: return tostring(self.name) flickerstreak@30: end flickerstreak@30: return tostring(self) flickerstreak@30: end flickerstreak@30: flickerstreak@30: local function figureCurrentAddon(pos) flickerstreak@30: local stack = debugstack(pos+1, 1, 0) flickerstreak@30: local folder = stack:match("[Oo%.][Nn%.][Ss%.]\\([^\\]+)\\") flickerstreak@30: if folder then flickerstreak@30: return folder flickerstreak@30: end flickerstreak@30: flickerstreak@30: local partFolder = stack:match("...([^\\]+)\\") flickerstreak@30: if partFolder then flickerstreak@30: local partFolder_len = #partFolder flickerstreak@30: for i = 1, GetNumAddOns() do flickerstreak@30: local name = GetAddOnInfo(i) flickerstreak@30: if #name >= partFolder_len then flickerstreak@30: local partName = name:sub(-partFolder_len) flickerstreak@30: if partName == partFolder then flickerstreak@30: return name flickerstreak@30: end flickerstreak@30: end flickerstreak@30: end flickerstreak@30: end flickerstreak@30: return nil flickerstreak@30: end flickerstreak@30: flickerstreak@30: --[[--------------------------------------------------------------------------- flickerstreak@30: Returns: flickerstreak@30: string - the localized name of the given category. flickerstreak@30: Arguments: flickerstreak@30: string - the English name of the category. flickerstreak@30: Example: flickerstreak@30: local uf = Rock:GetLocalizedCategory("UnitFrame") flickerstreak@30: -----------------------------------------------------------------------------]] flickerstreak@30: function Rock:GetLocalizedCategory(name) flickerstreak@30: if type(name) ~= "string" then flickerstreak@30: error(("Bad argument #2 to `GetLocalizedCategory'. Expected %q, got %q."):format("string", type(name)), 2) flickerstreak@30: end flickerstreak@30: local cat = CATEGORIES[name] flickerstreak@30: if cat then flickerstreak@30: return cat flickerstreak@30: end flickerstreak@30: local name_lower = name:lower() flickerstreak@30: for k in pairs(CATEGORIES) do flickerstreak@30: if k:lower() == name_lower then flickerstreak@30: return k flickerstreak@30: end flickerstreak@30: end flickerstreak@30: return _G.UNKNOWN or "Unknown" flickerstreak@30: end flickerstreak@30: flickerstreak@30: local weak = {__mode = 'kv'} flickerstreak@30: flickerstreak@30: Rock.recycleData = oldRock and oldRock.recycleData or {} flickerstreak@30: local recycleData = Rock.recycleData flickerstreak@30: if recycleData.pools then flickerstreak@30: setmetatable(recycleData.pools, weak) flickerstreak@30: end flickerstreak@30: if recycleData.debugPools then flickerstreak@30: setmetatable(recycleData.debugPools, weak) flickerstreak@30: end flickerstreak@30: if recycleData.newList then flickerstreak@30: setmetatable(recycleData.newList, weak) flickerstreak@30: end flickerstreak@30: if recycleData.newDict then flickerstreak@30: setmetatable(recycleData.newDict, weak) flickerstreak@30: end flickerstreak@30: if recycleData.newSet then flickerstreak@30: setmetatable(recycleData.newSet, weak) flickerstreak@30: end flickerstreak@30: if recycleData.del then flickerstreak@30: setmetatable(recycleData.del, weak) flickerstreak@30: end flickerstreak@30: flickerstreak@30: local tmp = {} flickerstreak@30: local function myUnpack(t, start) flickerstreak@30: if not start then flickerstreak@30: start = 1 flickerstreak@30: end flickerstreak@30: local value = t[start] flickerstreak@30: if value == nil then flickerstreak@30: return flickerstreak@30: end flickerstreak@30: t[start] = nil flickerstreak@30: return value, myUnpack(t, start+1) flickerstreak@30: end flickerstreak@30: flickerstreak@30: --[[--------------------------------------------------------------------------- flickerstreak@30: Notes: flickerstreak@30: * Returns functions for the specified namespace based on what is provided. flickerstreak@30: * function types: flickerstreak@30: ; "newList" : to create a list flickerstreak@30: ; "newDict" : to create a dictionary flickerstreak@30: ; "newSet" : to create a set flickerstreak@30: ; "del" : to delete a table flickerstreak@30: ; "unpackListAndDel" : deletes a table and returns what its contents were as a list, in order. flickerstreak@30: ; "unpackSetAndDel" : deletes a table and returns what its contents were as a set, in no particular order. flickerstreak@30: ; "unpackDictAndDel" : deletes a table and returns what its contents were as a dictionary, in no particular order. flickerstreak@30: * If you provide "Debug" as the last argument, then the namespace can be debugged with ''':DebugRecycle''' flickerstreak@30: * It is '''not recommended''' to use table recycling with tables that have more than 128 keys, as it is typically faster to let lua's garbage collector handle it. flickerstreak@30: Arguments: flickerstreak@30: string - the namespace. ''Note: this doesn't necessarily have to be a string.'' flickerstreak@30: Example: flickerstreak@30: local newList, newDict, newSet, del, unpackListAndDel, unpackSetAndDel, unpackDictAndDel = Rock:GetRecyclingFunctions("MyNamespace", "newList", "newDict", "newSet", "del", "unpackListAndDel", "unpackSetAndDel", "unpackDictAndDel") flickerstreak@30: flickerstreak@30: local t = newList('alpha', 'bravo') -- same as t = {'alpha', 'bravo'} flickerstreak@30: local u = newDict('alpha', 'bravo') -- same as t = {['alpha'] = 'bravo'} flickerstreak@30: local v = newSet('alpha', 'bravo') -- same as t = {['alpha'] = true, ['bravo'] = true} flickerstreak@30: t = del(t) -- you want to clear your reference as well as deleting. flickerstreak@30: u = del(u) flickerstreak@30: v = del(v) flickerstreak@30: flickerstreak@30: -- for debugging flickerstreak@30: local newList = Rock:GetRecyclingFunctions("MyNamespace", "newList", "Debug") flickerstreak@30: local t = newList() flickerstreak@30: Rock:DebugRecycle("MyNamespace") flickerstreak@30: t = del(t) flickerstreak@30: flickerstreak@30: -- unpacking functions flickerstreak@30: unpackListAndDel(newList(...)) => ... flickerstreak@30: unpackSetAndDel(newSet(...)) => ... flickerstreak@30: unpackDictAndDel(newDict(...)) => ... flickerstreak@30: newList(unpackListAndDel(t)) => t flickerstreak@30: newSet(unpackSetAndDel(t)) => t flickerstreak@30: newDict(unpackDictAndDel(t)) => t flickerstreak@30: -- as you can see, they are inverses of each other. flickerstreak@30: -----------------------------------------------------------------------------]] flickerstreak@30: function Rock:GetRecyclingFunctions(namespace, ...) flickerstreak@30: local pools = recycleData.pools flickerstreak@30: if not pools then flickerstreak@30: pools = setmetatable({}, weak) flickerstreak@30: recycleData.pools = pools flickerstreak@30: end flickerstreak@30: if namespace == "newList" or namespace == "newSet" or namespace == "newDict" or namespace == "del" or namespace == "unpackListAndDel" or namespace == "unpackSetAndDel" or namespace == "unpackDictAndDel" then flickerstreak@30: error(("Bad argument #2 to `GetRecyclingFunctions'. Cannot be %q"):format(namespace), 2) flickerstreak@30: end flickerstreak@30: local pool = pools[namespace] flickerstreak@30: if not pool then flickerstreak@30: pool = setmetatable({}, weak) flickerstreak@30: pools[namespace] = pool flickerstreak@30: end flickerstreak@30: local n = select('#', ...) flickerstreak@30: local debug = select(n, ...) == "Debug" flickerstreak@30: if debug then flickerstreak@30: n = n - 1 flickerstreak@30: local debugPools = recycleData.debugPools flickerstreak@30: if not debugPools then flickerstreak@30: debugPools = setmetatable({}, weak) flickerstreak@30: recycleData.debugPools = debugPools flickerstreak@30: end flickerstreak@30: debug = debugPools[namespace] flickerstreak@30: if not debug then flickerstreak@30: debug = { num = 0 } flickerstreak@30: debugPools[namespace] = debug flickerstreak@30: end flickerstreak@30: elseif recycleData.debugPools and recycleData.debugPools[namespace] then flickerstreak@30: debug = recycleData.debugPools[namespace] flickerstreak@30: end flickerstreak@30: for i = 1, n do flickerstreak@30: local func = select(i, ...) flickerstreak@30: local recycleData_func = recycleData[func] flickerstreak@30: if not recycleData_func then flickerstreak@30: recycleData_func = setmetatable({}, weak) flickerstreak@30: recycleData[func] = recycleData_func flickerstreak@30: end flickerstreak@30: if func == "newList" then flickerstreak@30: local newList = recycleData_func[namespace] flickerstreak@30: if not newList then flickerstreak@30: function newList(...) flickerstreak@30: local t = next(pool) flickerstreak@30: local n = select('#', ...) flickerstreak@30: if t then flickerstreak@30: pool[t] = nil flickerstreak@30: for i = 1, n do flickerstreak@30: t[i] = select(i, ...) flickerstreak@30: end flickerstreak@30: else flickerstreak@30: t = { ... } flickerstreak@30: end flickerstreak@30: flickerstreak@30: if debug then flickerstreak@30: debug[t] = debugstack(2) flickerstreak@30: debug.num = debug.num + 1 flickerstreak@30: end flickerstreak@30: flickerstreak@30: return t, n flickerstreak@30: end flickerstreak@30: recycleData_func[namespace] = newList flickerstreak@30: end flickerstreak@30: tmp[i] = newList flickerstreak@30: elseif func == "newDict" then flickerstreak@30: local newDict = recycleData_func[namespace] flickerstreak@30: if not newDict then flickerstreak@30: function newDict(...) flickerstreak@30: local t = next(pool) flickerstreak@30: if t then flickerstreak@30: pool[t] = nil flickerstreak@30: else flickerstreak@30: t = {} flickerstreak@30: end flickerstreak@30: flickerstreak@30: for i = 1, select('#', ...), 2 do flickerstreak@30: t[select(i, ...)] = select(i+1, ...) flickerstreak@30: end flickerstreak@30: flickerstreak@30: if debug then flickerstreak@30: debug[t] = debugstack(2) flickerstreak@30: debug.num = debug.num + 1 flickerstreak@30: end flickerstreak@30: flickerstreak@30: return t flickerstreak@30: end flickerstreak@30: recycleData_func[namespace] = newDict flickerstreak@30: end flickerstreak@30: tmp[i] = newDict flickerstreak@30: elseif func == "newSet" then flickerstreak@30: local newSet = recycleData_func[namespace] flickerstreak@30: if not newSet then flickerstreak@30: function newSet(...) flickerstreak@30: local t = next(pool) flickerstreak@30: if t then flickerstreak@30: pool[t] = nil flickerstreak@30: else flickerstreak@30: t = {} flickerstreak@30: end flickerstreak@30: flickerstreak@30: for i = 1, select('#', ...) do flickerstreak@30: t[select(i, ...)] = true flickerstreak@30: end flickerstreak@30: flickerstreak@30: if debug then flickerstreak@30: debug[t] = debugstack(2) flickerstreak@30: debug.num = debug.num + 1 flickerstreak@30: end flickerstreak@30: flickerstreak@30: return t flickerstreak@30: end flickerstreak@30: recycleData_func[namespace] = newSet flickerstreak@30: end flickerstreak@30: tmp[i] = newSet flickerstreak@30: elseif func == "del" then flickerstreak@30: local del = recycleData_func[namespace] flickerstreak@30: if not del then flickerstreak@30: function del(t) flickerstreak@30: if not t then flickerstreak@30: error(("Bad argument #1 to `del'. Expected %q, got %q."):format("table", type(t)), 2) flickerstreak@30: end flickerstreak@30: if pool[t] then flickerstreak@30: local _, ret = pcall(error, "Error, double-free syndrome.", 3) flickerstreak@30: geterrorhandler()(ret) flickerstreak@30: end flickerstreak@30: setmetatable(t, nil) flickerstreak@30: for k in pairs(t) do flickerstreak@30: t[k] = nil flickerstreak@30: end flickerstreak@30: t[true] = true flickerstreak@30: t[true] = nil flickerstreak@30: pool[t] = true flickerstreak@30: flickerstreak@30: if debug then flickerstreak@30: debug[t] = nil flickerstreak@30: debug.num = debug.num - 1 flickerstreak@30: end flickerstreak@30: return nil flickerstreak@30: end flickerstreak@30: recycleData_func[namespace] = del flickerstreak@30: end flickerstreak@30: tmp[i] = del flickerstreak@30: elseif func == "unpackListAndDel" then flickerstreak@30: local unpackListAndDel = recycleData_func[namespace] flickerstreak@30: if not unpackListAndDel then flickerstreak@30: local function f(t, start, finish) flickerstreak@30: if start > finish then flickerstreak@30: for k in pairs(t) do flickerstreak@30: t[k] = nil flickerstreak@30: end flickerstreak@30: t[true] = true flickerstreak@30: t[true] = nil flickerstreak@30: pool[t] = true flickerstreak@30: return flickerstreak@30: end flickerstreak@30: return t[start], f(t, start+1, finish) flickerstreak@30: end flickerstreak@30: function unpackListAndDel(t, start, finish) flickerstreak@30: if not t then flickerstreak@30: error(("Bad argument #1 to `unpackListAndDel'. Expected %q, got %q."):format("table", type(t)), 2) flickerstreak@30: end flickerstreak@30: if not start then flickerstreak@30: start = 1 flickerstreak@30: end flickerstreak@30: if not finish then flickerstreak@30: finish = #t flickerstreak@30: end flickerstreak@30: setmetatable(t, nil) flickerstreak@30: if debug then flickerstreak@30: debug[t] = nil flickerstreak@30: debug.num = debug.num - 1 flickerstreak@30: end flickerstreak@30: return f(t, start, finish) flickerstreak@30: end flickerstreak@30: end flickerstreak@30: tmp[i] = unpackListAndDel flickerstreak@30: elseif func == "unpackSetAndDel" then flickerstreak@30: local unpackSetAndDel = recycleData_func[namespace] flickerstreak@30: if not unpackSetAndDel then flickerstreak@30: local function f(t, current) flickerstreak@30: current = next(t, current) flickerstreak@30: if current == nil then flickerstreak@30: for k in pairs(t) do flickerstreak@30: t[k] = nil flickerstreak@30: end flickerstreak@30: t[true] = true flickerstreak@30: t[true] = nil flickerstreak@30: pool[t] = true flickerstreak@30: return flickerstreak@30: end flickerstreak@30: return current, f(t, current) flickerstreak@30: end flickerstreak@30: function unpackSetAndDel(t) flickerstreak@30: if not t then flickerstreak@30: error(("Bad argument #1 to `unpackListAndDel'. Expected %q, got %q."):format("table", type(t)), 2) flickerstreak@30: end flickerstreak@30: setmetatable(t, nil) flickerstreak@30: if debug then flickerstreak@30: debug[t] = nil flickerstreak@30: debug.num = debug.num - 1 flickerstreak@30: end flickerstreak@30: return f(t, nil) flickerstreak@30: end flickerstreak@30: end flickerstreak@30: tmp[i] = unpackSetAndDel flickerstreak@30: elseif func == "unpackDictAndDel" then flickerstreak@30: local unpackDictAndDel = recycleData_func[namespace] flickerstreak@30: if not unpackDictAndDel then flickerstreak@30: local function f(t, current) flickerstreak@30: local value flickerstreak@30: current, value = next(t, current) flickerstreak@30: if current == nil then flickerstreak@30: for k in pairs(t) do flickerstreak@30: t[k] = nil flickerstreak@30: end flickerstreak@30: t[true] = true flickerstreak@30: t[true] = nil flickerstreak@30: pool[t] = true flickerstreak@30: return flickerstreak@30: end flickerstreak@30: return current, value, f(t, current) flickerstreak@30: end flickerstreak@30: function unpackDictAndDel(t) flickerstreak@30: if not t then flickerstreak@30: error(("Bad argument #1 to `unpackListAndDel'. Expected %q, got %q."):format("table", type(t)), 2) flickerstreak@30: end flickerstreak@30: setmetatable(t, nil) flickerstreak@30: if debug then flickerstreak@30: debug[t] = nil flickerstreak@30: debug.num = debug.num - 1 flickerstreak@30: end flickerstreak@30: return f(t, nil) flickerstreak@30: end flickerstreak@30: end flickerstreak@30: tmp[i] = unpackDictAndDel flickerstreak@30: else flickerstreak@30: error(("Bad argument #%d to `GetRecyclingFunctions': %q, %q, %q, %q, %q, %q, or %q expected, got %s"):format(i+2, "newList", "newDict", "newSet", "del", "unpackListAndDel", "unpackSetAndDel", "unpackDictAndDel", type(func) == "string" and ("%q"):format(func) or tostring(func)), 2) flickerstreak@30: end flickerstreak@30: end flickerstreak@30: return myUnpack(tmp) flickerstreak@30: end flickerstreak@30: flickerstreak@30: --[[--------------------------------------------------------------------------- flickerstreak@30: Notes: flickerstreak@30: * Prints information about the specified recycling namespace, including what tables are still in play and where they come from and how many there are. flickerstreak@30: * This goes in tandem with ''':GetRecyclingFunctions''' flickerstreak@30: Arguments: flickerstreak@30: string - the namespace. ''Note: this doesn't necessarily have to be a string.'' flickerstreak@30: Example: flickerstreak@30: local newList = Rock:GetRecyclingFunctions("MyNamespace", "newList", "Debug") flickerstreak@30: local t = newList() flickerstreak@30: Rock:DebugRecycle("MyNamespace") flickerstreak@30: t = del(t) flickerstreak@30: -----------------------------------------------------------------------------]] flickerstreak@30: function Rock:DebugRecycle(namespace) flickerstreak@30: local debug = recycleData.debugPools and recycleData.debugPools[namespace] flickerstreak@30: if not debug then flickerstreak@30: return flickerstreak@30: end flickerstreak@30: for k, v in pairs(debug) do flickerstreak@30: if k ~= "num" then flickerstreak@30: _G.DEFAULT_CHAT_FRAME:AddMessage(v) flickerstreak@30: _G.DEFAULT_CHAT_FRAME:AddMessage("------") flickerstreak@30: end flickerstreak@30: end flickerstreak@30: _G.DEFAULT_CHAT_FRAME:AddMessage(("%s: %d tables in action."):format(tostring(namespace), debug.num)) flickerstreak@30: end flickerstreak@30: flickerstreak@30: local newList, del, unpackListAndDel, unpackDictAndDel = Rock:GetRecyclingFunctions(MAJOR_VERSION, "newList", "del", "unpackListAndDel", "unpackDictAndDel") flickerstreak@30: flickerstreak@30: --[[--------------------------------------------------------------------------- flickerstreak@30: Notes: flickerstreak@30: * Adds a unit test for the specified namespace flickerstreak@30: * The function provided is called, and it should be where tests are performed, if a problem occurs, an error should fire. If no problems occur, it should return silently. flickerstreak@30: * You can have as many tests per namespace as you want. flickerstreak@30: Arguments: flickerstreak@30: string - the namespace. flickerstreak@30: function - the function to call. flickerstreak@30: Example: flickerstreak@30: Rock:AddUnitTest("LibMonkey-1.0", function() flickerstreak@30: local LibMonkey = Rock("LibMonkey-1.0") flickerstreak@30: assert(LibMonkey:Fling() == "Poo") flickerstreak@30: end) flickerstreak@30: -----------------------------------------------------------------------------]] flickerstreak@30: function Rock:AddUnitTest(namespace, func) flickerstreak@30: if not isStandalone then flickerstreak@30: return flickerstreak@30: end flickerstreak@30: if type(namespace) ~= "string" then flickerstreak@30: error(("Bad argument #2 to `AddUnitTest'. Expected %q, got %q."):format("string", type(namespace)), 2) flickerstreak@30: end flickerstreak@30: if namespace:find("^Lib[A-Z]") then flickerstreak@30: local addon = figureCurrentAddon(2) flickerstreak@30: if addon ~= namespace then flickerstreak@30: return flickerstreak@30: end flickerstreak@30: end flickerstreak@30: if type(func) ~= "function" then flickerstreak@30: error(("Bad argument #3 to `AddUnitTest'. Expected %q, got %q."):format("function", type(func)), 2) flickerstreak@30: end flickerstreak@30: local addon = figureCurrentAddon(2) flickerstreak@30: if libraries[namespace] and addon ~= namespace then flickerstreak@30: -- only work on standalone libraries. flickerstreak@30: return flickerstreak@30: end flickerstreak@30: local unitTests_namespace = unitTests[namespace] flickerstreak@30: if not unitTests_namespace then flickerstreak@30: unitTests_namespace = newList() flickerstreak@30: unitTests[namespace] = unitTests_namespace flickerstreak@30: end flickerstreak@30: if not unitTests_namespace.addon then flickerstreak@30: unitTests_namespace.addon = addon flickerstreak@30: end flickerstreak@30: if unitTestDB and not unitTestDB[namespace] then flickerstreak@30: return flickerstreak@30: end flickerstreak@30: unitTests_namespace[#unitTests_namespace+1] = func flickerstreak@30: end flickerstreak@30: flickerstreak@30: local LibRockEvent flickerstreak@30: local LibRockModuleCore flickerstreak@30: local OpenDonationFrame, OpenIssueFrame flickerstreak@30: function Rock:OnLibraryLoad(major, library) flickerstreak@30: if major == "LibRockEvent-1.0" then flickerstreak@30: LibRockEvent = library flickerstreak@30: LibRockEvent:Embed(Rock) flickerstreak@30: elseif major == "LibRockModuleCore-1.0" then flickerstreak@30: LibRockModuleCore = library flickerstreak@30: elseif major == "LibRockConfig-1.0" then flickerstreak@30: if isStandalone then flickerstreak@30: library.rockOptions.args.advanced = { flickerstreak@30: type = 'group', flickerstreak@30: groupType = 'inline', flickerstreak@30: name = L["Advanced options"], flickerstreak@30: desc = L["Advanced options for developers and power users."], flickerstreak@30: order = -1, flickerstreak@30: args = { flickerstreak@30: unitTests = { flickerstreak@30: type = 'multichoice', flickerstreak@30: name = L["Unit tests"], flickerstreak@30: desc = L["Enable unit tests to be run. This is for developers only.\n\nYou must ReloadUI for changes to take effect."], flickerstreak@30: get = function(key) flickerstreak@30: return unitTestDB[key] flickerstreak@30: end, flickerstreak@30: set = function(key, value) flickerstreak@30: unitTestDB[key] = value or nil flickerstreak@30: end, flickerstreak@30: choices = function() flickerstreak@30: local t = newList() flickerstreak@30: for k in pairs(unitTests) do flickerstreak@30: t[k] = k flickerstreak@30: end flickerstreak@30: return "@dict", unpackDictAndDel(t) flickerstreak@30: end flickerstreak@30: }, flickerstreak@30: contracts = { flickerstreak@30: type = 'boolean', flickerstreak@30: name = L["Contracts"], flickerstreak@30: desc = L["Enable contracts to be run. This is for developers and anyone wanting to file a bug. Do not file a bug unless contracts are enabled. This will slightly slow down your addons if enabled."], flickerstreak@30: get = function() flickerstreak@30: return enableContracts flickerstreak@30: end, flickerstreak@30: set = function(value) flickerstreak@30: _G.LibRock_1_0DB.contracts = value or nil flickerstreak@30: enableContracts = value flickerstreak@30: end, flickerstreak@30: } flickerstreak@30: } flickerstreak@30: } flickerstreak@30: end flickerstreak@30: library.rockOptions.args.reloadui = { flickerstreak@30: type = 'execute', flickerstreak@30: name = L["Reload UI"], flickerstreak@30: desc = L["Reload the User Interface for some changes to take effect."], flickerstreak@30: buttonText = L["Reload"], flickerstreak@30: func = function() flickerstreak@30: _G.ReloadUI() flickerstreak@30: end, flickerstreak@30: order = -2, flickerstreak@30: } flickerstreak@30: Rock.donate = "Paypal:ckknight AT gmail DOT com" flickerstreak@30: library.rockOptions.args.donate = { flickerstreak@30: type = 'execute', flickerstreak@30: name = L["Give donation"], flickerstreak@30: buttonText = L["Donate"], flickerstreak@30: desc = L["Give a much-needed donation to the author of this addon."], flickerstreak@30: func = OpenDonationFrame, flickerstreak@30: passValue = Rock, flickerstreak@30: order = -3, flickerstreak@30: } flickerstreak@30: Rock.issueTracker = "Wowace:10027" flickerstreak@30: library.rockOptions.args.issue = { flickerstreak@30: type = 'execute', flickerstreak@30: name = L["File issue"], flickerstreak@30: buttonText = L["Report"], flickerstreak@30: desc = L["File a bug or request a new feature or an improvement to this addon."], flickerstreak@30: func = OpenIssueFrame, flickerstreak@30: passValue = Rock, flickerstreak@30: order = -4, flickerstreak@30: } flickerstreak@30: end flickerstreak@30: end flickerstreak@30: flickerstreak@30: addon_mt.__index = {} flickerstreak@30: local addon_mt___index = addon_mt.__index flickerstreak@30: --[[--------------------------------------------------------------------------- flickerstreak@30: #FORCE_DOC flickerstreak@30: Notes: flickerstreak@30: * This is exported to all addons. flickerstreak@30: * This information is retrieved from LibRockModuleCore-1.0 if it is a module, otherwise from LibRockDB-1.0 if it uses that as a mixin, otherwise it keeps a variable locally. flickerstreak@30: Returns: flickerstreak@30: boolean - whether the addon is in an active state or not. flickerstreak@30: Example: flickerstreak@30: local active = MyAddon:IsActive() flickerstreak@30: -----------------------------------------------------------------------------]] flickerstreak@30: function addon_mt___index:IsActive() flickerstreak@30: if LibRockModuleCore then flickerstreak@30: local core = LibRockModuleCore:HasModule(self) flickerstreak@30: if core then flickerstreak@30: return core:IsModuleActive(self) flickerstreak@30: end flickerstreak@30: end flickerstreak@30: flickerstreak@30: local self_db = self.db flickerstreak@30: if self_db then flickerstreak@30: local disabled flickerstreak@30: local self_db_raw = self_db.raw flickerstreak@30: if self_db_raw then flickerstreak@30: local self_db_raw_disabled = self_db_raw.disabled flickerstreak@30: if self_db_raw_disabled then flickerstreak@30: local profile = type(self.GetProfile) == "function" and select(2, self:GetProfile()) or false flickerstreak@30: disabled = self_db_raw_disabled[profile] flickerstreak@30: end flickerstreak@30: else flickerstreak@30: return false flickerstreak@30: end flickerstreak@30: return not disabled flickerstreak@30: end flickerstreak@30: flickerstreak@30: return not inactiveAddons[self] flickerstreak@30: end flickerstreak@30: --[[--------------------------------------------------------------------------- flickerstreak@30: #FORCE_DOC flickerstreak@30: Notes: flickerstreak@30: * This is exported to all addons. flickerstreak@30: * If it enables the addon, it will call :OnEnable(first) on the addon and :OnEmbedEnable(addon, first) on all its mixins. flickerstreak@30: * If it disables the addon, it will call :OnDisable(first) on the addon and :OnEmbedDisable(addon, first) on all its mixins. flickerstreak@30: * This information is stored by LibRockModuleCore-1.0 if it is a module, otherwise from LibRockDB-1.0 if it uses that as a mixin, otherwise it keeps a variable locally. flickerstreak@30: Arguments: flickerstreak@30: [optional] boolean - whether the addon should be in an active state or not. Default: not :IsActive() flickerstreak@30: Returns: flickerstreak@30: boolean - whether the addon is in an active state or not. flickerstreak@30: Example: flickerstreak@30: MyAddon:ToggleActive() -- switch flickerstreak@30: MyAddon:ToggleActive(true) -- force on flickerstreak@30: MyAddon:ToggleActive(false) -- force off flickerstreak@30: -----------------------------------------------------------------------------]] flickerstreak@30: function addon_mt___index:ToggleActive(state) flickerstreak@30: if state and state ~= true then flickerstreak@30: error(("Bad argument #2 to `ToggleActive'. Expected %q or %q, got %q."):format("boolean", "nil", type(state)), 2) flickerstreak@30: end flickerstreak@30: if LibRockModuleCore then flickerstreak@30: local core = LibRockModuleCore:HasModule(self) flickerstreak@30: if core then flickerstreak@30: return core:ToggleModuleActive(self, state) flickerstreak@30: end flickerstreak@30: end flickerstreak@30: flickerstreak@30: local self_db = self.db flickerstreak@30: if self_db then flickerstreak@30: local self_db_raw = self_db.raw flickerstreak@30: if not self_db_raw then flickerstreak@30: error("Error saving to database with `ToggleActive'. db.raw not available.", 2) flickerstreak@30: end flickerstreak@30: local self_db_raw_disabled = self_db_raw.disabled flickerstreak@30: if not self_db_raw_disabled then flickerstreak@30: self_db_raw_disabled = newList() flickerstreak@30: self_db_raw.disabled = self_db_raw_disabled flickerstreak@30: end flickerstreak@30: local profile = type(self.GetProfile) == "function" and select(2, self:GetProfile()) or false flickerstreak@30: if state == nil then flickerstreak@30: state = not not self_db_raw_disabled[profile] flickerstreak@30: elseif (not self_db_raw_disabled[profile]) == state then flickerstreak@30: return flickerstreak@30: end flickerstreak@30: self_db_raw_disabled[profile] = not state or nil flickerstreak@30: if next(self_db_raw_disabled) == nil then flickerstreak@30: self_db_raw.disabled = del(self_db_raw_disabled) flickerstreak@30: end flickerstreak@30: else flickerstreak@30: if state == nil then flickerstreak@30: state = not not inactiveAddons[self] flickerstreak@30: elseif (not inactiveAddons[self]) == state then flickerstreak@30: return flickerstreak@30: end flickerstreak@30: inactiveAddons[self] = not state or nil flickerstreak@30: end flickerstreak@30: flickerstreak@30: Rock:RecheckEnabledStates() flickerstreak@30: flickerstreak@30: return state flickerstreak@30: end flickerstreak@30: flickerstreak@30: local function noop() end flickerstreak@30: flickerstreak@30: do flickerstreak@30: local preconditions = setmetatable({}, weakKey) flickerstreak@30: local postconditions = setmetatable({}, weakKey) flickerstreak@30: local postconditionsOld = setmetatable({}, weakKey) flickerstreak@30: flickerstreak@30: local currentMethod = nil flickerstreak@30: flickerstreak@30: local function hook(object, method) flickerstreak@30: local object_method = object[method] flickerstreak@30: object[method] = function(...) flickerstreak@30: local pre = preconditions[object_method] flickerstreak@30: local post = postconditions[object_method] flickerstreak@30: if pre then flickerstreak@30: local old_currentMethod = currentMethod flickerstreak@30: currentMethod = method flickerstreak@30: pre(...) flickerstreak@30: currentMethod = old_currentMethod flickerstreak@30: end flickerstreak@30: if not post then flickerstreak@30: return object_method(...) flickerstreak@30: end flickerstreak@30: local oldFunc = postconditionsOld[object_method] flickerstreak@30: local old flickerstreak@30: if oldFunc then flickerstreak@30: old = newList() flickerstreak@30: oldFunc(old, ...) flickerstreak@30: end flickerstreak@30: flickerstreak@30: local old_currentMethod = currentMethod flickerstreak@30: currentMethod = nil flickerstreak@30: local ret, n = newList(object_method(...)) flickerstreak@30: flickerstreak@30: currentMethod = method flickerstreak@30: if old then flickerstreak@30: post(old, ret, ...) flickerstreak@30: old = del(old) flickerstreak@30: else flickerstreak@30: post(ret, ...) flickerstreak@30: end flickerstreak@30: currentMethod = old_currentMethod flickerstreak@30: return unpackListAndDel(ret, 1, n) flickerstreak@30: end flickerstreak@30: end flickerstreak@30: flickerstreak@30: local function precondition(object, method, func) flickerstreak@30: if type(object) ~= "table" then flickerstreak@30: error(("Bad argument #1 to `precondition'. Expected %q, got %q."):format("table", type(object)), 2) flickerstreak@30: end flickerstreak@30: if type(object[method]) ~= "function" then flickerstreak@30: error(("Method %q not found on object %s. Expected %q, got %q."):format(tostring(method), tostring(object), "function", type(object[method])), 2) flickerstreak@30: end flickerstreak@30: if type(func) ~= "function" then flickerstreak@30: error(("Bad argument #3 to `precondition'. Expected %q, got %q."):format("function", type(func)), 2) flickerstreak@30: end flickerstreak@30: flickerstreak@30: local object_method = object[method] flickerstreak@30: if preconditions[object_method] then flickerstreak@30: error("Cannot call `preconditon' on the same method twice.", 2) flickerstreak@30: end flickerstreak@30: preconditions[object_method] = func flickerstreak@30: flickerstreak@30: if not postconditions[object_method] then flickerstreak@30: hook(object, method) flickerstreak@30: end flickerstreak@30: end flickerstreak@30: flickerstreak@30: local function postcondition(object, method, func, fillOld) flickerstreak@30: if type(object) ~= "table" then flickerstreak@30: error(("Bad argument #1 to `postcondition'. Expected %q, got %q."):format("table", type(object)), 2) flickerstreak@30: end flickerstreak@30: if type(object[method]) ~= "function" then flickerstreak@30: error(("Method %q not found on object %s. Expected %q, got %q."):format(tostring(method), tostring(object), "function", type(object[method])), 2) flickerstreak@30: end flickerstreak@30: if type(func) ~= "function" then flickerstreak@30: error(("Bad argument #3 to `postcondition'. Expected %q, got %q."):format("function", type(func)), 2) flickerstreak@30: end flickerstreak@30: if fillOld and type(fillOld) ~= "function" then flickerstreak@30: error(("Bad argument #4 to `postcondition'. Expected %q or %q, got %q."):format("function", "nil", type(func)), 2) flickerstreak@30: end flickerstreak@30: flickerstreak@30: local object_method = object[method] flickerstreak@30: if postconditions[object_method] then flickerstreak@30: error("Cannot call `postcondition' on the same method twice.", 2) flickerstreak@30: end flickerstreak@30: postconditions[object_method] = func flickerstreak@30: postconditionsOld[object_method] = fillOld flickerstreak@30: flickerstreak@30: if not preconditions[object_method] then flickerstreak@30: hook(object, method) flickerstreak@30: end flickerstreak@30: end flickerstreak@30: flickerstreak@30: local function argCheck(value, position, ...) flickerstreak@30: if not currentMethod then flickerstreak@30: error("Cannot call `argCheck' outside of a pre/post-condition.", 2) flickerstreak@30: end flickerstreak@30: if type(position) ~= "number" then flickerstreak@30: error(("Bad argument #2 to `argCheck'. Expected %q, got %q"):format("number", type(position)), 2) flickerstreak@30: end flickerstreak@30: local type_value = type(value) flickerstreak@30: for i = 1, select('#', ...) do flickerstreak@30: local v = select(i, ...) flickerstreak@30: if type(v) ~= "string" then flickerstreak@30: error(("Bad argument #%d to `argCheck'. Expected %q, got %q"):format(i+1, "string", type(v)), 2) flickerstreak@30: end flickerstreak@30: if v == type_value then flickerstreak@30: return flickerstreak@30: end flickerstreak@30: end flickerstreak@30: local t = newList(...) flickerstreak@30: t[#t] = nil flickerstreak@30: for i,v in ipairs(t) do flickerstreak@30: t[i] = ("%q"):format(v) flickerstreak@30: end flickerstreak@30: local s flickerstreak@30: if #t == 0 then flickerstreak@30: s = ("%q"):format((...)) flickerstreak@30: elseif #t == 1 then flickerstreak@30: s = ("%q or %q"):format(...) flickerstreak@30: else flickerstreak@30: s = table_concat(t, ", ") .. ", or " .. ("%q"):format(select(#t+1, ...)) flickerstreak@30: end flickerstreak@30: t = del(t) flickerstreak@30: flickerstreak@30: error(("Bad argument #%d to `%s'. Expected %s, got %q."):format(position, tostring(currentMethod), s, type_value), 4) flickerstreak@30: end flickerstreak@30: flickerstreak@30: --[[--------------------------------------------------------------------------- flickerstreak@30: Notes: flickerstreak@30: * Returns functions for the specified namespace based on what is provided. flickerstreak@30: * function types: flickerstreak@30: ; "precondition" : to set the pre-condition for a method. flickerstreak@30: ; "postcondition" : to set the post-condition for a method. flickerstreak@30: ; "argCheck" : to check the type of an argument, to be executed within a pre-condition. flickerstreak@30: * preconditon is in the form of precondition(object, "methodName", func(self, ...)) flickerstreak@30: * postcondition is in the form of either postcondition(object, "methodName", func(returnValues, self, ...)) or postcondition(object, "methodName", func(oldValues, returnValues, self, ...), populateOld(oldValues, self, ...)) flickerstreak@30: ** returnValues is the list of return values, empty if no return values were sent. flickerstreak@30: ** if the populateOld function is provided, then the empty oldValues table is provided and expected to be filled, and then given to the func. flickerstreak@30: * argCheck is in the form of argCheck(value, n, "type1" [, "type2", ...]) flickerstreak@30: ** value is the value provided to the function you're checking. flickerstreak@30: ** n is the argument position. ''Note: 1 is the position of `self'. 2 would be the first "real" position.'' flickerstreak@30: ** the tuple of types can be any string, but specifically "nil", "boolean", "string", "number", "function", "userdata", "table", etc. flickerstreak@30: Arguments: flickerstreak@30: string - the namespace. ''Note: this doesn't necessarily have to be a string.'' flickerstreak@30: Example: flickerstreak@30: local precondition, postcondition, argCheck = Rock:GetRecyclingFunctions("Stack", "precondition", "postcondition", "argCheck") flickerstreak@30: flickerstreak@30: local stack = {} flickerstreak@30: stack.IsEmpty = function(self) flickerstreak@30: return self[1] == nil flickerstreak@30: end flickerstreak@30: stack.GetLength = function(self) flickerstreak@30: return #self flickerstreak@30: end flickerstreak@30: stack.Push = function(self, value) flickerstreak@30: self[#self+1] = value flickerstreak@30: end flickerstreak@30: precondition(stack, "Push", function(self, value) flickerstreak@30: argCheck(value, 2, "string") -- only accept strings, no other values flickerstreak@30: end) flickerstreak@30: postcondition(stack, "Push", function(old, ret, self, value) flickerstreak@30: assert(self:GetLength() == old.length+1) flickerstreak@30: assert(not self:IsEmpty()) flickerstreak@30: end, function(old, self) flickerstreak@30: old.length = self:GetLength() flickerstreak@30: end) flickerstreak@30: stack.Pop = function(self) flickerstreak@30: local value = self[#self] flickerstreak@30: self[#self] = nil flickerstreak@30: return value flickerstreak@30: end flickerstreak@30: precondition(stack, "Pop", function(self) flickerstreak@30: assert(self:GetLength() >= 1) flickerstreak@30: end) flickerstreak@30: postcondition(stack, "Pop", function(old, ret, self) flickerstreak@30: assert(self:GetLength() == old.length-1) flickerstreak@30: end, function(old, self) flickerstreak@30: old.length = self:GetLength() flickerstreak@30: end) flickerstreak@30: stack.Peek = function(self) flickerstreak@30: return self[#self] flickerstreak@30: end flickerstreak@30: precondition(stack, "Peek", function(self) flickerstreak@30: assert(self:GetLength() >= 1) flickerstreak@30: end) flickerstreak@30: postcondition(stack, "Peek", function(old, ret, self) flickerstreak@30: assert(self:GetLength() == old.length) flickerstreak@30: end, function(old, self) flickerstreak@30: old.length = self:GetLength() flickerstreak@30: end) flickerstreak@30: flickerstreak@30: local t = setmetatable({}, {__index=stack}) flickerstreak@30: t:Push("Alpha") flickerstreak@30: t:Push("Bravo") flickerstreak@30: t:Push(5) -- error, only strings flickerstreak@30: assert(t:Pop() == "Bravo") flickerstreak@30: assert(t:Pop() == "Alpha") flickerstreak@30: t:Pop() -- error, out of values flickerstreak@30: -----------------------------------------------------------------------------]] flickerstreak@30: function Rock:GetContractFunctions(namespace, ...) flickerstreak@30: if namespace == "precondition" or namespace == "postcondition" or namespace == "argCheck" then flickerstreak@30: error(("Bad argument #2 to `GetContractFunctions'. Cannot be %q."):format(namespace), 2) flickerstreak@30: end flickerstreak@30: local t = newList() flickerstreak@30: if enableContracts then flickerstreak@30: for i = 1, select('#', ...) do flickerstreak@30: local v = select(i, ...) flickerstreak@30: if v == "precondition" then flickerstreak@30: t[i] = precondition flickerstreak@30: elseif v == "postcondition" then flickerstreak@30: t[i] = postcondition flickerstreak@30: elseif v == "argCheck" then flickerstreak@30: t[i] = argCheck flickerstreak@30: else flickerstreak@30: error(("Bad argument #%d to `GetContractFunctions'. Expected %q, %q, or %q, got %q."):format(i+2, "precondition", "postcondition", "argCheck", tostring(v))) flickerstreak@30: end flickerstreak@30: end flickerstreak@30: else flickerstreak@30: for i = 1, select('#', ...) do flickerstreak@30: t[i] = noop flickerstreak@30: end flickerstreak@30: end flickerstreak@30: return unpackListAndDel(t) flickerstreak@30: end flickerstreak@30: end flickerstreak@30: flickerstreak@30: --[[--------------------------------------------------------------------------- flickerstreak@30: Notes: flickerstreak@30: * convert a revision string to a number flickerstreak@30: Arguments: flickerstreak@30: string - revision string flickerstreak@30: Returns: flickerstreak@30: string or number - the string given or the number retrieved from it. flickerstreak@30: -----------------------------------------------------------------------------]] flickerstreak@30: local function coerceRevisionToNumber(version) flickerstreak@30: if type(version) == "string" then flickerstreak@30: return tonumber(version:match("(%-?%d+)")) or version flickerstreak@30: else flickerstreak@30: return version flickerstreak@30: end flickerstreak@30: end flickerstreak@30: flickerstreak@30: --[[--------------------------------------------------------------------------- flickerstreak@30: Notes: flickerstreak@30: * try to enable the standalone library specified flickerstreak@30: Arguments: flickerstreak@30: string - name of the library. flickerstreak@30: Returns: flickerstreak@30: boolean - whether the library is properly enabled and loadable. flickerstreak@30: -----------------------------------------------------------------------------]] flickerstreak@30: local function TryToEnable(addon) flickerstreak@30: local islod = IsAddOnLoadOnDemand(addon) flickerstreak@30: if islod then flickerstreak@30: local _, _, _, enabled = GetAddOnInfo(addon) flickerstreak@30: EnableAddOn(addon) flickerstreak@30: local _, _, _, _, loadable = GetAddOnInfo(addon) flickerstreak@30: if not loadable and not enabled then flickerstreak@30: DisableAddOn(addon) flickerstreak@30: end flickerstreak@30: flickerstreak@30: return loadable flickerstreak@30: end flickerstreak@30: end flickerstreak@30: flickerstreak@30: --[[--------------------------------------------------------------------------- flickerstreak@30: Notes: flickerstreak@30: * try to load the standalone library specified flickerstreak@30: Arguments: flickerstreak@30: string - name of the library. flickerstreak@30: Returns: flickerstreak@30: boolean - whether the library is loaded. flickerstreak@30: -----------------------------------------------------------------------------]] flickerstreak@30: local function TryToLoadStandalone(major) flickerstreak@30: major = major:lower() flickerstreak@30: if scannedLibraries[major] then flickerstreak@30: return flickerstreak@30: end flickerstreak@30: scannedLibraries[major] = true flickerstreak@30: local name, _, _, enabled, loadable, state = GetAddOnInfo(major) flickerstreak@30: if state == "MISSING" or not IsAddOnLoadOnDemand(major) then flickerstreak@30: -- backwards compatibility for X-AceLibrary flickerstreak@30: local field = "X-AceLibrary-" .. major flickerstreak@30: local loaded flickerstreak@30: for i = 1, GetNumAddOns() do flickerstreak@30: if GetAddOnMetadata(i, field) then flickerstreak@30: name, _, _, enabled, loadable = GetAddOnInfo(i) flickerstreak@30: flickerstreak@30: loadable = (enabled and loadable) or TryToEnable(name) flickerstreak@30: if loadable then flickerstreak@30: loaded = true flickerstreak@30: LoadAddOn(name) flickerstreak@30: end flickerstreak@30: end flickerstreak@30: end flickerstreak@30: flickerstreak@30: return loaded flickerstreak@30: elseif (enabled and loadable) or TryToEnable(major) then flickerstreak@30: LoadAddOn(major) flickerstreak@30: return true flickerstreak@30: else flickerstreak@30: return false flickerstreak@30: end flickerstreak@30: end flickerstreak@30: flickerstreak@30: --[[--------------------------------------------------------------------------- flickerstreak@30: Notes: flickerstreak@30: * Return the LibStub library, casing is unimportant. flickerstreak@30: Arguments: flickerstreak@30: string - name of the library. flickerstreak@30: Returns: flickerstreak@30: table or nil - library flickerstreak@30: number - minor version flickerstreak@30: -----------------------------------------------------------------------------]] flickerstreak@30: local function GetLibStubLibrary(major) flickerstreak@30: local lib, minor = LibStub:GetLibrary(major, true) flickerstreak@30: if lib then flickerstreak@30: return lib, minor flickerstreak@30: end flickerstreak@30: major = major:lower() flickerstreak@30: for m, lib in LibStub:IterateLibraries() do flickerstreak@30: if m:lower() == major then flickerstreak@30: return LibStub:GetLibrary(m) flickerstreak@30: end flickerstreak@30: end flickerstreak@30: return nil, nil flickerstreak@30: end flickerstreak@30: flickerstreak@30: local finishLibraryRegistration flickerstreak@30: --[[--------------------------------------------------------------------------- flickerstreak@30: Notes: flickerstreak@30: * create a new library if the version provided is not out of date. flickerstreak@30: Arguments: flickerstreak@30: string - name of the library. flickerstreak@30: number - version of the library. flickerstreak@30: Returns: flickerstreak@30: library, oldLibrary flickerstreak@30: * table or nil - the library with which to manipulate flickerstreak@30: * table or nil - the old version of the library to upgrade from flickerstreak@30: Example: flickerstreak@30: local LibMonkey, oldLib = Rock:NewLibrary("LibMonkey-1.0", 50) flickerstreak@30: if not LibMonkey then flickerstreak@30: -- opt out now, out of date flickerstreak@30: return flickerstreak@30: end flickerstreak@30: -----------------------------------------------------------------------------]] flickerstreak@30: function Rock:NewLibrary(major, version) flickerstreak@30: if type(major) ~= "string" then flickerstreak@30: error(("Bad argument #2 to `NewLibrary'. Expected %q, got %q."):format("string", type(major)), 2) flickerstreak@30: end flickerstreak@30: if not major:match("^Lib[A-Z][A-Za-z%d%-]*%-%d+%.%d+$") then flickerstreak@30: error(("Bad argument #2 to `NewLibrary'. Must match %q, got %q."):format("^Lib[A-Z][A-Za-z%d%-]*%-%d+%.%d+$", major), 2) flickerstreak@30: end flickerstreak@30: TryToLoadStandalone(major) flickerstreak@30: version = coerceRevisionToNumber(version) flickerstreak@30: if type(version) ~= "number" then flickerstreak@30: error(("Bad argument #3 to `NewLibrary'. Expected %q, got %q."):format("number", type(version)), 2) flickerstreak@30: end flickerstreak@30: local library, oldMinor = LibStub:GetLibrary(major, true) flickerstreak@30: if oldMinor and oldMinor >= version then flickerstreak@30: -- in case LibStub is acting funny flickerstreak@30: return nil, nil flickerstreak@30: end flickerstreak@30: local library, oldMinor = LibStub:NewLibrary(major, version) flickerstreak@30: if not library then flickerstreak@30: return nil, nil flickerstreak@30: end flickerstreak@30: local unitTests_major = unitTests[major] flickerstreak@30: if unitTests_major then flickerstreak@30: for k,v in pairs(unitTests_major) do flickerstreak@30: unitTests_major[k] = nil flickerstreak@30: end flickerstreak@30: end flickerstreak@30: for k, v in pairs(recycleData) do flickerstreak@30: v[major] = nil flickerstreak@30: end flickerstreak@30: local mixinToObject_library = mixinToObject[library] flickerstreak@30: flickerstreak@30: local oldLib flickerstreak@30: if oldMinor then flickerstreak@30: -- previous version exists flickerstreak@30: local mixins = newList() flickerstreak@30: for mixin, objectSet in pairs(mixinToObject) do flickerstreak@30: if objectSet[library] then flickerstreak@30: mixins[mixin] = true flickerstreak@30: end flickerstreak@30: end flickerstreak@30: for mixin in pairs(mixins) do flickerstreak@30: mixin:Unembed(library) flickerstreak@30: end flickerstreak@30: mixins = del(mixins) flickerstreak@30: oldLib = newList() flickerstreak@30: for k, v in pairs(library) do flickerstreak@30: oldLib[k] = v flickerstreak@30: library[k] = nil flickerstreak@30: end flickerstreak@30: setmetatable(oldLib, getmetatable(library)) flickerstreak@30: setmetatable(library, nil) flickerstreak@30: end flickerstreak@30: finishLibraryRegistration(major, version, library, figureCurrentAddon(2)) flickerstreak@30: flickerstreak@30: return library, oldLib flickerstreak@30: end flickerstreak@30: function finishLibraryRegistration(major, version, library, folder) flickerstreak@30: library.name = major flickerstreak@30: flickerstreak@30: libraries[major] = library flickerstreak@30: pendingLibraries[library] = folder flickerstreak@30: local exportedMethods_library = exportedMethods[library] flickerstreak@30: if exportedMethods_library then flickerstreak@30: local mixinToObject_library = mixinToObject[library] flickerstreak@30: if mixinToObject_library then flickerstreak@30: for object in pairs(mixinToObject_library) do flickerstreak@30: for _,v in ipairs(exportedMethods_library) do flickerstreak@30: object[v] = nil flickerstreak@30: end flickerstreak@30: end flickerstreak@30: end flickerstreak@30: exportedMethods[library] = del(exportedMethods_library) flickerstreak@30: end flickerstreak@30: if library ~= Rock then flickerstreak@30: Rock:Embed(library) flickerstreak@30: end flickerstreak@30: flickerstreak@30: frame:Show() flickerstreak@30: end flickerstreak@30: if not oldRock then flickerstreak@30: finishLibraryRegistration(MAJOR_VERSION, MINOR_VERSION, Rock, figureCurrentAddon(1)) flickerstreak@30: end flickerstreak@30: flickerstreak@30: -- #NODOC flickerstreak@30: local function __removeLibrary(libName) flickerstreak@30: libraries[libName] = nil flickerstreak@30: if LibStub.libs then flickerstreak@30: LibStub.libs[libName] = nil flickerstreak@30: end flickerstreak@30: if LibStub.minors then flickerstreak@30: LibStub.minors[libName] = nil flickerstreak@30: end flickerstreak@30: local lastCount flickerstreak@30: repeat flickerstreak@30: lastCount = collectgarbage('count') flickerstreak@30: collectgarbage('collect') flickerstreak@30: until lastCount == collectgarbage('count') flickerstreak@30: end flickerstreak@30: local function run(_,a) flickerstreak@30: if a < 1/30 then flickerstreak@30: collectgarbage('step') flickerstreak@30: end flickerstreak@30: end flickerstreak@30: flickerstreak@30: --[[--------------------------------------------------------------------------- flickerstreak@30: Notes: flickerstreak@30: * properly finalizes the library, essentially stating that it has loaded properly. flickerstreak@30: * This will call :OnLibraryLoad("major", library) on every other library flickerstreak@30: * This will also call :OnLibraryLoad("major", library) on the library provided, using every other library as the arguments. flickerstreak@30: * An error will occur if this is not done before ADDON_LOADED. flickerstreak@30: Arguments: flickerstreak@30: string - name of the library. flickerstreak@30: Example: flickerstreak@30: local LibMonkey, oldLib = Rock:NewLibrary("LibMonkey-1.0", 50) flickerstreak@30: if not LibMonkey then flickerstreak@30: -- opt out now, out of date flickerstreak@30: return flickerstreak@30: end flickerstreak@30: Rock:FinalizeLibrary("LibMonkey-1.0") flickerstreak@30: -----------------------------------------------------------------------------]] flickerstreak@30: function Rock:FinalizeLibrary(major) flickerstreak@30: if type(major) ~= "string" then flickerstreak@30: error(("Bad argument #2 to `FinalizeLibrary'. Expected %q, got %q."):format("string", type(major)), 2) flickerstreak@30: end flickerstreak@30: local library = libraries[major] flickerstreak@30: if not library then flickerstreak@30: error(("Bad argument #2 to `FinalizeLibrary'. %q is not a library."):format("string", major), 2) flickerstreak@30: end flickerstreak@30: pendingLibraries[library] = nil flickerstreak@30: local library_OnLibraryLoad = library.OnLibraryLoad flickerstreak@30: if library_OnLibraryLoad then flickerstreak@30: for maj, lib in LibStub:IterateLibraries() do -- for all libraries flickerstreak@30: if maj ~= major then flickerstreak@30: local success, ret = pcall(library_OnLibraryLoad, library, maj, lib) flickerstreak@30: if not success then flickerstreak@30: geterrorhandler()(ret) flickerstreak@30: break flickerstreak@30: end flickerstreak@30: end flickerstreak@30: end flickerstreak@30: end flickerstreak@30: if finalizedLibraries[library] then flickerstreak@30: return flickerstreak@30: end flickerstreak@30: finalizedLibraries[library] = true flickerstreak@30: for maj, lib in pairs(libraries) do -- just Rock libraries flickerstreak@30: if maj ~= major then flickerstreak@30: local lib_OnLibraryLoad = lib.OnLibraryLoad flickerstreak@30: if lib_OnLibraryLoad then flickerstreak@30: local success, ret = pcall(lib_OnLibraryLoad, lib, major, library) flickerstreak@30: if not success then flickerstreak@30: geterrorhandler()(ret) flickerstreak@30: end flickerstreak@30: end flickerstreak@30: end flickerstreak@30: end flickerstreak@30: if LibRockEvent then flickerstreak@30: self:DispatchEvent("LibraryLoad", major, library) flickerstreak@30: end flickerstreak@30: end flickerstreak@30: flickerstreak@30: local function manualFinalize(major, library) flickerstreak@30: if libraries[major] then -- non-Rock libraries only flickerstreak@30: return flickerstreak@30: end flickerstreak@30: if finalizedLibraries[library] then -- don't do it twice flickerstreak@30: return flickerstreak@30: end flickerstreak@30: finalizedLibraries[library] = true flickerstreak@30: for maj, lib in pairs(libraries) do -- just Rock libraries flickerstreak@30: if maj ~= major then flickerstreak@30: local lib_OnLibraryLoad = lib.OnLibraryLoad flickerstreak@30: if lib_OnLibraryLoad then flickerstreak@30: local success, ret = pcall(lib_OnLibraryLoad, lib, major, library) flickerstreak@30: if not success then flickerstreak@30: geterrorhandler()(ret) flickerstreak@30: end flickerstreak@30: end flickerstreak@30: end flickerstreak@30: end flickerstreak@30: if LibRockEvent then flickerstreak@30: Rock:DispatchEvent("LibraryLoad", major, library) flickerstreak@30: end flickerstreak@30: end flickerstreak@30: flickerstreak@30: --[[--------------------------------------------------------------------------- flickerstreak@30: Arguments: flickerstreak@30: string - name of the library. flickerstreak@30: [optional] boolean - whether to not load a library if it is not found. Default: false flickerstreak@30: [optional] boolean - whether to not error if a library is not found. Default: false flickerstreak@30: Returns: flickerstreak@30: library flickerstreak@30: * table or nil - the library requested flickerstreak@30: Example: flickerstreak@30: local LibMonkey = Rock:GetLibrary("LibMonkey-1.0") flickerstreak@30: -- or flickerstreak@30: local LibMonkey = Rock("LibMonkey-1.0") flickerstreak@30: -----------------------------------------------------------------------------]] flickerstreak@30: function Rock:GetLibrary(major, dontLoad, dontError) flickerstreak@30: if type(major) ~= "string" then flickerstreak@30: error(("Bad argument #2 to `GetLibrary'. Expected %q, got %q."):format("string", type(major)), 2) flickerstreak@30: end flickerstreak@30: if dontLoad and dontLoad ~= true then flickerstreak@30: error(("Bad argument #3 to `GetLibrary'. Expected %q or %q, got %q."):format("boolean", "nil", type(dontLoad)), 2) flickerstreak@30: end flickerstreak@30: if dontError and dontError ~= true then flickerstreak@30: error(("Bad argument #4 to `GetLibrary'. Expected %q or %q, got %q."):format("boolean", "nil", type(dontError)), 2) flickerstreak@30: end flickerstreak@30: if not dontLoad then flickerstreak@30: TryToLoadStandalone(major) flickerstreak@30: end flickerstreak@30: flickerstreak@30: local library = GetLibStubLibrary(major) flickerstreak@30: if not library then flickerstreak@30: if dontError then flickerstreak@30: return nil flickerstreak@30: end flickerstreak@30: error(("Library %q not found."):format(major), 2) flickerstreak@30: end flickerstreak@30: flickerstreak@30: return library flickerstreak@30: end flickerstreak@30: flickerstreak@30: setmetatable(Rock, { __call = Rock.GetLibrary }) flickerstreak@30: flickerstreak@30: --[[--------------------------------------------------------------------------- flickerstreak@30: Arguments: flickerstreak@30: string - name of the library. flickerstreak@30: Returns: flickerstreak@30: boolean - whether the library exists and is a proper mixin which can be embedded. flickerstreak@30: Example: flickerstreak@30: local isMixin = Rock:IsLibraryMixin("LibMonkey-1.0") flickerstreak@30: -----------------------------------------------------------------------------]] flickerstreak@30: function Rock:IsLibraryMixin(name) flickerstreak@30: local library = self:GetLibrary(name, false, true) flickerstreak@30: if not library then flickerstreak@30: return false flickerstreak@30: end flickerstreak@30: return not not exportedMethods[library] flickerstreak@30: end flickerstreak@30: flickerstreak@30: --[[--------------------------------------------------------------------------- flickerstreak@30: Arguments: flickerstreak@30: string - name of the library. flickerstreak@30: [optional] boolean - whether to not load a library if it is not found. Default: false flickerstreak@30: Returns: flickerstreak@30: library flickerstreak@30: * table or nil - the library requested flickerstreak@30: Example: flickerstreak@30: local hasLibMonkey = Rock:HasLibrary("LibMonkey-1.0") flickerstreak@30: -----------------------------------------------------------------------------]] flickerstreak@30: function Rock:HasLibrary(major, dontLoad) flickerstreak@30: if type(major) ~= "string" then flickerstreak@30: error(("Bad argument #2 to `HasLibrary'. Expected %q, got %q."):format("string", type(major)), 2) flickerstreak@30: end flickerstreak@30: if dontLoad and dontLoad ~= true then flickerstreak@30: error(("Bad argument #3 to `HasLibrary'. Expected %q or %q, got %q."):format("boolean", "nil", type(dontLoad)), 2) flickerstreak@30: end flickerstreak@30: if not dontLoad then flickerstreak@30: TryToLoadStandalone(major) flickerstreak@30: end flickerstreak@30: return not not GetLibStubLibrary(major) flickerstreak@30: end flickerstreak@30: flickerstreak@30: --[[--------------------------------------------------------------------------- flickerstreak@30: Notes: flickerstreak@30: * This is exported to all libraries flickerstreak@30: Returns: flickerstreak@30: major, minor flickerstreak@30: * string - name of the library flickerstreak@30: * number - version of the library flickerstreak@30: Example: flickerstreak@30: local major, minor = Rock:GetLibraryVersion() -- will be "LibRock-1.0", 12345 flickerstreak@30: local major, minor = LibMonkey:GetLibraryVersion() -- will be "LibMonkey-1.0", 50 flickerstreak@30: -----------------------------------------------------------------------------]] flickerstreak@30: function Rock:GetLibraryVersion() flickerstreak@30: if type(self) ~= "table" then flickerstreak@30: return nil, nil flickerstreak@30: end flickerstreak@30: local major flickerstreak@30: local name = self.name flickerstreak@30: if name and GetLibStubLibrary(name) == self then flickerstreak@30: major = name flickerstreak@30: else flickerstreak@30: for m, instance in LibStub:IterateLibraries() do flickerstreak@30: if instance == self then flickerstreak@30: major = m flickerstreak@30: break flickerstreak@30: end flickerstreak@30: end flickerstreak@30: if not major then flickerstreak@30: return nil, nil flickerstreak@30: end flickerstreak@30: end flickerstreak@30: local _, minor = GetLibStubLibrary(major) flickerstreak@30: return major, minor flickerstreak@30: end flickerstreak@30: flickerstreak@30: --[[--------------------------------------------------------------------------- flickerstreak@30: Returns: flickerstreak@30: an iterator to traverse all registered libraries. flickerstreak@30: Example: flickerstreak@30: for major, library in Rock:IterateLibraries() do flickerstreak@30: -- do something with major and library flickerstreak@30: end flickerstreak@30: -----------------------------------------------------------------------------]] flickerstreak@30: function Rock:IterateLibraries() flickerstreak@30: return LibStub:IterateLibraries() flickerstreak@30: end flickerstreak@30: flickerstreak@30: --[[--------------------------------------------------------------------------- flickerstreak@30: Notes: flickerstreak@30: * This is exported to all libraries flickerstreak@30: * Allows you to set precisely what methods for the library to export. flickerstreak@30: * This automatically turns a library into a mixin. flickerstreak@30: Arguments: flickerstreak@30: tuple - the list of method names to export. flickerstreak@30: Example: flickerstreak@30: local LibMonkey = Rock:NewLibrary("LibMonkey-1.0", 50) flickerstreak@30: LibMonkey.FlingPoo = function(self) flickerstreak@30: return "Splat!" flickerstreak@30: end flickerstreak@30: LibMonkey:SetExportedMethods("FlingPoo") flickerstreak@30: -- later flickerstreak@30: local Darwin = Rock:NewAddon("Darwin", "LibMonkey-1.0") flickerstreak@30: assert(Darwin:FlingPoo() == "Splat!") flickerstreak@30: -----------------------------------------------------------------------------]] flickerstreak@30: function Rock:SetExportedMethods(...) flickerstreak@30: if exportedMethods[self] then flickerstreak@30: error("Cannot call `SetExportedMethods' more than once.", 2) flickerstreak@30: end flickerstreak@30: local t = newList(...) flickerstreak@30: if #t == 0 then flickerstreak@30: error("Must supply at least 1 method to `SetExportedMethods'.", 2) flickerstreak@30: end flickerstreak@30: for i,v in ipairs(t) do flickerstreak@30: if type(self[v]) ~= "function" then flickerstreak@30: error(("Bad argument #%d to `SetExportedMethods'. Method %q does not exist."):format(i+1, tostring(v)), 2) flickerstreak@30: end flickerstreak@30: end flickerstreak@30: exportedMethods[self] = t flickerstreak@30: flickerstreak@30: local mixinToObject_library = mixinToObject[self] flickerstreak@30: if mixinToObject_library then flickerstreak@30: for object in pairs(mixinToObject_library) do flickerstreak@30: for _,method in ipairs(t) do flickerstreak@30: object[method] = self[method] flickerstreak@30: end flickerstreak@30: end flickerstreak@30: end flickerstreak@30: end flickerstreak@30: flickerstreak@30: --[[--------------------------------------------------------------------------- flickerstreak@30: Notes: flickerstreak@30: * This is exported to all libraries flickerstreak@30: * Embeds all the methods previously set to export onto a table. flickerstreak@30: * This will call :OnEmbed(object) on the library if it is available. flickerstreak@30: Arguments: flickerstreak@30: table - the table with which to export methods onto. flickerstreak@30: Returns: flickerstreak@30: The table provided, after embedding. flickerstreak@30: Example: flickerstreak@30: local LibMonkey = Rock:NewLibrary("LibMonkey-1.0", 50) flickerstreak@30: LibMonkey.FlingPoo = function(self) flickerstreak@30: return "Splat!" flickerstreak@30: end flickerstreak@30: LibMonkey:SetExportedMethods("FlingPoo") flickerstreak@30: -- later flickerstreak@30: local Darwin = {} flickerstreak@30: Rock("LibMonkey-1.0"):Embed(Darwin) flickerstreak@30: assert(Darwin:FlingPoo() == "Splat!") flickerstreak@30: -----------------------------------------------------------------------------]] flickerstreak@30: function Rock:Embed(object) flickerstreak@30: if not exportedMethods[self] then flickerstreak@30: error(("Cannot call `Embed' for library %q if `SetExportedMethods' has not been called."):format(tostring(self.name)), 2) flickerstreak@30: end flickerstreak@30: if type(object) ~= "table" then flickerstreak@30: error(("Bad argument #2 to `Embed'. Expected %q, got %q."):format("table", type(object)), 2) flickerstreak@30: end flickerstreak@30: flickerstreak@30: for i,v in ipairs(exportedMethods[self]) do flickerstreak@30: if type(self[v]) ~= "function" then flickerstreak@30: error(("Problem embedding method %q from library %q. Expected %q, got %q."):format(tostring(v), better_tostring(self), "function", type(self[v]))) flickerstreak@30: end flickerstreak@30: object[v] = self[v] flickerstreak@30: end flickerstreak@30: flickerstreak@30: if not mixinToObject[self] then flickerstreak@30: -- weak because objects come and go flickerstreak@30: mixinToObject[self] = setmetatable(newList(), weakKey) flickerstreak@30: end flickerstreak@30: if mixinToObject[self][object] then flickerstreak@30: error(("Cannot embed library %q into the same object %q more than once."):format(better_tostring(self), better_tostring(object)), 2) flickerstreak@30: end flickerstreak@30: mixinToObject[self][object] = true flickerstreak@30: if type(rawget(object, 'mixins')) == "table" then flickerstreak@30: object.mixins[self] = true flickerstreak@30: end flickerstreak@30: flickerstreak@30: local self_OnEmbed = self.OnEmbed flickerstreak@30: if self_OnEmbed then flickerstreak@30: local success, ret = pcall(self_OnEmbed, self, object) flickerstreak@30: if not success then flickerstreak@30: geterrorhandler()(ret) flickerstreak@30: end flickerstreak@30: end flickerstreak@30: flickerstreak@30: return object flickerstreak@30: end flickerstreak@30: flickerstreak@30: --[[--------------------------------------------------------------------------- flickerstreak@30: Notes: flickerstreak@30: * This is exported to all libraries flickerstreak@30: * Unembeds all the methods previously set to export onto a table. flickerstreak@30: * This will error if the library is not embedded on the object flickerstreak@30: * This will call :OnUnembed(object) on the library if it is available. flickerstreak@30: Arguments: flickerstreak@30: table - the table with which to export methods onto. flickerstreak@30: Returns: flickerstreak@30: The table provided, after embedding. flickerstreak@30: Example: flickerstreak@30: local LibMonkey = Rock:NewLibrary("LibMonkey-1.0", 50) flickerstreak@30: LibMonkey.FlingPoo = function(self) flickerstreak@30: return "Splat!" flickerstreak@30: end flickerstreak@30: LibMonkey:SetExportedMethods("FlingPoo") flickerstreak@30: -- later flickerstreak@30: local Darwin = {} flickerstreak@30: Rock("LibMonkey-1.0"):Embed(Darwin) flickerstreak@30: assert(Darwin:FlingPoo() == "Splat!") flickerstreak@30: Rock("LibMonkey-1.0"):Unembed(Darwin) flickerstreak@30: assert(Darwin.FlingPoo == nil) flickerstreak@30: -----------------------------------------------------------------------------]] flickerstreak@30: function Rock:Unembed(object) flickerstreak@30: if not exportedMethods[self] then flickerstreak@30: error(("Cannot call `Unembed' for library %q if `SetExportedMethods' has not been called."):format(better_tostring(self)), 2) flickerstreak@30: end flickerstreak@30: flickerstreak@30: if not mixinToObject[self] or not mixinToObject[self][object] then flickerstreak@30: error(("Cannot unembed library %q from object %q, since it is not embedded originally."):format(better_tostring(self), better_tostring(object)), 2) flickerstreak@30: end flickerstreak@30: local mixinToObject_self = mixinToObject[self] flickerstreak@30: mixinToObject_self[object] = nil flickerstreak@30: if not next(mixinToObject_self) then flickerstreak@30: mixinToObject[self] = del(mixinToObject_self) flickerstreak@30: end flickerstreak@30: flickerstreak@30: local mixin_OnUnembed = self.OnUnembed flickerstreak@30: if mixin_OnUnembed then flickerstreak@30: local success, ret = pcall(mixin_OnUnembed, self, object) flickerstreak@30: if not success then flickerstreak@30: geterrorhandler()(ret) flickerstreak@30: end flickerstreak@30: end flickerstreak@30: flickerstreak@30: for i,v in ipairs(exportedMethods[self]) do flickerstreak@30: object[v] = nil flickerstreak@30: end flickerstreak@30: end flickerstreak@30: flickerstreak@30: local function embedAce2Mixin(mixin, object) flickerstreak@30: if not mixinToObject[mixin] then flickerstreak@30: mixinToObject[mixin] = setmetatable(newList(), weakKey) flickerstreak@30: end flickerstreak@30: mixinToObject[mixin][object] = true flickerstreak@30: mixin:embed(object) flickerstreak@30: end flickerstreak@30: flickerstreak@30: local function embedLibStubMixin(mixin, object) flickerstreak@30: if not mixinToObject[mixin] then flickerstreak@30: mixinToObject[mixin] = setmetatable(newList(), weakKey) flickerstreak@30: end flickerstreak@30: mixinToObject[mixin][object] = true flickerstreak@30: mixin:Embed(object) flickerstreak@30: end flickerstreak@30: flickerstreak@30: --[[--------------------------------------------------------------------------- flickerstreak@30: Notes: flickerstreak@30: * create a new addon with the specified name. flickerstreak@30: Arguments: flickerstreak@30: string - name of the addon. flickerstreak@30: tuple - list of mixins with which to embed into this addon. flickerstreak@30: Returns: flickerstreak@30: addon flickerstreak@30: * table - the addon with which to manipulate flickerstreak@30: Example: flickerstreak@30: local MyAddon = Rock:NewAddon("MyAddon", "Mixin-1.0", "OtherMixin-2.0") flickerstreak@30: -----------------------------------------------------------------------------]] flickerstreak@30: function Rock:NewAddon(name, ...) flickerstreak@30: if type(name) ~= "string" then flickerstreak@30: error(("Bad argument #2 to `NewAddon'. Expected %q, got %q"):format("string", type(name)), 2) flickerstreak@30: end flickerstreak@30: if name:match("^Lib[A-Z]") then flickerstreak@30: error(("Bad argument #2 to `NewAddon'. Cannot start with %q, got %q."):format("Lib", name), 2) flickerstreak@30: end flickerstreak@30: if self == Rock and name:match("_") then flickerstreak@30: error(("Bad argument #2 to `NewAddon'. Cannot contain underscores, got %q."):format(name), 2) flickerstreak@30: end flickerstreak@30: flickerstreak@30: if addons[name] then flickerstreak@30: error(("Bad argument #2 to `NewAddon'. Addon %q already created."):format(name), 2) flickerstreak@30: end flickerstreak@30: local addon = setmetatable(newList(), addon_mt) flickerstreak@30: addon.name = name flickerstreak@30: flickerstreak@30: local mixinSet = newList() flickerstreak@30: flickerstreak@30: for i = 1, select('#', ...) do flickerstreak@30: local libName = select(i, ...) flickerstreak@30: if mixinSet[libName] then flickerstreak@30: error(("Bad argument #%d to `NewAddon'. %q already stated."):format(i+2, tostring(libName)), 2) flickerstreak@30: end flickerstreak@30: mixinSet[libName] = true flickerstreak@30: TryToLoadStandalone(libName) flickerstreak@30: local library = Rock:GetLibrary(libName, false, true) flickerstreak@30: if not library then flickerstreak@30: error(("Bad argument #%d to `NewAddon'. Library %q is not found."):format(i+2, tostring(libName)), 2) flickerstreak@30: end flickerstreak@30: flickerstreak@30: local style = 'rock' flickerstreak@30: flickerstreak@30: if not exportedMethods[library] then flickerstreak@30: local good = false flickerstreak@30: if AceLibrary then flickerstreak@30: local AceOO = AceLibrary:HasInstance("AceOO-2.0", false) and AceLibrary("AceOO-2.0") flickerstreak@30: if AceOO.inherits(library, AceOO.Mixin) then flickerstreak@30: good = true flickerstreak@30: style = 'ace2' flickerstreak@30: end flickerstreak@30: end flickerstreak@30: if not good and type(rawget(library, 'Embed')) == "function" then flickerstreak@30: good = true flickerstreak@30: style = 'libstub' flickerstreak@30: end flickerstreak@30: if not good then flickerstreak@30: error(("Bad argument #%d to `NewAddon'. Library %q is not a mixin."):format(i+2, tostring(libName)), 2) flickerstreak@30: end flickerstreak@30: end flickerstreak@30: flickerstreak@30: if library == Rock then flickerstreak@30: error(("Bad argument #%d to `NewAddon'. Cannot use %q as a mixin."):format(i+2, tostring(libName)), 2) flickerstreak@30: end flickerstreak@30: flickerstreak@30: if style == 'rock' then flickerstreak@30: library:Embed(addon) flickerstreak@30: elseif style == 'ace2' then flickerstreak@30: embedAce2Mixin(library, addon) flickerstreak@30: elseif style == 'libstub' then flickerstreak@30: embedLibStubMixin(library, addon) flickerstreak@30: end flickerstreak@30: end flickerstreak@30: flickerstreak@30: mixinSet = del(mixinSet) flickerstreak@30: flickerstreak@30: addons[name] = addon flickerstreak@30: pendingAddons[#pendingAddons+1] = addon flickerstreak@30: pendingAddonsEnable[#pendingAddonsEnable+1] = addon flickerstreak@30: addonToFolder[addon] = figureCurrentAddon(self == Rock and 2 or 4) flickerstreak@30: flickerstreak@30: frame:Show() flickerstreak@30: flickerstreak@30: return addon flickerstreak@30: end flickerstreak@30: flickerstreak@30: --[[--------------------------------------------------------------------------- flickerstreak@30: Arguments: flickerstreak@30: string - name of the addon. flickerstreak@30: Returns: flickerstreak@30: addon flickerstreak@30: * table or nil - the addon requested flickerstreak@30: Example: flickerstreak@30: local MyAddon = Rock:GetAddon("MyAddon") flickerstreak@30: -----------------------------------------------------------------------------]] flickerstreak@30: function Rock:GetAddon(name) flickerstreak@30: if type(name) ~= "string" then flickerstreak@30: return nil flickerstreak@30: end flickerstreak@30: local addon = addons[name] flickerstreak@30: if addon then flickerstreak@30: return addon flickerstreak@30: end flickerstreak@30: name = name:lower() flickerstreak@30: for k, v in pairs(addons) do flickerstreak@30: if k:lower() == name then flickerstreak@30: return v flickerstreak@30: end flickerstreak@30: end flickerstreak@30: return nil flickerstreak@30: end flickerstreak@30: flickerstreak@30: --[[--------------------------------------------------------------------------- flickerstreak@30: Arguments: flickerstreak@30: string or table - name of the addon or the addon itself. flickerstreak@30: Returns: flickerstreak@30: boolean - whether the addon requested exists. flickerstreak@30: Example: flickerstreak@30: local hasMyAddon = Rock:HasAddon("MyAddon") flickerstreak@30: -- or flickerstreak@30: local hasMyAddon = Rock:HasAddon(MyAddon) flickerstreak@30: -----------------------------------------------------------------------------]] flickerstreak@30: function Rock:HasAddon(name) flickerstreak@30: if type(name) == "string" then flickerstreak@30: local addon = addons[name] flickerstreak@30: if addon then flickerstreak@30: return true flickerstreak@30: end flickerstreak@30: name = name:lower() flickerstreak@30: for k, v in pairs(addons) do flickerstreak@30: if k:lower() == name then flickerstreak@30: return true flickerstreak@30: end flickerstreak@30: end flickerstreak@30: elseif type(name) == "table" then flickerstreak@30: for k,v in pairs(addons) do flickerstreak@30: if v == name then flickerstreak@30: return true flickerstreak@30: end flickerstreak@30: end flickerstreak@30: end flickerstreak@30: return false flickerstreak@30: end flickerstreak@30: flickerstreak@30: --[[--------------------------------------------------------------------------- flickerstreak@30: Returns: flickerstreak@30: an iterator to traverse all addons created with Rock. flickerstreak@30: Example: flickerstreak@30: for name, addon in Rock:IterateAddons() do flickerstreak@30: -- do something with name and addon flickerstreak@30: end flickerstreak@30: -----------------------------------------------------------------------------]] flickerstreak@30: function Rock:IterateAddons() flickerstreak@30: return pairs(addons) flickerstreak@30: end flickerstreak@30: flickerstreak@30: --[[--------------------------------------------------------------------------- flickerstreak@30: Arguments: flickerstreak@30: string - major version of the mixin library flickerstreak@30: Returns: flickerstreak@30: an iterator to traverse all objects that the given mixin has embedded into flickerstreak@30: Example: flickerstreak@30: local LibMonkey = Rock:NewLibrary("LibMonkey-1.0") flickerstreak@30: local Darwin = Rock:NewAddon("Darwin", "LibMonkey-1.0") flickerstreak@30: for object in LibMonkey:IterateMixinObjects("LibMonkey-1.0") do flickerstreak@30: assert(object == Darwin) flickerstreak@30: end flickerstreak@30: -----------------------------------------------------------------------------]] flickerstreak@30: function Rock:IterateMixinObjects(mixinName) flickerstreak@30: local mixin flickerstreak@30: if type(mixinName) == "table" then flickerstreak@30: mixin = mixinName flickerstreak@30: else flickerstreak@30: if type(mixinName) ~= "string" then flickerstreak@30: error(("Bad argument #2 to `IterateMixinObjects'. Expected %q or %q, got %q."):format("table", "string", type(mixinName)), 2) flickerstreak@30: end flickerstreak@30: mixin = libraries[mixinName] flickerstreak@30: end flickerstreak@30: local mixinToObject_mixin = mixinToObject[mixin] flickerstreak@30: if not mixinToObject_mixin then flickerstreak@30: return noop flickerstreak@30: end flickerstreak@30: return pairs(mixinToObject_mixin) flickerstreak@30: end flickerstreak@30: flickerstreak@30: local function iter(object, mixin) flickerstreak@30: mixin = next(mixinToObject, mixin) flickerstreak@30: if not mixin then flickerstreak@30: return nil flickerstreak@30: elseif mixinToObject[mixin][object] then flickerstreak@30: return mixin flickerstreak@30: end flickerstreak@30: return iter(object, mixin) -- try next mixin flickerstreak@30: end flickerstreak@30: --[[--------------------------------------------------------------------------- flickerstreak@30: Returns: flickerstreak@30: an iterator to traverse all mixins that an object has embedded flickerstreak@30: Example: flickerstreak@30: local LibMonkey = Rock:NewLibrary("LibMonkey-1.0") flickerstreak@30: local Darwin = Rock:NewAddon("Darwin", "LibMonkey-1.0") flickerstreak@30: for mixin in Rock:IterateObjectMixins(Darwin) do flickerstreak@30: assert(mixin == LibMonkey) flickerstreak@30: end flickerstreak@30: -----------------------------------------------------------------------------]] flickerstreak@30: function Rock:IterateObjectMixins(object) flickerstreak@30: if type(object) ~= "table" then flickerstreak@30: error(("Bad argument #2 to `IterateObjectMixins'. Expected %q, got %q."):format("table", type(object)), 2) flickerstreak@30: end flickerstreak@30: return iter, object, nil flickerstreak@30: end flickerstreak@30: flickerstreak@30: --[[--------------------------------------------------------------------------- flickerstreak@30: Arguments: flickerstreak@30: table - the object to check flickerstreak@30: string - the mixin to check flickerstreak@30: Returns: flickerstreak@30: boolean - whether the object has the given mixin embedded into it. flickerstreak@30: Example: flickerstreak@30: local LibMonkey = Rock:NewLibrary("LibMonkey-1.0") flickerstreak@30: local Darwin = Rock:NewAddon("Darwin", "LibMonkey-1.0") flickerstreak@30: assert(Rock:DoesObjectUseMixin(Darwin, "LibMonkey-1.0")) flickerstreak@30: -----------------------------------------------------------------------------]] flickerstreak@30: function Rock:DoesObjectUseMixin(object, mixinName) flickerstreak@30: if type(object) ~= "table" then flickerstreak@30: error(("Bad argument #2 to `IterateObjectMixins'. Expected %q, got %q."):format("table", type(object)), 2) flickerstreak@30: end flickerstreak@30: local mixin flickerstreak@30: if type(mixinName) == "table" then flickerstreak@30: mixin = mixinName flickerstreak@30: else flickerstreak@30: if type(mixinName) ~= "string" then flickerstreak@30: error(("Bad argument #3 to `IterateMiDoesObjectUseMixininObjects'. Expected %q or %q, got %q."):format("table", "string", type(mixinName)), 2) flickerstreak@30: end flickerstreak@30: mixin = libraries[mixinName] flickerstreak@30: end flickerstreak@30: if not mixin then flickerstreak@30: return false flickerstreak@30: end flickerstreak@30: flickerstreak@30: local mixinToObject_mixin = mixinToObject[mixin] flickerstreak@30: if not mixinToObject_mixin then flickerstreak@30: return false flickerstreak@30: end flickerstreak@30: return not not mixinToObject_mixin[object] flickerstreak@30: end flickerstreak@30: flickerstreak@30: Rock.UID_NUM = oldRock and oldRock.UID_NUM or 0 flickerstreak@30: --[[--------------------------------------------------------------------------- flickerstreak@30: Notes: flickerstreak@30: * This UID is not unique across sessions. If you save a UID in a saved variable, the same UID can be generated in another session. flickerstreak@30: Returns: flickerstreak@30: number - a unique number. flickerstreak@30: Example: flickerstreak@30: local UID = Rock:GetUID() flickerstreak@30: -----------------------------------------------------------------------------]] flickerstreak@30: function Rock:GetUID() flickerstreak@30: local num = Rock.UID_NUM + 1 flickerstreak@30: Rock.UID_NUM = num flickerstreak@30: return num flickerstreak@30: end flickerstreak@30: flickerstreak@30: local function unobfuscateEmail(email) flickerstreak@30: return email:gsub(" AT ", "@"):gsub(" DOT ", ".") flickerstreak@30: end flickerstreak@30: local function fix(char) flickerstreak@30: return ("%%%02x"):format(char:byte()) flickerstreak@30: end flickerstreak@30: local function urlencode(text) flickerstreak@30: return text:gsub("[^0-9A-Za-z]", fix) flickerstreak@30: end flickerstreak@30: flickerstreak@30: local url flickerstreak@30: local function makeURLFrame() flickerstreak@30: makeURLFrame = nil flickerstreak@30: local function bumpFrameLevels(frame, amount) flickerstreak@30: frame:SetFrameLevel(frame:GetFrameLevel()+amount) flickerstreak@30: local children = newList(frame:GetChildren()) flickerstreak@30: for _,v in ipairs(children) do flickerstreak@30: bumpFrameLevels(v, amount) flickerstreak@30: end flickerstreak@30: children = del(children) flickerstreak@30: end flickerstreak@30: -- some code borrowed from Prat here flickerstreak@30: StaticPopupDialogs["ROCK_SHOW_URL"] = { flickerstreak@30: text = not IsMacClient() and L["Press Ctrl-C to copy, then Alt-Tab out of the game, open your favorite web browser, and paste the link into the address bar."] or L["Press Cmd-C to copy, then Cmd-Tab out of the game, open your favorite web browser, and paste the link into the address bar."], flickerstreak@30: button2 = ACCEPT, flickerstreak@30: hasEditBox = 1, flickerstreak@30: hasWideEditBox = 1, flickerstreak@30: showAlert = 1, -- HACK : it's the only way I found to make de StaticPopup have sufficient width to show WideEditBox :( flickerstreak@30: flickerstreak@30: OnShow = function() flickerstreak@30: local editBox = _G[this:GetName() .. "WideEditBox"] flickerstreak@30: editBox:SetText(url) flickerstreak@30: editBox:SetFocus() flickerstreak@30: editBox:HighlightText(0) flickerstreak@30: editBox:SetScript("OnTextChanged", function() StaticPopup_EditBoxOnTextChanged() end) flickerstreak@30: flickerstreak@30: local button = _G[this:GetName() .. "Button2"] flickerstreak@30: button:ClearAllPoints() flickerstreak@30: button:SetWidth(200) flickerstreak@30: button:SetPoint("CENTER", editBox, "CENTER", 0, -30) flickerstreak@30: flickerstreak@30: _G[this:GetName() .. "AlertIcon"]:Hide() -- HACK : we hide the false AlertIcon flickerstreak@30: this:SetFrameStrata("FULLSCREEN_DIALOG") flickerstreak@30: bumpFrameLevels(this, 30) flickerstreak@30: end, flickerstreak@30: OnHide = function() flickerstreak@30: local editBox = _G[this:GetName() .. "WideEditBox"] flickerstreak@30: editBox:SetScript("OnTextChanged", nil) flickerstreak@30: this:SetFrameStrata("DIALOG") flickerstreak@30: bumpFrameLevels(this, -30) flickerstreak@30: end, flickerstreak@30: OnAccept = function() end, flickerstreak@30: OnCancel = function() end, flickerstreak@30: EditBoxOnEscapePressed = function() this:GetParent():Hide() end, flickerstreak@30: EditBoxOnTextChanged = function() flickerstreak@30: this:SetText(url) flickerstreak@30: this:SetFocus() flickerstreak@30: this:HighlightText(0) flickerstreak@30: end, flickerstreak@30: timeout = 0, flickerstreak@30: whileDead = 1, flickerstreak@30: hideOnEscape = 1 flickerstreak@30: } flickerstreak@30: end flickerstreak@30: flickerstreak@30: function OpenDonationFrame(self) flickerstreak@30: if makeURLFrame then flickerstreak@30: makeURLFrame() flickerstreak@30: end flickerstreak@30: flickerstreak@30: local donate = self.donate flickerstreak@30: if type(donate) ~= "string" then flickerstreak@30: donate = "Wowace" flickerstreak@30: end flickerstreak@30: local style, data = (":"):split(donate, 2) flickerstreak@30: style = style:lower() flickerstreak@30: if style ~= "website" and style ~= "paypal" then flickerstreak@30: style = "wowace" flickerstreak@30: end flickerstreak@30: if style == "wowace" then flickerstreak@30: url = "http://www.wowace.com/wiki/Donations" flickerstreak@30: elseif style == "website" then flickerstreak@30: url = data flickerstreak@30: else -- PayPal flickerstreak@30: local text = "https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&business=" .. urlencode(unobfuscateEmail(data)) flickerstreak@30: local name flickerstreak@30: if type(self.title) == "string" then flickerstreak@30: name = self.title flickerstreak@30: elseif type(self.name) == "string" then flickerstreak@30: name = self.name flickerstreak@30: end flickerstreak@30: if name == MAJOR_VERSION then flickerstreak@30: name = "Rock" flickerstreak@30: end flickerstreak@30: if name then flickerstreak@30: name = name:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", "") flickerstreak@30: text = text .. "&item_name=" .. urlencode(name) flickerstreak@30: end flickerstreak@30: url = text flickerstreak@30: end flickerstreak@30: flickerstreak@30: StaticPopup_Show("ROCK_SHOW_URL") flickerstreak@30: end flickerstreak@30: function OpenIssueFrame(self) flickerstreak@30: if makeURLFrame then flickerstreak@30: makeURLFrame() flickerstreak@30: end flickerstreak@30: flickerstreak@30: local issueTracker = self.issueTracker flickerstreak@30: if type(issueTracker) ~= "string" then flickerstreak@30: return flickerstreak@30: end flickerstreak@30: local style, data = (":"):split(issueTracker, 2) flickerstreak@30: style = style:lower() flickerstreak@30: if style ~= "website" and style ~= "wowace" then flickerstreak@30: return flickerstreak@30: end flickerstreak@30: if style == "wowace" then flickerstreak@30: url = "http://jira.wowace.com/secure/CreateIssue.jspa?pid=" .. data flickerstreak@30: elseif style == "website" then flickerstreak@30: url = data flickerstreak@30: end flickerstreak@30: flickerstreak@30: StaticPopup_Show("ROCK_SHOW_URL") flickerstreak@30: end flickerstreak@30: local function donate_hidden(addon) flickerstreak@30: return type(addon.donate) ~= "string" flickerstreak@30: end flickerstreak@30: flickerstreak@30: local function issue_hidden(addon) flickerstreak@30: return type(addon.issueTracker) ~= "string" flickerstreak@30: end flickerstreak@30: flickerstreak@30: -- #NODOC flickerstreak@30: function Rock:GetRockConfigOptions(addon) flickerstreak@30: return 'active', { flickerstreak@30: type = 'boolean', flickerstreak@30: name = L["Enabled"], flickerstreak@30: desc = L["Enable or disable this addon."], flickerstreak@30: get = 'IsActive', flickerstreak@30: set = 'ToggleActive', flickerstreak@30: handler = addon, flickerstreak@30: order = -1, flickerstreak@30: }, 'donate', { flickerstreak@30: type = 'execute', flickerstreak@30: name = L["Give donation"], flickerstreak@30: buttonText = L["Donate"], flickerstreak@30: desc = L["Give a much-needed donation to the author of this addon."], flickerstreak@30: func = OpenDonationFrame, flickerstreak@30: hidden = donate_hidden, flickerstreak@30: passValue = addon, flickerstreak@30: order = -2, flickerstreak@30: }, 'issue', { flickerstreak@30: type = 'execute', flickerstreak@30: name = L["File issue"], flickerstreak@30: buttonText = L["Report"], flickerstreak@30: desc = L["File a bug or request a new feature or an improvement to this addon."], flickerstreak@30: func = OpenIssueFrame, flickerstreak@30: hidden = issue_hidden, flickerstreak@30: passValue = addon, flickerstreak@30: order = -3, flickerstreak@30: } flickerstreak@30: end flickerstreak@30: flickerstreak@30: local function initAddon(addon, name) flickerstreak@30: name = addonToFolder[addon] or name or "" flickerstreak@30: -- TOC checks flickerstreak@30: if addon.title == nil then flickerstreak@30: addon.title = GetAddOnMetadata(name, "Title") flickerstreak@30: end flickerstreak@30: if type(addon.title) == "string" then flickerstreak@30: addon.title = addon.title:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", ""):gsub("%-Rock%-$", ""):trim() flickerstreak@30: end flickerstreak@30: if addon.notes == nil then flickerstreak@30: addon.notes = GetAddOnMetadata(name, "Notes") flickerstreak@30: end flickerstreak@30: if type(addon.notes) == "string" then flickerstreak@30: addon.notes = addon.notes:trim() flickerstreak@30: end flickerstreak@30: if addon.version == nil then flickerstreak@30: addon.version = GetAddOnMetadata(name, "Version") flickerstreak@30: end flickerstreak@30: if type(addon.version) == "string" then flickerstreak@30: addon.version = addon.version:trim() flickerstreak@30: end flickerstreak@30: if addon.author == nil then flickerstreak@30: addon.author = GetAddOnMetadata(name, "Author") flickerstreak@30: end flickerstreak@30: if type(addon.author) == "string" then flickerstreak@30: addon.author = addon.author:trim() flickerstreak@30: end flickerstreak@30: if addon.credits == nil then flickerstreak@30: addon.credits = GetAddOnMetadata(name, "X-Credits") flickerstreak@30: end flickerstreak@30: if type(addon.credits) == "string" then flickerstreak@30: addon.credits = addon.credits:trim() flickerstreak@30: end flickerstreak@30: if addon.donate == nil then flickerstreak@30: addon.donate = GetAddOnMetadata(name, "X-Donate") flickerstreak@30: end flickerstreak@30: if type(addon.donate) == "string" then flickerstreak@30: addon.donate = addon.donate:trim() flickerstreak@30: end flickerstreak@30: if addon.issueTracker == nil then flickerstreak@30: addon.issueTracker = GetAddOnMetadata(name, "X-IssueTracker") flickerstreak@30: end flickerstreak@30: if type(addon.issueTracker) == "string" then flickerstreak@30: addon.issueTracker = addon.issueTracker:trim() flickerstreak@30: end flickerstreak@30: if addon.category == nil then flickerstreak@30: addon.category = GetAddOnMetadata(name, "X-Category") flickerstreak@30: end flickerstreak@30: if type(addon.category) == "string" then flickerstreak@30: addon.category = addon.category:trim() flickerstreak@30: end flickerstreak@30: if addon.email == nil then flickerstreak@30: addon.email = GetAddOnMetadata(name, "X-eMail") or GetAddOnMetadata(name, "X-Email") flickerstreak@30: end flickerstreak@30: if type(addon.email) == "string" then flickerstreak@30: addon.email = addon.email:trim() flickerstreak@30: end flickerstreak@30: if addon.license == nil then flickerstreak@30: addon.license = GetAddOnMetadata(name, "X-License") flickerstreak@30: end flickerstreak@30: if type(addon.license) == "string" then flickerstreak@30: addon.license = addon.license:trim() flickerstreak@30: end flickerstreak@30: if addon.website == nil then flickerstreak@30: addon.website = GetAddOnMetadata(name, "X-Website") flickerstreak@30: end flickerstreak@30: if type(addon.website) == "string" then flickerstreak@30: addon.website = addon.website:trim() flickerstreak@30: end flickerstreak@30: flickerstreak@30: for mixin in Rock:IterateObjectMixins(addon) do flickerstreak@30: local mixin_OnEmbedInitialize = mixin.OnEmbedInitialize flickerstreak@30: if mixin_OnEmbedInitialize then flickerstreak@30: local success, ret = pcall(mixin_OnEmbedInitialize, mixin, addon) flickerstreak@30: if not success then flickerstreak@30: geterrorhandler()(ret) flickerstreak@30: end flickerstreak@30: end flickerstreak@30: end flickerstreak@30: flickerstreak@30: local addon_OnInitialize = addon.OnInitialize flickerstreak@30: if addon_OnInitialize then flickerstreak@30: local success, ret = pcall(addon_OnInitialize, addon) flickerstreak@30: if not success then flickerstreak@30: geterrorhandler()(ret) flickerstreak@30: end flickerstreak@30: end flickerstreak@30: flickerstreak@30: if LibRockEvent then flickerstreak@30: Rock:DispatchEvent("AddonInitialized", addon) flickerstreak@30: end flickerstreak@30: end flickerstreak@30: flickerstreak@30: flickerstreak@30: local function manualEnable(addon) flickerstreak@30: for i,v in ipairs(pendingAddons) do flickerstreak@30: if v == addon then flickerstreak@30: return flickerstreak@30: end flickerstreak@30: end flickerstreak@30: if currentlyEnabledAddons[addon] then flickerstreak@30: return false flickerstreak@30: end flickerstreak@30: currentlyEnabledAddons[addon] = true flickerstreak@30: flickerstreak@30: local first = not addonsAlreadyEnabled[addon] flickerstreak@30: addonsAlreadyEnabled[addon] = true flickerstreak@30: flickerstreak@30: for mixin in Rock:IterateObjectMixins(addon) do flickerstreak@30: local mixin_OnEmbedEnable = mixin.OnEmbedEnable flickerstreak@30: if mixin_OnEmbedEnable then flickerstreak@30: local success, ret = pcall(mixin_OnEmbedEnable, mixin, addon, first) flickerstreak@30: if not success then flickerstreak@30: geterrorhandler()(ret) flickerstreak@30: end flickerstreak@30: end flickerstreak@30: end flickerstreak@30: local addon_OnEnable = addon.OnEnable flickerstreak@30: if addon_OnEnable then flickerstreak@30: local success, ret = pcall(addon_OnEnable, addon, first) flickerstreak@30: if not success then flickerstreak@30: geterrorhandler()(ret) flickerstreak@30: end flickerstreak@30: end flickerstreak@30: flickerstreak@30: if LibRockEvent then flickerstreak@30: Rock:DispatchEvent("AddonEnabled", addon, first) flickerstreak@30: end flickerstreak@30: flickerstreak@30: return true, first flickerstreak@30: end flickerstreak@30: flickerstreak@30: local function manualDisable(addon) flickerstreak@30: if not currentlyEnabledAddons[addon] then flickerstreak@30: return false flickerstreak@30: end flickerstreak@30: currentlyEnabledAddons[addon] = nil flickerstreak@30: flickerstreak@30: for mixin in Rock:IterateObjectMixins(addon) do flickerstreak@30: local mixin_OnEmbedDisable = mixin.OnEmbedDisable flickerstreak@30: if mixin_OnEmbedDisable then flickerstreak@30: local success, ret = pcall(mixin_OnEmbedDisable, mixin, addon) flickerstreak@30: if not success then flickerstreak@30: geterrorhandler()(ret) flickerstreak@30: end flickerstreak@30: end flickerstreak@30: end flickerstreak@30: local addon_OnDisable = addon.OnDisable flickerstreak@30: if addon_OnDisable then flickerstreak@30: local success, ret = pcall(addon_OnDisable, addon) flickerstreak@30: if not success then flickerstreak@30: geterrorhandler()(ret) flickerstreak@30: end flickerstreak@30: end flickerstreak@30: flickerstreak@30: if LibRockEvent then flickerstreak@30: Rock:DispatchEvent("AddonDisabled", addon) flickerstreak@30: end flickerstreak@30: return true flickerstreak@30: end flickerstreak@30: flickerstreak@30: local function enableAddon(addon) flickerstreak@30: for i,v in ipairs(pendingAddons) do flickerstreak@30: if v == addon then flickerstreak@30: return flickerstreak@30: end flickerstreak@30: end flickerstreak@30: if addon_mt___index.IsActive(addon) then flickerstreak@30: manualEnable(addon) flickerstreak@30: end flickerstreak@30: end flickerstreak@30: flickerstreak@30: -- #NODOC flickerstreak@30: -- This is used by internal Rock libraries after updating the active state. flickerstreak@30: function Rock:RecheckEnabledStates() flickerstreak@30: local changed = false flickerstreak@30: for _,addon in pairs(addons) do flickerstreak@30: local good = true flickerstreak@30: for _,a in ipairs(pendingAddonsEnable) do flickerstreak@30: if addon == a then flickerstreak@30: good = false flickerstreak@30: break flickerstreak@30: end flickerstreak@30: end flickerstreak@30: if good then flickerstreak@30: if addon_mt___index.IsActive(addon) then flickerstreak@30: if manualEnable(addon) then flickerstreak@30: changed = true flickerstreak@30: end flickerstreak@30: else flickerstreak@30: if manualDisable(addon) then flickerstreak@30: changed = true flickerstreak@30: end flickerstreak@30: end flickerstreak@30: end flickerstreak@30: end flickerstreak@30: if changed then flickerstreak@30: return self:RecheckEnabledStates() flickerstreak@30: end flickerstreak@30: end flickerstreak@30: flickerstreak@30: frame:UnregisterAllEvents() flickerstreak@30: frame:RegisterEvent("ADDON_LOADED") flickerstreak@30: frame:RegisterEvent("PLAYER_LOGIN") flickerstreak@30: local function runMainAddonLoadedChunk(name) flickerstreak@30: local tmp = newList() flickerstreak@30: tmp, pendingAddons = pendingAddons, tmp flickerstreak@30: for i, addon in ipairs(tmp) do flickerstreak@30: local folder = addonToFolder[addon] flickerstreak@30: if name and folder and not foldersLoaded[folder] then flickerstreak@30: for j = i, #tmp do flickerstreak@30: pendingAddons[#pendingAddons+1] = tmp[j] flickerstreak@30: tmp[j] = nil flickerstreak@30: end flickerstreak@30: break flickerstreak@30: end flickerstreak@30: initAddon(addon, name) flickerstreak@30: end flickerstreak@30: flickerstreak@30: if IsLoggedIn() then flickerstreak@30: for i, addon in ipairs(tmp) do flickerstreak@30: for j, v in ipairs(pendingAddonsEnable) do flickerstreak@30: if v == addon then flickerstreak@30: table_remove(pendingAddonsEnable, i) flickerstreak@30: break flickerstreak@30: end flickerstreak@30: end flickerstreak@30: enableAddon(addon) flickerstreak@30: end flickerstreak@30: for i, addon in ipairs(pendingAddonsEnable) do flickerstreak@30: local good = true flickerstreak@30: for j, v in ipairs(pendingAddons) do flickerstreak@30: if v == addon then flickerstreak@30: good = false flickerstreak@30: break flickerstreak@30: end flickerstreak@30: end flickerstreak@30: if not good then flickerstreak@30: break flickerstreak@30: end flickerstreak@30: pendingAddonsEnable[i] = nil flickerstreak@30: enableAddon(addon) flickerstreak@30: end flickerstreak@30: end flickerstreak@30: tmp = del(tmp) flickerstreak@30: for library, addonName in pairs(pendingLibraries) do flickerstreak@30: if not name or foldersLoaded[addonName] then flickerstreak@30: local success, ret = pcall(error, ("Library %q not finalized before ADDON_LOADED."):format(better_tostring(library)), 3) flickerstreak@30: geterrorhandler()(ret) flickerstreak@30: Rock:FinalizeLibrary((library:GetLibraryVersion())) flickerstreak@30: end flickerstreak@30: end flickerstreak@30: flickerstreak@30: if isStandalone then flickerstreak@30: local LibRock_1_0DB = _G.LibRock_1_0DB flickerstreak@30: if type(LibRock_1_0DB) ~= "table" then flickerstreak@30: LibRock_1_0DB = {} flickerstreak@30: _G.LibRock_1_0DB = LibRock_1_0DB flickerstreak@30: end flickerstreak@30: if type(LibRock_1_0DB.unitTests) ~= "table" then flickerstreak@30: LibRock_1_0DB.unitTests = {} flickerstreak@30: end flickerstreak@30: enableContracts = LibRock_1_0DB.contracts or false flickerstreak@30: unitTestDB = LibRock_1_0DB.unitTests flickerstreak@30: for namespace, data in pairs(unitTests) do flickerstreak@30: if not unitTestDB[namespace] then flickerstreak@30: if data then flickerstreak@30: del(data) flickerstreak@30: unitTests[namespace] = false flickerstreak@30: end flickerstreak@30: elseif data and (not name or data.addon == name) then flickerstreak@30: local stats = newList() flickerstreak@30: for i,v in ipairs(data) do flickerstreak@30: data[i] = nil flickerstreak@30: flickerstreak@30: local libs = newList() flickerstreak@30: for k,v in pairs(libraries) do flickerstreak@30: libs[k] = v flickerstreak@30: end flickerstreak@30: flickerstreak@30: local success, ret = pcall(v) flickerstreak@30: if not success then flickerstreak@30: geterrorhandler()(ret) flickerstreak@30: stats[i] = ret flickerstreak@30: else flickerstreak@30: stats[i] = false flickerstreak@30: end flickerstreak@30: flickerstreak@30: for k in pairs(libraries) do flickerstreak@30: if not libs[k] then flickerstreak@30: __removeLibrary(k) flickerstreak@30: end flickerstreak@30: end flickerstreak@30: libs = del(libs) flickerstreak@30: flickerstreak@30: local lastCount flickerstreak@30: repeat flickerstreak@30: lastCount = collectgarbage('count') flickerstreak@30: collectgarbage('collect') flickerstreak@30: until lastCount == collectgarbage('count') flickerstreak@30: end flickerstreak@30: del(data) flickerstreak@30: unitTests[namespace] = false flickerstreak@30: if #stats >= 1 then flickerstreak@30: local pass, fail = 0, 0 flickerstreak@30: for i,v in ipairs(stats) do flickerstreak@30: if v then flickerstreak@30: fail = fail + 1 flickerstreak@30: else flickerstreak@30: pass = pass + 1 flickerstreak@30: end flickerstreak@30: end flickerstreak@30: flickerstreak@30: local color flickerstreak@30: if fail == 0 then flickerstreak@30: _G.DEFAULT_CHAT_FRAME:AddMessage(("|cff00ff00%s: %d unit test(s) passed."):format(namespace, pass)) flickerstreak@30: elseif pass > 0 then flickerstreak@30: _G.DEFAULT_CHAT_FRAME:AddMessage(("|cffff0000%s: %d unit test(s) passed, %d unit test(s) failed."):format(namespace, pass, fail)) flickerstreak@30: else flickerstreak@30: _G.DEFAULT_CHAT_FRAME:AddMessage(("|cffff0000%s: %d unit test(s) failed."):format(namespace, fail)) flickerstreak@30: end flickerstreak@30: for i,v in ipairs(stats) do flickerstreak@30: if v then flickerstreak@30: _G.DEFAULT_CHAT_FRAME:AddMessage(("|cffff0000%s|r"):format(tostring(v))) flickerstreak@30: end flickerstreak@30: end flickerstreak@30: if fail > 0 then flickerstreak@30: _G.DEFAULT_CHAT_FRAME:AddMessage("|cffff0000----------|r") flickerstreak@30: end flickerstreak@30: end flickerstreak@30: stats = del(stats) flickerstreak@30: end flickerstreak@30: end flickerstreak@30: end flickerstreak@30: if isStandalone and name == MAJOR_VERSION then flickerstreak@30: Rock("LibRockEvent-1.0", false, true) -- load if possible flickerstreak@30: Rock("LibRockConsole-1.0", false, true) -- load if possible - I like the default chat commands flickerstreak@30: Rock("LibRockComm-1.0", false, true) -- load if possible - has version checking and the like flickerstreak@30: Rock("LibRockConfig-1.0", false, true) -- load if possible - LibRock-1.0 registers with it. flickerstreak@30: end flickerstreak@30: flickerstreak@30: for major, library in LibStub:IterateLibraries() do flickerstreak@30: manualFinalize(major, library) flickerstreak@30: end flickerstreak@30: flickerstreak@30: if IsLoggedIn() then flickerstreak@30: collectgarbage('collect') flickerstreak@30: end flickerstreak@30: end flickerstreak@30: flickerstreak@30: frame:Show() flickerstreak@30: frame:SetScript("OnUpdate", function(this, elapsed) flickerstreak@30: -- capture all un-initialized addons. flickerstreak@30: runMainAddonLoadedChunk() flickerstreak@30: collectgarbage('collect') flickerstreak@30: this:SetScript("OnUpdate", run) flickerstreak@30: end) flickerstreak@30: frame:SetScript("OnEvent", function(this, event, ...) flickerstreak@30: if event == "ADDON_LOADED" then flickerstreak@30: -- this creates a new table and flushes the old in case someone LoDs an addon inside ADDON_LOADED. flickerstreak@30: local name = ... flickerstreak@30: foldersLoaded[name] = true flickerstreak@30: runMainAddonLoadedChunk(name) flickerstreak@30: frame:Show() flickerstreak@30: elseif event == "PLAYER_LOGIN" then flickerstreak@30: for i, addon in ipairs(pendingAddonsEnable) do flickerstreak@30: local good = true flickerstreak@30: for _, a in ipairs(pendingAddons) do flickerstreak@30: if a == addon then flickerstreak@30: good = false flickerstreak@30: break flickerstreak@30: end flickerstreak@30: end flickerstreak@30: if good then flickerstreak@30: pendingAddonsEnable[i] = nil flickerstreak@30: enableAddon(addon) flickerstreak@30: end flickerstreak@30: end flickerstreak@30: collectgarbage('collect') flickerstreak@30: end flickerstreak@30: end) flickerstreak@30: flickerstreak@30: Rock:SetExportedMethods("SetExportedMethods", "Embed", "Unembed", "GetLibraryVersion") flickerstreak@30: flickerstreak@30: Rock:FinalizeLibrary(MAJOR_VERSION) flickerstreak@30: flickerstreak@30: for major, library in LibStub:IterateLibraries() do flickerstreak@30: manualFinalize(major, library) flickerstreak@30: end flickerstreak@30: flickerstreak@30: Rock:AddUnitTest(MAJOR_VERSION, function() flickerstreak@30: -- test recycling flickerstreak@30: local newList, newDict, newSet, del = Rock:GetRecyclingFunctions(MAJOR_VERSION .. "_UnitTest", "newList", "newDict", "newSet", "del", "Debug") flickerstreak@30: local t = newList("Alpha", "Bravo", "Charlie") flickerstreak@30: assert(t[1] == "Alpha") flickerstreak@30: assert(t[2] == "Bravo") flickerstreak@30: assert(t[3] == "Charlie") flickerstreak@30: t = del(t) flickerstreak@30: t = newList("Alpha", "Bravo", "Charlie") flickerstreak@30: -- check recycled table flickerstreak@30: assert(t[1] == "Alpha") flickerstreak@30: assert(t[2] == "Bravo") flickerstreak@30: assert(t[3] == "Charlie") flickerstreak@30: t = del(t) flickerstreak@30: t = newDict("Alpha", "Bravo", "Charlie", "Delta") flickerstreak@30: assert(t.Alpha == "Bravo") flickerstreak@30: assert(t.Charlie == "Delta") flickerstreak@30: t = del(t) flickerstreak@30: t = newSet("Alpha", "Bravo", "Charlie") flickerstreak@30: assert(t.Alpha) flickerstreak@30: assert(t.Bravo) flickerstreak@30: assert(t.Charlie) flickerstreak@30: t = del(t) flickerstreak@30: flickerstreak@30: local debug = recycleData.debugPools[MAJOR_VERSION .. "_UnitTest"] flickerstreak@30: assert(debug.num == 0) flickerstreak@30: t = newList() flickerstreak@30: assert(debug.num == 1) flickerstreak@30: t[1] = newList() flickerstreak@30: assert(debug.num == 2) flickerstreak@30: t[2] = newList() flickerstreak@30: assert(debug.num == 3) flickerstreak@30: t[1] = del(t[1]) flickerstreak@30: assert(debug.num == 2) flickerstreak@30: t[2] = del(t[2]) flickerstreak@30: assert(debug.num == 1) flickerstreak@30: t = del(t) flickerstreak@30: assert(debug.num == 0) flickerstreak@30: end) flickerstreak@30: flickerstreak@30: Rock:AddUnitTest(MAJOR_VERSION, function() flickerstreak@30: -- test :GetUID() flickerstreak@30: local t = {} flickerstreak@30: for i = 1, 10000 do flickerstreak@30: local uid = Rock:GetUID() flickerstreak@30: if t[i] then flickerstreak@30: error(("UID match for iteration %d, UID %s"):format(i, uid)) flickerstreak@30: end flickerstreak@30: t[i] = true flickerstreak@30: end flickerstreak@30: end) flickerstreak@30: flickerstreak@30: Rock:AddUnitTest(MAJOR_VERSION, function() flickerstreak@30: -- test basic creation and deletion flickerstreak@30: assert(not LibStub:GetLibrary("LibRockFakeLib-1.0", true)) flickerstreak@30: assert(not Rock:HasLibrary("LibRockFakeLib-1.0")) flickerstreak@30: local lib = Rock:NewLibrary("LibRockFakeLib-1.0", 1) flickerstreak@30: Rock:FinalizeLibrary("LibRockFakeLib-1.0") flickerstreak@30: lib = nil flickerstreak@30: assert(LibStub:GetLibrary("LibRockFakeLib-1.0", true)) flickerstreak@30: assert(Rock:HasLibrary("LibRockFakeLib-1.0")) flickerstreak@30: local good = false flickerstreak@30: for _, lib in pairs(libraries) do flickerstreak@30: if lib.name == "LibRockFakeLib-1.0" then flickerstreak@30: good = true flickerstreak@30: break flickerstreak@30: end flickerstreak@30: end flickerstreak@30: assert(good) flickerstreak@30: __removeLibrary("LibRockFakeLib-1.0") flickerstreak@30: for _, lib in pairs(libraries) do flickerstreak@30: assert(lib.name ~= "LibRockFakeLib-1.0") flickerstreak@30: end flickerstreak@30: assert(not LibStub:GetLibrary("LibRockFakeLib-1.0", true)) flickerstreak@30: assert(not Rock:HasLibrary("LibRockFakeLib-1.0")) flickerstreak@30: end) flickerstreak@30: flickerstreak@30: Rock:AddUnitTest(MAJOR_VERSION, function() flickerstreak@30: -- test library creation and the like flickerstreak@30: assert(not Rock:HasLibrary("LibRockFakeLib-1.0")) flickerstreak@30: for name in Rock:IterateLibraries() do flickerstreak@30: assert(name ~= "LibRockFakeLib-1.0") flickerstreak@30: end flickerstreak@30: flickerstreak@30: local myLib, oldLib = Rock:NewLibrary("LibRockFakeLib-1.0", 1) flickerstreak@30: assert(myLib) flickerstreak@30: assert(myLib.name == "LibRockFakeLib-1.0") flickerstreak@30: assert(not oldLib) flickerstreak@30: flickerstreak@30: assert(myLib:GetLibraryVersion() == "LibRockFakeLib-1.0") flickerstreak@30: assert(select(2, myLib:GetLibraryVersion()) == 1) flickerstreak@30: flickerstreak@30: local good = false flickerstreak@30: for name in Rock:IterateLibraries() do flickerstreak@30: if name == "LibRockFakeLib-1.0" then flickerstreak@30: good = true flickerstreak@30: break flickerstreak@30: end flickerstreak@30: end flickerstreak@30: assert(good) flickerstreak@30: assert(Rock:HasLibrary("LibRockFakeLib-1.0")) flickerstreak@30: assert(Rock:GetLibrary("LibRockFakeLib-1.0") == myLib) flickerstreak@30: assert(Rock("LibRockFakeLib-1.0") == myLib) flickerstreak@30: flickerstreak@30: assert(not Rock:IsLibraryMixin("LibRockFakeLib-1.0")) flickerstreak@30: function myLib:DoSomething() flickerstreak@30: return "Something" flickerstreak@30: end flickerstreak@30: myLib:SetExportedMethods("DoSomething") flickerstreak@30: assert(Rock:IsLibraryMixin("LibRockFakeLib-1.0")) flickerstreak@30: local t = {} flickerstreak@30: assert(not Rock:DoesObjectUseMixin(t, "LibRockFakeLib-1.0")) flickerstreak@30: assert(not t.DoSomething) flickerstreak@30: for mixin in Rock:IterateObjectMixins(t) do flickerstreak@30: assert(false) flickerstreak@30: end flickerstreak@30: for object in Rock:IterateMixinObjects("LibRockFakeLib-1.0") do flickerstreak@30: assert(false) flickerstreak@30: end flickerstreak@30: myLib:Embed(t) flickerstreak@30: assert(t:DoSomething() == "Something") flickerstreak@30: assert(Rock:DoesObjectUseMixin(t, "LibRockFakeLib-1.0")) flickerstreak@30: for mixin in Rock:IterateObjectMixins(t) do flickerstreak@30: assert(mixin == myLib) flickerstreak@30: end flickerstreak@30: for object in Rock:IterateMixinObjects("LibRockFakeLib-1.0") do flickerstreak@30: assert(object == t) flickerstreak@30: end flickerstreak@30: flickerstreak@30: Rock:FinalizeLibrary("LibRockFakeLib-1.0") flickerstreak@30: flickerstreak@30: local myNewLib, oldLib = Rock:NewLibrary("LibRockFakeLib-1.0", 2) flickerstreak@30: assert(myNewLib == myLib) flickerstreak@30: assert(oldLib) flickerstreak@30: assert(Rock:GetLibrary("LibRockFakeLib-1.0") == myLib) flickerstreak@30: flickerstreak@30: function myLib:DoSomething() flickerstreak@30: return "Something else" flickerstreak@30: end flickerstreak@30: function myLib:TrySomething() flickerstreak@30: return "Blah" flickerstreak@30: end flickerstreak@30: myLib:SetExportedMethods("DoSomething", "TrySomething") flickerstreak@30: assert(Rock:IsLibraryMixin("LibRockFakeLib-1.0")) flickerstreak@30: assert(t:DoSomething() == "Something else") flickerstreak@30: assert(t:TrySomething() == "Blah") flickerstreak@30: assert(Rock:DoesObjectUseMixin(t, "LibRockFakeLib-1.0")) flickerstreak@30: for mixin in Rock:IterateObjectMixins(t) do flickerstreak@30: assert(mixin == myLib) flickerstreak@30: end flickerstreak@30: for object in Rock:IterateMixinObjects("LibRockFakeLib-1.0") do flickerstreak@30: assert(object == t) flickerstreak@30: end flickerstreak@30: flickerstreak@30: Rock:FinalizeLibrary("LibRockFakeLib-1.0") flickerstreak@30: flickerstreak@30: local myNewLib, oldLib = Rock:NewLibrary("LibRockFakeLib-1.0", 3) flickerstreak@30: assert(myNewLib == myLib) flickerstreak@30: assert(oldLib) flickerstreak@30: assert(Rock:GetLibrary("LibRockFakeLib-1.0") == myLib) flickerstreak@30: flickerstreak@30: function myLib:DoSomething() flickerstreak@30: return "Something" flickerstreak@30: end flickerstreak@30: myLib:SetExportedMethods("DoSomething") flickerstreak@30: assert(Rock:IsLibraryMixin("LibRockFakeLib-1.0")) flickerstreak@30: assert(t:DoSomething() == "Something") flickerstreak@30: assert(t.TrySomething == nil) flickerstreak@30: assert(Rock:DoesObjectUseMixin(t, "LibRockFakeLib-1.0")) flickerstreak@30: for mixin in Rock:IterateObjectMixins(t) do flickerstreak@30: assert(mixin == myLib) flickerstreak@30: end flickerstreak@30: for object in Rock:IterateMixinObjects("LibRockFakeLib-1.0") do flickerstreak@30: assert(object == t) flickerstreak@30: end flickerstreak@30: flickerstreak@30: Rock:FinalizeLibrary("LibRockFakeLib-1.0") flickerstreak@30: flickerstreak@30: assert(not Rock:NewLibrary("LibRockFakeLib-1.0", 2)) -- out of date flickerstreak@30: assert(not Rock:NewLibrary("LibRockFakeLib-1.0", 3)) -- same revision flickerstreak@30: end) flickerstreak@30: flickerstreak@30: Rock:AddUnitTest(MAJOR_VERSION, function() flickerstreak@30: assert(not Rock:HasAddon("RockFakeAddon")) flickerstreak@30: for name in Rock:IterateAddons() do flickerstreak@30: assert(name ~= "RockFakeAddon") flickerstreak@30: end flickerstreak@30: flickerstreak@30: local myAddon = Rock:NewAddon("RockFakeAddon") flickerstreak@30: flickerstreak@30: assert(myAddon) flickerstreak@30: assert(myAddon.name == "RockFakeAddon") flickerstreak@30: flickerstreak@30: local good = false flickerstreak@30: for name in Rock:IterateAddons() do flickerstreak@30: if name == "RockFakeAddon" then flickerstreak@30: good = true flickerstreak@30: break flickerstreak@30: end flickerstreak@30: end flickerstreak@30: assert(good) flickerstreak@30: assert(Rock:HasAddon("RockFakeAddon")) flickerstreak@30: assert(Rock:GetAddon("RockFakeAddon") == myAddon) flickerstreak@30: end) flickerstreak@30: flickerstreak@30: Rock:AddUnitTest(MAJOR_VERSION, function() flickerstreak@30: -- test :OnLibraryLoad flickerstreak@30: local lib = Rock:NewLibrary("LibRockFakeLib-1.0", 1) flickerstreak@30: local triggered = false flickerstreak@30: function lib:OnLibraryLoad(major, instance) flickerstreak@30: if major == "LibRockFakeLib-2.0" then flickerstreak@30: triggered = true flickerstreak@30: end flickerstreak@30: end flickerstreak@30: Rock:FinalizeLibrary("LibRockFakeLib-1.0") flickerstreak@30: flickerstreak@30: local lib = Rock:NewLibrary("LibRockFakeLib-2.0", 1) flickerstreak@30: assert(not triggered) flickerstreak@30: Rock:FinalizeLibrary("LibRockFakeLib-2.0") flickerstreak@30: assert(triggered) flickerstreak@30: triggered = false flickerstreak@30: local lib = Rock:NewLibrary("LibRockFakeLib-2.0", 2) flickerstreak@30: assert(not triggered) flickerstreak@30: Rock:FinalizeLibrary("LibRockFakeLib-2.0") flickerstreak@30: assert(not triggered) flickerstreak@30: end)