--[[ 空想具現化プログラミング http://hammm.blog21.fc2.com/ http://hammm.dw.land.to/lua/ documentation by silica as 冬物語の人 http://winter.sgv417.jp/ [Lua] 暗黙のグローバル変数定義を抑制する方法 http://hammm.blog21.fc2.com/blog-entry-8.html [Lua] 明示的グローバル変数宣言モジュール http://hammm.blog21.fc2.com/blog-entry-13.html -- 特徴 -- 以下のようにグローバル変数を明示的に宣言できます。 global "myvar" -- 以下の関数を記述すると「グローバル変数定義抑制」が有効になります。 use_explicit_globals() -- 定義方法 global("変数名",値) global "変数名" -- モジュール未使用 このモジュールを使って組んだコードをこのモジュールを使わないで動かす場合、以下のような宣言をすれば問題なく動きます。 function global() end function use_explicit_globals() end function use_implicit_globals() end ----------- example ------------ require "explicit_globals" use_explicit_globals(true) -- メインチャンクでも明示的な宣言を行う --- OK case global "my_global_variable" my_global_variable = 1 local a = my_global_variable --- NG case my_undeclared_variable = 1 -- NG local a = my_undeclared_variable2 -- NG --- functions declarations function undeclared_global_func() end --- ok undeclared_global_func2 = function() end --- ok function test() global "my_global_func" function my_global_func() end --- ok function undeclared_global_func3() end --- NG end test() --]] ---- explicit_globals.lua --- -- table for global var declaration checking local gdef = {} local gdef_enabled = nil -- the function to define global vars function global(n, v) if not gdef_enabled then error("calling function global() when explicit-globals not enabled",2) end if gdef[n] == true then error("re-definition of global \"" .. tostring(n) .. "\"",2) end rawset(_G, n, v) gdef[n] = true return end local function registerglobal(t,n,v) gdef[n] = true rawset(t,n,v) end -- forbid implicit definition of global vars function use_explicit_globals( is_explicit_in_main_chunk ) -- set metatable for gloval environment local mt = getmetatable(_G) if mt == nil then mt = {} setmetatable(_G, mt) end -- include implicitly-declared globals in gdef table, -- in case some of it becomes nil and __index,__newindex be called. -- drawback: if the value is nil now, it will not be included. for k,v in pairs(_G) do gdef[k] = true end mt.__newindex = function (t,n,v) if gdef[n] ~= nil then -- declared global rawset(t,n,v);return end local upfuncinfo = debug.getinfo(2,"S") if upfuncinfo == nil then registerglobal(t,n,v);return end local w = upfuncinfo.what if w == "C" then -- in C chunk registerglobal(t,n,v);return end if ( not is_explicit_in_main_chunk and w == "main" ) then -- in main chunk registerglobal(t,n,v);return end if type(v) == "function" then -- funtcion value if w == "main" then -- declatration of functions in main chunk is ok. registerglobal(t,n,v);return else error("assignment of undeclared global function \"" .. tostring(n) .. "\" outside of main chunk. use global(\"var\", val)", 2) end else -- not function value error("assignment of undeclared global \"" .. tostring(n) .. "\". use global(\"var\", val)", 2) end end mt.__index = function (t,n) local upfuncinfo = debug.getinfo(2,"S") if gdef[n] == nil and upfuncinfo ~= nil and upfuncinfo.what ~= "C" then error("attempt to use undeclared global \"" .. tostring(n) .. "\". use global(\"var\", val)", 2) end return rawget(t, n) end gdef_enabled = true end -- back to normal, implicit global declaration. function use_implicit_globals() local mt = getmetatable(_G) if mt ~= nil then mt.__newindex = nil mt.__index = nil end gdef_enabled = nil end use_explicit_globals( true ) -- use explicit globals from start, except main chunk