diff --git a/CLAUDE.md b/CLAUDE.md index 6f72694..509cec1 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -16,7 +16,7 @@ mix test # Run all tests (auto-creates/migrates test DB) mix test test/path_test.exs # Run a single test file mix test test/path_test.exs:42 # Run a specific test by line number mix test --failed # Re-run previously failed tests -mix precommit # Compile (warnings-as-errors) + unlock unused deps + format + test +mix precommit # Compile (warnings-as-errors) + unlock unused deps + format + credo --strict + test mix format # Format code mix ecto.gen.migration name # Generate a new migration mix ecto.migrate # Run pending migrations diff --git a/lib/ammoprices/application.ex b/lib/ammoprices/application.ex index b767bc0..9f1f2a2 100644 --- a/lib/ammoprices/application.ex +++ b/lib/ammoprices/application.ex @@ -5,6 +5,8 @@ defmodule Ammoprices.Application do use Application + alias Ammoprices.Scraping.ScrapeJob + @impl true def start(_type, _args) do children = [ @@ -22,7 +24,7 @@ defmodule Ammoprices.Application do result = Supervisor.start_link(children, opts) # Seed the self-scheduling scrape job chain (unique constraint prevents duplicates) - Ammoprices.Scraping.ScrapeJob.schedule_next() + ScrapeJob.schedule_next() result end diff --git a/lib/ammoprices/scraping/retailers/lucky_gunner.ex b/lib/ammoprices/scraping/retailers/lucky_gunner.ex index 47d508a..e9aafb8 100644 --- a/lib/ammoprices/scraping/retailers/lucky_gunner.ex +++ b/lib/ammoprices/scraping/retailers/lucky_gunner.ex @@ -114,27 +114,20 @@ defmodule Ammoprices.Scraping.Retailers.LuckyGunner do end defp extract_price_per_round(item) do - case Floki.find(item, ".cprc") do - [{_, _, _} = node] -> - text = node |> Floki.text() |> String.trim() + with [{_, _, _} = node] <- Floki.find(item, ".cprc"), + text = node |> Floki.text() |> String.trim(), + [_, amount] <- Regex.run(~r/([0-9.]+)¢/, text) do + {:ok, parse_cents(amount)} + else + _ -> :error + end + end - case Regex.run(~r/([0-9.]+)¢/, text) do - [_, amount] -> - cents = - if String.contains?(amount, ".") do - amount |> String.to_float() |> trunc() - else - String.to_integer(amount) - end - - {:ok, cents} - - _ -> - :error - end - - _ -> - :error + defp parse_cents(amount) do + if String.contains?(amount, ".") do + amount |> String.to_float() |> trunc() + else + String.to_integer(amount) end end diff --git a/lib/ammoprices_web/components/core_components.ex b/lib/ammoprices_web/components/core_components.ex index 8e5f338..b321721 100644 --- a/lib/ammoprices_web/components/core_components.ex +++ b/lib/ammoprices_web/components/core_components.ex @@ -29,6 +29,7 @@ defmodule AmmopricesWeb.CoreComponents do use Phoenix.Component use Gettext, backend: AmmopricesWeb.Gettext + alias Phoenix.HTML.Form alias Phoenix.HTML.FormField alias Phoenix.LiveView.JS @@ -200,7 +201,7 @@ defmodule AmmopricesWeb.CoreComponents do def input(%{type: "checkbox"} = assigns) do assigns = assign_new(assigns, :checked, fn -> - Phoenix.HTML.Form.normalize_value("checkbox", assigns[:value]) + Form.normalize_value("checkbox", assigns[:value]) end) ~H""" diff --git a/mix.exs b/mix.exs index 79740ef..82f144b 100644 --- a/mix.exs +++ b/mix.exs @@ -63,7 +63,8 @@ defmodule Ammoprices.MixProject do {:jason, "~> 1.2"}, {:dns_cluster, "~> 0.2.0"}, {:bandit, "~> 1.5"}, - {:styler, "~> 1.4", only: [:dev, :test], runtime: false} + {:styler, "~> 1.4", only: [:dev, :test], runtime: false}, + {:credo, "~> 1.7", only: [:dev, :test], runtime: false} ] end @@ -86,7 +87,7 @@ defmodule Ammoprices.MixProject do "esbuild ammoprices --minify", "phx.digest" ], - precommit: ["compile --warnings-as-errors", "deps.unlock --unused", "format", "test"] + precommit: ["compile --warnings-as-errors", "deps.unlock --unused", "format", "credo --strict", "test"] ] end end diff --git a/mix.lock b/mix.lock index efe7430..cc30bb4 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,8 @@ %{ "bandit": {:hex, :bandit, "1.10.3", "1e5d168fa79ec8de2860d1b4d878d97d4fbbe2fdbe7b0a7d9315a4359d1d4bb9", [:mix], [{:hpax, "~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}, {:plug, "~> 1.18", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:thousand_island, "~> 1.0", [hex: :thousand_island, repo: "hexpm", optional: false]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "99a52d909c48db65ca598e1962797659e3c0f1d06e825a50c3d75b74a5e2db18"}, + "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, "cc_precompiler": {:hex, :cc_precompiler, "0.1.11", "8c844d0b9fb98a3edea067f94f616b3f6b29b959b6b3bf25fee94ffe34364768", [:mix], [{:elixir_make, "~> 0.7", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "3427232caf0835f94680e5bcf082408a70b48ad68a5f5c0b02a3bea9f3a075b9"}, + "credo": {:hex, :credo, "1.7.17", "f92b6aa5b26301eaa5a35e4d48ebf5aa1e7094ac00ae38f87086c562caf8a22f", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "1eb5645c835f0b6c9b5410f94b5a185057bcf6d62a9c2b476da971cde8749645"}, "db_connection": {:hex, :db_connection, "2.9.0", "a6a97c5c958a2d7091a58a9be40caf41ab496b0701d21e1d1abff3fa27a7f371", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "17d502eacaf61829db98facf6f20808ed33da6ccf495354a41e64fe42f9c509c"}, "decimal": {:hex, :decimal, "2.3.0", "3ad6255aa77b4a3c4f818171b12d237500e63525c2fd056699967a3e7ea20f62", [:mix], [], "hexpm", "a4d66355cb29cb47c3cf30e71329e58361cfcb37c34235ef3bf1d7bf3773aeac"}, "dns_cluster": {:hex, :dns_cluster, "0.2.0", "aa8eb46e3bd0326bd67b84790c561733b25c5ba2fe3c7e36f28e88f384ebcb33", [:mix], [], "hexpm", "ba6f1893411c69c01b9e8e8f772062535a4cf70f3f35bcc964a324078d8c8240"},