2012-02-13 3 views
7

for 루프의 모든 반복을 평가하는 동적 표현식에 컨텍스트를 전달하려고합니다. 로드 문자열은 로컬 변수가 액세스 할 수 없음을 의미하는 전역 컨텍스트 내에서만 평가된다는 점을 이해합니다. 필자의 경우 문자열 평가를 위해 로컬을 전역으로 변환하여이 제한을 해결합니다. 내가 좋아하는 뭔가를 할 수있는 곳 유혹 엔진과 같은 XSLT를 구축하기 위해 (루아 마스터 이외의)Lua : 컨텍스트를 loadstring에 전달 하시겠습니까?

require 'cosmo' 

model = { { player = "Cliff", age = 35, gender = "male" }, { player = "Ally", age = 36, gender = "female" }, { player = "Jasmine", age = 13, gender = "female" }, { player = "Lauren", age = 6.5, gender = "female" } } 

values = { eval = function(args) 
    output = '' 
    condition = assert(loadstring('return ' .. args.condition)) 
    for _, it in ipairs(model) do 
     each = it 
     if condition() then 
      output = output .. each.player .. ' age: ' .. each.age .. ' ' .. '\n' 
     end 
    end 
    return output 
end } 
template = "$eval{ condition = 'each.age < 30' }" 

result = cosmo.fill(template, values) 
print (result) 

내 궁극적 인 목표입니다 :

apply_templates{ match = each.age > 30}[[<parent-player>$each.player</parent-player>]] 

apply_templates{ match = each.age > 30}[[<child-player>$each.player</child-player>]] 

을 ... 그리고 다른 생성 여기에 내가 가진 무엇 출력. 현재 저는 세계를 통해 지역 맥락을 공유하는 위의 매파적인 수단에 매달려 있습니다. 여기있는 사람이 내가하려고하는 일을 어떻게 수행 할 것인지에 대한 더 나은 통찰력을 가지고 있습니까?

답변

7

setfenv()으로 함수의 컨텍스트를 변경할 수 있습니다. 이렇게하면 기본적으로로드 된 함수를 자체 환경에 샌드위치 할 수 있습니다. 다음과 같은 뭔가 작업을해야합니다 :

local context = {} 
local condition = assert(loadstring('return ' .. args.condition)) 
setfenv(condition, context) 
for _, it in ipairs(model) do 
    context['each'] = it 
    if condition() then 
     -- ... 

이 또한 당신이 그것을 원하지 않아요 당신이 어떤 데이터를 수정, 그것은에, 또는 좀 더 결정적으로 원하지 않는 데이터에 액세스 할 수있는에서 조건 값을 방지 할 수 있습니다 . 단, condition에 액세스 할 수 있도록 context 테이블에 최상위 수준의 바인딩을 노출해야합니다 (예 : math 패키지에 액세스 할 수 있도록하려면 해당 테이블을 고수해야합니다. context에 입력). 전역 액세스하지 condition 어떤 문제가 발생하지 않고 단순히 지역 전역을하지 처리하려는 경우 또는, 당신은 그것을 통해 알 수없는 인덱스를 통과하도록 context에 메타 테이블을 사용할 수 있습니다 _G에 :

setmetatable(context, { __index = _G }) 
+0

저는 [웹 데이터 마이너] (https://github.com/mkottman/wdm/blob/master/wdm.lua#L156)에서 저의 가난한 사람의 XML 요소 검색에서 비슷한 것을 사용합니다. –

+0

훌륭하게 작동합니다! 고맙습니다! :) – Cliff

9

setfenv was removed from Lua 5.2 and loadstring is deprecated은 주목할 가치가 있습니다. 당신이 잠시 동안 그것에 대해 걱정하지 않도록 5.2 아주 새로운,하지만 부하 두 버전 모두 작동 루틴을 작성할 수 있습니다 :

local function load_code(code, environment) 
    if setfenv and loadstring then 
     local f = assert(loadstring(code)) 
     setfenv(f,environment) 
     return f 
    else 
     return assert(load(code, nil,"t",environment)) 
    end 
end 

local context = {} 
context.string = string 
context.table = table 
-- etc. add libraries/functions that are safe for your application. 
-- see: http://lua-users.org/wiki/SandBoxes 
local condition = load_code("return " .. args.condition, context) 

버전 5.2의 load 핸들을 모두 이전 loadstring을 환경을 설정합니다 (예 : 컨텍스트). 버전 5.2도 environments의 개념을 변경하므로 loadstring은 걱정거리가 될 수 있습니다. 그래도 길 아래로 자신을 구할 수있는 가능성을 고려해야합니다.

+0

감사합니다 코빈! :) 현재 5.1에서 작업하고있는 동안 원래 5.2 환경을 사용하고있었습니다. 이것은 분명히 나에게 몇 가지 두통을 저장해야합니다! – Cliff

관련 문제