2015-11-20 69 views
3

在鳳凰城創建的應用程序的方法陣列的方法(PARAM)的綁定變量的一部分,我想實現這樣的如何創建由宏

#= Bouncers.Bouncer.check_entry(conn, %MyApp.User{}) 
#=> true 

defmodule Bouncers.Bouncer do 
    alias Bouncers.Areas 

    def check_entry(conn, resource) do 
    verify(resource, conn.path_info) 
    end 

    defp verify(resource, path) do 
    try do 
     Areas.verify(resource, path) 
    rescue 
     _ -> false 
    end 
    end 

end 

defmodule Bouncers.Doors do 

    defmacro bouncer_for(model, allowed_routes) do 
    for route <- allowed_routes do 
     quote bind_quoted: [route: route, resource: model] do 
     def verify(resource, route), do: true 
     end 
    end 
    end 
end 

defmodule Bouncers.Areas do 
    require Bouncers.Doors 
    import Bouncers.Doors 

    bouncer_for %MyApp.User{}, [ 
    ["api", "users"] 
    ] 
end 

bouncer_for授權創建多個verify方法一個結構和path_info陣列

bouncer_for %MyApp.User{}, [ 
     ["api", "users"], 
     ["api", "posts"] 
] 

將創建

def verify(%MyApp.User{}, ["api", "users"], do: true 
def verify(%MyApp.User{}, ["api", "posts"], do: true 

它適用於這些paths,但我堅持格式爲["api", "users", _ ]的路徑,這會引發有關未綁定變量的錯誤。我想這樣的事情ATLEAST,

bouncer_for %MyApp.User{}, [ 
     ["api", "users", "*"], 
] 

而且隨着_取代"*"由宏產生的方法的參數內,。任何指針?

+1

邊注:如果您已經'import'一個模塊,我認爲額外的'require'不必要。 –

回答

4

您需要定義這樣的宏:

defmodule Bouncers.Doors do 
    defmacro bouncer_for(model, allowed_routes) do 
    for route <- allowed_routes do 
     quote do 
     def verify(unquote(model), unquote(route)), do: true 
     end 
    end 
    end 
end 

那麼就應該按預期工作。

原因是bind_quoted會嘗試將綁定(即實際值)傳遞給宏,但["api", "users", _]本身不是有效值。這是一種模式,您可以使用unquote將其嵌入到動態生成的函數定義中。這將表現得好像你直接在定義中寫入了模式。爲了說明這個問題,這裏是一些代碼,大致相當於由宏生成的定義:

# using bind_quoted 
@route ["api", "users", _]     # invalid value, raises error 
def verify(%MyApp.User{}, @route), do: true 

# using unquote 
def verify(%MyApp.User{}, ["api", "users", _]), do: true