2016-07-14 59 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