Chelmite
Chelmite

Reputation: 390

How can I access a “property” by the name, given as a string?

I'm trying to build some objects in Lua. I found http://lua-users.org/wiki/ObjectProperties, and http://lua-users.org/wiki/SimpleLuaClasses, which allowed me to build:

package.path = "../src/?.lua;" .. package.path
require("class")

Feeds = {}
Feeds.__index = Feeds

-- Make proxy object with property support.
-- Notes:
--   If key is found in <getters> (or <setters>), then
--     corresponding function is used, else lookup turns to the
--     <class> metatable (or first to <priv> if <is_expose_private> is true).
--   Given a proxy object <self>, <priv> can be obtained with
--     getmetatable(self).priv .
-- @param class - metatable acting as the object class.
-- @param priv - table containing private data for object.
-- @param getters - table of getter functions
--                  with keys as property names. (default is nil)
-- @param setters - table of setter functions,
--                  with keys as property names. (default is nil)
-- @param is_expose_private - Boolean whether to expose <priv> through proxy.
--                  (default is nil/false)
-- @version 3 - 20060921 (D.Manura)
local function make_proxy(class, priv, getters, setters, is_expose_private)
  setmetatable(priv, class)  -- fallback priv lookups to class
  local fallback = is_expose_private and priv or class
  local index = getters and
    function(self, key)
      -- read from getter, else from fallback
      local func = getters[key]
      if func then return func(self) else return fallback[key] end
    end
    or fallback  -- default to fast property reads through table
  local newindex = setters and
    function(self, key, value)
      -- write to setter, else to proxy
      local func = setters[key]
      if func then func(self, value)
      else rawset(self, key, value) end
    end
    or fallback  -- default to fast property writes through table
  local proxy_mt = {         -- create metatable for proxy object
    __newindex = newindex,
    __index = index,
    priv = priv
  }
  local self = setmetatable({}, proxy_mt)  -- create proxy object
  return self
end

function Feeds:new(...)
   local names = {
      "material",
      "diameter",
      "flutes",
      "pass_depth",
      "stepover",
      "entry",
      "aggressiveness",
      "spindle_speed",
      "feedrate",
      "entry_rate",
      "sec_per_in",
      "delta_t",
      "feed_better",
      "hp",
      "hp_percent",
      "deflection",
      "defl_percent",
      "mrr",
      "surface_speed",
      "chipload"}
   local rv = {}
   local p
   for i, v in ipairs(...) do
      if i <= #names then
--        print("for ".. i .. "\t" .. names[i] .. ": "..v)
        rv[names[i]] = v
      end
   end
  return make_proxy(Feeds, rv, Feeds_getters, Feeds_setters) 
end


local Feeds_attribute_setters = {
  material = function(self, material)
    local priv = getmetatable(self).priv
    assert(type(material) == "string")
    priv.material = material
  end
}

local Feeds_getters = {
  b = function(self, value)
    local priv = getmetatable(self).priv
    return priv.a
  end
}

Unlike the simple examples on the above web pages (a single parameter, called a that's set to 5.), I have an object that takes 20 positional parameters. (They're columns from a spreadsheet.) The names of these parameters are shown as the local names.

The parameters seem to be set properly, with the value passed in associated with the corresponding name in the priv variable.

The problem is in accessing the class fields. If name is the variable containing the name of the desired parameter, I need to be able to get the associated value.

    actual = Feeds:new(arg)
    print("name= " .. actual.name)

This doesn't work because (I think) .name is supposed to be accessing the field called name. If name="material", I want to get the value for value of name, which is material and the parameter material's value, "MDF".

How do I do that?

Upvotes: 1

Views: 1427

Answers (1)

Paul Kulchenko
Paul Kulchenko

Reputation: 26774

You're looking for actual[name]. actual.name is a syntax sugar for actual["name"], so you can pass a variable (name in your case) instead of a literal value.

Upvotes: 3

Related Questions