### Configure ExSlop Checks Source: https://context7.com/dannote/ex_slop/llms.txt Example of how to configure ExSlop to opt into specific checks by listing them in the .credo.exs configuration file. ```elixir %{ configs: [ %{ name: "default", checks: %{ extra: [ # Warnings {ExSlop.Check.Warning.BlanketRescue, []}, {ExSlop.Check.Warning.RescueWithoutReraise, []}, {ExSlop.Check.Warning.RepoAllThenFilter, []}, {ExSlop.Check.Warning.QueryInEnumMap, []}, {ExSlop.Check.Warning.GenserverAsKvStore, []}, # Opt-in performance checks {ExSlop.Check.Refactor.ListFold, []}, {ExSlop.Check.Refactor.ListLast, []}, {ExSlop.Check.Refactor.LengthInGuard, []}, {ExSlop.Check.Refactor.PreferEnumSlice, []}, # Readability with custom keywords {ExSlop.Check.Readability.ObviousComment, [additional_keywords: ["Log the", "Print the"]}}, {ExSlop.Check.Readability.StepComment, []}, {ExSlop.Check.Readability.UnaliasedModuleUse, []} ] } } ] } ``` -------------------------------- ### LengthInGuard Check (EXS4025) Example Source: https://context7.com/dannote/ex_slop/llms.txt Demonstrates the LengthInGuard check, flagging `length(list) == 0` or `length(list) > 0` in guards. The 'GOOD' example shows the preferred pattern matching approach. ```elixir # LengthInGuard example # BAD def process(list) when length(list) == 0, do: :empty # W [EXS4025] def process(list) when length(list) > 0, do: :nonempty # GOOD — pattern match avoids full traversal def process([]), do: :empty def process([_ | _]), do: :nonempty ``` -------------------------------- ### Example ExSlop Output Source: https://context7.com/dannote/ex_slop/llms.txt This output demonstrates typical warnings generated by ExSlop when AI-generated code patterns are detected, including blanket rescues, N+1 queries, and redundant documentation. ```text lib/my_app/users.ex:42:5: W [EXS1001] Blanket `rescue` swallows all exceptions — rescue specific ones or let it crash. lib/my_app/users.ex:17:5: W [EXS1003] Database query inside `Enum.map/2` — this is an N+1 query. Use `Repo.preload/2` or a join. lib/my_app/users.ex:8:3: R [EXS3001] "This module/function provides..." restates the name — explain WHY or delete the doc. ``` -------------------------------- ### PreferEnumSlice Check (EXS4018) Example Source: https://context7.com/dannote/ex_slop/llms.txt Shows the PreferEnumSlice check, which flags the combination of `Enum.drop` followed by `Enum.take`. The 'GOOD' example uses the more efficient `Enum.slice`. ```elixir # PreferEnumSlice example # BAD items |> Enum.drop(5) |> Enum.take(10) # W [EXS4018] # GOOD Enum.slice(items, 5, 10) ``` -------------------------------- ### ObviousComment Check (EXS3003) Example Source: https://context7.com/dannote/ex_slop/llms.txt This example shows comments flagged by EXS3003 for starting with 'Verb + article' patterns. Good examples include self-explanatory code or comments explaining 'why'. ```elixir # BAD — flagged by EXS3003 def update_user(id, attrs) do # Fetch the user ← W [EXS3003] user = Repo.get!(User, id) # Create the changeset ← W [EXS3003] changeset = User.changeset(user, attrs) # Return the result ← W [EXS3003] Repo.update(changeset) end # GOOD — no comment (code is self-explanatory), or explain WHY def update_user(id, attrs) do user = Repo.get!(User, id) # Fetch with lock to prevent concurrent updates # user = Repo.get!(User, id, lock: "FOR UPDATE") User.changeset(user, attrs) |> Repo.update() end # GOOD — keeper keywords are never flagged # TODO: add optimistic locking here # NOTE: email changes require re-verification # FIXME: rate limiting not yet implemented ``` -------------------------------- ### UnaliasedModuleUse Check (EXS3009) Example Source: https://context7.com/dannote/ex_slop/llms.txt This example demonstrates the EXS3009 check, which flags repeated fully-qualified module names within a function without an alias. The 'GOOD' example shows the correct usage with an alias. ```elixir # BAD — flagged by EXS3009 (Credo.Code used 3× without alias) def analyze(source) do ast = Credo.Code.prewalk(source, &walk/2, []) tokens = Credo.Code.to_tokens(source) lines = Credo.Code.to_lines(source) {ast, tokens, lines} end # GOOD alias Credo.Code def analyze(source) do ast = Code.prewalk(source, &walk/2, []) tokens = Code.to_tokens(source) lines = Code.to_lines(source) {ast, tokens, lines} end ``` -------------------------------- ### Get Curated Recommended ExSlop Checks Source: https://context7.com/dannote/ex_slop/llms.txt Use `ExSlop.recommended_checks/0` to get a list of the 29 stable, low-noise checks automatically enabled by the default plugin registration. These are suitable for most Elixir codebases. ```elixir ExSlop.recommended_checks() # => [ # ExSlop.Check.Warning.BlanketRescue, # ExSlop.Check.Warning.RescueWithoutReraise, # ExSlop.Check.Warning.RepoAllThenFilter, # ExSlop.Check.Warning.QueryInEnumMap, # ExSlop.Check.Warning.GenserverAsKvStore, # ExSlop.Check.Warning.PathExpandPriv, # ExSlop.Check.Warning.DualKeyAccess, # ExSlop.Check.Refactor.FilterNil, # ExSlop.Check.Refactor.RejectNil, # ExSlop.Check.Refactor.ReduceAsMap, # ExSlop.Check.Refactor.MapIntoLiteral, # ExSlop.Check.Refactor.IdentityPassthrough, # ExSlop.Check.Refactor.IdentityMap, # ExSlop.Check.Refactor.TryRescueWithSafeAlternative, # ExSlop.Check.Refactor.WithIdentityElse, # ExSlop.Check.Refactor.WithIdentityDo, # ExSlop.Check.Refactor.SortThenReverse, # ExSlop.Check.Refactor.StringConcatInReduce, # ExSlop.Check.Refactor.ReduceMapPut, # ExSlop.Check.Refactor.RedundantBooleanIf, # ExSlop.Check.Refactor.FlatMapFilter, # ExSlop.Check.Readability.NarratorDoc, # ExSlop.Check.Readability.BoilerplateDocParams, # ExSlop.Check.Readability.NarratorComment, # ExSlop.Check.Refactor.RedundantEnumJoinSeparator, # ExSlop.Check.Refactor.GraphemesLength, # ExSlop.Check.Refactor.ManualStringReverse, # ExSlop.Check.Refactor.SortThenAt, # ExSlop.Check.Refactor.ExplicitSumReduce # ] ``` ```elixir ExSlop.recommended_checks() |> length() # => 29 ``` -------------------------------- ### Use Agent for Key-Value Stores in Elixir Source: https://context7.com/dannote/ex_slop/llms.txt Avoid reimplementing key-value store functionality with GenServer when `Agent` or ETS can be used. This example shows a GenServer incorrectly used as a KV store. ```elixir # BAD — flagged by EXS1005 defmodule MyApp.Cache do use GenServer def handle_call({:get, key}, _from, state) do # W [EXS1005] {:reply, Map.get(state, key), state} end def handle_call({:put, key, value}, _from, state) do {:reply, :ok, Map.put(state, key, value)} end end # GOOD — use Agent defmodule MyApp.Cache do use Agent def start_link(_), do: Agent.start_link(fn -> %{} end, name: __MODULE__) def get(key), do: Agent.get(__MODULE__, &Map.get(&1, key)) def put(key, value), do: Agent.update(__MODULE__, &Map.put(&1, key, value)) end ``` -------------------------------- ### Optimizing Sort Then At in Elixir Source: https://github.com/dannote/ex_slop/blob/master/README.md Suggests using `Enum.min/1`, `Enum.max/1`, or specific selection logic instead of sorting the entire list to get an element. ```elixir Enum.sort() |> Enum.at(0) ``` ```elixir Enum.min/1, Enum.max/1, or selection logic ``` -------------------------------- ### Using String Length in Elixir Source: https://github.com/dannote/ex_slop/blob/master/README.md Replaces `String.graphemes(s) |> length()` with the more efficient `String.length(s)` for getting string length. ```elixir String.graphemes(s) |> length() ``` ```elixir String.length(s) ``` -------------------------------- ### Enable Opt-In Performance Checks in .credo.exs Source: https://context7.com/dannote/ex_slop/llms.txt Configure your .credo.exs file to enable opt-in performance checks like ListFold, ListLast, LengthInGuard, and PreferEnumSlice. ```elixir # .credo.exs — enabling opt-in checks %{ configs: [ %{ name: "default", plugins: [{ExSlop, []}], checks: %{ extra: [ # ListFold (EXS4023): List.foldl/foldr → Enum.reduce {ExSlop.Check.Refactor.ListFold, []}, # ListLast (EXS4024): List.last/1 traverses entire list {ExSlop.Check.Refactor.ListLast, []}, # LengthInGuard (EXS4025): length(xs) == 0 in guard → pattern match {ExSlop.Check.Refactor.LengthInGuard, []}, # PreferEnumSlice (EXS4018): Enum.drop |> Enum.take → Enum.slice {ExSlop.Check.Refactor.PreferEnumSlice, []} ] } } ] } ``` -------------------------------- ### Run Basic Development Tasks with Mix Aliases Source: https://github.com/dannote/ex_slop/blob/master/AGENTS.md Use these Mix aliases for common development tasks like fetching dependencies, compiling, testing, and formatting code. ```shell mix deps.get mix compile mix test mix format ``` -------------------------------- ### Expose Recommended Checks Programmatically Source: https://context7.com/dannote/ex_slop/llms.txt Access the curated list of recommended checks provided by ExSlop. This function returns a list of check modules suitable for programmatic integration. ```elixir ExSlop.recommended_checks/0 ``` -------------------------------- ### Register ExSlop as a Credo Plugin Source: https://context7.com/dannote/ex_slop/llms.txt Register ExSlop in your `.credo.exs` configuration file to automatically enable its checks. The `init/1` callback injects the recommended check bundle. ```elixir %{ configs: [ %{ name: "default", plugins: [{ExSlop, []}] } ] } ``` -------------------------------- ### List All Available ExSlop Checks Source: https://context7.com/dannote/ex_slop/llms.txt Call `ExSlop.checks/0` to retrieve a list of all available check modules provided by ExSlop, including core, high-signal, and opt-in checks. ```elixir # Inspect all available checks ExSlop.checks() # => [ # ExSlop.Check.Warning.BlanketRescue, # ExSlop.Check.Warning.RescueWithoutReraise, # ExSlop.Check.Warning.RepoAllThenFilter, # ExSlop.Check.Warning.QueryInEnumMap, # ExSlop.Check.Warning.GenserverAsKvStore, # ExSlop.Check.Warning.PathExpandPriv, # ExSlop.Check.Warning.DualKeyAccess, # ExSlop.Check.Refactor.FilterNil, # # ... 32 more # ] ``` ```elixir # Count total checks ExSlop.checks() |> length() # => 40 ``` -------------------------------- ### Configuring Credo Built-in Checks Source: https://github.com/dannote/ex_slop/blob/master/README.md Shows how to enable specific Credo built-in checks in the `.credo.exs` configuration file to catch common code smells and performance issues. ```elixir # Catches length(list) == 0 (traverses entire list) → use list == [] or Enum.empty?/1 {Credo.Check.Warning.ExpensiveEmptyEnumCheck, []}, # Catches acc ++ [item] (O(n²) append) → use [item | acc] then Enum.reverse {Credo.Check.Refactor.AppendSingleItem, []}, # Catches !!var (double negation) — LLMs use this to "cast to boolean" {Credo.Check.Refactor.DoubleBooleanNegation, []}, # Catches case x do true -> a; false -> b end → if/else {Credo.Check.Refactor.CondStatements, []}, # Catches Enum.map |> Enum.map → single Enum.map {Credo.Check.Refactor.MapMap, []}, # Catches Enum.filter |> Enum.filter → single Enum.filter {Credo.Check.Refactor.FilterFilter, []}, # Catches Enum.reject |> Enum.reject → single Enum.reject {Credo.Check.Refactor.RejectReject, []}, # Catches Enum.count(enum) > 0 → Enum.any?/1 {Credo.Check.Refactor.FilterCount, []}, # Catches negated conditions in unless → rewrite with positive condition {Credo.Check.Refactor.NegatedConditionsInUnless, []}, # Catches unless x do .. else .. end → if/else (clearer) {Credo.Check.Refactor.UnlessWithElse, []} ``` -------------------------------- ### Optimizing Sort For Top K in Elixir Source: https://github.com/dannote/ex_slop/blob/master/README.md Recommends using `Enum.min/1`, `Enum.max/1`, or top-k selection algorithms instead of sorting the entire list to find the top elements. ```elixir Enum.sort() |> Enum.take(1) ``` ```elixir Enum.min/1, Enum.max/1, or top-k selection ``` -------------------------------- ### ExSlop.checks/0 Source: https://context7.com/dannote/ex_slop/llms.txt Returns all available check modules registered by ExSlop, including core checks, high-signal credence ports, and opt-in credence ports. ```APIDOC ## `ExSlop.checks/0` — List All Available Checks Returns all 40+ check modules registered by ExSlop: core checks, high-signal credence ports, and opt-in credence ports combined. ```elixir # Inspect all available checks ExSlop.checks() # => [ # ExSlop.Check.Warning.BlanketRescue, # ExSlop.Check.Warning.RescueWithoutReraise, # ExSlop.Check.Warning.RepoAllThenFilter, # ExSlop.Check.Warning.QueryInEnumMap, # ExSlop.Check.Warning.GenserverAsKvStore, # ExSlop.Check.Warning.PathExpandPriv, # ExSlop.Check.Warning.DualKeyAccess, # ExSlop.Check.Refactor.FilterNil, # # ... 32 more # ] # Count total checks ExSlop.checks() |> length() # => 40 ``` ``` -------------------------------- ### Add ExSlop to mix.exs Source: https://github.com/dannote/ex_slop/blob/master/README.md Include ExSlop as a development dependency in your `mix.exs` file. It's typically used only for development and testing. ```elixir def deps do [ {:ex_slop, "~> 0.1", only: [:dev, :test], runtime: false} ] end ``` -------------------------------- ### ExSlop.recommended_checks/0 Source: https://context7.com/dannote/ex_slop/llms.txt Returns a curated list of 29 high-signal checks that are enabled by default when ExSlop is registered as a plugin. These checks are stable and suitable for most Elixir codebases. ```APIDOC ## `ExSlop.recommended_checks/0` — Curated High-Signal Bundle Returns the 29 checks that are enabled by the `{ExSlop, []}` plugin registration. These are stable, low-noise checks appropriate for any mature Elixir codebase; noisier checks (`ListLast`, `LengthInGuard`, etc.) are excluded from this bundle but still available for explicit opt-in. ```elixir ExSlop.recommended_checks() # => [ # ExSlop.Check.Warning.BlanketRescue, # ExSlop.Check.Warning.RescueWithoutReraise, # ExSlop.Check.Warning.RepoAllThenFilter, # ExSlop.Check.Warning.QueryInEnumMap, # ExSlop.Check.Warning.GenserverAsKvStore, # ExSlop.Check.Warning.PathExpandPriv, # ExSlop.Check.Warning.DualKeyAccess, # ExSlop.Check.Refactor.FilterNil, # ExSlop.Check.Refactor.RejectNil, # ExSlop.Check.Refactor.ReduceAsMap, # ExSlop.Check.Refactor.MapIntoLiteral, # ExSlop.Check.Refactor.IdentityPassthrough, # ExSlop.Check.Refactor.IdentityMap, # ExSlop.Check.Refactor.TryRescueWithSafeAlternative, # ExSlop.Check.Refactor.WithIdentityElse, # ExSlop.Check.Refactor.WithIdentityDo, # ExSlop.Check.Refactor.SortThenReverse, # ExSlop.Check.Refactor.StringConcatInReduce, # ExSlop.Check.Refactor.ReduceMapPut, # ExSlop.Check.Refactor.RedundantBooleanIf, # ExSlop.Check.Refactor.FlatMapFilter, # ExSlop.Check.Readability.NarratorDoc, # ExSlop.Check.Readability.BoilerplateDocParams, # ExSlop.Check.Readability.NarratorComment, # ExSlop.Check.Refactor.RedundantEnumJoinSeparator, # ExSlop.Check.Refactor.GraphemesLength, # ExSlop.Check.Refactor.ManualStringReverse, # ExSlop.Check.Refactor.SortThenAt, # ExSlop.Check.Refactor.ExplicitSumReduce # ] ExSlop.recommended_checks() |> length() # => 29 ``` ``` -------------------------------- ### Register ExSlop Plugin in .credo.exs Source: https://github.com/dannote/ex_slop/blob/master/README.md Register ExSlop as a plugin in your `.credo.exs` configuration file to enable its checks. This configuration enables default checks. ```elixir # .credo.exs %{ configs: [ %{ name: "default", plugins: [{ExSlop, []}] } ] } ``` -------------------------------- ### Run Credo Against a Single File Source: https://context7.com/dannote/ex_slop/llms.txt Analyze a specific file with Credo by providing the file path as an argument to the `mix credo` command. ```bash # Run against a single file mix credo lib/my_app/users.ex --strict ``` -------------------------------- ### Cherry-pick ExSlop Checks Source: https://github.com/dannote/ex_slop/blob/master/README.md Customize your Credo configuration by cherry-picking specific ExSlop checks to include in the `extra` list. This allows for fine-grained control over code analysis. ```elixir # .credo.exs {ExSlop.Check.Warning.BlanketRescue, []}, {ExSlop.Check.Warning.RescueWithoutReraise, []}, {ExSlop.Check.Warning.RepoAllThenFilter, []}, {ExSlop.Check.Warning.QueryInEnumMap, []}, {ExSlop.Check.Warning.GenserverAsKvStore, []}, {ExSlop.Check.Warning.PathExpandPriv, []}, {ExSlop.Check.Warning.DualKeyAccess, []}, {ExSlop.Check.Refactor.FilterNil, []}, {ExSlop.Check.Refactor.RejectNil, []}, {ExSlop.Check.Refactor.ReduceAsMap, []}, {ExSlop.Check.Refactor.MapIntoLiteral, []}, {ExSlop.Check.Refactor.IdentityPassthrough, []}, {ExSlop.Check.Refactor.IdentityMap, []}, {ExSlop.Check.Refactor.CaseTrueFalse, []}, {ExSlop.Check.Refactor.TryRescueWithSafeAlternative, []}, {ExSlop.Check.Refactor.WithIdentityElse, []}, {ExSlop.Check.Refactor.WithIdentityDo, []}, {ExSlop.Check.Refactor.SortThenReverse, []}, {ExSlop.Check.Refactor.StringConcatInReduce, []}, {ExSlop.Check.Refactor.ReduceMapPut, []}, {ExSlop.Check.Refactor.RedundantBooleanIf, []}, {ExSlop.Check.Refactor.FlatMapFilter, []}, {ExSlop.Check.Refactor.RedundantEnumJoinSeparator, []}, {ExSlop.Check.Refactor.UseMapJoin, []}, {ExSlop.Check.Refactor.PreferEnumSlice, []}, {ExSlop.Check.Refactor.GraphemesLength, []}, {ExSlop.Check.Refactor.ManualStringReverse, []}, {ExSlop.Check.Refactor.SortThenAt, []}, {ExSlop.Check.Refactor.SortForTopK, []}, {ExSlop.Check.Refactor.ListFold, []}, {ExSlop.Check.Refactor.ListLast, []}, {ExSlop.Check.Refactor.LengthInGuard, []}, {ExSlop.Check.Refactor.ExplicitSumReduce, []}, {ExSlop.Check.Readability.NarratorDoc, []}, {ExSlop.Check.Readability.DocFalseOnPublicFunction, []}, {ExSlop.Check.Readability.BoilerplateDocParams, []}, {ExSlop.Check.Readability.ObviousComment, [additional_keywords: []]}, {ExSlop.Check.Readability.StepComment, []}, {ExSlop.Check.Readability.NarratorComment, []}, {ExSlop.Check.Readability.UnaliasedModuleUse, []} ``` -------------------------------- ### Run ExSlop in CI with `mix credo --strict` Source: https://context7.com/dannote/ex_slop/llms.txt Integrate ExSlop into your CI pipeline by running `mix credo --strict`. This command ensures all Credo checks, including ExSlop's, are enforced. ```yaml # .github/workflows/ci.yml - name: Run Credo (includes ExSlop checks) run: mix credo --strict ``` -------------------------------- ### Optimize Repo.all with Ecto Queries in Elixir Source: https://context7.com/dannote/ex_slop/llms.txt Avoid loading all rows into memory with `Repo.all` followed by `Enum.filter/reject/find`. Instead, push filtering logic down to the SQL query for better performance. ```elixir # BAD — loads all rows, filters in Elixir; flagged by EXS1002 active_users = Repo.all(User) |> Enum.filter(& &1.active) # W [EXS1002] `Repo.all/1 |> Enum.filter/2` loads all records — filter in the Ecto query instead. admins = Repo.all(User) |> Enum.find(&(&1.role == :admin)) # W [EXS1002] `Repo.all/1 |> Enum.find/2` loads all records ... # GOOD — push the filter down to SQL import Ecto.Query active_users = from(u in User, where: u.active == true) |> Repo.all() admin = from(u in User, where: u.role == :admin, limit: 1) |> Repo.one() ``` -------------------------------- ### Avoid Blanket Rescues in Elixir Source: https://context7.com/dannote/ex_slop/llms.txt Demonstrates how to avoid `rescue _ -> nil` or `rescue _e -> {:error, "..."}` patterns that silently swallow exceptions. Always rescue specific exceptions or let the process crash. ```elixir # BAD — flagged by EXS1001 def fetch_user(id) do try do Repo.get!(User, id) rescue _ -> nil # W [EXS1001] line 4 end end def parse_config(path) do try do File.read!(path) |> Jason.decode!() rescue _e -> {:error, "Something went wrong"} # W [EXS1001] line 10 end end # GOOD — rescue specific exceptions or let it crash def fetch_user(id) do Repo.get(User, id) # returns nil on miss; no rescue needed end def parse_config(path) do with {:ok, contents} <- File.read(path), {:ok, config} <- Jason.decode(contents) do {:ok, config} end end ``` -------------------------------- ### Replacing Try/Rescue with Integer Parse in Elixir Source: https://github.com/dannote/ex_slop/blob/master/README.md Recommends using `Integer.parse/1` which returns `{:ok, integer}` or `{:error, reason}` instead of `try/rescue` for safe integer conversion. ```elixir try do String.to_integer(x) rescue _ -> nil end ``` ```elixir Integer.parse(x) ``` -------------------------------- ### Use ETS for Concurrent Read-Heavy Access Source: https://context7.com/dannote/ex_slop/llms.txt Demonstrates the use of :ets.new with read_concurrency for efficient concurrent read access to a table. Ensure keys are normalized at the system boundary. ```elixir :ets.new(:cache, [:named_table, :public, read_concurrency: true]) :ets.insert(:cache, {key, value}) [{^key, value}] = :ets.lookup(:cache, key) ``` -------------------------------- ### Expose All Checks Programmatically Source: https://context7.com/dannote/ex_slop/llms.txt Access all available check modules provided by ExSlop. This function returns a list of all check modules, enabling custom validation tool configurations. ```elixir ExSlop.checks/0 ``` -------------------------------- ### Refactoring Nil Filtering in Elixir Source: https://github.com/dannote/ex_slop/blob/master/README.md Demonstrates replacing `Enum.filter` with a nil check with `Enum.reject` and `is_nil/1` for conciseness. ```elixir Enum.filter(fn x -> x != nil end) ``` ```elixir Enum.reject(&is_nil/1) ``` -------------------------------- ### Run Only ExSlop Checks Source: https://context7.com/dannote/ex_slop/llms.txt Execute only ExSlop-tagged Credo checks by using the `--only ex_slop` flag with the `mix credo` command. ```bash # Run only ExSlop-tagged checks (all checks share the :ex_slop tag) mix credo --strict --only ex_slop ``` -------------------------------- ### Perform Full CI Check with Mix Alias Source: https://github.com/dannote/ex_slop/blob/master/AGENTS.md Execute a comprehensive Continuous Integration check using the 'mix ci' alias. This ensures all aspects of the code quality are verified. ```shell mix ci ``` -------------------------------- ### Refactoring Nil Rejection in Elixir Source: https://github.com/dannote/ex_slop/blob/master/README.md Shows how to simplify `Enum.reject` with a nil check by using `is_nil/1`. ```elixir Enum.reject(fn x -> x == nil end) ``` ```elixir Enum.reject(&is_nil/1) ``` -------------------------------- ### Define CI Alias in `mix.exs` Source: https://context7.com/dannote/ex_slop/llms.txt Create a `ci` alias in your `mix.exs` file to conveniently run a full suite of checks, including compilation, formatting, tests, Credo, and Dialyzer. ```elixir # mix.exs — alias for full CI suite defp aliases do [ ci: [ "compile --warnings-as-errors", "format --check-formatted", "test", "credo --strict", "dialyzer" ] ] end ``` -------------------------------- ### Run Credo with ExSlop Checks Source: https://context7.com/dannote/ex_slop/llms.txt Execute Credo with the `--strict` flag to run all enabled ExSlop checks and identify potential AI-generated code patterns. This command will output warnings for detected 'slop'. ```bash mix credo --strict ``` -------------------------------- ### Use Safe Alternatives to Raising Functions in Elixir Source: https://context7.com/dannote/ex_slop/llms.txt Replaces try/rescue blocks around functions that have non-raising alternatives (e.g., Integer.parse, Jason.decode) with the safe variants. This simplifies error handling using case statements. ```elixir # BAD — all flagged by EXS4005 result = try do String.to_integer(user_input) # W: use Integer.parse/1 rescue _ -> nil end config = try do Jason.decode!(raw_json) # W: use Jason.decode/1 rescue _ -> %{} end ``` ```elixir # GOOD — use the non-raising variant result = case Integer.parse(user_input) do {n, ""} -> n _ -> nil end config = case Jason.decode(raw_json) do {:ok, map} -> map {:error, _reason} -> %{} end ``` -------------------------------- ### Using Enum Map Join in Elixir Source: https://github.com/dannote/ex_slop/blob/master/README.md Replaces `Enum.map |> Enum.join` with the more efficient `Enum.map_join`. ```elixir Enum.map(...) |> Enum.join(...) ``` ```elixir Enum.map_join(...) ``` -------------------------------- ### Use Map.new for Building Maps from Enumerables in Elixir Source: https://context7.com/dannote/ex_slop/llms.txt Replaces manual Enum.reduce with Map.put operations with the more idiomatic and efficient Map.new/2. This is suitable for creating maps where each element maps to a key-value pair. ```elixir # BAD — flagged by EXS4013 index = Enum.reduce(users, %{}, fn user, acc -> Map.put(acc, user.id, user) end) ``` ```elixir # GOOD index = Map.new(users, fn user -> {user.id, user} end) # Also works with key transformation name_index = Map.new(users, &{&1.id, &1.name}) ``` -------------------------------- ### Avoid Boilerplate in Elixir Module and Function Docs Source: https://context7.com/dannote/ex_slop/llms.txt Detects and discourages overly verbose documentation strings (e.g., '@moduledoc "This module provides..."'). Such documentation restates the module/function name without adding value. Prefer concise, informative descriptions. ```elixir # BAD — flagged by EXS3001 defmodule MyApp.UserContext do @moduledoc """ This module provides functionality for managing users. """ @doc """ This function creates a new user in the system. """ def create_user(attrs), do: ... ``` -------------------------------- ### Detailed Full CI Alias Breakdown Source: https://github.com/dannote/ex_slop/blob/master/AGENTS.md This alias includes a series of commands for a thorough CI process, covering compilation with warnings as errors, formatting checks, tests, Credo strict checks, Dialyzer, Ex-DNA, and dogfooding. ```shell mix compile --warnings-as-errors mix format --check-formatted mix test mix credo --strict mix dialyzer mix ex_dna mix dogfood ``` -------------------------------- ### Using Pattern Matching for Length Check in Elixir Source: https://github.com/dannote/ex_slop/blob/master/README.md Replaces `length(xs) == 0` in guards with pattern matching on `[]` or `[_ | _]` for efficiency. ```elixir def f(xs) when length(xs) == 0 ``` ```elixir pattern match on `[]` / `[_ | _]` ``` -------------------------------- ### Simplifying With Identity Do in Elixir Source: https://github.com/dannote/ex_slop/blob/master/README.md Removes redundant `with` clauses that simply return the successful result. ```elixir with {:ok, v} <- f() do {:ok, v} end ``` ```elixir f() ``` -------------------------------- ### Handle Rescues Without Reraising in Elixir Source: https://context7.com/dannote/ex_slop/llms.txt Shows how to avoid logging errors and returning generic values without re-raising, which silently discards exception context. Log and re-raise, or return structured error information. ```elixir # BAD — flagged by EXS1004 rescue e -> Logger.error("Failed: #{inspect(e)}") :error # W [EXS1004] # GOOD — log and re-raise, preserving the stacktrace rescue e -> Logger.error("Failed: #{Exception.message(e)}") reraise e, __STACKTRACE__ # GOOD — return structured error with actual exception info rescue e in [DBConnection.ConnectionError] -> {:error, Exception.message(e)} ``` -------------------------------- ### Configure ObviousComment Check with Custom Keywords Source: https://context7.com/dannote/ex_slop/llms.txt Add custom keywords to the ObviousComment check in your .credo.exs configuration file to prevent flagging specific comment patterns. ```elixir # .credo.exs — configure with custom keywords {ExSlop.Check.Readability.ObviousComment, [additional_keywords: ["Log the", "Print the"]]} ``` -------------------------------- ### Using Enum Slice in Elixir Source: https://github.com/dannote/ex_slop/blob/master/README.md Recommends `Enum.slice/3` over chaining `Enum.drop/2` and `Enum.take/2` for extracting a sublist. ```elixir Enum.drop(n) |> Enum.take(k) ``` ```elixir Enum.slice(enum, n, k) ``` -------------------------------- ### Prevent N+1 Queries in Elixir with Preloading Source: https://context7.com/dannote/ex_slop/llms.txt Avoid making one database query per list element using `Enum.map` with `Repo.get/one/all`. Use Ecto's `preload` function or join queries to fetch related data efficiently. ```elixir # BAD — N+1 queries; flagged by EXS1003 posts_with_authors = Repo.all(Post) |> Enum.map(fn post -> author = Repo.get(User, post.user_id) # W [EXS1003] N+1 query %{post | author: author} end) # GOOD — preload in one query posts_with_authors = Repo.all(Post) |> Repo.preload(:author) # GOOD — join in query import Ecto.Query posts_with_authors = from(p in Post, preload: [:author]) |> Repo.all() ``` -------------------------------- ### Replacing Case with If/Else in Elixir Source: https://github.com/dannote/ex_slop/blob/master/README.md Suggests using `if/else` for simple boolean conditions instead of `case` statements. ```elixir case flag do true -> a; false -> b end ``` ```elixir if flag, do: a, else: b ``` -------------------------------- ### Use Enum.map Instead of Reduce for Transformations in Elixir Source: https://context7.com/dannote/ex_slop/llms.txt Replaces manual prepend or O(n^2) append operations within Enum.reduce with the simpler and more efficient Enum.map/2. This is suitable when transforming each element into a new list. ```elixir # BAD — flagged by EXS4003 transformed = Enum.reduce(items, [], fn item, acc -> [String.upcase(item) | acc] # manual prepend end) also_bad = Enum.reduce(items, [], fn item, acc -> acc ++ [String.upcase(item)] # O(n^2) append end) ``` ```elixir # GOOD transformed = Enum.map(items, &String.upcase/1) ``` -------------------------------- ### Using Enum Sum in Elixir Source: https://github.com/dannote/ex_slop/blob/master/README.md Replaces `Enum.reduce` for summing numbers with the more concise `Enum.sum/1`. ```elixir Enum.reduce(nums, 0, fn n, acc -> n + acc end) ``` ```elixir Enum.sum(nums) ``` -------------------------------- ### Using String Reverse in Elixir Source: https://github.com/dannote/ex_slop/blob/master/README.md Replaces manual string reversal using `String.graphemes`, `Enum.reverse`, and `Enum.join` with the built-in `String.reverse/1`. ```elixir String.graphemes(s) |> Enum.reverse() |> Enum.join() ``` ```elixir String.reverse(s) ``` -------------------------------- ### Refactoring String Concatenation in Reduce in Elixir Source: https://github.com/dannote/ex_slop/blob/master/README.md Suggests using `Enum.join/1` or IO data for string concatenation within `Enum.reduce` to avoid performance issues. ```elixir Enum.reduce("", fn x, acc -> acc <> x end) ``` ```elixir Enum.join/1 or IO data ``` -------------------------------- ### Using Enum Reduce for List Fold in Elixir Source: https://github.com/dannote/ex_slop/blob/master/README.md Replaces `List.foldl/3` with the more idiomatic `Enum.reduce/3`. ```elixir List.foldl(list, acc, fun) ``` ```elixir Enum.reduce(list, acc, fun) ``` -------------------------------- ### Refactoring Reduce to Map in Elixir Source: https://github.com/dannote/ex_slop/blob/master/README.md Replaces `Enum.reduce` used for mapping into a list with a more direct `Enum.map`. ```elixir Enum.reduce([], fn x, acc -> [f(x) | acc] end) ``` ```elixir Enum.map(&f/1) ``` -------------------------------- ### Simplifying Redundant Boolean If in Elixir Source: https://github.com/dannote/ex_slop/blob/master/README.md Recommends using the condition directly when an `if` statement returns `true` or `false`. ```elixir if cond, do: true, else: false ``` ```elixir use the condition directly ``` -------------------------------- ### Simplifying Identity Passthrough in Elixir Source: https://github.com/dannote/ex_slop/blob/master/README.md Removes redundant `case` statements that simply pass through `{:ok, v}` or `{:error, e}`. ```elixir case r do {:ok, v} -> {:ok, v}; {:error, e} -> {:error, e} end ``` ```elixir r ``` -------------------------------- ### Avoiding List Last in Elixir Source: https://github.com/dannote/ex_slop/blob/master/README.md Suggests redesigning logic to avoid needing the last element after traversal, implying `List.last/1` can be inefficient. ```elixir List.last(list) ``` ```elixir avoid needing the last element after traversal ``` -------------------------------- ### Refactoring Reduce Map Put in Elixir Source: https://github.com/dannote/ex_slop/blob/master/README.md Replaces `Enum.reduce` with `Map.put` with `Map.new/2` for creating maps. ```elixir Enum.reduce(%{}, fn x, acc -> Map.put(acc, k, v) end) ``` ```elixir Map.new/2 ``` -------------------------------- ### Use Descending Sort Option Directly in Elixir Source: https://context7.com/dannote/ex_slop/llms.txt Replaces the pattern of sorting and then reversing with the direct :desc option in Enum.sort/2 and Enum.sort_by/3. This is more efficient and readable. ```elixir # BAD — all flagged by EXS4009 list |> Enum.sort() |> Enum.reverse() Enum.reverse(Enum.sort(list)) list |> Enum.sort_by(& &1.inserted_at) |> Enum.reverse() ``` ```elixir # GOOD Enum.sort(list, :desc) Enum.sort_by(list, & &1.inserted_at, :desc) ``` -------------------------------- ### Refactoring Map into Literal Map in Elixir Source: https://github.com/dannote/ex_slop/blob/master/README.md Suggests using `Map.new` directly instead of chaining `Enum.map` with `Enum.into(%{})`. ```elixir Enum.map(...) |> Enum.into(%{}) ``` ```elixir Map.new(...) ``` -------------------------------- ### Avoid Mixed Atom/String Key Access in Elixir Source: https://context7.com/dannote/ex_slop/llms.txt Detects and corrects mixed atom and string key access in maps. Normalize keys to a single type (e.g., atoms) at the system boundary to prevent this. ```elixir # BAD — flagged by EXS1007 value = params[:user_id] || params["user_id"] name = Map.get(attrs, :name) || Map.get(attrs, "name") token = get_in(conn.assigns, [:token]) || get_in(conn.assigns, ["token"]) ``` ```elixir # GOOD — normalize keys once at the system boundary defp atomize_keys(map) do Map.new(map, fn {k, v} -> {String.to_existing_atom(to_string(k)), v} end) end # Then access with a single key type throughout params = atomize_keys(raw_params) value = params[:user_id] ``` -------------------------------- ### Simplifying Redundant Enum Join Separator in Elixir Source: https://github.com/dannote/ex_slop/blob/master/README.md Removes the empty string separator from `Enum.join` when joining string parts. ```elixir Enum.join(parts, "") ``` ```elixir Enum.join(parts) ``` -------------------------------- ### Use Enum.filter Instead of FlatMap for Conditional Inclusion in Elixir Source: https://context7.com/dannote/ex_slop/llms.txt Replaces verbose Enum.flat_map patterns used for conditional inclusion (returning `[x]` or `[]`) with the simpler Enum.filter/2. This improves code clarity when the goal is just to select elements. ```elixir # BAD — flagged by EXS4015 active = Enum.flat_map(users, fn user -> if user.active, do: [user], else: [] end) ``` ```elixir # GOOD active = Enum.filter(users, & &1.active) ``` -------------------------------- ### Refactoring Sort Then Reverse in Elixir Source: https://github.com/dannote/ex_slop/blob/master/README.md Replaces `Enum.sort() |> Enum.reverse()` with the more efficient `Enum.sort(:desc)`. ```elixir Enum.sort() |> Enum.reverse() ``` ```elixir Enum.sort(:desc) ``` -------------------------------- ### Refactoring FlatMap Filter in Elixir Source: https://github.com/dannote/ex_slop/blob/master/README.md Replaces `Enum.flat_map` with a conditional list return with `Enum.filter/2`. ```elixir Enum.flat_map(fn x -> if cond, do: [x], else: [] end) ``` ```elixir Enum.filter/2 ``` -------------------------------- ### Simplifying With Identity Else in Elixir Source: https://github.com/dannote/ex_slop/blob/master/README.md Removes the `else` block from a `with` statement when it simply returns the error. ```elixir with {:ok, v} <- f() do v else {:error, r} -> {:error, r} end ``` ```elixir drop the `else` ``` -------------------------------- ### Removing Identity Map in Elixir Source: https://github.com/dannote/ex_slop/blob/master/README.md Advises removing `Enum.map` calls where the function simply returns its input. ```elixir Enum.map(fn x -> x end) ``` ```elixir remove the call ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.