lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


> Problem with this approach is that the user won't be able to do stuff
> like "table.foreach(textbuffer,print)" to print all lines.

> Is there anyway around this?

Yep, write your own table.foreach :) Here's an easy one which shows
a general solution. Unfortunately, it doesn't work with syntactic
iteration (for k,v in table do ... end). I think there is an
undocumented solution to that, too.

do
  local old_foreach = table.foreach
  function table.foreach(obj, fn)
    local meta = getmetatable(obj)
    if meta and meta.__foreach then
        return meta.__foreach(obj, fn)
      else
        return old_foreach(obj, fn)
    end
  end
end


> Another problem is that there is also a settings table and the user
> could change this as he pleases.

> Rather than having to go through the entire table when the script exits
> (to see what is changed) then I would prefer to supply some sort of
> callback function -- unfortunately it seems that 'newindex' (from the
> metatable) is only called when new indexes are created, and not when
> old ones are updated.

> Any way around that?

Sure, use an empty proxy table. Then you can see all accesses. For an
application like this, though, it might not make any difference; if the
user is going to edit the config table and then you're going to reread
it, you might as well scan through the whole thing afterwards, unless
there are a bunch of things that you put in there first.

Anyway, here is the basic solution. It doesn't trap get's, so it's not
that inefficient.

do
  local config_table = {} -- could fill in initial values here

  trigger_table = setmetamethod({},
    {
     __index = config_table,
     __newindex = function(t, k, v)
                    config_changed(k, v)
                    config_table[k] = v
                  end
    })
end


If you only want to trigger on certain keys, you could put other keys
into the external table directly.

In the following version, if config_changed returns nil or false,
it means "I'm not interested in this key":

do
  local config_table = {} -- could fill in initial values here

  trigger_table = setmetamethod({},
    {
     __index = config_table,
     __newindex = function(t, k, v)
                    if config_changed(k, v)
                      then config_table[k] = v
                      else rawset(t, k, v)
                    end
                  end
    })
end

Other variations are possible (like config_changed might provide a
"corrected" value.) Hope that helps.

R.