如何避免Elixir中的嵌套if语句?

时间:2016-05-27 13:33:32

标签: elixir

有没有办法在Elixir中重构它以使其更具可读性?

  def validate(params) do
    Repo.start_link

    if validate_oauth_params(params) === true do
      oauth_client = Repo.get_by(OauthClient, random_id: params["client_id"], secret: params["secret"])

      if oauth_client != nil do
        allowed_grant_types = Poison.Parser.parse!(oauth_client.allowed_grant_types)
        if Map.has_key?(allowed_grant_types, params["grant_type"]) do
          case params["grant_type"] do
            "password" ->
              process_password_grant(params, oauth_client)
            "refresh_token" ->
              process_refresh_token_grant(params["refresh_token"], oauth_client)
            "client_credentials" ->
              process_client_credentials_grant(oauth_client)
            nil ->
              %{message: "Invalid oauth credentials", code: 400}
          end
        end
      else
        %{message: "Invalid oauth credentials", code: 400}
      end
    else
      %{message: "Invalid oauth credentials", code: 400}
    end
  end

Elixir的做法是什么,因为这段代码看起来像PHP。我没有写。

3 个答案:

答案 0 :(得分:4)

你是对的,它看起来像PHP。不使用elixir的模式匹配的好处。

很难重构这一件,因为似乎其他方法也应该重构,以使其更干净。例如,POST /accounts/client/_search { "bool": { "must": [ { "match": { "name": "big" <--- free text name match } } ], "filter": { "geo_shape": { "location": { "indexed_shape": { "id": "M320JG-2", <--- located within two miles of M32 0JG "type": "UK_postcode", "index": "locations", "path": "location" } } } } } } 函数“可以”返回一个元组而不是一个布尔值,所以你可以对它进行模式匹配,你会这样做:

validate_oauth_params

类似这样的东西,这根本不是代码,只是为了给出一个想法,模式匹配如何工作及其好处

答案 1 :(得分:3)

您可以尝试使用with表达式将此代码重写为类似

的内容
def validate(params) do
  with
    {:ok, p} <- validate_oauth_params(params),
    {:ok, client} = get_client_for_params(p),
    {:ok, allowed_grant_types} <- Poison.Parser.parse(oauth_client.allowed_grant_types)
  do
    case params["grant_type"] do
      "password" ->
        process_password_grant(params, oauth_client)
      "refresh_token" ->
        process_refresh_token_grant(params["refresh_token"], oauth_client)
      "client_credentials" ->
        process_client_credentials_grant(oauth_client)
      nil -> :error
    end
  end |> case do
    {:ok, something} -> something
    _ -> %{message: "Invalid oauth credentials", code: 400}
  end
end

然而,这样的refactiong可能需要在其他代码中进行更多更改或引入辅助函数以返回可识别的值和错误。 with目前不支持模式中的守卫,但它将在1.3中支持。

答案 2 :(得分:-1)

当逻辑变得非常复杂且带有/ do语句不够时,我喜欢使用这种方法。

def validate(params) do
    try do
        if !validate_oauth_params(params), do: 
            throw({:error, %{message: "Invalid oauth credentials", code: 400}})

        if !oauth_client, do: 
            throw({:error, %{message: "Invalid oauth credentials", code: 400}})

        allowed_grant_types = Poison.Parser.parse!(oauth_client.allowed_grant_types)
        if !Map.has_key?(allowed_grant_types, params["grant_type"]), do:
            throw({:error, %{message: "No grant type", code: 400}})

        case params["grant_type"] do
            "password" ->
                process_password_grant(params, oauth_client)
            "refresh_token" ->
                process_refresh_token_grant(params["refresh_token"], oauth_client)
            "client_credentials" ->
                process_client_credentials_grant(oauth_client)
            nil ->
                throw({:error, %{message: "Invalid oauth credentials", code: 400}})
        end
    catch
        {:error, map} -> {:error, map}
    else
        result -> {:ok, result}
    end
end