2012-02-13 21 views
7

私は、forループのすべての反復を評価する動的式にコンテキストを渡そうとしています。私はロード文字列がローカル変数がアクセス不能であることを意味するグローバルコンテキスト内でのみ評価することを理解しています。私の場合は、文字列評価の目的でローカルをグローバルに変換することでこの制限を回避します。ここで私が持っているものです。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) 

(Luaのマスタリング以外の)私の究極の目標は、私のような何かを行うことができエンジン誘惑のようなXSLTアウト構築することである。

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

[webデータマイナー](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

関連する問題