lua-users home
lua-l archive

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


Hi,

Diego wrote:
>     local http = require("http")
>     http.PROXY = "http://locahost:3128"; -- make all requests use the proxy
>     print(http.get("http://www.cs.princeton.edu/~diego";))
>     print(http.get("http://www.tecgraf.puc-rio.br/~diego";))
> 
> What I am saying is that if you do
> 
>     http2 = clone(http)
>     http2.PROXY = "whatever"
> 
> the implementation will still see the first value of PROXY, unless the
> "clone" function is magic. I believe this is a problem, or is it?

Well, that is exactly what Rici's constructor approach solves:

return function(module, name)
  module.PROXY = "some-default-proxy"

  function module.get(url)
    if module.PROXY then        --> module is an upvalue
      ...
    else
      ...
    end
  end

  return module
end

A sandbox needs to call the constructor a second time with a different table.
This way the get() method closure has a different upvalue for the module
and gets a different PROXY member.

Namespace cloning is a dirty solution, because the library that created
the namespace is not aware of it. Sonner or later you will need to add
a __clone() method. But then you might as well use a constructor ...

Another advantage is that the namespace a constructor is supposed to fill
does not need to be the environment of the module chunk itself. This way
a 'trusted' module can use all functions provided by the environment
to create a safe namespace for the sandbox.

Here is a simple checking wrapper (please note that the check is not safe
and for demonstration purposes only):

local string = require("string")
local http = require("http")

return function(module, name)

  function module.get(url)
    if string.find(url, "^http://example%.com/";) then
      return http.get(url)
    else
      ... raise sandbox error ...
    end
  end

  return module
end

The module chunk is executed outside the sandbox and can load other modules
or access other globals. The constructor is executed inside the sandbox,
but gets access to the outside through upvalues defined as locals for
the module scope.

Try to do this in a generic way without the constructor approach. :-)

I guess you (and Roberto) just don't like the syntax that is required
to write a module. Since it is highly stylized anyway, we might as well
go and define a convenient replacement syntax.

A metasyntactic addition would be the proper way to do it for Lua. In fact
I like the way Ruby allows passing a local block to a function. We might
define something similar and then make FUNCTION BLOCK a shorthand for
FUNCTION(BLOCK). The semantics need to be cleared up, but then we can write:

module do
  function get(url)
    ...
  end
end

Which is syntactic sugar for module(do ... end) which in turn could
be defined as module(function(...) ... end). And module() is just another
function provided by the base library.

A 10 line patch to the parser is all that is required (I guess).

BTW: What about:
     io.open('filename') do ... end      -- close when the block ends
     thread.synchronized do ... end      -- unlock when the block ends
     thread.run do ... end               -- execute block asynchronously
     window.onclick do ... end           -- easy callbacks
     finally do ... end do ... end       -- =8-)

Bye,
     Mike