2016-07-14 63 views
1

我努力學習仙丹(但主要是函數式編程)藥劑和功能輸入驗證

我實現一個非常簡單的GenServer基本上包裝條目列表。條目,每個條目參數的時最大計數和最大尺寸(以字節爲單位)限制(配置文件)

defmodule List do 

    def init(_) do 
     {:ok, []} 
    end 

    def handle_call({:insert, param1, param2, param3}, from, list) do 

     import Application 

     param1_max_size = get_env(:app, ....) 
     param2_max_size = get_env(:app, ....) 
     param2_max_size = get_env(:app, ....) 

     max_items_count = get_env(:app, ....) 

     ## should be {:reply, {:error, :your_list_is_full}, list} if list is full 

     ## should be {:reply, {:error, {:check_this_args_please, wrong_params_list}, list} if any param is wrong. wrong_params_list contains the offending params 

     ## should be {:reply, {:ok}, [{param1, param2, param3} | list ]} otherwise 

    end 

end 

我知道這似乎很容易,但基本上我試圖找到一個優雅的功能性的方式來做到這一點。我的頭腦是程序性的,並且我總是以=運算符的形式出現在「嵌套的if-else-hell」中,就像它是C語言一樣。

THX

回答

3

我知道驗證多個參數的最徹底的方法是Ectochangesets。你可能想要實現一些非常相似的東西。

  1. 創建包含的價值觀和驗證錯誤數據結構
  2. 使所有的驗證功能,採取數據結構作爲第一個參數,返回此數據結構,使其便於管道。我打算將它稱爲changeset,與Ecto相同。

的代碼可能是這樣的:

changeset = %{data: {param1, param2, param3}, errors: []} 

def validate_param(changeset, number) do 
    max_size = get_env(:app, :"param#{number}" 
    if elem(changeset.data, number-1) < max_size do 
    changeset 
    else 
    errors = [{:"param#{number}", elem(changeset.data, number-1)} | changeset.errors 
    %{ changeset | errors: errors} 
    end 
end 

validated_changeset = 
    changeset 
    |> validate_param(1) 
    |> validate_param(2) 
    |> validate_param(3) 

case validated_changeset.errors do 
    [] -> {:reply, :ok, [changeset.data | list]} 
    errors -> {:reply, errors, list} 
end 

在藥劑可以用引號包含特殊字符定義一個原子。如果沒有特殊字符,它是一樣的不帶引號:

iex(1)> :"a b" 
:"a b" 
iex(10)> :"ab" 
:ab 

引號內可使用的字符串內插,因此您可以使用原子:"param#{number}"創建通用validate_param

elem函數是零索引的,所以我們需要從number減去1:elem(changeset.data, number-1)

如果沒有錯誤,我們將返回變更集而不做任何修改。

錯誤將具有結構{field_name, field_value}。將list添加到變更集應該很容易,並創建一個更多的驗證函數來檢查列表長度並附加正確的錯誤。

您也可以使用List.foldl調用validate_param 3次刪除重複:

List.foldl([1, 2, 3], changeset, fn(number, changeset) -> validate_number(changeset, number) end) 

甚至更​​短:

List.foldl([1, 2, 3], changeset, &validate_number(&2, &1)) 

,最重要的是函數返回相同的類型,因爲他們的模式作爲第一個參數。它可以很容易地避免許多嵌套的ifcase語句。

+0

這真的很好,thx – justatester