Quantcast

Correctly initialize the sandbox when translating profiles into scripts.

Johnny C. Lam [12-26-14 - 22:48]
Correctly initialize the sandbox when translating profiles into scripts.

The sandbox needs the correct class and specialization before generating
the script in case the translator uses the information.

Remove the GetValidProfiles() method from OvaleSimulationCraft and
directly embed the code into the translation scripts since that code must
be loaded and run before entering the sandbox.
Filename
SimulationCraft.lua
tests/simc.t
utils/generate.lua
diff --git a/SimulationCraft.lua b/SimulationCraft.lua
index d477b46..962536a 100644
--- a/SimulationCraft.lua
+++ b/SimulationCraft.lua
@@ -3581,90 +3581,6 @@ function OvaleSimulationCraft:Release(profile)
 	profile.actionList = nil
 end

--- Filter out invalid profile names from the given array of profile names.
-function OvaleSimulationCraft:GetValidProfiles(array)
-	-- Add any names to be filtered out into the filter table.
-	local filter = {}
-	for _, name in ipairs(array) do
-		local ok = true
-		local lowername = strlower(name)
-
-		-- Lexer for the profile filename.
-		local tokenIterator = gmatch(lowername, "[^_.]+")
-
-		-- Profile names always end in ".simc".
-		ok = ok and strsub(lowername, -5, -1) == ".simc"
-
-		local baseProfileName
-		-- Profile names always start with a class name.
-		if ok then
-			-- The first token should be the class.
-			local class = tokenIterator()
-			-- SimulationCraft uses "death_knight" while WoW uses "deathknight".
-			local wowClass = class
-			if class == "death" then
-				local token = tokenIterator()
-				class = class .. "_" .. token
-				wowClass = wowClass .. token
-			end
-			baseProfileName = class
-			wowClass = strupper(wowClass)
-			if not RAID_CLASS_COLORS[wowClass] then
-				ok = false
-			end
-			-- Skip class driver profile that just forces other profiles to be run.
-			if ok and strmatch(lowername, class .. "_t%d+[a-z].simc") then
-				ok = false
-			end
-		end
-
-		-- The next token should be the required specialization.
-		if ok then
-			local specialization = tokenIterator()
-			baseProfileName = baseProfileName .. "_" .. specialization
-		end
-
-		-- Filter out any profiles that are modifications of an existing base profile.
-		if ok then
-			-- Valid modifiers that can come before the tier designation that are part
-			-- of the base profile name.
-			local VALID_PRE_TIER_MODIFIER = {
-				["1h"] = true,
-				["2h"] = true,
-			}
-			local modifier = tokenIterator()
-			while ok and modifier do
-				if strmatch(modifier, "t%d+[a-z]") then
-					baseProfileName = baseProfileName .. "_" .. modifier
-					break
-				elseif VALID_PRE_TIER_MODIFIER[modifier] then
-					baseProfileName = baseProfileName .. "_" .. modifier
-				end
-				modifier = tokenIterator()
-			end
-			baseProfileName = baseProfileName .. ".simc"
-			if lowername ~= baseProfileName then
-				for _, fileName in ipairs(array) do
-					if baseProfileName == strlower(fileName) then
-						ok = false
-						break
-					end
-				end
-			end
-		end
-		if not ok then
-			filter[name] = true
-		end
-	end
-	for k = #array, 1, -1 do
-		if filter[array[k]] then
-			tremove(array, k)
-		end
-	end
-	tsort(array)
-	return array
-end
-
 function OvaleSimulationCraft:ParseProfile(simc)
 	local profile = {}
 	for line in gmatch(simc, "[^\r\n]+") do
diff --git a/tests/simc.t b/tests/simc.t
index 83645d3..b5cfaf7 100644
--- a/tests/simc.t
+++ b/tests/simc.t
@@ -1,42 +1,46 @@
--- Create WoWMock sandbox.
-local root = "../"
-dofile(root .. "WoWMock.lua")
-local sandbox = WoWMock:NewSandbox()
-
--- Load addon files into the sandbox.
-sandbox:LoadAddonFile("Ovale.toc", root)
+--[[
+	Load each SimulationCraft profile and do the following things:

--- Fire events to simulate the addon-loading process.
-sandbox:Fire("ADDON_LOADED")
-sandbox:Fire("SPELLS_CHANGED")
-sandbox:Fire("PLAYER_LOGIN")
-sandbox:Fire("PLAYER_ENTERING_WORLD")
+	1. Unparse the profile to verify the action list is being properly parsed.
+	2. Emit the corresponding Ovale script to standard output.
+--]]

--- Enter sandbox.
-setfenv(1, sandbox)
+-- Constants.
+local profilesDirectory = "../../SimulationCraft/profiles/Tier17M"
+local root = "../"
+local separator = string.rep("-", 80)

-local OvaleSimulationCraft = Ovale.OvaleSimulationCraft
+local SIMC_CLASS = {
+	deathknight = true,
+	druid = true,
+	hunter = true,
+	mage = true,
+	monk = true,
+	paladin = true,
+	priest = true,
+	rogue = true,
+	shaman = true,
+	warlock = true,
+	warrior = true,
+}

+local gmatch = string.gmatch
 local gsub = string.gsub
 local ipairs = ipairs
 local strfind = string.find
+local strlen = string.len
+local strlower = string.lower
+local strsub = string.sub
+local strupper = string.upper
 local tinsert = table.insert
-
-local profilesDirectory = "../../SimulationCraft/profiles/Tier17M"
+local tremove = table.remove
+local tsort = table.sort

 -- Save original input and output handles.
 local saveInput = io.input()
 local saveOutput = io.output()

---[[
-	Load each SimulationCraft profile and do the following things:
-
-	1. Unparse the profile to verify the action list is being properly parsed.
-	2. Emit the corresponding Ovale script to standard output.
---]]
-
-local separator = string.rep("-", 80)
-
+-- Get the valid profile names from the profiles directory.
 local files = {}
 do
 	local dir = io.popen("dir /b " .. gsub(profilesDirectory, "/", "\\"))
@@ -44,7 +48,85 @@ do
 		tinsert(files, name)
 	end
 	dir:close()
-	OvaleSimulationCraft:GetValidProfiles(files)
+
+	-- Filter out invalid profile names.
+	local filter = {}
+	for _, name in ipairs(files) do
+		local ok = true
+		local lowername = strlower(name)
+
+		-- Lexer for the profile filename.
+		local tokenIterator = gmatch(lowername, "[^_.]+")
+
+		-- Profile names always end in ".simc".
+		ok = ok and strsub(lowername, -5, -1) == ".simc"
+
+		local baseProfileName
+		-- Profile names always start with a class name.
+		if ok then
+			-- The first token should be the class.
+			local class = tokenIterator()
+			-- SimulationCraft uses "death_knight" while WoW uses "deathknight".
+			local wowClass = class
+			if class == "death" then
+				local token = tokenIterator()
+				class = class .. "_" .. token
+				wowClass = wowClass .. token
+			end
+			baseProfileName = class
+			if not SIMC_CLASS[wowClass] then
+				ok = false
+			end
+			-- Skip class driver profile that just forces other profiles to be run.
+			if ok and strfind(lowername, class .. "_t%d+[a-z].simc") then
+				ok = false
+			end
+		end
+
+		-- The next token should be the required specialization.
+		if ok then
+			local specialization = tokenIterator()
+			baseProfileName = baseProfileName .. "_" .. specialization
+		end
+
+		-- Filter out any profiles that are modifications of an existing base profile.
+		if ok then
+			-- Valid modifiers that can come before the tier designation that are part
+			-- of the base profile name.
+			local VALID_PRE_TIER_MODIFIER = {
+				["1h"] = true,
+				["2h"] = true,
+			}
+			local modifier = tokenIterator()
+			while ok and modifier do
+				if strfind(modifier, "t%d+[a-z]") then
+					baseProfileName = baseProfileName .. "_" .. modifier
+					break
+				elseif VALID_PRE_TIER_MODIFIER[modifier] then
+					baseProfileName = baseProfileName .. "_" .. modifier
+				end
+				modifier = tokenIterator()
+			end
+			baseProfileName = baseProfileName .. ".simc"
+			if lowername ~= baseProfileName then
+				for _, fileName in ipairs(files) do
+					if baseProfileName == strlower(fileName) then
+						ok = false
+						break
+					end
+				end
+			end
+		end
+		if not ok then
+			filter[name] = true
+		end
+	end
+	for k = #files, 1, -1 do
+		if filter[files[k]] then
+			tremove(files, k)
+		end
+	end
+	tsort(files)
 end

 for _, name in ipairs(files) do
@@ -53,6 +135,48 @@ for _, name in ipairs(files) do
 	local simc = io.read("*all")
 	-- Valid profiles never set "optimal_raid".
 	if not strfind(simc, "optimal_raid=") then
+		-- Find the class and specialization from the profile.
+		local class, specialization
+		for line in gmatch(simc, "[^\r\n]+") do
+			if not class then
+				for simcClass in pairs(SIMC_CLASS) do
+					local length = strlen(simcClass)
+					if strsub(line, 1, length + 1) == simcClass .. "=" then
+						class = strupper(simcClass)
+					end
+				end
+			end
+			if not specialization then
+				if strsub(line, 1, 5) == "spec=" then
+					specialication = strsub(line, 6)
+				end
+			end
+			if class and specialization then
+				break
+			end
+		end
+		-- Create WoWMock sandbox.
+		dofile(root .. "WoWMock.lua")
+		local config = {
+			class = class,
+			specialization = specialization,
+		}
+		local sandbox = WoWMock:NewSandbox(config)
+
+		-- Load addon files into the sandbox.
+		sandbox:LoadAddonFile("Ovale.toc", root)
+
+		-- Fire events to simulate the addon-loading process.
+		sandbox:Fire("ADDON_LOADED")
+		sandbox:Fire("SPELLS_CHANGED")
+		sandbox:Fire("PLAYER_LOGIN")
+		sandbox:Fire("PLAYER_ENTERING_WORLD")
+
+		-- Enter sandbox.
+		setfenv(1, sandbox)
+
+		local OvaleSimulationCraft = Ovale.OvaleSimulationCraft
+
 		-- Parse SimulationCraft profile and emit the corresponding Ovale script.
 		local profile = OvaleSimulationCraft:ParseProfile(simc)
 		if profile then
diff --git a/utils/generate.lua b/utils/generate.lua
index c9ece95..9d3f890 100644
--- a/utils/generate.lua
+++ b/utils/generate.lua
@@ -1,38 +1,44 @@
--- Create WoWMock sandbox.
+-- Constants.
+local outputDirectory = "../scripts"
+local profilesDirectory = "../../SimulationCraft/profiles/Tier17M"
 local root = "../"
-dofile(root .. "WoWMock.lua")
-local sandbox = WoWMock:NewSandbox()
-
--- Load addon files into the sandbox.
-sandbox:LoadAddonFile("Ovale.toc", root)

--- Fire events to simulate the addon-loading process.
-sandbox:Fire("ADDON_LOADED")
-sandbox:Fire("SPELLS_CHANGED")
-sandbox:Fire("PLAYER_LOGIN")
-sandbox:Fire("PLAYER_ENTERING_WORLD")
-
--- Enter sandbox.
-setfenv(1, sandbox)
-
-local OvaleSimulationCraft = Ovale.OvaleSimulationCraft
+local SIMC_CLASS = {
+	deathknight = true,
+	druid = true,
+	hunter = true,
+	mage = true,
+	monk = true,
+	paladin = true,
+	priest = true,
+	rogue = true,
+	shaman = true,
+	warlock = true,
+	warrior = true,
+}

 local format = string.format
+local gmatch = string.gmatch
 local gsub = string.gsub
+local ipairs = ipairs
 local strfind = string.find
+local strlen = string.len
 local strlower = string.lower
 local strsub = string.sub
+local strupper = string.upper
 local tconcat = table.concat
 local tinsert = table.insert
-local wipe = wipe
-
-local profilesDirectory = "../../SimulationCraft/profiles/Tier17M"
-local outputDirectory = "../scripts"
+local tremove = table.remove
+local tsort = table.sort

 -- Save original input and output handles.
 local saveInput = io.input()
 local saveOutput = io.output()

+-- Create the output directory.
+os.execute("mkdir " .. gsub(outputDirectory, "/", "\\"))
+
+-- Get the valid profile names from the profiles directory.
 local files = {}
 do
 	local dir = io.popen("dir /b " .. gsub(profilesDirectory, "/", "\\"))
@@ -40,11 +46,85 @@ do
 		tinsert(files, name)
 	end
 	dir:close()
-	OvaleSimulationCraft:GetValidProfiles(files)

-	-- Create the output directory.
-	local outputDir =
-	os.execute("mkdir " .. gsub(outputDirectory, "/", "\\"))
+	-- Filter out invalid profile names.
+	local filter = {}
+	for _, name in ipairs(files) do
+		local ok = true
+		local lowername = strlower(name)
+
+		-- Lexer for the profile filename.
+		local tokenIterator = gmatch(lowername, "[^_.]+")
+
+		-- Profile names always end in ".simc".
+		ok = ok and strsub(lowername, -5, -1) == ".simc"
+
+		local baseProfileName
+		-- Profile names always start with a class name.
+		if ok then
+			-- The first token should be the class.
+			local class = tokenIterator()
+			-- SimulationCraft uses "death_knight" while WoW uses "deathknight".
+			local wowClass = class
+			if class == "death" then
+				local token = tokenIterator()
+				class = class .. "_" .. token
+				wowClass = wowClass .. token
+			end
+			baseProfileName = class
+			if not SIMC_CLASS[wowClass] then
+				ok = false
+			end
+			-- Skip class driver profile that just forces other profiles to be run.
+			if ok and strfind(lowername, class .. "_t%d+[a-z].simc") then
+				ok = false
+			end
+		end
+
+		-- The next token should be the required specialization.
+		if ok then
+			local specialization = tokenIterator()
+			baseProfileName = baseProfileName .. "_" .. specialization
+		end
+
+		-- Filter out any profiles that are modifications of an existing base profile.
+		if ok then
+			-- Valid modifiers that can come before the tier designation that are part
+			-- of the base profile name.
+			local VALID_PRE_TIER_MODIFIER = {
+				["1h"] = true,
+				["2h"] = true,
+			}
+			local modifier = tokenIterator()
+			while ok and modifier do
+				if strfind(modifier, "t%d+[a-z]") then
+					baseProfileName = baseProfileName .. "_" .. modifier
+					break
+				elseif VALID_PRE_TIER_MODIFIER[modifier] then
+					baseProfileName = baseProfileName .. "_" .. modifier
+				end
+				modifier = tokenIterator()
+			end
+			baseProfileName = baseProfileName .. ".simc"
+			if lowername ~= baseProfileName then
+				for _, fileName in ipairs(files) do
+					if baseProfileName == strlower(fileName) then
+						ok = false
+						break
+					end
+				end
+			end
+		end
+		if not ok then
+			filter[name] = true
+		end
+	end
+	for k = #files, 1, -1 do
+		if filter[files[k]] then
+			tremove(files, k)
+		end
+	end
+	tsort(files)
 end

 local output = {}
@@ -54,6 +134,50 @@ for _, filename in ipairs(files) do
 	local simc = io.read("*all")
 	-- Valid profiles never set "optimal_raid".
 	if not strfind(simc, "optimal_raid=") then
+		-- Find the class and specialization from the profile.
+		local class, specialization
+		for line in gmatch(simc, "[^\r\n]+") do
+			if not class then
+				for simcClass in pairs(SIMC_CLASS) do
+					local length = strlen(simcClass)
+					if strsub(line, 1, length + 1) == simcClass .. "=" then
+						class = strupper(simcClass)
+					end
+				end
+			end
+			if not specialization then
+				if strsub(line, 1, 5) == "spec=" then
+					specialication = strsub(line, 6)
+				end
+			end
+			if class and specialization then
+				break
+			end
+		end
+
+		-- Create WoWMock sandbox.
+		dofile(root .. "WoWMock.lua")
+		local config = {
+			class = class,
+			specialization = specialization,
+		}
+		local sandbox = WoWMock:NewSandbox(config)
+
+		-- Load addon files into the sandbox.
+		sandbox:LoadAddonFile("Ovale.toc", root)
+
+		-- Fire events to simulate the addon-loading process.
+		sandbox:Fire("ADDON_LOADED")
+		sandbox:Fire("SPELLS_CHANGED")
+		sandbox:Fire("PLAYER_LOGIN")
+		sandbox:Fire("PLAYER_ENTERING_WORLD")
+
+		-- Enter sandbox.
+		setfenv(1, sandbox)
+
+		local OvaleSimulationCraft = Ovale.OvaleSimulationCraft
+		local wipe = wipe
+
 		-- Parse SimulationCraft profile and emit the corresponding Ovale script.
 		local profile = OvaleSimulationCraft:ParseProfile(simc)
 		local name = format("SimulationCraft: %s", strsub(profile.annotation.name, 2, -2))
@@ -82,6 +206,7 @@ for _, filename in ipairs(files) do
 		local outputName = outputDirectory .. "/" .. outputFileName
 		io.output(outputName)
 		io.write(tconcat(output, "\n"))
+		io.close()
 	end
 end