zf

zenflows testing
git clone https://s.sonu.ch/~srfsh/zf.git
Log | Files | Refs | Submodules | README | LICENSE

with_custom_tagged_tuple.ex (2577B)


      1 defmodule Credo.Check.Readability.WithCustomTaggedTuple do
      2   use Credo.Check,
      3     category: :warning,
      4     base_priority: :low,
      5     explanations: [
      6       check: """
      7       Avoid using custom tags for error reporting from `with` macros.
      8 
      9       This code injects placeholder tags such as `:resource` and `:authz` for the purpose of error
     10       reporting.
     11 
     12           with {:resource, {:ok, resource}} <- {:resource, Resource.fetch(user)},
     13                {:authz, :ok} <- {:authz, Resource.authorize(resource, user)} do
     14             do_something_with(resource)
     15           else
     16             {:resource, _} -> {:error, :not_found}
     17             {:authz, _} -> {:error, :unauthorized}
     18           end
     19 
     20       Instead, extract each validation into a separate helper function which returns error
     21       information immediately:
     22 
     23           defp find_resource(user) do
     24             with :error <- Resource.fetch(user), do: {:error, :not_found}
     25           end
     26 
     27           defp authorize(resource, user) do
     28             with :error <- Resource.authorize(resource, user), do: {:error, :unauthorized}
     29           end
     30 
     31       At this point, the validation chain in `with` becomes clearer and easier to understand:
     32 
     33           with {:ok, resource} <- find_resource(user),
     34                :ok <- authorize(resource, user),
     35                do: do_something(user)
     36 
     37       Like all `Readability` issues, this one is not a technical concern.
     38       But you can improve the odds of others reading and liking your code by making
     39       it easier to follow.
     40       """
     41     ]
     42 
     43   @doc false
     44   @impl true
     45   def run(%SourceFile{} = source_file, params \\ []) do
     46     source_file
     47     |> errors()
     48     |> Enum.map(&credo_error(&1, IssueMeta.for(source_file, params)))
     49   end
     50 
     51   defp errors(source_file) do
     52     {_ast, errors} = Macro.prewalk(Credo.Code.ast(source_file), MapSet.new(), &traverse/2)
     53     Enum.sort_by(errors, &{&1.line, &1.column})
     54   end
     55 
     56   defp traverse({:with, _meta, args}, errors) do
     57     errors =
     58       args
     59       |> Stream.map(&placeholder/1)
     60       |> Enum.reject(&is_nil/1)
     61       |> Enum.into(errors)
     62 
     63     {args, errors}
     64   end
     65 
     66   defp traverse(ast, state), do: {ast, state}
     67 
     68   defp placeholder({:<-, meta, [{placeholder, _}, {placeholder, _}]}) when is_atom(placeholder),
     69     do: %{placeholder: placeholder, line: meta[:line], column: meta[:column]}
     70 
     71   defp placeholder(_), do: nil
     72 
     73   defp credo_error(error, issue_meta) do
     74     format_issue(
     75       issue_meta,
     76       message: "Invalid usage of placeholder `#{inspect(error.placeholder)}` in with",
     77       line_no: error.line,
     78       column: error.column
     79     )
     80   end
     81 end