Creating New Scripts Dynamically in Lua
For absolute clarity, here is the code that the questions asks to review (this is lua):
local ScriptWriter = {}
local twoSpaceIndent = " "
local equalsWithSpaces = " = "
local newLine = "\n"
--scriptNameToCreate must be a string
--argumentsForNew and instanceVariablesToCreate must be tables and not nil
function ScriptWriter:new(scriptNameToCreate, argumentsForNew, instanceVariablesToCreate)
local instance = setmetatable({}, { __index = self })
instance.name = scriptNameToCreate
instance.newArguments = argumentsForNew
instance.instanceVariables = instanceVariablesToCreate
instance.stringList = {}
return instance
end
function ScriptWriter:makeFileForLoadedSettings()
self:buildInstanceMetatable()
self:buildInstanceCreationMethod()
self:buildSettersAndGetters()
self:buildReturn()
self:writeStringsToFile()
end
--very first line of any script that will have instances
function ScriptWriter:buildInstanceMetatable()
table.insert(self.stringList, "local " .. self.name .. " = {}" .. newLine)
table.insert(self.stringList, newLine)
end
--every script made this way needs a new method to create its instances
function ScriptWriter:buildInstanceCreationMethod()
--new() function declaration
table.insert(self.stringList, ("function " .. self.name .. ":new("))
self:buildNewArguments()
table.insert(self.stringList, ")" .. newLine)
--first line inside :new() function
table.insert(self.stringList, twoSpaceIndent .. "local instance = setmetatable({}, { __index = self })" .. newLine)
--add designated arguments inside :new()
self:buildNewArgumentVariables()
--create the instance variables with the loaded values
for key,value in pairs(self.instanceVariables) do
table.insert(self.stringList, twoSpaceIndent .. "instance." .. key .. equalsWithSpaces .. value .. newLine)
end
--close the :new() function
table.insert(self.stringList, twoSpaceIndent .. "return instance" .. newLine)
table.insert(self.stringList, "end" .. newLine)
table.insert(self.stringList, newLine)
end
function ScriptWriter:buildNewArguments()
--if there are arguments for :new(), add them
for key,value in ipairs(self.newArguments) do
table.insert(self.stringList, value)
table.insert(self.stringList, ", ")
end
if next(self.newArguments) ~= nil then --makes sure the table is not empty first
table.remove(self.stringList) --remove the very last element, which will be the extra ", "
end
end
function ScriptWriter:buildNewArgumentVariables()
--add the designated arguments to :new()
for key, value in ipairs(self.newArguments) do
table.insert(self.stringList, twoSpaceIndent .. "instance." .. value .. equalsWithSpaces .. value .. newLine)
end
end
--the instance variables need separate code because their names have to be the key and not the argument name
function ScriptWriter:buildSettersAndGetters()
for key,value in ipairs(self.newArguments) do
self:buildArgumentSetter(value)
self:buildArgumentGetter(value)
table.insert(self.stringList, newLine)
end
for key,value in pairs(self.instanceVariables) do
self:buildInstanceVariableSetter(key, value)
self:buildInstanceVariableGetter(key, value)
table.insert(self.stringList, newLine)
end
end
--code for arguments passed in
function ScriptWriter:buildArgumentSetter(variable)
table.insert(self.stringList, "function " .. self.name .. ":set_" .. variable .. "(newValue)" .. newLine)
table.insert(self.stringList, twoSpaceIndent .. "self." .. variable .. equalsWithSpaces .. "newValue" .. newLine)
table.insert(self.stringList, "end" .. newLine)
end
function ScriptWriter:buildArgumentGetter(variable)
table.insert(self.stringList, "function " .. self.name .. ":get_" .. variable .. "()" .. newLine)
table.insert(self.stringList, twoSpaceIndent .. "return " .. "self." .. variable .. newLine)
table.insert(self.stringList, "end" .. newLine)
end
--code for instance variable values passed in
function ScriptWriter:buildInstanceVariableSetter(key, variable)
table.insert(self.stringList, "function " .. self.name .. ":set_" .. key .. "(newValue)" .. newLine)
table.insert(self.stringList, twoSpaceIndent .. "self." .. key .. equalsWithSpaces .. "newValue" .. newLine)
table.insert(self.stringList, "end" .. newLine)
end
function ScriptWriter:buildInstanceVariableGetter(key, variable)
table.insert(self.stringList, "function " .. self.name .. ":get_" .. key .. "()" .. newLine)
table.insert(self.stringList, twoSpaceIndent .. "return " .. "self." .. key .. newLine)
table.insert(self.stringList, "end" .. newLine)
end
--last line of any script that will have instances
function ScriptWriter:buildReturn()
table.insert(self.stringList, "return " .. self.name)
end
function ScriptWriter:writeStringsToFile()
local fileName = (self.name .. ".lua")
file = io.open(fileName, 'w')
for key,value in ipairs(self.stringList) do
file:write(value)
end
file:close()
end
return ScriptWriter
The other two code snippets provided in the question are provided purely as context code.
Moreover, the last bit of the questions makes it clear what the asker wants:
I am not sure if I am correct that this could be useful in certain situations. What I am looking for is feedback on the readability of the code, and following Lua best practices. I would also love to hear whether this approach is a valid one, and whether the way that I have done things will be extensible.
This question sounds on-topic to me. And I can't see what in the provided code snippet would warrant moving the question.
Did this question get moved because of the context examples provided? That seems highly inappropriate. Would this question be better for CodeReview without the usage and output examples?
The actual reason this question was migrated seems to be because the migrator determined this question was off-topic for Code Review, but was still interesting and would work on another SE website. I understand that this question could be a good fit for where it was migrated to, so if we could instead focus on whether or not it's a good fit for Code Review and if not, why, that would be appreciated.