Mercurial > wow > reaction
comparison modules/FuBar_ReActionFu/lib/LibRock-1.0/LibRock-1.0.lua @ 30:0d95ce7a9ec2
- added Ace3 externs
- converted ReAction_ConfigUI to use blizzard interface addons panel via AceConfigDialog-3.0
- partially converted FuBar module to LibRock, deprecated it (going to remove it entirely later)
- cleaned up a couple other tidbits
author | Flick <flickerstreak@gmail.com> |
---|---|
date | Wed, 02 Apr 2008 23:31:13 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
29:9c89042bc328 | 30:0d95ce7a9ec2 |
---|---|
1 --[[ | |
2 Name: LibRock-1.0 | |
3 Revision: $Rev: 63317 $ | |
4 Developed by: ckknight (ckknight@gmail.com) | |
5 Website: http://www.wowace.com/ | |
6 Description: Library to allow for library and addon creation and easy table recycling functions. | |
7 License: LGPL v2.1 | |
8 ]] | |
9 | |
10 local MAJOR_VERSION = "LibRock-1.0" | |
11 local MINOR_VERSION = tonumber(("$Revision: 63317 $"):match("(%d+)")) - 60000 | |
12 | |
13 local _G = _G | |
14 local GetLocale = _G.GetLocale | |
15 local CATEGORIES | |
16 if GetLocale() == "deDE" then | |
17 CATEGORIES = { | |
18 ["Action Bars"] = "Aktionsleisten", | |
19 ["Auction"] = "Auktion", | |
20 ["Audio"] = "Audio", | |
21 ["Battlegrounds/PvP"] = "Schlachtfeld/PvP", | |
22 ["Buffs"] = "Stärkungszauber", | |
23 ["Chat/Communication"] = "Chat/Kommunikation", | |
24 ["Druid"] = "Druide", | |
25 ["Hunter"] = "Jäger", | |
26 ["Mage"] = "Magier", | |
27 ["Paladin"] = "Paladin", | |
28 ["Priest"] = "Priester", | |
29 ["Rogue"] = "Schurke", | |
30 ["Shaman"] = "Schamane", | |
31 ["Warlock"] = "Hexenmeister", | |
32 ["Warrior"] = "Krieger", | |
33 ["Healer"] = "Heiler", | |
34 ["Tank"] = "Tank", | |
35 ["Caster"] = "Zauberer", | |
36 ["Combat"] = "Kampf", | |
37 ["Compilations"] = "Zusammenstellungen", | |
38 ["Data Export"] = "Datenexport", | |
39 ["Development Tools"] = "Entwicklungstools", | |
40 ["Guild"] = "Gilde", | |
41 ["Frame Modification"] = "Frameveränderungen", | |
42 ["Interface Enhancements"] = "Interfaceverbesserungen", | |
43 ["Inventory"] = "Inventar", | |
44 ["Library"] = "Bibliotheken", | |
45 ["Map"] = "Karte", | |
46 ["Mail"] = "Post", | |
47 ["Miscellaneous"] = "Diverses", | |
48 ["Quest"] = "Quest", | |
49 ["Raid"] = "Schlachtzug", | |
50 ["Tradeskill"] = "Beruf", | |
51 ["UnitFrame"] = "Einheiten-Fenster", | |
52 } | |
53 elseif GetLocale() == "frFR" then | |
54 CATEGORIES = { | |
55 ["Action Bars"] = "Barres d'action", | |
56 ["Auction"] = "Hôtel des ventes", | |
57 ["Audio"] = "Audio", | |
58 ["Battlegrounds/PvP"] = "Champs de bataille/JcJ", | |
59 ["Buffs"] = "Buffs", | |
60 ["Chat/Communication"] = "Chat/Communication", | |
61 ["Druid"] = "Druide", | |
62 ["Hunter"] = "Chasseur", | |
63 ["Mage"] = "Mage", | |
64 ["Paladin"] = "Paladin", | |
65 ["Priest"] = "Prêtre", | |
66 ["Rogue"] = "Voleur", | |
67 ["Shaman"] = "Chaman", | |
68 ["Warlock"] = "Démoniste", | |
69 ["Warrior"] = "Guerrier", | |
70 ["Healer"] = "Soigneur", | |
71 ["Tank"] = "Tank", | |
72 ["Caster"] = "Casteur", | |
73 ["Combat"] = "Combat", | |
74 ["Compilations"] = "Compilations", | |
75 ["Data Export"] = "Exportation de données", | |
76 ["Development Tools"] = "Outils de développement", | |
77 ["Guild"] = "Guilde", | |
78 ["Frame Modification"] = "Modification des fenêtres", | |
79 ["Interface Enhancements"] = "Améliorations de l'interface", | |
80 ["Inventory"] = "Inventaire", | |
81 ["Library"] = "Bibliothèques", | |
82 ["Map"] = "Carte", | |
83 ["Mail"] = "Courrier", | |
84 ["Miscellaneous"] = "Divers", | |
85 ["Quest"] = "Quêtes", | |
86 ["Raid"] = "Raid", | |
87 ["Tradeskill"] = "Métiers", | |
88 ["UnitFrame"] = "Fenêtres d'unité", | |
89 } | |
90 elseif GetLocale() == "koKR" then | |
91 CATEGORIES = { | |
92 ["Action Bars"] = "액션바", | |
93 ["Auction"] = "경매", | |
94 ["Audio"] = "음향", | |
95 ["Battlegrounds/PvP"] = "전장/PvP", | |
96 ["Buffs"] = "버프", | |
97 ["Chat/Communication"] = "대화/의사소통", | |
98 ["Druid"] = "드루이드", | |
99 ["Hunter"] = "사냥꾼", | |
100 ["Mage"] = "마법사", | |
101 ["Paladin"] = "성기사", | |
102 ["Priest"] = "사제", | |
103 ["Rogue"] = "도적", | |
104 ["Shaman"] = "주술사", | |
105 ["Warlock"] = "흑마법사", | |
106 ["Warrior"] = "전사", | |
107 ["Healer"] = "힐러", | |
108 ["Tank"] = "탱커", | |
109 ["Caster"] = "캐스터", | |
110 ["Combat"] = "전투", | |
111 ["Compilations"] = "복합", | |
112 ["Data Export"] = "자료 출력", | |
113 ["Development Tools"] = "개발 도구", | |
114 ["Guild"] = "길드", | |
115 ["Frame Modification"] = "구조 변경", | |
116 ["Interface Enhancements"] = "인터페이스 강화", | |
117 ["Inventory"] = "인벤토리", | |
118 ["Library"] = "라이브러리", | |
119 ["Map"] = "지도", | |
120 ["Mail"] = "우편", | |
121 ["Miscellaneous"] = "기타", | |
122 ["Quest"] = "퀘스트", | |
123 ["Raid"] = "공격대", | |
124 ["Tradeskill"] = "전문기술", | |
125 ["UnitFrame"] = "유닛 프레임", | |
126 } | |
127 elseif GetLocale() == "zhTW" then | |
128 CATEGORIES = { | |
129 ["Action Bars"] = "動作列", | |
130 ["Auction"] = "拍賣", | |
131 ["Audio"] = "音效", | |
132 ["Battlegrounds/PvP"] = "戰場/PvP", | |
133 ["Buffs"] = "增益", | |
134 ["Chat/Communication"] = "聊天/通訊", | |
135 ["Druid"] = "德魯伊", | |
136 ["Hunter"] = "獵人", | |
137 ["Mage"] = "法師", | |
138 ["Paladin"] = "聖騎士", | |
139 ["Priest"] = "牧師", | |
140 ["Rogue"] = "盜賊", | |
141 ["Shaman"] = "薩滿", | |
142 ["Warlock"] = "術士", | |
143 ["Warrior"] = "戰士", | |
144 ["Healer"] = "治療者", | |
145 ["Tank"] = "坦克", | |
146 ["Caster"] = "施法者", | |
147 ["Combat"] = "戰鬥", | |
148 ["Compilations"] = "整合", | |
149 ["Data Export"] = "資料匯出", | |
150 ["Development Tools"] = "開發工具", | |
151 ["Guild"] = "公會", | |
152 ["Frame Modification"] = "框架修改", | |
153 ["Interface Enhancements"] = "介面增強", | |
154 ["Inventory"] = "庫存", | |
155 ["Library"] = "程式庫", | |
156 ["Map"] = "地圖", | |
157 ["Mail"] = "郵件", | |
158 ["Miscellaneous"] = "雜項", | |
159 ["Quest"] = "任務", | |
160 ["Raid"] = "團隊", | |
161 ["Tradeskill"] = "交易技能", | |
162 ["UnitFrame"] = "頭像框架", | |
163 } | |
164 elseif GetLocale() == "zhCN" then | |
165 CATEGORIES = { | |
166 ["Action Bars"] = "动作条", | |
167 ["Auction"] = "拍卖", | |
168 ["Audio"] = "音频", | |
169 ["Battlegrounds/PvP"] = "战场/PvP", | |
170 ["Buffs"] = "增益魔法", | |
171 ["Chat/Communication"] = "聊天/交流", | |
172 ["Druid"] = "德鲁伊", | |
173 ["Hunter"] = "猎人", | |
174 ["Mage"] = "法师", | |
175 ["Paladin"] = "圣骑士", | |
176 ["Priest"] = "牧师", | |
177 ["Rogue"] = "潜行者", | |
178 ["Shaman"] = "萨满祭司", | |
179 ["Warlock"] = "术士", | |
180 ["Warrior"] = "战士", | |
181 ["Healer"] = "治疗", | |
182 ["Tank"] = "坦克", | |
183 ["Caster"] = "远程输出", | |
184 ["Combat"] = "战斗", | |
185 ["Compilations"] = "编译", | |
186 ["Data Export"] = "数据导出", | |
187 ["Development Tools"] = "开发工具", | |
188 ["Guild"] = "公会", | |
189 ["Frame Modification"] = "框架修改", | |
190 ["Interface Enhancements"] = "界面增强", | |
191 ["Inventory"] = "背包", | |
192 ["Library"] = "库", | |
193 ["Map"] = "地图", | |
194 ["Mail"] = "邮件", | |
195 ["Miscellaneous"] = "杂项", | |
196 ["Quest"] = "任务", | |
197 ["Raid"] = "团队", | |
198 ["Tradeskill"] = "商业技能", | |
199 ["UnitFrame"] = "头像框架", | |
200 } | |
201 elseif GetLocale() == "esES" then | |
202 CATEGORIES = { | |
203 ["Action Bars"] = "Barras de Acción", | |
204 ["Auction"] = "Subasta", | |
205 ["Audio"] = "Audio", | |
206 ["Battlegrounds/PvP"] = "Campos de Batalla/JcJ", | |
207 ["Buffs"] = "Buffs", | |
208 ["Chat/Communication"] = "Chat/Comunicación", | |
209 ["Druid"] = "Druida", | |
210 ["Hunter"] = "Cazador", | |
211 ["Mage"] = "Mago", | |
212 ["Paladin"] = "Paladín", | |
213 ["Priest"] = "Sacerdote", | |
214 ["Rogue"] = "Pícaro", | |
215 ["Shaman"] = "Chamán", | |
216 ["Warlock"] = "Brujo", | |
217 ["Warrior"] = "Guerrero", | |
218 ["Healer"] = "Sanador", | |
219 ["Tank"] = "Tanque", | |
220 ["Caster"] = "Conjurador", | |
221 ["Combat"] = "Combate", | |
222 ["Compilations"] = "Compilaciones", | |
223 ["Data Export"] = "Exportar Datos", | |
224 ["Development Tools"] = "Herramientas de Desarrollo", | |
225 ["Guild"] = "Hermandad", | |
226 ["Frame Modification"] = "Modificación de Marcos", | |
227 ["Interface Enhancements"] = "Mejoras de la Interfaz", | |
228 ["Inventory"] = "Inventario", | |
229 ["Library"] = "Biblioteca", | |
230 ["Map"] = "Mapa", | |
231 ["Mail"] = "Correo", | |
232 ["Miscellaneous"] = "Misceláneo", | |
233 ["Quest"] = "Misión", | |
234 ["Raid"] = "Banda", | |
235 ["Tradeskill"] = "Habilidad de Comercio", | |
236 ["UnitFrame"] = "Marco de Unidades", | |
237 } | |
238 else -- enUS | |
239 CATEGORIES = { | |
240 ["Action Bars"] = "Action Bars", | |
241 ["Auction"] = "Auction", | |
242 ["Audio"] = "Audio", | |
243 ["Battlegrounds/PvP"] = "Battlegrounds/PvP", | |
244 ["Buffs"] = "Buffs", | |
245 ["Chat/Communication"] = "Chat/Communication", | |
246 ["Druid"] = "Druid", | |
247 ["Hunter"] = "Hunter", | |
248 ["Mage"] = "Mage", | |
249 ["Paladin"] = "Paladin", | |
250 ["Priest"] = "Priest", | |
251 ["Rogue"] = "Rogue", | |
252 ["Shaman"] = "Shaman", | |
253 ["Warlock"] = "Warlock", | |
254 ["Warrior"] = "Warrior", | |
255 ["Healer"] = "Healer", | |
256 ["Tank"] = "Tank", | |
257 ["Caster"] = "Caster", | |
258 ["Combat"] = "Combat", | |
259 ["Compilations"] = "Compilations", | |
260 ["Data Export"] = "Data Export", | |
261 ["Development Tools"] = "Development Tools", | |
262 ["Guild"] = "Guild", | |
263 ["Frame Modification"] = "Frame Modification", | |
264 ["Interface Enhancements"] = "Interface Enhancements", | |
265 ["Inventory"] = "Inventory", | |
266 ["Library"] = "Library", | |
267 ["Map"] = "Map", | |
268 ["Mail"] = "Mail", | |
269 ["Miscellaneous"] = "Miscellaneous", | |
270 ["Quest"] = "Quest", | |
271 ["Raid"] = "Raid", | |
272 ["Tradeskill"] = "Tradeskill", | |
273 ["UnitFrame"] = "UnitFrame", | |
274 } | |
275 end | |
276 | |
277 local select = _G.select | |
278 local tostring = _G.tostring | |
279 local pairs = _G.pairs | |
280 local ipairs = _G.ipairs | |
281 local error = _G.error | |
282 local setmetatable = _G.setmetatable | |
283 local getmetatable = _G.getmetatable | |
284 local type = _G.type | |
285 local pcall = _G.pcall | |
286 local next = _G.next | |
287 local tonumber = _G.tonumber | |
288 local strmatch = _G.strmatch | |
289 local table_remove = _G.table.remove | |
290 local debugstack = _G.debugstack | |
291 local LoadAddOn = _G.LoadAddOn | |
292 local GetAddOnInfo = _G.GetAddOnInfo | |
293 local GetAddOnMetadata = _G.GetAddOnMetadata | |
294 local GetNumAddOns = _G.GetNumAddOns | |
295 local DisableAddOn = _G.DisableAddOn | |
296 local EnableAddOn = _G.EnableAddOn | |
297 local IsAddOnLoadOnDemand = _G.IsAddOnLoadOnDemand | |
298 local IsLoggedIn = _G.IsLoggedIn | |
299 local geterrorhandler = _G.geterrorhandler | |
300 local assert = _G.assert | |
301 local collectgarbage = _G.collectgarbage | |
302 local table_sort = _G.table.sort | |
303 local table_concat = _G.table.concat | |
304 | |
305 -- #AUTODOC_NAMESPACE Rock | |
306 | |
307 | |
308 local LibStub = _G.LibStub | |
309 | |
310 local Rock = LibStub:GetLibrary(MAJOR_VERSION, true) or _G.Rock | |
311 local oldRock | |
312 if not Rock then | |
313 Rock = LibStub:NewLibrary(MAJOR_VERSION, MINOR_VERSION) | |
314 if not Rock then | |
315 return | |
316 end | |
317 Rock.name = MAJOR_VERSION | |
318 else | |
319 Rock, oldRock = Rock:NewLibrary(MAJOR_VERSION, MINOR_VERSION) | |
320 if not Rock then | |
321 return | |
322 end | |
323 end | |
324 _G.Rock = Rock | |
325 | |
326 local L = setmetatable({}, {__index=function(self,key) self[key] = key; return key end}) | |
327 if GetLocale() == "zhCN" then | |
328 L["Advanced options"] = "高级选项" | |
329 L["Advanced options for developers and power users."] = "开发者与高级用户的高级选项" | |
330 L["Unit tests"] = "框体测试" | |
331 L["Enable unit tests to be run. This is for developers only.\n\nYou must ReloadUI for changes to take effect."] = "开启框体测试,仅供开发者使用。\n\n需要重载用户界面。" | |
332 L["Contracts"] = "侦错协定" | |
333 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."] = "启用侦错协定,这是给插件作者用来通报错误所使用。" | |
334 L["Reload UI"] = "重载UI" | |
335 L["Reload the User Interface for some changes to take effect."] = "部分功能更改需要重载用户界面才会生效。" | |
336 L["Reload"] = "重载" | |
337 L["Give donation"] = "捐赠" | |
338 L["Donate"] = "捐赠" | |
339 L["Give a much-needed donation to the author of this addon."] = "给插件作者捐赠支持插件开发。" | |
340 L["File issue"] = "通报错误" | |
341 L["Report"] = "报告" | |
342 L["File a bug or request a new feature or an improvement to this addon."] = "发送错误报告或请求新功能及要改进的部分。" | |
343 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切换到桌面,打开浏览器,在地址栏贴上网址。" | |
344 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切换到电脑桌面,打开浏览器,在地址栏贴上网址。" | |
345 L["Enabled"] = "开启" | |
346 L["Enable or disable this addon."] = "启用这个插件。" | |
347 | |
348 elseif GetLocale() == "zhTW" then | |
349 L["Advanced options"] = "進階選項" | |
350 L["Advanced options for developers and power users."] = "插件作者、進階用戶選項" | |
351 L["Unit tests"] = "單元測試" | |
352 L["Enable unit tests to be run. This is for developers only.\n\nYou must ReloadUI for changes to take effect."] = "啟用單元測試,這是給插件作者使用的功能。\n\n需要重載介面才能使用。" | |
353 L["Contracts"] = "偵錯協定" | |
354 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."] = "啟用偵錯協定,這是給插件作者用來通報錯誤所使用。" | |
355 L["Reload UI"] = "重載介面" | |
356 L["Reload the User Interface for some changes to take effect."] = "重新載入使用者介面,部分功能才會生效。" | |
357 L["Reload"] = "重載" | |
358 L["Give donation"] = "捐贈" | |
359 L["Donate"] = "捐贈" | |
360 L["Give a much-needed donation to the author of this addon."] = "捐贈金錢給插件作者。" | |
361 L["File issue"] = "通報錯誤" | |
362 L["Report"] = "報告" | |
363 L["File a bug or request a new feature or an improvement to this addon."] = "發出錯誤報告或請求新功能及要改進的部分。" | |
364 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切換到電腦桌面,打開瀏覽器,在網址列貼上網址。" | |
365 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切換到電腦桌面,打開瀏覽器,在網址列貼上網址。" | |
366 L["Enabled"] = "啟用" | |
367 L["Enable or disable this addon."] = "啟用這個插件。" | |
368 elseif GetLocale() == "koKR" then | |
369 L["Advanced options"] = "상세 옵션" | |
370 L["Advanced options for developers and power users."] = "개발자와 파워 사용자를 위한 상세 옵션입니다." | |
371 L["Unit tests"] = "유닛 테스트" | |
372 L["Enable unit tests to be run. This is for developers only.\n\nYou must ReloadUI for changes to take effect."] = "유닛 테스트를 사용합니다. 이것은 개발자만을 위한 옵션입니다.\n\n변경된 결과를 적용하기 위해 당신의 UI를 재실행 합니다." | |
373 L["Contracts"] = "계약" | |
374 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."] = "계약을 사용합니다. 이것은 개발자와 버그 파일을 알릴 분이면 누구나 사용 가능합니다. 계약이 가능하지 않으면 버그 파일을 보내지 마십시오. 이것은 당신의 애드온 속도를 약간 떨어뜨립니다." | |
375 L["Reload UI"] = "UI 재실행" | |
376 L["Reload the User Interface for some changes to take effect."] = "변경된 결과를 적용하기 위해 사용자 인터페이스를 재실행합니다." | |
377 L["Reload"] = "재실행" | |
378 L["Give donation"] = "기부" | |
379 L["Donate"] = "기부" | |
380 L["Give a much-needed donation to the author of this addon."] = "이 애드온의 제작자에게 필요한 기부를 합니다." | |
381 L["File issue"] = "파일 이슈" | |
382 L["Report"] = "보고" | |
383 L["File a bug or request a new feature or an improvement to this addon."] = "버그 파일을 알리거나 새로운 기능 또는 이 애드온에 대한 개선을 부탁합니다." | |
384 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 눌려 게임으로 부터 나간후 웹 브라우저를 엽니다. 복사된 링크를 주소 창에 붙여넣기 합니다." | |
385 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 눌려 게임으로 부터 나간후 웹 브라우저를 엽니다. 복사된 링크를 주소 창에 붙여넣기 합니다." | |
386 L["Enabled"] = "사용" | |
387 L["Enable or disable this addon."] = "이 애드온을 사용하거나 사용하지 않습니다." | |
388 elseif GetLocale() == "frFR" then | |
389 L["Advanced options"] = "Options avancées" | |
390 L["Advanced options for developers and power users."] = "Options avancées à l'attention des développeurs et des utilisateurs expérimentés." | |
391 L["Reload UI"] = "Recharger IU" | |
392 L["Reload the User Interface for some changes to take effect."] = "Recharge l'interface utilisateur afin que certains changements prennent effet." | |
393 L["Reload"] = "Recharger" | |
394 L["Give donation"] = "Faire un don" | |
395 L["Donate"] = "Don" | |
396 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." | |
397 L["File issue"] = "Problème" | |
398 L["Report"] = "Signaler" | |
399 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." | |
400 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." | |
401 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." | |
402 L["Enabled"] = "Activé" | |
403 L["Enable or disable this addon."] = "Active ou désactive cet addon." | |
404 end | |
405 | |
406 local isStandalone = debugstack():match("[Oo%.][Nn%.][Ss%.]\\([^\\]+)\\") == MAJOR_VERSION or nil | |
407 local unitTestDB, enableContracts | |
408 | |
409 local weakKey = { __mode = 'k' } | |
410 | |
411 -- frame to manage events from | |
412 Rock.frame = oldRock and oldRock.frame or _G.CreateFrame("Frame") | |
413 local frame = Rock.frame | |
414 -- dict of libraries in { ["major"] = object } form | |
415 Rock.libraries = oldRock and oldRock.libraries or { [MAJOR_VERSION] = Rock } | |
416 local libraries = Rock.libraries | |
417 -- set of libraries which have gone through the finalization process in { [object] = true } form | |
418 Rock.finalizedLibraries = setmetatable(oldRock and oldRock.finalizedLibraries or { }, weakKey) | |
419 local finalizedLibraries = Rock.finalizedLibraries | |
420 -- set of libraries which have been tried to be loaded. | |
421 Rock.scannedLibraries = oldRock and oldRock.scannedLibraries or {} | |
422 local scannedLibraries = Rock.scannedLibraries | |
423 -- exportedMethods[library] = { "method1", "method2" } | |
424 Rock.exportedMethods = setmetatable(oldRock and oldRock.exportedMethods or {}, weakKey) | |
425 local exportedMethods = Rock.exportedMethods | |
426 -- mixinToObject[mixin][object] = true | |
427 Rock.mixinToObject = setmetatable(oldRock and oldRock.mixinToObject or {}, weakKey) | |
428 local mixinToObject = Rock.mixinToObject | |
429 -- dict of addons in { ["name"] = object } form | |
430 Rock.addons = oldRock and oldRock.addons or {} | |
431 local addons = Rock.addons | |
432 -- set of libraries that should be finalized before ADDON_LOADED. | |
433 Rock.pendingLibraries = setmetatable(oldRock and oldRock.pendingLibraries or { }, weakKey) | |
434 local pendingLibraries = Rock.pendingLibraries | |
435 -- list of addons in order of created that need to be initialized by ADDON_LOADED. | |
436 Rock.pendingAddons = oldRock and oldRock.pendingAddons or {} | |
437 local pendingAddons = Rock.pendingAddons | |
438 -- dictionary of addons to their folder names | |
439 Rock.addonToFolder = oldRock and oldRock.addonToFolder or {} | |
440 local addonToFolder = Rock.addonToFolder | |
441 -- set of folders which have been loaded | |
442 Rock.foldersLoaded = oldRock and oldRock.foldersLoaded or {} | |
443 local foldersLoaded = Rock.foldersLoaded | |
444 -- list of addons in order of created that need to be enabled by PLAYER_LOGIN. | |
445 Rock.pendingAddonsEnable = oldRock and oldRock.pendingAddonsEnable or {} | |
446 local pendingAddonsEnable = Rock.pendingAddonsEnable | |
447 -- set of addons which have been enabled at least once. | |
448 Rock.addonsAlreadyEnabled = oldRock and oldRock.addonsAlreadyEnabled or {} | |
449 local addonsAlreadyEnabled = Rock.addonsAlreadyEnabled | |
450 -- set of addons which have no database and are set to be inactive. | |
451 Rock.inactiveAddons = oldRock and oldRock.inactiveAddons or {} | |
452 local inactiveAddons = Rock.inactiveAddons | |
453 -- set of addons which are currently enabled (not necessarily should be) | |
454 Rock.currentlyEnabledAddons = oldRock and oldRock.currentlyEnabledAddons or {} | |
455 local currentlyEnabledAddons = Rock.currentlyEnabledAddons | |
456 -- dictionary of namespace to list of functions which will be run. | |
457 Rock.unitTests = oldRock and oldRock.unitTests or {} | |
458 local unitTests = Rock.unitTests | |
459 -- metatable for addons | |
460 Rock.addon_mt = oldRock and oldRock.addon_mt or {} | |
461 local addon_mt = Rock.addon_mt | |
462 for k in pairs(addon_mt) do | |
463 addon_mt[k] = nil | |
464 end | |
465 function addon_mt:__tostring() | |
466 return tostring(self.name) | |
467 end | |
468 | |
469 local function better_tostring(self) | |
470 if type(self) == "table" and self.name then | |
471 return tostring(self.name) | |
472 end | |
473 return tostring(self) | |
474 end | |
475 | |
476 local function figureCurrentAddon(pos) | |
477 local stack = debugstack(pos+1, 1, 0) | |
478 local folder = stack:match("[Oo%.][Nn%.][Ss%.]\\([^\\]+)\\") | |
479 if folder then | |
480 return folder | |
481 end | |
482 | |
483 local partFolder = stack:match("...([^\\]+)\\") | |
484 if partFolder then | |
485 local partFolder_len = #partFolder | |
486 for i = 1, GetNumAddOns() do | |
487 local name = GetAddOnInfo(i) | |
488 if #name >= partFolder_len then | |
489 local partName = name:sub(-partFolder_len) | |
490 if partName == partFolder then | |
491 return name | |
492 end | |
493 end | |
494 end | |
495 end | |
496 return nil | |
497 end | |
498 | |
499 --[[--------------------------------------------------------------------------- | |
500 Returns: | |
501 string - the localized name of the given category. | |
502 Arguments: | |
503 string - the English name of the category. | |
504 Example: | |
505 local uf = Rock:GetLocalizedCategory("UnitFrame") | |
506 -----------------------------------------------------------------------------]] | |
507 function Rock:GetLocalizedCategory(name) | |
508 if type(name) ~= "string" then | |
509 error(("Bad argument #2 to `GetLocalizedCategory'. Expected %q, got %q."):format("string", type(name)), 2) | |
510 end | |
511 local cat = CATEGORIES[name] | |
512 if cat then | |
513 return cat | |
514 end | |
515 local name_lower = name:lower() | |
516 for k in pairs(CATEGORIES) do | |
517 if k:lower() == name_lower then | |
518 return k | |
519 end | |
520 end | |
521 return _G.UNKNOWN or "Unknown" | |
522 end | |
523 | |
524 local weak = {__mode = 'kv'} | |
525 | |
526 Rock.recycleData = oldRock and oldRock.recycleData or {} | |
527 local recycleData = Rock.recycleData | |
528 if recycleData.pools then | |
529 setmetatable(recycleData.pools, weak) | |
530 end | |
531 if recycleData.debugPools then | |
532 setmetatable(recycleData.debugPools, weak) | |
533 end | |
534 if recycleData.newList then | |
535 setmetatable(recycleData.newList, weak) | |
536 end | |
537 if recycleData.newDict then | |
538 setmetatable(recycleData.newDict, weak) | |
539 end | |
540 if recycleData.newSet then | |
541 setmetatable(recycleData.newSet, weak) | |
542 end | |
543 if recycleData.del then | |
544 setmetatable(recycleData.del, weak) | |
545 end | |
546 | |
547 local tmp = {} | |
548 local function myUnpack(t, start) | |
549 if not start then | |
550 start = 1 | |
551 end | |
552 local value = t[start] | |
553 if value == nil then | |
554 return | |
555 end | |
556 t[start] = nil | |
557 return value, myUnpack(t, start+1) | |
558 end | |
559 | |
560 --[[--------------------------------------------------------------------------- | |
561 Notes: | |
562 * Returns functions for the specified namespace based on what is provided. | |
563 * function types: | |
564 ; "newList" : to create a list | |
565 ; "newDict" : to create a dictionary | |
566 ; "newSet" : to create a set | |
567 ; "del" : to delete a table | |
568 ; "unpackListAndDel" : deletes a table and returns what its contents were as a list, in order. | |
569 ; "unpackSetAndDel" : deletes a table and returns what its contents were as a set, in no particular order. | |
570 ; "unpackDictAndDel" : deletes a table and returns what its contents were as a dictionary, in no particular order. | |
571 * If you provide "Debug" as the last argument, then the namespace can be debugged with ''':DebugRecycle''' | |
572 * 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. | |
573 Arguments: | |
574 string - the namespace. ''Note: this doesn't necessarily have to be a string.'' | |
575 Example: | |
576 local newList, newDict, newSet, del, unpackListAndDel, unpackSetAndDel, unpackDictAndDel = Rock:GetRecyclingFunctions("MyNamespace", "newList", "newDict", "newSet", "del", "unpackListAndDel", "unpackSetAndDel", "unpackDictAndDel") | |
577 | |
578 local t = newList('alpha', 'bravo') -- same as t = {'alpha', 'bravo'} | |
579 local u = newDict('alpha', 'bravo') -- same as t = {['alpha'] = 'bravo'} | |
580 local v = newSet('alpha', 'bravo') -- same as t = {['alpha'] = true, ['bravo'] = true} | |
581 t = del(t) -- you want to clear your reference as well as deleting. | |
582 u = del(u) | |
583 v = del(v) | |
584 | |
585 -- for debugging | |
586 local newList = Rock:GetRecyclingFunctions("MyNamespace", "newList", "Debug") | |
587 local t = newList() | |
588 Rock:DebugRecycle("MyNamespace") | |
589 t = del(t) | |
590 | |
591 -- unpacking functions | |
592 unpackListAndDel(newList(...)) => ... | |
593 unpackSetAndDel(newSet(...)) => ... | |
594 unpackDictAndDel(newDict(...)) => ... | |
595 newList(unpackListAndDel(t)) => t | |
596 newSet(unpackSetAndDel(t)) => t | |
597 newDict(unpackDictAndDel(t)) => t | |
598 -- as you can see, they are inverses of each other. | |
599 -----------------------------------------------------------------------------]] | |
600 function Rock:GetRecyclingFunctions(namespace, ...) | |
601 local pools = recycleData.pools | |
602 if not pools then | |
603 pools = setmetatable({}, weak) | |
604 recycleData.pools = pools | |
605 end | |
606 if namespace == "newList" or namespace == "newSet" or namespace == "newDict" or namespace == "del" or namespace == "unpackListAndDel" or namespace == "unpackSetAndDel" or namespace == "unpackDictAndDel" then | |
607 error(("Bad argument #2 to `GetRecyclingFunctions'. Cannot be %q"):format(namespace), 2) | |
608 end | |
609 local pool = pools[namespace] | |
610 if not pool then | |
611 pool = setmetatable({}, weak) | |
612 pools[namespace] = pool | |
613 end | |
614 local n = select('#', ...) | |
615 local debug = select(n, ...) == "Debug" | |
616 if debug then | |
617 n = n - 1 | |
618 local debugPools = recycleData.debugPools | |
619 if not debugPools then | |
620 debugPools = setmetatable({}, weak) | |
621 recycleData.debugPools = debugPools | |
622 end | |
623 debug = debugPools[namespace] | |
624 if not debug then | |
625 debug = { num = 0 } | |
626 debugPools[namespace] = debug | |
627 end | |
628 elseif recycleData.debugPools and recycleData.debugPools[namespace] then | |
629 debug = recycleData.debugPools[namespace] | |
630 end | |
631 for i = 1, n do | |
632 local func = select(i, ...) | |
633 local recycleData_func = recycleData[func] | |
634 if not recycleData_func then | |
635 recycleData_func = setmetatable({}, weak) | |
636 recycleData[func] = recycleData_func | |
637 end | |
638 if func == "newList" then | |
639 local newList = recycleData_func[namespace] | |
640 if not newList then | |
641 function newList(...) | |
642 local t = next(pool) | |
643 local n = select('#', ...) | |
644 if t then | |
645 pool[t] = nil | |
646 for i = 1, n do | |
647 t[i] = select(i, ...) | |
648 end | |
649 else | |
650 t = { ... } | |
651 end | |
652 | |
653 if debug then | |
654 debug[t] = debugstack(2) | |
655 debug.num = debug.num + 1 | |
656 end | |
657 | |
658 return t, n | |
659 end | |
660 recycleData_func[namespace] = newList | |
661 end | |
662 tmp[i] = newList | |
663 elseif func == "newDict" then | |
664 local newDict = recycleData_func[namespace] | |
665 if not newDict then | |
666 function newDict(...) | |
667 local t = next(pool) | |
668 if t then | |
669 pool[t] = nil | |
670 else | |
671 t = {} | |
672 end | |
673 | |
674 for i = 1, select('#', ...), 2 do | |
675 t[select(i, ...)] = select(i+1, ...) | |
676 end | |
677 | |
678 if debug then | |
679 debug[t] = debugstack(2) | |
680 debug.num = debug.num + 1 | |
681 end | |
682 | |
683 return t | |
684 end | |
685 recycleData_func[namespace] = newDict | |
686 end | |
687 tmp[i] = newDict | |
688 elseif func == "newSet" then | |
689 local newSet = recycleData_func[namespace] | |
690 if not newSet then | |
691 function newSet(...) | |
692 local t = next(pool) | |
693 if t then | |
694 pool[t] = nil | |
695 else | |
696 t = {} | |
697 end | |
698 | |
699 for i = 1, select('#', ...) do | |
700 t[select(i, ...)] = true | |
701 end | |
702 | |
703 if debug then | |
704 debug[t] = debugstack(2) | |
705 debug.num = debug.num + 1 | |
706 end | |
707 | |
708 return t | |
709 end | |
710 recycleData_func[namespace] = newSet | |
711 end | |
712 tmp[i] = newSet | |
713 elseif func == "del" then | |
714 local del = recycleData_func[namespace] | |
715 if not del then | |
716 function del(t) | |
717 if not t then | |
718 error(("Bad argument #1 to `del'. Expected %q, got %q."):format("table", type(t)), 2) | |
719 end | |
720 if pool[t] then | |
721 local _, ret = pcall(error, "Error, double-free syndrome.", 3) | |
722 geterrorhandler()(ret) | |
723 end | |
724 setmetatable(t, nil) | |
725 for k in pairs(t) do | |
726 t[k] = nil | |
727 end | |
728 t[true] = true | |
729 t[true] = nil | |
730 pool[t] = true | |
731 | |
732 if debug then | |
733 debug[t] = nil | |
734 debug.num = debug.num - 1 | |
735 end | |
736 return nil | |
737 end | |
738 recycleData_func[namespace] = del | |
739 end | |
740 tmp[i] = del | |
741 elseif func == "unpackListAndDel" then | |
742 local unpackListAndDel = recycleData_func[namespace] | |
743 if not unpackListAndDel then | |
744 local function f(t, start, finish) | |
745 if start > finish then | |
746 for k in pairs(t) do | |
747 t[k] = nil | |
748 end | |
749 t[true] = true | |
750 t[true] = nil | |
751 pool[t] = true | |
752 return | |
753 end | |
754 return t[start], f(t, start+1, finish) | |
755 end | |
756 function unpackListAndDel(t, start, finish) | |
757 if not t then | |
758 error(("Bad argument #1 to `unpackListAndDel'. Expected %q, got %q."):format("table", type(t)), 2) | |
759 end | |
760 if not start then | |
761 start = 1 | |
762 end | |
763 if not finish then | |
764 finish = #t | |
765 end | |
766 setmetatable(t, nil) | |
767 if debug then | |
768 debug[t] = nil | |
769 debug.num = debug.num - 1 | |
770 end | |
771 return f(t, start, finish) | |
772 end | |
773 end | |
774 tmp[i] = unpackListAndDel | |
775 elseif func == "unpackSetAndDel" then | |
776 local unpackSetAndDel = recycleData_func[namespace] | |
777 if not unpackSetAndDel then | |
778 local function f(t, current) | |
779 current = next(t, current) | |
780 if current == nil then | |
781 for k in pairs(t) do | |
782 t[k] = nil | |
783 end | |
784 t[true] = true | |
785 t[true] = nil | |
786 pool[t] = true | |
787 return | |
788 end | |
789 return current, f(t, current) | |
790 end | |
791 function unpackSetAndDel(t) | |
792 if not t then | |
793 error(("Bad argument #1 to `unpackListAndDel'. Expected %q, got %q."):format("table", type(t)), 2) | |
794 end | |
795 setmetatable(t, nil) | |
796 if debug then | |
797 debug[t] = nil | |
798 debug.num = debug.num - 1 | |
799 end | |
800 return f(t, nil) | |
801 end | |
802 end | |
803 tmp[i] = unpackSetAndDel | |
804 elseif func == "unpackDictAndDel" then | |
805 local unpackDictAndDel = recycleData_func[namespace] | |
806 if not unpackDictAndDel then | |
807 local function f(t, current) | |
808 local value | |
809 current, value = next(t, current) | |
810 if current == nil then | |
811 for k in pairs(t) do | |
812 t[k] = nil | |
813 end | |
814 t[true] = true | |
815 t[true] = nil | |
816 pool[t] = true | |
817 return | |
818 end | |
819 return current, value, f(t, current) | |
820 end | |
821 function unpackDictAndDel(t) | |
822 if not t then | |
823 error(("Bad argument #1 to `unpackListAndDel'. Expected %q, got %q."):format("table", type(t)), 2) | |
824 end | |
825 setmetatable(t, nil) | |
826 if debug then | |
827 debug[t] = nil | |
828 debug.num = debug.num - 1 | |
829 end | |
830 return f(t, nil) | |
831 end | |
832 end | |
833 tmp[i] = unpackDictAndDel | |
834 else | |
835 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) | |
836 end | |
837 end | |
838 return myUnpack(tmp) | |
839 end | |
840 | |
841 --[[--------------------------------------------------------------------------- | |
842 Notes: | |
843 * Prints information about the specified recycling namespace, including what tables are still in play and where they come from and how many there are. | |
844 * This goes in tandem with ''':GetRecyclingFunctions''' | |
845 Arguments: | |
846 string - the namespace. ''Note: this doesn't necessarily have to be a string.'' | |
847 Example: | |
848 local newList = Rock:GetRecyclingFunctions("MyNamespace", "newList", "Debug") | |
849 local t = newList() | |
850 Rock:DebugRecycle("MyNamespace") | |
851 t = del(t) | |
852 -----------------------------------------------------------------------------]] | |
853 function Rock:DebugRecycle(namespace) | |
854 local debug = recycleData.debugPools and recycleData.debugPools[namespace] | |
855 if not debug then | |
856 return | |
857 end | |
858 for k, v in pairs(debug) do | |
859 if k ~= "num" then | |
860 _G.DEFAULT_CHAT_FRAME:AddMessage(v) | |
861 _G.DEFAULT_CHAT_FRAME:AddMessage("------") | |
862 end | |
863 end | |
864 _G.DEFAULT_CHAT_FRAME:AddMessage(("%s: %d tables in action."):format(tostring(namespace), debug.num)) | |
865 end | |
866 | |
867 local newList, del, unpackListAndDel, unpackDictAndDel = Rock:GetRecyclingFunctions(MAJOR_VERSION, "newList", "del", "unpackListAndDel", "unpackDictAndDel") | |
868 | |
869 --[[--------------------------------------------------------------------------- | |
870 Notes: | |
871 * Adds a unit test for the specified namespace | |
872 * 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. | |
873 * You can have as many tests per namespace as you want. | |
874 Arguments: | |
875 string - the namespace. | |
876 function - the function to call. | |
877 Example: | |
878 Rock:AddUnitTest("LibMonkey-1.0", function() | |
879 local LibMonkey = Rock("LibMonkey-1.0") | |
880 assert(LibMonkey:Fling() == "Poo") | |
881 end) | |
882 -----------------------------------------------------------------------------]] | |
883 function Rock:AddUnitTest(namespace, func) | |
884 if not isStandalone then | |
885 return | |
886 end | |
887 if type(namespace) ~= "string" then | |
888 error(("Bad argument #2 to `AddUnitTest'. Expected %q, got %q."):format("string", type(namespace)), 2) | |
889 end | |
890 if namespace:find("^Lib[A-Z]") then | |
891 local addon = figureCurrentAddon(2) | |
892 if addon ~= namespace then | |
893 return | |
894 end | |
895 end | |
896 if type(func) ~= "function" then | |
897 error(("Bad argument #3 to `AddUnitTest'. Expected %q, got %q."):format("function", type(func)), 2) | |
898 end | |
899 local addon = figureCurrentAddon(2) | |
900 if libraries[namespace] and addon ~= namespace then | |
901 -- only work on standalone libraries. | |
902 return | |
903 end | |
904 local unitTests_namespace = unitTests[namespace] | |
905 if not unitTests_namespace then | |
906 unitTests_namespace = newList() | |
907 unitTests[namespace] = unitTests_namespace | |
908 end | |
909 if not unitTests_namespace.addon then | |
910 unitTests_namespace.addon = addon | |
911 end | |
912 if unitTestDB and not unitTestDB[namespace] then | |
913 return | |
914 end | |
915 unitTests_namespace[#unitTests_namespace+1] = func | |
916 end | |
917 | |
918 local LibRockEvent | |
919 local LibRockModuleCore | |
920 local OpenDonationFrame, OpenIssueFrame | |
921 function Rock:OnLibraryLoad(major, library) | |
922 if major == "LibRockEvent-1.0" then | |
923 LibRockEvent = library | |
924 LibRockEvent:Embed(Rock) | |
925 elseif major == "LibRockModuleCore-1.0" then | |
926 LibRockModuleCore = library | |
927 elseif major == "LibRockConfig-1.0" then | |
928 if isStandalone then | |
929 library.rockOptions.args.advanced = { | |
930 type = 'group', | |
931 groupType = 'inline', | |
932 name = L["Advanced options"], | |
933 desc = L["Advanced options for developers and power users."], | |
934 order = -1, | |
935 args = { | |
936 unitTests = { | |
937 type = 'multichoice', | |
938 name = L["Unit tests"], | |
939 desc = L["Enable unit tests to be run. This is for developers only.\n\nYou must ReloadUI for changes to take effect."], | |
940 get = function(key) | |
941 return unitTestDB[key] | |
942 end, | |
943 set = function(key, value) | |
944 unitTestDB[key] = value or nil | |
945 end, | |
946 choices = function() | |
947 local t = newList() | |
948 for k in pairs(unitTests) do | |
949 t[k] = k | |
950 end | |
951 return "@dict", unpackDictAndDel(t) | |
952 end | |
953 }, | |
954 contracts = { | |
955 type = 'boolean', | |
956 name = L["Contracts"], | |
957 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."], | |
958 get = function() | |
959 return enableContracts | |
960 end, | |
961 set = function(value) | |
962 _G.LibRock_1_0DB.contracts = value or nil | |
963 enableContracts = value | |
964 end, | |
965 } | |
966 } | |
967 } | |
968 end | |
969 library.rockOptions.args.reloadui = { | |
970 type = 'execute', | |
971 name = L["Reload UI"], | |
972 desc = L["Reload the User Interface for some changes to take effect."], | |
973 buttonText = L["Reload"], | |
974 func = function() | |
975 _G.ReloadUI() | |
976 end, | |
977 order = -2, | |
978 } | |
979 Rock.donate = "Paypal:ckknight AT gmail DOT com" | |
980 library.rockOptions.args.donate = { | |
981 type = 'execute', | |
982 name = L["Give donation"], | |
983 buttonText = L["Donate"], | |
984 desc = L["Give a much-needed donation to the author of this addon."], | |
985 func = OpenDonationFrame, | |
986 passValue = Rock, | |
987 order = -3, | |
988 } | |
989 Rock.issueTracker = "Wowace:10027" | |
990 library.rockOptions.args.issue = { | |
991 type = 'execute', | |
992 name = L["File issue"], | |
993 buttonText = L["Report"], | |
994 desc = L["File a bug or request a new feature or an improvement to this addon."], | |
995 func = OpenIssueFrame, | |
996 passValue = Rock, | |
997 order = -4, | |
998 } | |
999 end | |
1000 end | |
1001 | |
1002 addon_mt.__index = {} | |
1003 local addon_mt___index = addon_mt.__index | |
1004 --[[--------------------------------------------------------------------------- | |
1005 #FORCE_DOC | |
1006 Notes: | |
1007 * This is exported to all addons. | |
1008 * 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. | |
1009 Returns: | |
1010 boolean - whether the addon is in an active state or not. | |
1011 Example: | |
1012 local active = MyAddon:IsActive() | |
1013 -----------------------------------------------------------------------------]] | |
1014 function addon_mt___index:IsActive() | |
1015 if LibRockModuleCore then | |
1016 local core = LibRockModuleCore:HasModule(self) | |
1017 if core then | |
1018 return core:IsModuleActive(self) | |
1019 end | |
1020 end | |
1021 | |
1022 local self_db = self.db | |
1023 if self_db then | |
1024 local disabled | |
1025 local self_db_raw = self_db.raw | |
1026 if self_db_raw then | |
1027 local self_db_raw_disabled = self_db_raw.disabled | |
1028 if self_db_raw_disabled then | |
1029 local profile = type(self.GetProfile) == "function" and select(2, self:GetProfile()) or false | |
1030 disabled = self_db_raw_disabled[profile] | |
1031 end | |
1032 else | |
1033 return false | |
1034 end | |
1035 return not disabled | |
1036 end | |
1037 | |
1038 return not inactiveAddons[self] | |
1039 end | |
1040 --[[--------------------------------------------------------------------------- | |
1041 #FORCE_DOC | |
1042 Notes: | |
1043 * This is exported to all addons. | |
1044 * If it enables the addon, it will call :OnEnable(first) on the addon and :OnEmbedEnable(addon, first) on all its mixins. | |
1045 * If it disables the addon, it will call :OnDisable(first) on the addon and :OnEmbedDisable(addon, first) on all its mixins. | |
1046 * 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. | |
1047 Arguments: | |
1048 [optional] boolean - whether the addon should be in an active state or not. Default: not :IsActive() | |
1049 Returns: | |
1050 boolean - whether the addon is in an active state or not. | |
1051 Example: | |
1052 MyAddon:ToggleActive() -- switch | |
1053 MyAddon:ToggleActive(true) -- force on | |
1054 MyAddon:ToggleActive(false) -- force off | |
1055 -----------------------------------------------------------------------------]] | |
1056 function addon_mt___index:ToggleActive(state) | |
1057 if state and state ~= true then | |
1058 error(("Bad argument #2 to `ToggleActive'. Expected %q or %q, got %q."):format("boolean", "nil", type(state)), 2) | |
1059 end | |
1060 if LibRockModuleCore then | |
1061 local core = LibRockModuleCore:HasModule(self) | |
1062 if core then | |
1063 return core:ToggleModuleActive(self, state) | |
1064 end | |
1065 end | |
1066 | |
1067 local self_db = self.db | |
1068 if self_db then | |
1069 local self_db_raw = self_db.raw | |
1070 if not self_db_raw then | |
1071 error("Error saving to database with `ToggleActive'. db.raw not available.", 2) | |
1072 end | |
1073 local self_db_raw_disabled = self_db_raw.disabled | |
1074 if not self_db_raw_disabled then | |
1075 self_db_raw_disabled = newList() | |
1076 self_db_raw.disabled = self_db_raw_disabled | |
1077 end | |
1078 local profile = type(self.GetProfile) == "function" and select(2, self:GetProfile()) or false | |
1079 if state == nil then | |
1080 state = not not self_db_raw_disabled[profile] | |
1081 elseif (not self_db_raw_disabled[profile]) == state then | |
1082 return | |
1083 end | |
1084 self_db_raw_disabled[profile] = not state or nil | |
1085 if next(self_db_raw_disabled) == nil then | |
1086 self_db_raw.disabled = del(self_db_raw_disabled) | |
1087 end | |
1088 else | |
1089 if state == nil then | |
1090 state = not not inactiveAddons[self] | |
1091 elseif (not inactiveAddons[self]) == state then | |
1092 return | |
1093 end | |
1094 inactiveAddons[self] = not state or nil | |
1095 end | |
1096 | |
1097 Rock:RecheckEnabledStates() | |
1098 | |
1099 return state | |
1100 end | |
1101 | |
1102 local function noop() end | |
1103 | |
1104 do | |
1105 local preconditions = setmetatable({}, weakKey) | |
1106 local postconditions = setmetatable({}, weakKey) | |
1107 local postconditionsOld = setmetatable({}, weakKey) | |
1108 | |
1109 local currentMethod = nil | |
1110 | |
1111 local function hook(object, method) | |
1112 local object_method = object[method] | |
1113 object[method] = function(...) | |
1114 local pre = preconditions[object_method] | |
1115 local post = postconditions[object_method] | |
1116 if pre then | |
1117 local old_currentMethod = currentMethod | |
1118 currentMethod = method | |
1119 pre(...) | |
1120 currentMethod = old_currentMethod | |
1121 end | |
1122 if not post then | |
1123 return object_method(...) | |
1124 end | |
1125 local oldFunc = postconditionsOld[object_method] | |
1126 local old | |
1127 if oldFunc then | |
1128 old = newList() | |
1129 oldFunc(old, ...) | |
1130 end | |
1131 | |
1132 local old_currentMethod = currentMethod | |
1133 currentMethod = nil | |
1134 local ret, n = newList(object_method(...)) | |
1135 | |
1136 currentMethod = method | |
1137 if old then | |
1138 post(old, ret, ...) | |
1139 old = del(old) | |
1140 else | |
1141 post(ret, ...) | |
1142 end | |
1143 currentMethod = old_currentMethod | |
1144 return unpackListAndDel(ret, 1, n) | |
1145 end | |
1146 end | |
1147 | |
1148 local function precondition(object, method, func) | |
1149 if type(object) ~= "table" then | |
1150 error(("Bad argument #1 to `precondition'. Expected %q, got %q."):format("table", type(object)), 2) | |
1151 end | |
1152 if type(object[method]) ~= "function" then | |
1153 error(("Method %q not found on object %s. Expected %q, got %q."):format(tostring(method), tostring(object), "function", type(object[method])), 2) | |
1154 end | |
1155 if type(func) ~= "function" then | |
1156 error(("Bad argument #3 to `precondition'. Expected %q, got %q."):format("function", type(func)), 2) | |
1157 end | |
1158 | |
1159 local object_method = object[method] | |
1160 if preconditions[object_method] then | |
1161 error("Cannot call `preconditon' on the same method twice.", 2) | |
1162 end | |
1163 preconditions[object_method] = func | |
1164 | |
1165 if not postconditions[object_method] then | |
1166 hook(object, method) | |
1167 end | |
1168 end | |
1169 | |
1170 local function postcondition(object, method, func, fillOld) | |
1171 if type(object) ~= "table" then | |
1172 error(("Bad argument #1 to `postcondition'. Expected %q, got %q."):format("table", type(object)), 2) | |
1173 end | |
1174 if type(object[method]) ~= "function" then | |
1175 error(("Method %q not found on object %s. Expected %q, got %q."):format(tostring(method), tostring(object), "function", type(object[method])), 2) | |
1176 end | |
1177 if type(func) ~= "function" then | |
1178 error(("Bad argument #3 to `postcondition'. Expected %q, got %q."):format("function", type(func)), 2) | |
1179 end | |
1180 if fillOld and type(fillOld) ~= "function" then | |
1181 error(("Bad argument #4 to `postcondition'. Expected %q or %q, got %q."):format("function", "nil", type(func)), 2) | |
1182 end | |
1183 | |
1184 local object_method = object[method] | |
1185 if postconditions[object_method] then | |
1186 error("Cannot call `postcondition' on the same method twice.", 2) | |
1187 end | |
1188 postconditions[object_method] = func | |
1189 postconditionsOld[object_method] = fillOld | |
1190 | |
1191 if not preconditions[object_method] then | |
1192 hook(object, method) | |
1193 end | |
1194 end | |
1195 | |
1196 local function argCheck(value, position, ...) | |
1197 if not currentMethod then | |
1198 error("Cannot call `argCheck' outside of a pre/post-condition.", 2) | |
1199 end | |
1200 if type(position) ~= "number" then | |
1201 error(("Bad argument #2 to `argCheck'. Expected %q, got %q"):format("number", type(position)), 2) | |
1202 end | |
1203 local type_value = type(value) | |
1204 for i = 1, select('#', ...) do | |
1205 local v = select(i, ...) | |
1206 if type(v) ~= "string" then | |
1207 error(("Bad argument #%d to `argCheck'. Expected %q, got %q"):format(i+1, "string", type(v)), 2) | |
1208 end | |
1209 if v == type_value then | |
1210 return | |
1211 end | |
1212 end | |
1213 local t = newList(...) | |
1214 t[#t] = nil | |
1215 for i,v in ipairs(t) do | |
1216 t[i] = ("%q"):format(v) | |
1217 end | |
1218 local s | |
1219 if #t == 0 then | |
1220 s = ("%q"):format((...)) | |
1221 elseif #t == 1 then | |
1222 s = ("%q or %q"):format(...) | |
1223 else | |
1224 s = table_concat(t, ", ") .. ", or " .. ("%q"):format(select(#t+1, ...)) | |
1225 end | |
1226 t = del(t) | |
1227 | |
1228 error(("Bad argument #%d to `%s'. Expected %s, got %q."):format(position, tostring(currentMethod), s, type_value), 4) | |
1229 end | |
1230 | |
1231 --[[--------------------------------------------------------------------------- | |
1232 Notes: | |
1233 * Returns functions for the specified namespace based on what is provided. | |
1234 * function types: | |
1235 ; "precondition" : to set the pre-condition for a method. | |
1236 ; "postcondition" : to set the post-condition for a method. | |
1237 ; "argCheck" : to check the type of an argument, to be executed within a pre-condition. | |
1238 * preconditon is in the form of <tt>precondition(object, "methodName", func(self, ...))</tt> | |
1239 * postcondition is in the form of either <tt>postcondition(object, "methodName", func(returnValues, self, ...))</tt> or <tt>postcondition(object, "methodName", func(oldValues, returnValues, self, ...), populateOld(oldValues, self, ...))</tt> | |
1240 ** returnValues is the list of return values, empty if no return values were sent. | |
1241 ** if the populateOld function is provided, then the empty oldValues table is provided and expected to be filled, and then given to the func. | |
1242 * argCheck is in the form of <tt>argCheck(value, n, "type1" [, "type2", ...])</tt> | |
1243 ** value is the value provided to the function you're checking. | |
1244 ** n is the argument position. ''Note: 1 is the position of `self'. 2 would be the first "real" position.'' | |
1245 ** the tuple of types can be any string, but specifically "nil", "boolean", "string", "number", "function", "userdata", "table", etc. | |
1246 Arguments: | |
1247 string - the namespace. ''Note: this doesn't necessarily have to be a string.'' | |
1248 Example: | |
1249 local precondition, postcondition, argCheck = Rock:GetRecyclingFunctions("Stack", "precondition", "postcondition", "argCheck") | |
1250 | |
1251 local stack = {} | |
1252 stack.IsEmpty = function(self) | |
1253 return self[1] == nil | |
1254 end | |
1255 stack.GetLength = function(self) | |
1256 return #self | |
1257 end | |
1258 stack.Push = function(self, value) | |
1259 self[#self+1] = value | |
1260 end | |
1261 precondition(stack, "Push", function(self, value) | |
1262 argCheck(value, 2, "string") -- only accept strings, no other values | |
1263 end) | |
1264 postcondition(stack, "Push", function(old, ret, self, value) | |
1265 assert(self:GetLength() == old.length+1) | |
1266 assert(not self:IsEmpty()) | |
1267 end, function(old, self) | |
1268 old.length = self:GetLength() | |
1269 end) | |
1270 stack.Pop = function(self) | |
1271 local value = self[#self] | |
1272 self[#self] = nil | |
1273 return value | |
1274 end | |
1275 precondition(stack, "Pop", function(self) | |
1276 assert(self:GetLength() >= 1) | |
1277 end) | |
1278 postcondition(stack, "Pop", function(old, ret, self) | |
1279 assert(self:GetLength() == old.length-1) | |
1280 end, function(old, self) | |
1281 old.length = self:GetLength() | |
1282 end) | |
1283 stack.Peek = function(self) | |
1284 return self[#self] | |
1285 end | |
1286 precondition(stack, "Peek", function(self) | |
1287 assert(self:GetLength() >= 1) | |
1288 end) | |
1289 postcondition(stack, "Peek", function(old, ret, self) | |
1290 assert(self:GetLength() == old.length) | |
1291 end, function(old, self) | |
1292 old.length = self:GetLength() | |
1293 end) | |
1294 | |
1295 local t = setmetatable({}, {__index=stack}) | |
1296 t:Push("Alpha") | |
1297 t:Push("Bravo") | |
1298 t:Push(5) -- error, only strings | |
1299 assert(t:Pop() == "Bravo") | |
1300 assert(t:Pop() == "Alpha") | |
1301 t:Pop() -- error, out of values | |
1302 -----------------------------------------------------------------------------]] | |
1303 function Rock:GetContractFunctions(namespace, ...) | |
1304 if namespace == "precondition" or namespace == "postcondition" or namespace == "argCheck" then | |
1305 error(("Bad argument #2 to `GetContractFunctions'. Cannot be %q."):format(namespace), 2) | |
1306 end | |
1307 local t = newList() | |
1308 if enableContracts then | |
1309 for i = 1, select('#', ...) do | |
1310 local v = select(i, ...) | |
1311 if v == "precondition" then | |
1312 t[i] = precondition | |
1313 elseif v == "postcondition" then | |
1314 t[i] = postcondition | |
1315 elseif v == "argCheck" then | |
1316 t[i] = argCheck | |
1317 else | |
1318 error(("Bad argument #%d to `GetContractFunctions'. Expected %q, %q, or %q, got %q."):format(i+2, "precondition", "postcondition", "argCheck", tostring(v))) | |
1319 end | |
1320 end | |
1321 else | |
1322 for i = 1, select('#', ...) do | |
1323 t[i] = noop | |
1324 end | |
1325 end | |
1326 return unpackListAndDel(t) | |
1327 end | |
1328 end | |
1329 | |
1330 --[[--------------------------------------------------------------------------- | |
1331 Notes: | |
1332 * convert a revision string to a number | |
1333 Arguments: | |
1334 string - revision string | |
1335 Returns: | |
1336 string or number - the string given or the number retrieved from it. | |
1337 -----------------------------------------------------------------------------]] | |
1338 local function coerceRevisionToNumber(version) | |
1339 if type(version) == "string" then | |
1340 return tonumber(version:match("(%-?%d+)")) or version | |
1341 else | |
1342 return version | |
1343 end | |
1344 end | |
1345 | |
1346 --[[--------------------------------------------------------------------------- | |
1347 Notes: | |
1348 * try to enable the standalone library specified | |
1349 Arguments: | |
1350 string - name of the library. | |
1351 Returns: | |
1352 boolean - whether the library is properly enabled and loadable. | |
1353 -----------------------------------------------------------------------------]] | |
1354 local function TryToEnable(addon) | |
1355 local islod = IsAddOnLoadOnDemand(addon) | |
1356 if islod then | |
1357 local _, _, _, enabled = GetAddOnInfo(addon) | |
1358 EnableAddOn(addon) | |
1359 local _, _, _, _, loadable = GetAddOnInfo(addon) | |
1360 if not loadable and not enabled then | |
1361 DisableAddOn(addon) | |
1362 end | |
1363 | |
1364 return loadable | |
1365 end | |
1366 end | |
1367 | |
1368 --[[--------------------------------------------------------------------------- | |
1369 Notes: | |
1370 * try to load the standalone library specified | |
1371 Arguments: | |
1372 string - name of the library. | |
1373 Returns: | |
1374 boolean - whether the library is loaded. | |
1375 -----------------------------------------------------------------------------]] | |
1376 local function TryToLoadStandalone(major) | |
1377 major = major:lower() | |
1378 if scannedLibraries[major] then | |
1379 return | |
1380 end | |
1381 scannedLibraries[major] = true | |
1382 local name, _, _, enabled, loadable, state = GetAddOnInfo(major) | |
1383 if state == "MISSING" or not IsAddOnLoadOnDemand(major) then | |
1384 -- backwards compatibility for X-AceLibrary | |
1385 local field = "X-AceLibrary-" .. major | |
1386 local loaded | |
1387 for i = 1, GetNumAddOns() do | |
1388 if GetAddOnMetadata(i, field) then | |
1389 name, _, _, enabled, loadable = GetAddOnInfo(i) | |
1390 | |
1391 loadable = (enabled and loadable) or TryToEnable(name) | |
1392 if loadable then | |
1393 loaded = true | |
1394 LoadAddOn(name) | |
1395 end | |
1396 end | |
1397 end | |
1398 | |
1399 return loaded | |
1400 elseif (enabled and loadable) or TryToEnable(major) then | |
1401 LoadAddOn(major) | |
1402 return true | |
1403 else | |
1404 return false | |
1405 end | |
1406 end | |
1407 | |
1408 --[[--------------------------------------------------------------------------- | |
1409 Notes: | |
1410 * Return the LibStub library, casing is unimportant. | |
1411 Arguments: | |
1412 string - name of the library. | |
1413 Returns: | |
1414 table or nil - library | |
1415 number - minor version | |
1416 -----------------------------------------------------------------------------]] | |
1417 local function GetLibStubLibrary(major) | |
1418 local lib, minor = LibStub:GetLibrary(major, true) | |
1419 if lib then | |
1420 return lib, minor | |
1421 end | |
1422 major = major:lower() | |
1423 for m, lib in LibStub:IterateLibraries() do | |
1424 if m:lower() == major then | |
1425 return LibStub:GetLibrary(m) | |
1426 end | |
1427 end | |
1428 return nil, nil | |
1429 end | |
1430 | |
1431 local finishLibraryRegistration | |
1432 --[[--------------------------------------------------------------------------- | |
1433 Notes: | |
1434 * create a new library if the version provided is not out of date. | |
1435 Arguments: | |
1436 string - name of the library. | |
1437 number - version of the library. | |
1438 Returns: | |
1439 library, oldLibrary | |
1440 * table or nil - the library with which to manipulate | |
1441 * table or nil - the old version of the library to upgrade from | |
1442 Example: | |
1443 local LibMonkey, oldLib = Rock:NewLibrary("LibMonkey-1.0", 50) | |
1444 if not LibMonkey then | |
1445 -- opt out now, out of date | |
1446 return | |
1447 end | |
1448 -----------------------------------------------------------------------------]] | |
1449 function Rock:NewLibrary(major, version) | |
1450 if type(major) ~= "string" then | |
1451 error(("Bad argument #2 to `NewLibrary'. Expected %q, got %q."):format("string", type(major)), 2) | |
1452 end | |
1453 if not major:match("^Lib[A-Z][A-Za-z%d%-]*%-%d+%.%d+$") then | |
1454 error(("Bad argument #2 to `NewLibrary'. Must match %q, got %q."):format("^Lib[A-Z][A-Za-z%d%-]*%-%d+%.%d+$", major), 2) | |
1455 end | |
1456 TryToLoadStandalone(major) | |
1457 version = coerceRevisionToNumber(version) | |
1458 if type(version) ~= "number" then | |
1459 error(("Bad argument #3 to `NewLibrary'. Expected %q, got %q."):format("number", type(version)), 2) | |
1460 end | |
1461 local library, oldMinor = LibStub:GetLibrary(major, true) | |
1462 if oldMinor and oldMinor >= version then | |
1463 -- in case LibStub is acting funny | |
1464 return nil, nil | |
1465 end | |
1466 local library, oldMinor = LibStub:NewLibrary(major, version) | |
1467 if not library then | |
1468 return nil, nil | |
1469 end | |
1470 local unitTests_major = unitTests[major] | |
1471 if unitTests_major then | |
1472 for k,v in pairs(unitTests_major) do | |
1473 unitTests_major[k] = nil | |
1474 end | |
1475 end | |
1476 for k, v in pairs(recycleData) do | |
1477 v[major] = nil | |
1478 end | |
1479 local mixinToObject_library = mixinToObject[library] | |
1480 | |
1481 local oldLib | |
1482 if oldMinor then | |
1483 -- previous version exists | |
1484 local mixins = newList() | |
1485 for mixin, objectSet in pairs(mixinToObject) do | |
1486 if objectSet[library] then | |
1487 mixins[mixin] = true | |
1488 end | |
1489 end | |
1490 for mixin in pairs(mixins) do | |
1491 mixin:Unembed(library) | |
1492 end | |
1493 mixins = del(mixins) | |
1494 oldLib = newList() | |
1495 for k, v in pairs(library) do | |
1496 oldLib[k] = v | |
1497 library[k] = nil | |
1498 end | |
1499 setmetatable(oldLib, getmetatable(library)) | |
1500 setmetatable(library, nil) | |
1501 end | |
1502 finishLibraryRegistration(major, version, library, figureCurrentAddon(2)) | |
1503 | |
1504 return library, oldLib | |
1505 end | |
1506 function finishLibraryRegistration(major, version, library, folder) | |
1507 library.name = major | |
1508 | |
1509 libraries[major] = library | |
1510 pendingLibraries[library] = folder | |
1511 local exportedMethods_library = exportedMethods[library] | |
1512 if exportedMethods_library then | |
1513 local mixinToObject_library = mixinToObject[library] | |
1514 if mixinToObject_library then | |
1515 for object in pairs(mixinToObject_library) do | |
1516 for _,v in ipairs(exportedMethods_library) do | |
1517 object[v] = nil | |
1518 end | |
1519 end | |
1520 end | |
1521 exportedMethods[library] = del(exportedMethods_library) | |
1522 end | |
1523 if library ~= Rock then | |
1524 Rock:Embed(library) | |
1525 end | |
1526 | |
1527 frame:Show() | |
1528 end | |
1529 if not oldRock then | |
1530 finishLibraryRegistration(MAJOR_VERSION, MINOR_VERSION, Rock, figureCurrentAddon(1)) | |
1531 end | |
1532 | |
1533 -- #NODOC | |
1534 local function __removeLibrary(libName) | |
1535 libraries[libName] = nil | |
1536 if LibStub.libs then | |
1537 LibStub.libs[libName] = nil | |
1538 end | |
1539 if LibStub.minors then | |
1540 LibStub.minors[libName] = nil | |
1541 end | |
1542 local lastCount | |
1543 repeat | |
1544 lastCount = collectgarbage('count') | |
1545 collectgarbage('collect') | |
1546 until lastCount == collectgarbage('count') | |
1547 end | |
1548 local function run(_,a) | |
1549 if a < 1/30 then | |
1550 collectgarbage('step') | |
1551 end | |
1552 end | |
1553 | |
1554 --[[--------------------------------------------------------------------------- | |
1555 Notes: | |
1556 * properly finalizes the library, essentially stating that it has loaded properly. | |
1557 * This will call :OnLibraryLoad("major", library) on every other library | |
1558 * This will also call :OnLibraryLoad("major", library) on the library provided, using every other library as the arguments. | |
1559 * An error will occur if this is not done before ADDON_LOADED. | |
1560 Arguments: | |
1561 string - name of the library. | |
1562 Example: | |
1563 local LibMonkey, oldLib = Rock:NewLibrary("LibMonkey-1.0", 50) | |
1564 if not LibMonkey then | |
1565 -- opt out now, out of date | |
1566 return | |
1567 end | |
1568 Rock:FinalizeLibrary("LibMonkey-1.0") | |
1569 -----------------------------------------------------------------------------]] | |
1570 function Rock:FinalizeLibrary(major) | |
1571 if type(major) ~= "string" then | |
1572 error(("Bad argument #2 to `FinalizeLibrary'. Expected %q, got %q."):format("string", type(major)), 2) | |
1573 end | |
1574 local library = libraries[major] | |
1575 if not library then | |
1576 error(("Bad argument #2 to `FinalizeLibrary'. %q is not a library."):format("string", major), 2) | |
1577 end | |
1578 pendingLibraries[library] = nil | |
1579 local library_OnLibraryLoad = library.OnLibraryLoad | |
1580 if library_OnLibraryLoad then | |
1581 for maj, lib in LibStub:IterateLibraries() do -- for all libraries | |
1582 if maj ~= major then | |
1583 local success, ret = pcall(library_OnLibraryLoad, library, maj, lib) | |
1584 if not success then | |
1585 geterrorhandler()(ret) | |
1586 break | |
1587 end | |
1588 end | |
1589 end | |
1590 end | |
1591 if finalizedLibraries[library] then | |
1592 return | |
1593 end | |
1594 finalizedLibraries[library] = true | |
1595 for maj, lib in pairs(libraries) do -- just Rock libraries | |
1596 if maj ~= major then | |
1597 local lib_OnLibraryLoad = lib.OnLibraryLoad | |
1598 if lib_OnLibraryLoad then | |
1599 local success, ret = pcall(lib_OnLibraryLoad, lib, major, library) | |
1600 if not success then | |
1601 geterrorhandler()(ret) | |
1602 end | |
1603 end | |
1604 end | |
1605 end | |
1606 if LibRockEvent then | |
1607 self:DispatchEvent("LibraryLoad", major, library) | |
1608 end | |
1609 end | |
1610 | |
1611 local function manualFinalize(major, library) | |
1612 if libraries[major] then -- non-Rock libraries only | |
1613 return | |
1614 end | |
1615 if finalizedLibraries[library] then -- don't do it twice | |
1616 return | |
1617 end | |
1618 finalizedLibraries[library] = true | |
1619 for maj, lib in pairs(libraries) do -- just Rock libraries | |
1620 if maj ~= major then | |
1621 local lib_OnLibraryLoad = lib.OnLibraryLoad | |
1622 if lib_OnLibraryLoad then | |
1623 local success, ret = pcall(lib_OnLibraryLoad, lib, major, library) | |
1624 if not success then | |
1625 geterrorhandler()(ret) | |
1626 end | |
1627 end | |
1628 end | |
1629 end | |
1630 if LibRockEvent then | |
1631 Rock:DispatchEvent("LibraryLoad", major, library) | |
1632 end | |
1633 end | |
1634 | |
1635 --[[--------------------------------------------------------------------------- | |
1636 Arguments: | |
1637 string - name of the library. | |
1638 [optional] boolean - whether to not load a library if it is not found. Default: false | |
1639 [optional] boolean - whether to not error if a library is not found. Default: false | |
1640 Returns: | |
1641 library | |
1642 * table or nil - the library requested | |
1643 Example: | |
1644 local LibMonkey = Rock:GetLibrary("LibMonkey-1.0") | |
1645 -- or | |
1646 local LibMonkey = Rock("LibMonkey-1.0") | |
1647 -----------------------------------------------------------------------------]] | |
1648 function Rock:GetLibrary(major, dontLoad, dontError) | |
1649 if type(major) ~= "string" then | |
1650 error(("Bad argument #2 to `GetLibrary'. Expected %q, got %q."):format("string", type(major)), 2) | |
1651 end | |
1652 if dontLoad and dontLoad ~= true then | |
1653 error(("Bad argument #3 to `GetLibrary'. Expected %q or %q, got %q."):format("boolean", "nil", type(dontLoad)), 2) | |
1654 end | |
1655 if dontError and dontError ~= true then | |
1656 error(("Bad argument #4 to `GetLibrary'. Expected %q or %q, got %q."):format("boolean", "nil", type(dontError)), 2) | |
1657 end | |
1658 if not dontLoad then | |
1659 TryToLoadStandalone(major) | |
1660 end | |
1661 | |
1662 local library = GetLibStubLibrary(major) | |
1663 if not library then | |
1664 if dontError then | |
1665 return nil | |
1666 end | |
1667 error(("Library %q not found."):format(major), 2) | |
1668 end | |
1669 | |
1670 return library | |
1671 end | |
1672 | |
1673 setmetatable(Rock, { __call = Rock.GetLibrary }) | |
1674 | |
1675 --[[--------------------------------------------------------------------------- | |
1676 Arguments: | |
1677 string - name of the library. | |
1678 Returns: | |
1679 boolean - whether the library exists and is a proper mixin which can be embedded. | |
1680 Example: | |
1681 local isMixin = Rock:IsLibraryMixin("LibMonkey-1.0") | |
1682 -----------------------------------------------------------------------------]] | |
1683 function Rock:IsLibraryMixin(name) | |
1684 local library = self:GetLibrary(name, false, true) | |
1685 if not library then | |
1686 return false | |
1687 end | |
1688 return not not exportedMethods[library] | |
1689 end | |
1690 | |
1691 --[[--------------------------------------------------------------------------- | |
1692 Arguments: | |
1693 string - name of the library. | |
1694 [optional] boolean - whether to not load a library if it is not found. Default: false | |
1695 Returns: | |
1696 library | |
1697 * table or nil - the library requested | |
1698 Example: | |
1699 local hasLibMonkey = Rock:HasLibrary("LibMonkey-1.0") | |
1700 -----------------------------------------------------------------------------]] | |
1701 function Rock:HasLibrary(major, dontLoad) | |
1702 if type(major) ~= "string" then | |
1703 error(("Bad argument #2 to `HasLibrary'. Expected %q, got %q."):format("string", type(major)), 2) | |
1704 end | |
1705 if dontLoad and dontLoad ~= true then | |
1706 error(("Bad argument #3 to `HasLibrary'. Expected %q or %q, got %q."):format("boolean", "nil", type(dontLoad)), 2) | |
1707 end | |
1708 if not dontLoad then | |
1709 TryToLoadStandalone(major) | |
1710 end | |
1711 return not not GetLibStubLibrary(major) | |
1712 end | |
1713 | |
1714 --[[--------------------------------------------------------------------------- | |
1715 Notes: | |
1716 * This is exported to all libraries | |
1717 Returns: | |
1718 major, minor | |
1719 * string - name of the library | |
1720 * number - version of the library | |
1721 Example: | |
1722 local major, minor = Rock:GetLibraryVersion() -- will be "LibRock-1.0", 12345 | |
1723 local major, minor = LibMonkey:GetLibraryVersion() -- will be "LibMonkey-1.0", 50 | |
1724 -----------------------------------------------------------------------------]] | |
1725 function Rock:GetLibraryVersion() | |
1726 if type(self) ~= "table" then | |
1727 return nil, nil | |
1728 end | |
1729 local major | |
1730 local name = self.name | |
1731 if name and GetLibStubLibrary(name) == self then | |
1732 major = name | |
1733 else | |
1734 for m, instance in LibStub:IterateLibraries() do | |
1735 if instance == self then | |
1736 major = m | |
1737 break | |
1738 end | |
1739 end | |
1740 if not major then | |
1741 return nil, nil | |
1742 end | |
1743 end | |
1744 local _, minor = GetLibStubLibrary(major) | |
1745 return major, minor | |
1746 end | |
1747 | |
1748 --[[--------------------------------------------------------------------------- | |
1749 Returns: | |
1750 an iterator to traverse all registered libraries. | |
1751 Example: | |
1752 for major, library in Rock:IterateLibraries() do | |
1753 -- do something with major and library | |
1754 end | |
1755 -----------------------------------------------------------------------------]] | |
1756 function Rock:IterateLibraries() | |
1757 return LibStub:IterateLibraries() | |
1758 end | |
1759 | |
1760 --[[--------------------------------------------------------------------------- | |
1761 Notes: | |
1762 * This is exported to all libraries | |
1763 * Allows you to set precisely what methods for the library to export. | |
1764 * This automatically turns a library into a mixin. | |
1765 Arguments: | |
1766 tuple - the list of method names to export. | |
1767 Example: | |
1768 local LibMonkey = Rock:NewLibrary("LibMonkey-1.0", 50) | |
1769 LibMonkey.FlingPoo = function(self) | |
1770 return "Splat!" | |
1771 end | |
1772 LibMonkey:SetExportedMethods("FlingPoo") | |
1773 -- later | |
1774 local Darwin = Rock:NewAddon("Darwin", "LibMonkey-1.0") | |
1775 assert(Darwin:FlingPoo() == "Splat!") | |
1776 -----------------------------------------------------------------------------]] | |
1777 function Rock:SetExportedMethods(...) | |
1778 if exportedMethods[self] then | |
1779 error("Cannot call `SetExportedMethods' more than once.", 2) | |
1780 end | |
1781 local t = newList(...) | |
1782 if #t == 0 then | |
1783 error("Must supply at least 1 method to `SetExportedMethods'.", 2) | |
1784 end | |
1785 for i,v in ipairs(t) do | |
1786 if type(self[v]) ~= "function" then | |
1787 error(("Bad argument #%d to `SetExportedMethods'. Method %q does not exist."):format(i+1, tostring(v)), 2) | |
1788 end | |
1789 end | |
1790 exportedMethods[self] = t | |
1791 | |
1792 local mixinToObject_library = mixinToObject[self] | |
1793 if mixinToObject_library then | |
1794 for object in pairs(mixinToObject_library) do | |
1795 for _,method in ipairs(t) do | |
1796 object[method] = self[method] | |
1797 end | |
1798 end | |
1799 end | |
1800 end | |
1801 | |
1802 --[[--------------------------------------------------------------------------- | |
1803 Notes: | |
1804 * This is exported to all libraries | |
1805 * Embeds all the methods previously set to export onto a table. | |
1806 * This will call :OnEmbed(object) on the library if it is available. | |
1807 Arguments: | |
1808 table - the table with which to export methods onto. | |
1809 Returns: | |
1810 The table provided, after embedding. | |
1811 Example: | |
1812 local LibMonkey = Rock:NewLibrary("LibMonkey-1.0", 50) | |
1813 LibMonkey.FlingPoo = function(self) | |
1814 return "Splat!" | |
1815 end | |
1816 LibMonkey:SetExportedMethods("FlingPoo") | |
1817 -- later | |
1818 local Darwin = {} | |
1819 Rock("LibMonkey-1.0"):Embed(Darwin) | |
1820 assert(Darwin:FlingPoo() == "Splat!") | |
1821 -----------------------------------------------------------------------------]] | |
1822 function Rock:Embed(object) | |
1823 if not exportedMethods[self] then | |
1824 error(("Cannot call `Embed' for library %q if `SetExportedMethods' has not been called."):format(tostring(self.name)), 2) | |
1825 end | |
1826 if type(object) ~= "table" then | |
1827 error(("Bad argument #2 to `Embed'. Expected %q, got %q."):format("table", type(object)), 2) | |
1828 end | |
1829 | |
1830 for i,v in ipairs(exportedMethods[self]) do | |
1831 if type(self[v]) ~= "function" then | |
1832 error(("Problem embedding method %q from library %q. Expected %q, got %q."):format(tostring(v), better_tostring(self), "function", type(self[v]))) | |
1833 end | |
1834 object[v] = self[v] | |
1835 end | |
1836 | |
1837 if not mixinToObject[self] then | |
1838 -- weak because objects come and go | |
1839 mixinToObject[self] = setmetatable(newList(), weakKey) | |
1840 end | |
1841 if mixinToObject[self][object] then | |
1842 error(("Cannot embed library %q into the same object %q more than once."):format(better_tostring(self), better_tostring(object)), 2) | |
1843 end | |
1844 mixinToObject[self][object] = true | |
1845 if type(rawget(object, 'mixins')) == "table" then | |
1846 object.mixins[self] = true | |
1847 end | |
1848 | |
1849 local self_OnEmbed = self.OnEmbed | |
1850 if self_OnEmbed then | |
1851 local success, ret = pcall(self_OnEmbed, self, object) | |
1852 if not success then | |
1853 geterrorhandler()(ret) | |
1854 end | |
1855 end | |
1856 | |
1857 return object | |
1858 end | |
1859 | |
1860 --[[--------------------------------------------------------------------------- | |
1861 Notes: | |
1862 * This is exported to all libraries | |
1863 * Unembeds all the methods previously set to export onto a table. | |
1864 * This will error if the library is not embedded on the object | |
1865 * This will call :OnUnembed(object) on the library if it is available. | |
1866 Arguments: | |
1867 table - the table with which to export methods onto. | |
1868 Returns: | |
1869 The table provided, after embedding. | |
1870 Example: | |
1871 local LibMonkey = Rock:NewLibrary("LibMonkey-1.0", 50) | |
1872 LibMonkey.FlingPoo = function(self) | |
1873 return "Splat!" | |
1874 end | |
1875 LibMonkey:SetExportedMethods("FlingPoo") | |
1876 -- later | |
1877 local Darwin = {} | |
1878 Rock("LibMonkey-1.0"):Embed(Darwin) | |
1879 assert(Darwin:FlingPoo() == "Splat!") | |
1880 Rock("LibMonkey-1.0"):Unembed(Darwin) | |
1881 assert(Darwin.FlingPoo == nil) | |
1882 -----------------------------------------------------------------------------]] | |
1883 function Rock:Unembed(object) | |
1884 if not exportedMethods[self] then | |
1885 error(("Cannot call `Unembed' for library %q if `SetExportedMethods' has not been called."):format(better_tostring(self)), 2) | |
1886 end | |
1887 | |
1888 if not mixinToObject[self] or not mixinToObject[self][object] then | |
1889 error(("Cannot unembed library %q from object %q, since it is not embedded originally."):format(better_tostring(self), better_tostring(object)), 2) | |
1890 end | |
1891 local mixinToObject_self = mixinToObject[self] | |
1892 mixinToObject_self[object] = nil | |
1893 if not next(mixinToObject_self) then | |
1894 mixinToObject[self] = del(mixinToObject_self) | |
1895 end | |
1896 | |
1897 local mixin_OnUnembed = self.OnUnembed | |
1898 if mixin_OnUnembed then | |
1899 local success, ret = pcall(mixin_OnUnembed, self, object) | |
1900 if not success then | |
1901 geterrorhandler()(ret) | |
1902 end | |
1903 end | |
1904 | |
1905 for i,v in ipairs(exportedMethods[self]) do | |
1906 object[v] = nil | |
1907 end | |
1908 end | |
1909 | |
1910 local function embedAce2Mixin(mixin, object) | |
1911 if not mixinToObject[mixin] then | |
1912 mixinToObject[mixin] = setmetatable(newList(), weakKey) | |
1913 end | |
1914 mixinToObject[mixin][object] = true | |
1915 mixin:embed(object) | |
1916 end | |
1917 | |
1918 local function embedLibStubMixin(mixin, object) | |
1919 if not mixinToObject[mixin] then | |
1920 mixinToObject[mixin] = setmetatable(newList(), weakKey) | |
1921 end | |
1922 mixinToObject[mixin][object] = true | |
1923 mixin:Embed(object) | |
1924 end | |
1925 | |
1926 --[[--------------------------------------------------------------------------- | |
1927 Notes: | |
1928 * create a new addon with the specified name. | |
1929 Arguments: | |
1930 string - name of the addon. | |
1931 tuple - list of mixins with which to embed into this addon. | |
1932 Returns: | |
1933 addon | |
1934 * table - the addon with which to manipulate | |
1935 Example: | |
1936 local MyAddon = Rock:NewAddon("MyAddon", "Mixin-1.0", "OtherMixin-2.0") | |
1937 -----------------------------------------------------------------------------]] | |
1938 function Rock:NewAddon(name, ...) | |
1939 if type(name) ~= "string" then | |
1940 error(("Bad argument #2 to `NewAddon'. Expected %q, got %q"):format("string", type(name)), 2) | |
1941 end | |
1942 if name:match("^Lib[A-Z]") then | |
1943 error(("Bad argument #2 to `NewAddon'. Cannot start with %q, got %q."):format("Lib", name), 2) | |
1944 end | |
1945 if self == Rock and name:match("_") then | |
1946 error(("Bad argument #2 to `NewAddon'. Cannot contain underscores, got %q."):format(name), 2) | |
1947 end | |
1948 | |
1949 if addons[name] then | |
1950 error(("Bad argument #2 to `NewAddon'. Addon %q already created."):format(name), 2) | |
1951 end | |
1952 local addon = setmetatable(newList(), addon_mt) | |
1953 addon.name = name | |
1954 | |
1955 local mixinSet = newList() | |
1956 | |
1957 for i = 1, select('#', ...) do | |
1958 local libName = select(i, ...) | |
1959 if mixinSet[libName] then | |
1960 error(("Bad argument #%d to `NewAddon'. %q already stated."):format(i+2, tostring(libName)), 2) | |
1961 end | |
1962 mixinSet[libName] = true | |
1963 TryToLoadStandalone(libName) | |
1964 local library = Rock:GetLibrary(libName, false, true) | |
1965 if not library then | |
1966 error(("Bad argument #%d to `NewAddon'. Library %q is not found."):format(i+2, tostring(libName)), 2) | |
1967 end | |
1968 | |
1969 local style = 'rock' | |
1970 | |
1971 if not exportedMethods[library] then | |
1972 local good = false | |
1973 if AceLibrary then | |
1974 local AceOO = AceLibrary:HasInstance("AceOO-2.0", false) and AceLibrary("AceOO-2.0") | |
1975 if AceOO.inherits(library, AceOO.Mixin) then | |
1976 good = true | |
1977 style = 'ace2' | |
1978 end | |
1979 end | |
1980 if not good and type(rawget(library, 'Embed')) == "function" then | |
1981 good = true | |
1982 style = 'libstub' | |
1983 end | |
1984 if not good then | |
1985 error(("Bad argument #%d to `NewAddon'. Library %q is not a mixin."):format(i+2, tostring(libName)), 2) | |
1986 end | |
1987 end | |
1988 | |
1989 if library == Rock then | |
1990 error(("Bad argument #%d to `NewAddon'. Cannot use %q as a mixin."):format(i+2, tostring(libName)), 2) | |
1991 end | |
1992 | |
1993 if style == 'rock' then | |
1994 library:Embed(addon) | |
1995 elseif style == 'ace2' then | |
1996 embedAce2Mixin(library, addon) | |
1997 elseif style == 'libstub' then | |
1998 embedLibStubMixin(library, addon) | |
1999 end | |
2000 end | |
2001 | |
2002 mixinSet = del(mixinSet) | |
2003 | |
2004 addons[name] = addon | |
2005 pendingAddons[#pendingAddons+1] = addon | |
2006 pendingAddonsEnable[#pendingAddonsEnable+1] = addon | |
2007 addonToFolder[addon] = figureCurrentAddon(self == Rock and 2 or 4) | |
2008 | |
2009 frame:Show() | |
2010 | |
2011 return addon | |
2012 end | |
2013 | |
2014 --[[--------------------------------------------------------------------------- | |
2015 Arguments: | |
2016 string - name of the addon. | |
2017 Returns: | |
2018 addon | |
2019 * table or nil - the addon requested | |
2020 Example: | |
2021 local MyAddon = Rock:GetAddon("MyAddon") | |
2022 -----------------------------------------------------------------------------]] | |
2023 function Rock:GetAddon(name) | |
2024 if type(name) ~= "string" then | |
2025 return nil | |
2026 end | |
2027 local addon = addons[name] | |
2028 if addon then | |
2029 return addon | |
2030 end | |
2031 name = name:lower() | |
2032 for k, v in pairs(addons) do | |
2033 if k:lower() == name then | |
2034 return v | |
2035 end | |
2036 end | |
2037 return nil | |
2038 end | |
2039 | |
2040 --[[--------------------------------------------------------------------------- | |
2041 Arguments: | |
2042 string or table - name of the addon or the addon itself. | |
2043 Returns: | |
2044 boolean - whether the addon requested exists. | |
2045 Example: | |
2046 local hasMyAddon = Rock:HasAddon("MyAddon") | |
2047 -- or | |
2048 local hasMyAddon = Rock:HasAddon(MyAddon) | |
2049 -----------------------------------------------------------------------------]] | |
2050 function Rock:HasAddon(name) | |
2051 if type(name) == "string" then | |
2052 local addon = addons[name] | |
2053 if addon then | |
2054 return true | |
2055 end | |
2056 name = name:lower() | |
2057 for k, v in pairs(addons) do | |
2058 if k:lower() == name then | |
2059 return true | |
2060 end | |
2061 end | |
2062 elseif type(name) == "table" then | |
2063 for k,v in pairs(addons) do | |
2064 if v == name then | |
2065 return true | |
2066 end | |
2067 end | |
2068 end | |
2069 return false | |
2070 end | |
2071 | |
2072 --[[--------------------------------------------------------------------------- | |
2073 Returns: | |
2074 an iterator to traverse all addons created with Rock. | |
2075 Example: | |
2076 for name, addon in Rock:IterateAddons() do | |
2077 -- do something with name and addon | |
2078 end | |
2079 -----------------------------------------------------------------------------]] | |
2080 function Rock:IterateAddons() | |
2081 return pairs(addons) | |
2082 end | |
2083 | |
2084 --[[--------------------------------------------------------------------------- | |
2085 Arguments: | |
2086 string - major version of the mixin library | |
2087 Returns: | |
2088 an iterator to traverse all objects that the given mixin has embedded into | |
2089 Example: | |
2090 local LibMonkey = Rock:NewLibrary("LibMonkey-1.0") | |
2091 local Darwin = Rock:NewAddon("Darwin", "LibMonkey-1.0") | |
2092 for object in LibMonkey:IterateMixinObjects("LibMonkey-1.0") do | |
2093 assert(object == Darwin) | |
2094 end | |
2095 -----------------------------------------------------------------------------]] | |
2096 function Rock:IterateMixinObjects(mixinName) | |
2097 local mixin | |
2098 if type(mixinName) == "table" then | |
2099 mixin = mixinName | |
2100 else | |
2101 if type(mixinName) ~= "string" then | |
2102 error(("Bad argument #2 to `IterateMixinObjects'. Expected %q or %q, got %q."):format("table", "string", type(mixinName)), 2) | |
2103 end | |
2104 mixin = libraries[mixinName] | |
2105 end | |
2106 local mixinToObject_mixin = mixinToObject[mixin] | |
2107 if not mixinToObject_mixin then | |
2108 return noop | |
2109 end | |
2110 return pairs(mixinToObject_mixin) | |
2111 end | |
2112 | |
2113 local function iter(object, mixin) | |
2114 mixin = next(mixinToObject, mixin) | |
2115 if not mixin then | |
2116 return nil | |
2117 elseif mixinToObject[mixin][object] then | |
2118 return mixin | |
2119 end | |
2120 return iter(object, mixin) -- try next mixin | |
2121 end | |
2122 --[[--------------------------------------------------------------------------- | |
2123 Returns: | |
2124 an iterator to traverse all mixins that an object has embedded | |
2125 Example: | |
2126 local LibMonkey = Rock:NewLibrary("LibMonkey-1.0") | |
2127 local Darwin = Rock:NewAddon("Darwin", "LibMonkey-1.0") | |
2128 for mixin in Rock:IterateObjectMixins(Darwin) do | |
2129 assert(mixin == LibMonkey) | |
2130 end | |
2131 -----------------------------------------------------------------------------]] | |
2132 function Rock:IterateObjectMixins(object) | |
2133 if type(object) ~= "table" then | |
2134 error(("Bad argument #2 to `IterateObjectMixins'. Expected %q, got %q."):format("table", type(object)), 2) | |
2135 end | |
2136 return iter, object, nil | |
2137 end | |
2138 | |
2139 --[[--------------------------------------------------------------------------- | |
2140 Arguments: | |
2141 table - the object to check | |
2142 string - the mixin to check | |
2143 Returns: | |
2144 boolean - whether the object has the given mixin embedded into it. | |
2145 Example: | |
2146 local LibMonkey = Rock:NewLibrary("LibMonkey-1.0") | |
2147 local Darwin = Rock:NewAddon("Darwin", "LibMonkey-1.0") | |
2148 assert(Rock:DoesObjectUseMixin(Darwin, "LibMonkey-1.0")) | |
2149 -----------------------------------------------------------------------------]] | |
2150 function Rock:DoesObjectUseMixin(object, mixinName) | |
2151 if type(object) ~= "table" then | |
2152 error(("Bad argument #2 to `IterateObjectMixins'. Expected %q, got %q."):format("table", type(object)), 2) | |
2153 end | |
2154 local mixin | |
2155 if type(mixinName) == "table" then | |
2156 mixin = mixinName | |
2157 else | |
2158 if type(mixinName) ~= "string" then | |
2159 error(("Bad argument #3 to `IterateMiDoesObjectUseMixininObjects'. Expected %q or %q, got %q."):format("table", "string", type(mixinName)), 2) | |
2160 end | |
2161 mixin = libraries[mixinName] | |
2162 end | |
2163 if not mixin then | |
2164 return false | |
2165 end | |
2166 | |
2167 local mixinToObject_mixin = mixinToObject[mixin] | |
2168 if not mixinToObject_mixin then | |
2169 return false | |
2170 end | |
2171 return not not mixinToObject_mixin[object] | |
2172 end | |
2173 | |
2174 Rock.UID_NUM = oldRock and oldRock.UID_NUM or 0 | |
2175 --[[--------------------------------------------------------------------------- | |
2176 Notes: | |
2177 * 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. | |
2178 Returns: | |
2179 number - a unique number. | |
2180 Example: | |
2181 local UID = Rock:GetUID() | |
2182 -----------------------------------------------------------------------------]] | |
2183 function Rock:GetUID() | |
2184 local num = Rock.UID_NUM + 1 | |
2185 Rock.UID_NUM = num | |
2186 return num | |
2187 end | |
2188 | |
2189 local function unobfuscateEmail(email) | |
2190 return email:gsub(" AT ", "@"):gsub(" DOT ", ".") | |
2191 end | |
2192 local function fix(char) | |
2193 return ("%%%02x"):format(char:byte()) | |
2194 end | |
2195 local function urlencode(text) | |
2196 return text:gsub("[^0-9A-Za-z]", fix) | |
2197 end | |
2198 | |
2199 local url | |
2200 local function makeURLFrame() | |
2201 makeURLFrame = nil | |
2202 local function bumpFrameLevels(frame, amount) | |
2203 frame:SetFrameLevel(frame:GetFrameLevel()+amount) | |
2204 local children = newList(frame:GetChildren()) | |
2205 for _,v in ipairs(children) do | |
2206 bumpFrameLevels(v, amount) | |
2207 end | |
2208 children = del(children) | |
2209 end | |
2210 -- some code borrowed from Prat here | |
2211 StaticPopupDialogs["ROCK_SHOW_URL"] = { | |
2212 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."], | |
2213 button2 = ACCEPT, | |
2214 hasEditBox = 1, | |
2215 hasWideEditBox = 1, | |
2216 showAlert = 1, -- HACK : it's the only way I found to make de StaticPopup have sufficient width to show WideEditBox :( | |
2217 | |
2218 OnShow = function() | |
2219 local editBox = _G[this:GetName() .. "WideEditBox"] | |
2220 editBox:SetText(url) | |
2221 editBox:SetFocus() | |
2222 editBox:HighlightText(0) | |
2223 editBox:SetScript("OnTextChanged", function() StaticPopup_EditBoxOnTextChanged() end) | |
2224 | |
2225 local button = _G[this:GetName() .. "Button2"] | |
2226 button:ClearAllPoints() | |
2227 button:SetWidth(200) | |
2228 button:SetPoint("CENTER", editBox, "CENTER", 0, -30) | |
2229 | |
2230 _G[this:GetName() .. "AlertIcon"]:Hide() -- HACK : we hide the false AlertIcon | |
2231 this:SetFrameStrata("FULLSCREEN_DIALOG") | |
2232 bumpFrameLevels(this, 30) | |
2233 end, | |
2234 OnHide = function() | |
2235 local editBox = _G[this:GetName() .. "WideEditBox"] | |
2236 editBox:SetScript("OnTextChanged", nil) | |
2237 this:SetFrameStrata("DIALOG") | |
2238 bumpFrameLevels(this, -30) | |
2239 end, | |
2240 OnAccept = function() end, | |
2241 OnCancel = function() end, | |
2242 EditBoxOnEscapePressed = function() this:GetParent():Hide() end, | |
2243 EditBoxOnTextChanged = function() | |
2244 this:SetText(url) | |
2245 this:SetFocus() | |
2246 this:HighlightText(0) | |
2247 end, | |
2248 timeout = 0, | |
2249 whileDead = 1, | |
2250 hideOnEscape = 1 | |
2251 } | |
2252 end | |
2253 | |
2254 function OpenDonationFrame(self) | |
2255 if makeURLFrame then | |
2256 makeURLFrame() | |
2257 end | |
2258 | |
2259 local donate = self.donate | |
2260 if type(donate) ~= "string" then | |
2261 donate = "Wowace" | |
2262 end | |
2263 local style, data = (":"):split(donate, 2) | |
2264 style = style:lower() | |
2265 if style ~= "website" and style ~= "paypal" then | |
2266 style = "wowace" | |
2267 end | |
2268 if style == "wowace" then | |
2269 url = "http://www.wowace.com/wiki/Donations" | |
2270 elseif style == "website" then | |
2271 url = data | |
2272 else -- PayPal | |
2273 local text = "https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&business=" .. urlencode(unobfuscateEmail(data)) | |
2274 local name | |
2275 if type(self.title) == "string" then | |
2276 name = self.title | |
2277 elseif type(self.name) == "string" then | |
2278 name = self.name | |
2279 end | |
2280 if name == MAJOR_VERSION then | |
2281 name = "Rock" | |
2282 end | |
2283 if name then | |
2284 name = name:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", "") | |
2285 text = text .. "&item_name=" .. urlencode(name) | |
2286 end | |
2287 url = text | |
2288 end | |
2289 | |
2290 StaticPopup_Show("ROCK_SHOW_URL") | |
2291 end | |
2292 function OpenIssueFrame(self) | |
2293 if makeURLFrame then | |
2294 makeURLFrame() | |
2295 end | |
2296 | |
2297 local issueTracker = self.issueTracker | |
2298 if type(issueTracker) ~= "string" then | |
2299 return | |
2300 end | |
2301 local style, data = (":"):split(issueTracker, 2) | |
2302 style = style:lower() | |
2303 if style ~= "website" and style ~= "wowace" then | |
2304 return | |
2305 end | |
2306 if style == "wowace" then | |
2307 url = "http://jira.wowace.com/secure/CreateIssue.jspa?pid=" .. data | |
2308 elseif style == "website" then | |
2309 url = data | |
2310 end | |
2311 | |
2312 StaticPopup_Show("ROCK_SHOW_URL") | |
2313 end | |
2314 local function donate_hidden(addon) | |
2315 return type(addon.donate) ~= "string" | |
2316 end | |
2317 | |
2318 local function issue_hidden(addon) | |
2319 return type(addon.issueTracker) ~= "string" | |
2320 end | |
2321 | |
2322 -- #NODOC | |
2323 function Rock:GetRockConfigOptions(addon) | |
2324 return 'active', { | |
2325 type = 'boolean', | |
2326 name = L["Enabled"], | |
2327 desc = L["Enable or disable this addon."], | |
2328 get = 'IsActive', | |
2329 set = 'ToggleActive', | |
2330 handler = addon, | |
2331 order = -1, | |
2332 }, 'donate', { | |
2333 type = 'execute', | |
2334 name = L["Give donation"], | |
2335 buttonText = L["Donate"], | |
2336 desc = L["Give a much-needed donation to the author of this addon."], | |
2337 func = OpenDonationFrame, | |
2338 hidden = donate_hidden, | |
2339 passValue = addon, | |
2340 order = -2, | |
2341 }, 'issue', { | |
2342 type = 'execute', | |
2343 name = L["File issue"], | |
2344 buttonText = L["Report"], | |
2345 desc = L["File a bug or request a new feature or an improvement to this addon."], | |
2346 func = OpenIssueFrame, | |
2347 hidden = issue_hidden, | |
2348 passValue = addon, | |
2349 order = -3, | |
2350 } | |
2351 end | |
2352 | |
2353 local function initAddon(addon, name) | |
2354 name = addonToFolder[addon] or name or "" | |
2355 -- TOC checks | |
2356 if addon.title == nil then | |
2357 addon.title = GetAddOnMetadata(name, "Title") | |
2358 end | |
2359 if type(addon.title) == "string" then | |
2360 addon.title = addon.title:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", ""):gsub("%-Rock%-$", ""):trim() | |
2361 end | |
2362 if addon.notes == nil then | |
2363 addon.notes = GetAddOnMetadata(name, "Notes") | |
2364 end | |
2365 if type(addon.notes) == "string" then | |
2366 addon.notes = addon.notes:trim() | |
2367 end | |
2368 if addon.version == nil then | |
2369 addon.version = GetAddOnMetadata(name, "Version") | |
2370 end | |
2371 if type(addon.version) == "string" then | |
2372 addon.version = addon.version:trim() | |
2373 end | |
2374 if addon.author == nil then | |
2375 addon.author = GetAddOnMetadata(name, "Author") | |
2376 end | |
2377 if type(addon.author) == "string" then | |
2378 addon.author = addon.author:trim() | |
2379 end | |
2380 if addon.credits == nil then | |
2381 addon.credits = GetAddOnMetadata(name, "X-Credits") | |
2382 end | |
2383 if type(addon.credits) == "string" then | |
2384 addon.credits = addon.credits:trim() | |
2385 end | |
2386 if addon.donate == nil then | |
2387 addon.donate = GetAddOnMetadata(name, "X-Donate") | |
2388 end | |
2389 if type(addon.donate) == "string" then | |
2390 addon.donate = addon.donate:trim() | |
2391 end | |
2392 if addon.issueTracker == nil then | |
2393 addon.issueTracker = GetAddOnMetadata(name, "X-IssueTracker") | |
2394 end | |
2395 if type(addon.issueTracker) == "string" then | |
2396 addon.issueTracker = addon.issueTracker:trim() | |
2397 end | |
2398 if addon.category == nil then | |
2399 addon.category = GetAddOnMetadata(name, "X-Category") | |
2400 end | |
2401 if type(addon.category) == "string" then | |
2402 addon.category = addon.category:trim() | |
2403 end | |
2404 if addon.email == nil then | |
2405 addon.email = GetAddOnMetadata(name, "X-eMail") or GetAddOnMetadata(name, "X-Email") | |
2406 end | |
2407 if type(addon.email) == "string" then | |
2408 addon.email = addon.email:trim() | |
2409 end | |
2410 if addon.license == nil then | |
2411 addon.license = GetAddOnMetadata(name, "X-License") | |
2412 end | |
2413 if type(addon.license) == "string" then | |
2414 addon.license = addon.license:trim() | |
2415 end | |
2416 if addon.website == nil then | |
2417 addon.website = GetAddOnMetadata(name, "X-Website") | |
2418 end | |
2419 if type(addon.website) == "string" then | |
2420 addon.website = addon.website:trim() | |
2421 end | |
2422 | |
2423 for mixin in Rock:IterateObjectMixins(addon) do | |
2424 local mixin_OnEmbedInitialize = mixin.OnEmbedInitialize | |
2425 if mixin_OnEmbedInitialize then | |
2426 local success, ret = pcall(mixin_OnEmbedInitialize, mixin, addon) | |
2427 if not success then | |
2428 geterrorhandler()(ret) | |
2429 end | |
2430 end | |
2431 end | |
2432 | |
2433 local addon_OnInitialize = addon.OnInitialize | |
2434 if addon_OnInitialize then | |
2435 local success, ret = pcall(addon_OnInitialize, addon) | |
2436 if not success then | |
2437 geterrorhandler()(ret) | |
2438 end | |
2439 end | |
2440 | |
2441 if LibRockEvent then | |
2442 Rock:DispatchEvent("AddonInitialized", addon) | |
2443 end | |
2444 end | |
2445 | |
2446 | |
2447 local function manualEnable(addon) | |
2448 for i,v in ipairs(pendingAddons) do | |
2449 if v == addon then | |
2450 return | |
2451 end | |
2452 end | |
2453 if currentlyEnabledAddons[addon] then | |
2454 return false | |
2455 end | |
2456 currentlyEnabledAddons[addon] = true | |
2457 | |
2458 local first = not addonsAlreadyEnabled[addon] | |
2459 addonsAlreadyEnabled[addon] = true | |
2460 | |
2461 for mixin in Rock:IterateObjectMixins(addon) do | |
2462 local mixin_OnEmbedEnable = mixin.OnEmbedEnable | |
2463 if mixin_OnEmbedEnable then | |
2464 local success, ret = pcall(mixin_OnEmbedEnable, mixin, addon, first) | |
2465 if not success then | |
2466 geterrorhandler()(ret) | |
2467 end | |
2468 end | |
2469 end | |
2470 local addon_OnEnable = addon.OnEnable | |
2471 if addon_OnEnable then | |
2472 local success, ret = pcall(addon_OnEnable, addon, first) | |
2473 if not success then | |
2474 geterrorhandler()(ret) | |
2475 end | |
2476 end | |
2477 | |
2478 if LibRockEvent then | |
2479 Rock:DispatchEvent("AddonEnabled", addon, first) | |
2480 end | |
2481 | |
2482 return true, first | |
2483 end | |
2484 | |
2485 local function manualDisable(addon) | |
2486 if not currentlyEnabledAddons[addon] then | |
2487 return false | |
2488 end | |
2489 currentlyEnabledAddons[addon] = nil | |
2490 | |
2491 for mixin in Rock:IterateObjectMixins(addon) do | |
2492 local mixin_OnEmbedDisable = mixin.OnEmbedDisable | |
2493 if mixin_OnEmbedDisable then | |
2494 local success, ret = pcall(mixin_OnEmbedDisable, mixin, addon) | |
2495 if not success then | |
2496 geterrorhandler()(ret) | |
2497 end | |
2498 end | |
2499 end | |
2500 local addon_OnDisable = addon.OnDisable | |
2501 if addon_OnDisable then | |
2502 local success, ret = pcall(addon_OnDisable, addon) | |
2503 if not success then | |
2504 geterrorhandler()(ret) | |
2505 end | |
2506 end | |
2507 | |
2508 if LibRockEvent then | |
2509 Rock:DispatchEvent("AddonDisabled", addon) | |
2510 end | |
2511 return true | |
2512 end | |
2513 | |
2514 local function enableAddon(addon) | |
2515 for i,v in ipairs(pendingAddons) do | |
2516 if v == addon then | |
2517 return | |
2518 end | |
2519 end | |
2520 if addon_mt___index.IsActive(addon) then | |
2521 manualEnable(addon) | |
2522 end | |
2523 end | |
2524 | |
2525 -- #NODOC | |
2526 -- This is used by internal Rock libraries after updating the active state. | |
2527 function Rock:RecheckEnabledStates() | |
2528 local changed = false | |
2529 for _,addon in pairs(addons) do | |
2530 local good = true | |
2531 for _,a in ipairs(pendingAddonsEnable) do | |
2532 if addon == a then | |
2533 good = false | |
2534 break | |
2535 end | |
2536 end | |
2537 if good then | |
2538 if addon_mt___index.IsActive(addon) then | |
2539 if manualEnable(addon) then | |
2540 changed = true | |
2541 end | |
2542 else | |
2543 if manualDisable(addon) then | |
2544 changed = true | |
2545 end | |
2546 end | |
2547 end | |
2548 end | |
2549 if changed then | |
2550 return self:RecheckEnabledStates() | |
2551 end | |
2552 end | |
2553 | |
2554 frame:UnregisterAllEvents() | |
2555 frame:RegisterEvent("ADDON_LOADED") | |
2556 frame:RegisterEvent("PLAYER_LOGIN") | |
2557 local function runMainAddonLoadedChunk(name) | |
2558 local tmp = newList() | |
2559 tmp, pendingAddons = pendingAddons, tmp | |
2560 for i, addon in ipairs(tmp) do | |
2561 local folder = addonToFolder[addon] | |
2562 if name and folder and not foldersLoaded[folder] then | |
2563 for j = i, #tmp do | |
2564 pendingAddons[#pendingAddons+1] = tmp[j] | |
2565 tmp[j] = nil | |
2566 end | |
2567 break | |
2568 end | |
2569 initAddon(addon, name) | |
2570 end | |
2571 | |
2572 if IsLoggedIn() then | |
2573 for i, addon in ipairs(tmp) do | |
2574 for j, v in ipairs(pendingAddonsEnable) do | |
2575 if v == addon then | |
2576 table_remove(pendingAddonsEnable, i) | |
2577 break | |
2578 end | |
2579 end | |
2580 enableAddon(addon) | |
2581 end | |
2582 for i, addon in ipairs(pendingAddonsEnable) do | |
2583 local good = true | |
2584 for j, v in ipairs(pendingAddons) do | |
2585 if v == addon then | |
2586 good = false | |
2587 break | |
2588 end | |
2589 end | |
2590 if not good then | |
2591 break | |
2592 end | |
2593 pendingAddonsEnable[i] = nil | |
2594 enableAddon(addon) | |
2595 end | |
2596 end | |
2597 tmp = del(tmp) | |
2598 for library, addonName in pairs(pendingLibraries) do | |
2599 if not name or foldersLoaded[addonName] then | |
2600 local success, ret = pcall(error, ("Library %q not finalized before ADDON_LOADED."):format(better_tostring(library)), 3) | |
2601 geterrorhandler()(ret) | |
2602 Rock:FinalizeLibrary((library:GetLibraryVersion())) | |
2603 end | |
2604 end | |
2605 | |
2606 if isStandalone then | |
2607 local LibRock_1_0DB = _G.LibRock_1_0DB | |
2608 if type(LibRock_1_0DB) ~= "table" then | |
2609 LibRock_1_0DB = {} | |
2610 _G.LibRock_1_0DB = LibRock_1_0DB | |
2611 end | |
2612 if type(LibRock_1_0DB.unitTests) ~= "table" then | |
2613 LibRock_1_0DB.unitTests = {} | |
2614 end | |
2615 enableContracts = LibRock_1_0DB.contracts or false | |
2616 unitTestDB = LibRock_1_0DB.unitTests | |
2617 for namespace, data in pairs(unitTests) do | |
2618 if not unitTestDB[namespace] then | |
2619 if data then | |
2620 del(data) | |
2621 unitTests[namespace] = false | |
2622 end | |
2623 elseif data and (not name or data.addon == name) then | |
2624 local stats = newList() | |
2625 for i,v in ipairs(data) do | |
2626 data[i] = nil | |
2627 | |
2628 local libs = newList() | |
2629 for k,v in pairs(libraries) do | |
2630 libs[k] = v | |
2631 end | |
2632 | |
2633 local success, ret = pcall(v) | |
2634 if not success then | |
2635 geterrorhandler()(ret) | |
2636 stats[i] = ret | |
2637 else | |
2638 stats[i] = false | |
2639 end | |
2640 | |
2641 for k in pairs(libraries) do | |
2642 if not libs[k] then | |
2643 __removeLibrary(k) | |
2644 end | |
2645 end | |
2646 libs = del(libs) | |
2647 | |
2648 local lastCount | |
2649 repeat | |
2650 lastCount = collectgarbage('count') | |
2651 collectgarbage('collect') | |
2652 until lastCount == collectgarbage('count') | |
2653 end | |
2654 del(data) | |
2655 unitTests[namespace] = false | |
2656 if #stats >= 1 then | |
2657 local pass, fail = 0, 0 | |
2658 for i,v in ipairs(stats) do | |
2659 if v then | |
2660 fail = fail + 1 | |
2661 else | |
2662 pass = pass + 1 | |
2663 end | |
2664 end | |
2665 | |
2666 local color | |
2667 if fail == 0 then | |
2668 _G.DEFAULT_CHAT_FRAME:AddMessage(("|cff00ff00%s: %d unit test(s) passed."):format(namespace, pass)) | |
2669 elseif pass > 0 then | |
2670 _G.DEFAULT_CHAT_FRAME:AddMessage(("|cffff0000%s: %d unit test(s) passed, %d unit test(s) failed."):format(namespace, pass, fail)) | |
2671 else | |
2672 _G.DEFAULT_CHAT_FRAME:AddMessage(("|cffff0000%s: %d unit test(s) failed."):format(namespace, fail)) | |
2673 end | |
2674 for i,v in ipairs(stats) do | |
2675 if v then | |
2676 _G.DEFAULT_CHAT_FRAME:AddMessage(("|cffff0000%s|r"):format(tostring(v))) | |
2677 end | |
2678 end | |
2679 if fail > 0 then | |
2680 _G.DEFAULT_CHAT_FRAME:AddMessage("|cffff0000----------|r") | |
2681 end | |
2682 end | |
2683 stats = del(stats) | |
2684 end | |
2685 end | |
2686 end | |
2687 if isStandalone and name == MAJOR_VERSION then | |
2688 Rock("LibRockEvent-1.0", false, true) -- load if possible | |
2689 Rock("LibRockConsole-1.0", false, true) -- load if possible - I like the default chat commands | |
2690 Rock("LibRockComm-1.0", false, true) -- load if possible - has version checking and the like | |
2691 Rock("LibRockConfig-1.0", false, true) -- load if possible - LibRock-1.0 registers with it. | |
2692 end | |
2693 | |
2694 for major, library in LibStub:IterateLibraries() do | |
2695 manualFinalize(major, library) | |
2696 end | |
2697 | |
2698 if IsLoggedIn() then | |
2699 collectgarbage('collect') | |
2700 end | |
2701 end | |
2702 | |
2703 frame:Show() | |
2704 frame:SetScript("OnUpdate", function(this, elapsed) | |
2705 -- capture all un-initialized addons. | |
2706 runMainAddonLoadedChunk() | |
2707 collectgarbage('collect') | |
2708 this:SetScript("OnUpdate", run) | |
2709 end) | |
2710 frame:SetScript("OnEvent", function(this, event, ...) | |
2711 if event == "ADDON_LOADED" then | |
2712 -- this creates a new table and flushes the old in case someone LoDs an addon inside ADDON_LOADED. | |
2713 local name = ... | |
2714 foldersLoaded[name] = true | |
2715 runMainAddonLoadedChunk(name) | |
2716 frame:Show() | |
2717 elseif event == "PLAYER_LOGIN" then | |
2718 for i, addon in ipairs(pendingAddonsEnable) do | |
2719 local good = true | |
2720 for _, a in ipairs(pendingAddons) do | |
2721 if a == addon then | |
2722 good = false | |
2723 break | |
2724 end | |
2725 end | |
2726 if good then | |
2727 pendingAddonsEnable[i] = nil | |
2728 enableAddon(addon) | |
2729 end | |
2730 end | |
2731 collectgarbage('collect') | |
2732 end | |
2733 end) | |
2734 | |
2735 Rock:SetExportedMethods("SetExportedMethods", "Embed", "Unembed", "GetLibraryVersion") | |
2736 | |
2737 Rock:FinalizeLibrary(MAJOR_VERSION) | |
2738 | |
2739 for major, library in LibStub:IterateLibraries() do | |
2740 manualFinalize(major, library) | |
2741 end | |
2742 | |
2743 Rock:AddUnitTest(MAJOR_VERSION, function() | |
2744 -- test recycling | |
2745 local newList, newDict, newSet, del = Rock:GetRecyclingFunctions(MAJOR_VERSION .. "_UnitTest", "newList", "newDict", "newSet", "del", "Debug") | |
2746 local t = newList("Alpha", "Bravo", "Charlie") | |
2747 assert(t[1] == "Alpha") | |
2748 assert(t[2] == "Bravo") | |
2749 assert(t[3] == "Charlie") | |
2750 t = del(t) | |
2751 t = newList("Alpha", "Bravo", "Charlie") | |
2752 -- check recycled table | |
2753 assert(t[1] == "Alpha") | |
2754 assert(t[2] == "Bravo") | |
2755 assert(t[3] == "Charlie") | |
2756 t = del(t) | |
2757 t = newDict("Alpha", "Bravo", "Charlie", "Delta") | |
2758 assert(t.Alpha == "Bravo") | |
2759 assert(t.Charlie == "Delta") | |
2760 t = del(t) | |
2761 t = newSet("Alpha", "Bravo", "Charlie") | |
2762 assert(t.Alpha) | |
2763 assert(t.Bravo) | |
2764 assert(t.Charlie) | |
2765 t = del(t) | |
2766 | |
2767 local debug = recycleData.debugPools[MAJOR_VERSION .. "_UnitTest"] | |
2768 assert(debug.num == 0) | |
2769 t = newList() | |
2770 assert(debug.num == 1) | |
2771 t[1] = newList() | |
2772 assert(debug.num == 2) | |
2773 t[2] = newList() | |
2774 assert(debug.num == 3) | |
2775 t[1] = del(t[1]) | |
2776 assert(debug.num == 2) | |
2777 t[2] = del(t[2]) | |
2778 assert(debug.num == 1) | |
2779 t = del(t) | |
2780 assert(debug.num == 0) | |
2781 end) | |
2782 | |
2783 Rock:AddUnitTest(MAJOR_VERSION, function() | |
2784 -- test :GetUID() | |
2785 local t = {} | |
2786 for i = 1, 10000 do | |
2787 local uid = Rock:GetUID() | |
2788 if t[i] then | |
2789 error(("UID match for iteration %d, UID %s"):format(i, uid)) | |
2790 end | |
2791 t[i] = true | |
2792 end | |
2793 end) | |
2794 | |
2795 Rock:AddUnitTest(MAJOR_VERSION, function() | |
2796 -- test basic creation and deletion | |
2797 assert(not LibStub:GetLibrary("LibRockFakeLib-1.0", true)) | |
2798 assert(not Rock:HasLibrary("LibRockFakeLib-1.0")) | |
2799 local lib = Rock:NewLibrary("LibRockFakeLib-1.0", 1) | |
2800 Rock:FinalizeLibrary("LibRockFakeLib-1.0") | |
2801 lib = nil | |
2802 assert(LibStub:GetLibrary("LibRockFakeLib-1.0", true)) | |
2803 assert(Rock:HasLibrary("LibRockFakeLib-1.0")) | |
2804 local good = false | |
2805 for _, lib in pairs(libraries) do | |
2806 if lib.name == "LibRockFakeLib-1.0" then | |
2807 good = true | |
2808 break | |
2809 end | |
2810 end | |
2811 assert(good) | |
2812 __removeLibrary("LibRockFakeLib-1.0") | |
2813 for _, lib in pairs(libraries) do | |
2814 assert(lib.name ~= "LibRockFakeLib-1.0") | |
2815 end | |
2816 assert(not LibStub:GetLibrary("LibRockFakeLib-1.0", true)) | |
2817 assert(not Rock:HasLibrary("LibRockFakeLib-1.0")) | |
2818 end) | |
2819 | |
2820 Rock:AddUnitTest(MAJOR_VERSION, function() | |
2821 -- test library creation and the like | |
2822 assert(not Rock:HasLibrary("LibRockFakeLib-1.0")) | |
2823 for name in Rock:IterateLibraries() do | |
2824 assert(name ~= "LibRockFakeLib-1.0") | |
2825 end | |
2826 | |
2827 local myLib, oldLib = Rock:NewLibrary("LibRockFakeLib-1.0", 1) | |
2828 assert(myLib) | |
2829 assert(myLib.name == "LibRockFakeLib-1.0") | |
2830 assert(not oldLib) | |
2831 | |
2832 assert(myLib:GetLibraryVersion() == "LibRockFakeLib-1.0") | |
2833 assert(select(2, myLib:GetLibraryVersion()) == 1) | |
2834 | |
2835 local good = false | |
2836 for name in Rock:IterateLibraries() do | |
2837 if name == "LibRockFakeLib-1.0" then | |
2838 good = true | |
2839 break | |
2840 end | |
2841 end | |
2842 assert(good) | |
2843 assert(Rock:HasLibrary("LibRockFakeLib-1.0")) | |
2844 assert(Rock:GetLibrary("LibRockFakeLib-1.0") == myLib) | |
2845 assert(Rock("LibRockFakeLib-1.0") == myLib) | |
2846 | |
2847 assert(not Rock:IsLibraryMixin("LibRockFakeLib-1.0")) | |
2848 function myLib:DoSomething() | |
2849 return "Something" | |
2850 end | |
2851 myLib:SetExportedMethods("DoSomething") | |
2852 assert(Rock:IsLibraryMixin("LibRockFakeLib-1.0")) | |
2853 local t = {} | |
2854 assert(not Rock:DoesObjectUseMixin(t, "LibRockFakeLib-1.0")) | |
2855 assert(not t.DoSomething) | |
2856 for mixin in Rock:IterateObjectMixins(t) do | |
2857 assert(false) | |
2858 end | |
2859 for object in Rock:IterateMixinObjects("LibRockFakeLib-1.0") do | |
2860 assert(false) | |
2861 end | |
2862 myLib:Embed(t) | |
2863 assert(t:DoSomething() == "Something") | |
2864 assert(Rock:DoesObjectUseMixin(t, "LibRockFakeLib-1.0")) | |
2865 for mixin in Rock:IterateObjectMixins(t) do | |
2866 assert(mixin == myLib) | |
2867 end | |
2868 for object in Rock:IterateMixinObjects("LibRockFakeLib-1.0") do | |
2869 assert(object == t) | |
2870 end | |
2871 | |
2872 Rock:FinalizeLibrary("LibRockFakeLib-1.0") | |
2873 | |
2874 local myNewLib, oldLib = Rock:NewLibrary("LibRockFakeLib-1.0", 2) | |
2875 assert(myNewLib == myLib) | |
2876 assert(oldLib) | |
2877 assert(Rock:GetLibrary("LibRockFakeLib-1.0") == myLib) | |
2878 | |
2879 function myLib:DoSomething() | |
2880 return "Something else" | |
2881 end | |
2882 function myLib:TrySomething() | |
2883 return "Blah" | |
2884 end | |
2885 myLib:SetExportedMethods("DoSomething", "TrySomething") | |
2886 assert(Rock:IsLibraryMixin("LibRockFakeLib-1.0")) | |
2887 assert(t:DoSomething() == "Something else") | |
2888 assert(t:TrySomething() == "Blah") | |
2889 assert(Rock:DoesObjectUseMixin(t, "LibRockFakeLib-1.0")) | |
2890 for mixin in Rock:IterateObjectMixins(t) do | |
2891 assert(mixin == myLib) | |
2892 end | |
2893 for object in Rock:IterateMixinObjects("LibRockFakeLib-1.0") do | |
2894 assert(object == t) | |
2895 end | |
2896 | |
2897 Rock:FinalizeLibrary("LibRockFakeLib-1.0") | |
2898 | |
2899 local myNewLib, oldLib = Rock:NewLibrary("LibRockFakeLib-1.0", 3) | |
2900 assert(myNewLib == myLib) | |
2901 assert(oldLib) | |
2902 assert(Rock:GetLibrary("LibRockFakeLib-1.0") == myLib) | |
2903 | |
2904 function myLib:DoSomething() | |
2905 return "Something" | |
2906 end | |
2907 myLib:SetExportedMethods("DoSomething") | |
2908 assert(Rock:IsLibraryMixin("LibRockFakeLib-1.0")) | |
2909 assert(t:DoSomething() == "Something") | |
2910 assert(t.TrySomething == nil) | |
2911 assert(Rock:DoesObjectUseMixin(t, "LibRockFakeLib-1.0")) | |
2912 for mixin in Rock:IterateObjectMixins(t) do | |
2913 assert(mixin == myLib) | |
2914 end | |
2915 for object in Rock:IterateMixinObjects("LibRockFakeLib-1.0") do | |
2916 assert(object == t) | |
2917 end | |
2918 | |
2919 Rock:FinalizeLibrary("LibRockFakeLib-1.0") | |
2920 | |
2921 assert(not Rock:NewLibrary("LibRockFakeLib-1.0", 2)) -- out of date | |
2922 assert(not Rock:NewLibrary("LibRockFakeLib-1.0", 3)) -- same revision | |
2923 end) | |
2924 | |
2925 Rock:AddUnitTest(MAJOR_VERSION, function() | |
2926 assert(not Rock:HasAddon("RockFakeAddon")) | |
2927 for name in Rock:IterateAddons() do | |
2928 assert(name ~= "RockFakeAddon") | |
2929 end | |
2930 | |
2931 local myAddon = Rock:NewAddon("RockFakeAddon") | |
2932 | |
2933 assert(myAddon) | |
2934 assert(myAddon.name == "RockFakeAddon") | |
2935 | |
2936 local good = false | |
2937 for name in Rock:IterateAddons() do | |
2938 if name == "RockFakeAddon" then | |
2939 good = true | |
2940 break | |
2941 end | |
2942 end | |
2943 assert(good) | |
2944 assert(Rock:HasAddon("RockFakeAddon")) | |
2945 assert(Rock:GetAddon("RockFakeAddon") == myAddon) | |
2946 end) | |
2947 | |
2948 Rock:AddUnitTest(MAJOR_VERSION, function() | |
2949 -- test :OnLibraryLoad | |
2950 local lib = Rock:NewLibrary("LibRockFakeLib-1.0", 1) | |
2951 local triggered = false | |
2952 function lib:OnLibraryLoad(major, instance) | |
2953 if major == "LibRockFakeLib-2.0" then | |
2954 triggered = true | |
2955 end | |
2956 end | |
2957 Rock:FinalizeLibrary("LibRockFakeLib-1.0") | |
2958 | |
2959 local lib = Rock:NewLibrary("LibRockFakeLib-2.0", 1) | |
2960 assert(not triggered) | |
2961 Rock:FinalizeLibrary("LibRockFakeLib-2.0") | |
2962 assert(triggered) | |
2963 triggered = false | |
2964 local lib = Rock:NewLibrary("LibRockFakeLib-2.0", 2) | |
2965 assert(not triggered) | |
2966 Rock:FinalizeLibrary("LibRockFakeLib-2.0") | |
2967 assert(not triggered) | |
2968 end) |