Feedback on Class for Number Plus Percent

Post Reply
Jor'Mox
Posts: 1142
Joined: Wed Apr 03, 2013 2:19 am

Feedback on Class for Number Plus Percent

Post by Jor'Mox »

I'm building a class to use to manage values that represent both a raw number and a percentage value, which I hope to use, among other things, to make my Simple Window Manager Script easier to use, and hopefully more reliable as well. I'm hoping for some feedback on ways to make what I have here better. Any help is appreciated.
Code: [show] | [select all] lua
local pick_complex = function(a,b)
    if type(a) == "table" and a.type == "complex number" then
        return a, b
    else
        return b, a
    end
end

local complex_number_class = {
    __add = function(a, b)
        local tmp,self,value
        self,value = pick_complex(a,b)
        if type(value) == "table" and value.type == "complex number" then
            tmp = complex_number_class:new(self.number + value.number, self.percent + value.percent, self.max)
        elseif type(value) == "string" and string.find(value,"%%") then
            value = string.gsub(value,"%%","")
            tmp = complex_number_class:new(self.number, self.percent + tonumber(value), self.max)
        elseif tonumber(value) then
            tmp = complex_number_class:new(self.number + tonumber(value), self.percent, self.max)
        else
            error("Complex Number Class: Add: value must be a number or a percentage",1)
        end
        return tmp
    end,
    
    __sub = function(a, b)
        local tmp,self,value
        self,value = pick_complex(a,b)
        if type(value) == "table" and value.type == "complex number" then
            tmp = complex_number_class:new(self.number - value.number, self.percent - value.percent, self.max)
        elseif type(value) == "string" and string.find(value,"%%") then
            value = string.gsub(value,"%%","")
            tmp = complex_number_class:new(self.number, self.percent - tonumber(value), self.max)
        elseif tonumber(value) then
            tmp = complex_number_class:new(self.number - tonumber(value), self.percent, self.max)
        else
            error("Complex Number Class: Subtract: value must be a number or a percentage",1)
        end
        return tmp
    end,
    
    __mul = function(a, b)
        local tmp
        a,b = pick_complex(a,b)
        if tonumber(b) then
            tmp = complex_number_class:new(a.number * b, a.percent * b, a.max)
        else
            error("Complex Number Class: Multiply: value must be a number or a percentage",1)
        end
        return tmp
    end,
    
    __div = function(a, b)
        local tmp
        if tonumber(b) then
            tmp = complex_number_class:new(a.number / b, a.percent / b, a.max)
        else
            error("Complex Number Class: Divide: value must be a number or a percentage",1)
        end
        return tmp
    end,
    
    __unm = function(self)
        local tmp = complex_number_class:new(0 - self.number, 0 - self.percent, self.max)
        return tmp
    end,
    
    __tostring = function(self)
        local str = self.number
        if self.percent >= 0 then
            str = str .. " + "
        else
            str = str .. " - "
        end
        str = str .. self.percent .. "%"
        return str
    end,
    
    __index = function(self, key)
        if key == "value" then
            return self:getValue()
        else
            return getmetatable(self)[key] or self._values[key]
        end
    end,
    
    __newindex = function(self,key,value)
        if key == "number" or key == "percent" or key == "max" then
            if tonumber(value) then
                self._values[key] = tonumber(value)
            else
                error("Complex Number Class: property values must be numbers",1)
            end
        else
            error("Complex Number Class: cannot add index/key to class object",1)
        end
    end,
    
    getValue = function(self,rnd)
        local val = self.number + self.max * (self.percent / 100)
        if rnd then val = math.round(val,rnd) end
        return val
    end,
    
    new = function(self,number,percent,maximum)
        local o = {_values = {number = number or 0, percent = percent or 0, max = maximum or 1, type = "complex number"}}
        setmetatable(o,self)
        return o
    end,
}

function newComplexNumber(number,percent,maximum)
    return complex_number_class:new(number,percent,maximum)
end
Edit: Learned a good bit as I was messing around with this after the original post, so the code has been significantly modified to be both more robust, and to conform better to what I want it to do.

User avatar
Vadi
Posts: 5035
Joined: Sat Mar 14, 2009 3:13 pm

Re: Feedback on Class for Number Plus Percent

Post by Vadi »

Just generic tips:
- localise your function references if you use them more than once (http://stackoverflow.com/questions/3294 ... ter-in-lua)
- you might or might not be frustrated not knowing what is the actual incorrect value you passed when you get an error
- avoid concatenation building strings, use an indexed table + table.concat (Strings chapter in https://www.lua.org/gems/sample.pdf)

Good luck with your custom type! :)

Post Reply