This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
Maarten551's profile picture

[1.33] [0.1] Variable Register

Started by Maarten551, 03 June 2012 - 04:47 PM
Maarten551 #1
Posted 03 June 2012 - 06:47 PM
Hello people, Today, I have a new API to show you guys!

Introduction

I was writing a program, when I noticed that I needed a register to save my variables. So I build one!

What does it do First it makes a new file named : "registerFile" in the map "saves\[World name]\computer\[computer ID]\register". In this file, all the variables will be saved, so not one file for every variable! The file looks like this :
variable1 = something
lol = Lauging Out Loud
count = 181

This API comes with a few commands to make easier to handle.

Features
  • It uses only one file!
  • The file and the map will be created by itself.
  • You can acces all the variables on anytime and with any program you want.
  • It's possible to insert a new variable or change a variable manual.
  • Easy to use!
  • Converts and decode variables that can break register [Ver 0.1.1]
Notes (Important read these before programming)
  • Place the file into : ".minecraft\mods\ComputerCraft\lua\rom\apis\"
  • The maximum length of a variable is 35.
  • I don't know really how to start the API, because it starts automatic on my terminal? But I quess you need to do : os.loadAPI("/rom/apis/varRegister")
  • This is still in beta.
  • Please, if you found any error or problem, send me a message or post it here!
Download

Mediafire link : http://www.mediafire...ipm89gy1ypt4rss

Commands

varRegister.getVersion() – return the current version

varRegister.saveVar(variablename, input) – This saves a variable, or if it already exists, it will overwrite it. for example :
varRegister.saveVar("count", "1")

varRegister.loadVar(variable) – This loads the variable, it will return as an string,it will return nil when nothing is found. for example :
 if varRegister.loadVar("count") == "20" then print "Yeah, variable 'count' == 20 :D/>/>" else print "Ahhhh the variable isn't 20 :)/>/>" end 

varRegister.ifExists(variable) – returns a boolean if the variable exists, for example :
 if not varRegister.ifExists("count") then varRegister.saveVar("count", "1") else varRegister.saveVar("count", (tonumber(varRegister.loadVar("count"))+1)) end 

varRegister.list() – This will return all variables in an array, for example :
 local list = varRegister.list() for k,l in pairs(list) do print(k.." = "..l) end

This will print all the variables, you can also pick a single variable :
 local list = varRegister.list() print(list["count"])

Code

Spoiler

function getVersion()
	return "0.1.1"
end
local function makeLocation()
	if not fs.isDir("register") then fs.makeDir("register") end
	if not fs.exists("register/registerFile") then
		createMap = fs.open("register/registerFile", "w")
		createMap.close()
	end
end
local function decodeData(data)
	for i=1,20,1 do
		if string.sub(data, i, (i)) == "=" then
			return string.sub(data, 1, (i-2)), string.sub(data, (i+2), string.len(data))
		end
	end
end
local function convertData(cleanData)
	local chars = {"=", "/n", " "}
	local changeTo = {"$&1", "$&2", "$&3"}
	local newData = cleanData
	for i=1, table.getn(chars), 1 do
		newData = string.gsub(newData, chars[i], changeTo[i])
	end
	return newData
end
local function convertBack(convertedData)
	local chars = {"$&1", "$&2", "$&3"}
	local changeTo = {"=", "/n", " "}
	local newData = convertedData
	for i=1, table.getn(chars), 1 do
		newData = string.gsub(newData, chars[i], changeTo[i])
	end
	return newData
end
local function changeVar(data, varInput)
	for i=1,35,1 do
		if string.sub(data, i, (i)) == "=" then
			return string.sub(data, 1, (i)).." "..convertData(varInput)
		end
	end
end
function ifExists(varName)
	makeLocation()
	registerFile = fs.open("register/registerFile", "r")
	check = registerFile.readLine() or ""
	while check ~= "" and check ~= nil do
		if convertData(decodeData(check)) == convertData(varName) then
			return true
		end
		check = registerFile.readLine() or ""
	end
	registerFile.close()
	return false
end
function list()
	makeLocation()
	local registerFile = fs.open("register/registerFile", "r")
	local varList = {}
	local check = registerFile.readLine() or ""
	while check ~= "" and check ~= nil do
		variable, answer = decodeData(check)
		varList[convertBack(variable)] = convertBack(answer)
		check = registerFile.readLine() or ""
	end
	registerFile.close()
	return varList
end
function loadVar(varName)
	makeLocation()
	local registerFile = fs.open("register/registerFile", "r")
	local check = registerFile.readLine() or ""
	while check ~= "" and check ~= nil do
		variable, answer = decodeData(check)
		if convertBack(variable) == varName then
			return convertBack(answer)
		end
		check = registerFile.readLine() or ""
	end
	registerFile.close()
	return nil
end
function saveVar(varName, varInput)
	if varName ~= nul and varInput ~= nul then
		makeLocation()
		if ifExists(varName) then
			local registerFile = fs.open("register/registerFile", "r")
			local check = registerFile.readLine() or ""
			local newFile = ""
			while check ~= "" and check ~= nil do
				if convertData(decodeData(check)) == convertData(varName) then
					newFile = newFile..changeVar(check, varInput).."\n"
				else
					newFile = newFile..check.."\n"
				end
				check = registerFile.readLine() or ""
			end
			registerFile.close()
			local save = fs.open("register/registerFile", "w")
			save.write(newFile)
			save.close()
		else
			local oldFile = fs.open("register/registerFile", "r")
			oldFile = oldFile.readAll()
			local newFile = fs.open("register/registerFile", "w")
			if oldFile ~= "" then
				newFile.write(oldFile.."\n"..convertData(varName).." = "..convertData(varInput))
			else
				newFile.write(oldFile..convertData(varName).." = "..convertData(varInput))
			end
			newFile.close()
			return true
		end
	else
		print "Missing arguments, please enter in order : varName, varInput"
		return false
	end
end

Installation
  1. Download the file from mediafire.
  2. go to this derictory "%appdata%\.minecraft\mods\ComputerCraft\lua\rom\apis" and place the file you downloaded from mediafire.
  3. Write the following line into your code : os.loadAPI("/rom/apis/varRegister")
  4. Have fun writing applications with this ^^.
To do
  • Fix some simple bugs
  • Improve the performance
  • Add more commands
  • Add suggestions?
Conclusion I hope you guys will enjoy with this API and I like to hear your opinions, so don't be afraid to post it. And I like to say that I'm sorry for my English, it's a foreign language for me.
Roujo #2
Posted 04 June 2012 - 10:31 PM
Very nice! I'm currently coding something along the same lines, so it's nice to see that I'm not the only one trying to avoid the "one file per value" way of doing a registry. =)

Is there any reason why you're not using append mode when you're adding a key/value pair to the registry? That's what I'm doing, and I think it would be better performance wise - no need to read the whole file - but I'm not sure, so I'd like to know why you made that design choice.

Keep up the good work!
kazagistar #3
Posted 04 June 2012 - 11:46 PM
Flat registry files may be appealing, but the need to parse through the entire file in detail for every read or save is a cost that is only worth it is small use cases. The speedier solution is to just create a file for each variable. Also, the ability to have separate registries eliminates some of the namespace conflicts that would happen if multiple different authors tried to use the registry, so the ability to specify a "current working registry file" would be good.

I would look out for parsing edge cases… saveVar("a=b", "c") and saveVar("a", "b=c") would result in undesirable results. Also, saveVar("n","") will break your registry forever. I recommend adding data validation so people don't use values that are not legal.

Some optimizations: ifExists can be eliminated from code, since it is trivially equivalent to loadVar(name)==nil. Even the code for these functions looks identical. I would also recommend renaming makeLocation() to getRegistryFile() and having it return the registerFile name (so that you can more easily change location of the file in code).

I'm done for now. I don't mean to sound harsh, but persistence APIs are one of the most popular things to make in computer craft, so there is a lot of competition. :)/>/>
Maarten551 #4
Posted 05 June 2012 - 11:38 AM
First of all, thank you guys for the responds.
It doesn't matter if it's positive or negative, aslong I can learn from it.

@Roujo
I have chosen this method because, i'm not that very good at LUA, you can see that I have only 7 posts(8 by now).
Also don't forgot that this project is in early stage and is still in beta, I will try to advance this and make it more stable.
BTW : Thanks for the tip, I will try to learn more about the 'pending mode', I simple don't know it.

@kazagistar
I'm aware that reading the whole file isn't the fastest way, I will try to improve the system.
About the parsing part : I know the issue, and I have already found a solution for it.
I will parse "=" in "%&1"(or something) and "n" in "%&2", when someone want to load the variable, I will simple deparse(the opposite of parse :)/>/> ) it so they still can use the "=" and "n".
And indeed the 'ifExists()' is almost the exact code of 'loadVar()', but instead of returning nill it will return false. I thought it looks cleaner in the code ^^.
BreezerFly #5
Posted 05 June 2012 - 05:46 PM
Can't you just keep an in-memory list of the variables and on every .setVar you just overwrite the file (1 line) and to return variables, you have a list already?
Maarten551 #6
Posted 05 June 2012 - 06:20 PM
Can't you just keep an in-memory list of the variables and on every .setVar you just overwrite the file (1 line) and to return variables, you have a list already?

Hmmm, but sometimes, the program doesn't need the variables.
So why would I pre-load it? It will only cost time.
Edited on 06 June 2012 - 12:49 PM
Maarten551 #7
Posted 09 June 2012 - 11:50 PM
version 0.1.1 is out!

changelog
* characters that can break the register will be converted!


For example, You want to save this variable : varRegister.saveVar("/ntroll = ", "=troll=")
After this is saved, the variable in the register will look like this : $&2troll$&3$&1$&3 = $&1troll$&1

The download link is changed in the main post!

Code :
Spoiler

function getVersion()
return "0.1.1"
end
local function makeLocation()
if not fs.isDir("register") then fs.makeDir("register") end
if not fs.exists("register/registerFile") then
  createMap = fs.open("register/registerFile", "w")
  createMap.close()
end
end
local function decodeData(data)
for i=1,20,1 do
  if string.sub(data, i, (i)) == "=" then
   return string.sub(data, 1, (i-2)), string.sub(data, (i+2), string.len(data))
  end
end
end
local function convertData(cleanData)
local chars = {"=", "/n", " "}
local changeTo = {"$&1", "$&2", "$&3"}
local newData = cleanData
for i=1, table.getn(chars), 1 do
  newData = string.gsub(newData, chars[i], changeTo[i])
end
return newData
end
local function convertBack(convertedData)
local chars = {"$&1", "$&2", "$&3"}
local changeTo = {"=", "/n", " "}
local newData = convertedData
for i=1, table.getn(chars), 1 do
  newData = string.gsub(newData, chars[i], changeTo[i])
end
return newData
end
local function changeVar(data, varInput)
for i=1,35,1 do
  if string.sub(data, i, (i)) == "=" then
   return string.sub(data, 1, (i)).." "..convertData(varInput)
  end
end
end
function ifExists(varName)
makeLocation()
registerFile = fs.open("register/registerFile", "r")
check = registerFile.readLine() or ""
while check ~= "" and check ~= nil do
  if convertData(decodeData(check)) == convertData(varName) then
   return true
  end
  check = registerFile.readLine() or ""
end
registerFile.close()
return false
end
function list()
makeLocation()
local registerFile = fs.open("register/registerFile", "r")
local varList = {}
local check = registerFile.readLine() or ""
while check ~= "" and check ~= nil do
  variable, answer = decodeData(check)
  varList[convertBack(variable)] = convertBack(answer)
  check = registerFile.readLine() or ""
end
registerFile.close()
return varList
end
function loadVar(varName)
makeLocation()
local registerFile = fs.open("register/registerFile", "r")
local check = registerFile.readLine() or ""
while check ~= "" and check ~= nil do
  variable, answer = decodeData(check)
  if convertBack(variable) == varName then
   return convertBack(answer)
  end
  check = registerFile.readLine() or ""
end
registerFile.close()
return nil
end
function saveVar(varName, varInput)
if varName ~= nul and varInput ~= nul then
  makeLocation()
  if ifExists(varName) then
   local registerFile = fs.open("register/registerFile", "r")
   local check = registerFile.readLine() or ""
   local newFile = ""
   while check ~= "" and check ~= nil do
	if convertData(decodeData(check)) == convertData(varName) then
	 newFile = newFile..changeVar(check, varInput).."n"
	else
	 newFile = newFile..check.."n"
	end
	check = registerFile.readLine() or ""
   end
   registerFile.close()
   local save = fs.open("register/registerFile", "w")
   save.write(newFile)
   save.close()
  else
   local oldFile = fs.open("register/registerFile", "r")
   oldFile = oldFile.readAll()
   local newFile = fs.open("register/registerFile", "w")
   if oldFile ~= "" then
	newFile.write(oldFile.."n"..convertData(varName).." = "..convertData(varInput))
   else
	newFile.write(oldFile..convertData(varName).." = "..convertData(varInput))
   end
   newFile.close()
   return true
  end
else
  print "Missing arguments, please enter in order : varName, varInput"
  return false
end
end
veiIeddraconis #8
Posted 19 December 2012 - 12:33 AM
And indeed the 'ifExists()' is almost the exact code of 'loadVar()', but instead of returning nill it will return false. I thought it looks cleaner in the code ^^.

I can understand you might think it looks cleaner in code, but to another programmer it would be more confusing. Since lua interprets a nil return as false it is completely redundant. I would suggest instead that you simply comment on your functions to explain functionality.
Tiin57 #9
Posted 19 December 2012 - 08:03 AM
And indeed the 'ifExists()' is almost the exact code of 'loadVar()', but instead of returning nill it will return false. I thought it looks cleaner in the code ^^.

I can understand you might think it looks cleaner in code, but to another programmer it would be more confusing. Since lua interprets a nil return as false it is completely redundant. I would suggest instead that you simply comment on your functions to explain functionality.
Please look at the dates before you post; you're continuing a five month old discussion.