diff --git a/CHANGELOG.md b/CHANGELOG.md index 8539a24..f13e939 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # Changelog -## main +## 0.3.1 + +- Implements `String.Chars` protocol +- Implements `Phoenix.HTML.Safe` protocol +- Implements `Phoenix.Param` protocol + +## 0.3.0 - **BREAKING:** `type/1` has been renamed to `prefix/1` - `Ecto.ParameterizedType` implementation diff --git a/README.md b/README.md index ca76348..615420b 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ The package can be installed from [hex](https://hex.pm/packages/typeid_elixir) b ```elixir def deps do [ - {:typeid_elixir, "~> 0.3.0"} + {:typeid_elixir, "~> 0.3.1"} ] end ``` diff --git a/lib/type_id.ex b/lib/type_id.ex index f74db2c..c454478 100644 --- a/lib/type_id.ex +++ b/lib/type_id.ex @@ -67,6 +67,30 @@ defmodule TypeID do suffix end + @doc """ + Returns an `t:iodata/0` representation of the given `t:t/0`. + + ### Examples + + iex> tid = TypeID.from_string!("player_01h4rn40ybeqws3gfp073jt81b") + iex> TypeID.to_iodata(tid) + ["player", "_", "01h4rn40ybeqws3gfp073jt81b"] + + + iex> tid = TypeID.from_string!("01h4rn40ybeqws3gfp073jt81b") + iex> TypeID.to_iodata(tid) + "01h4rn40ybeqws3gfp073jt81b" + + """ + @spec to_iodata(tid :: t()) :: iodata() + def to_iodata(%__MODULE__{prefix: "", suffix: suffix}) do + suffix + end + + def to_iodata(%__MODULE__{prefix: prefix, suffix: suffix}) do + [prefix, "_", suffix] + end + @doc """ Returns a string representation of the given `t:t/0` @@ -78,12 +102,10 @@ defmodule TypeID do """ @spec to_string(tid :: t()) :: String.t() - def to_string(%__MODULE__{prefix: "", suffix: suffix}) do - suffix - end - - def to_string(%__MODULE__{prefix: prefix, suffix: suffix}) do - prefix <> "_" <> suffix + def to_string(%__MODULE__{} = tid) do + tid + |> to_iodata() + |> IO.iodata_to_binary() end @doc """ @@ -336,3 +358,19 @@ defimpl Inspect, for: TypeID do concat(["#TypeID<\"", TypeID.to_string(tid), "\">"]) end end + +defimpl String.Chars, for: TypeID do + defdelegate to_string(tid), to: TypeID +end + +if Code.ensure_loaded?(Phoenix.HTML.Safe) do + defimpl Phoenix.HTML.Safe, for: TypeID do + defdelegate to_iodata(tid), to: TypeID + end +end + +if Code.ensure_loaded?(Phoenix.Param) do + defimpl Phoenix.Param, for: TypeID do + defdelegate to_param(tid), to: TypeID, as: :to_string + end +end diff --git a/mix.exs b/mix.exs index 752161d..43c367b 100644 --- a/mix.exs +++ b/mix.exs @@ -1,7 +1,7 @@ defmodule TypeID.MixProject do use Mix.Project - @version "0.3.0" + @version "0.3.1" def project do [ @@ -43,6 +43,8 @@ defmodule TypeID.MixProject do defp deps do [ {:ecto, "~> 3.10", only: [:dev, :test], optional: true}, + {:phoenix_html, "~> 3.3", only: [:dev, :test], optional: true}, + {:phoenix, "~> 1.7", only: [:dev, :test], optional: true}, {:ex_doc, "~> 0.27", only: :dev, runtime: false}, {:yaml_elixir, "~> 2.9", only: [:dev, :test], runtime: false} ] diff --git a/mix.lock b/mix.lock index 3c45c20..009b2be 100644 --- a/mix.lock +++ b/mix.lock @@ -1,4 +1,5 @@ %{ + "castore": {:hex, :castore, "1.0.3", "7130ba6d24c8424014194676d608cb989f62ef8039efd50ff4b3f33286d06db8", [:mix], [], "hexpm", "680ab01ef5d15b161ed6a95449fac5c6b8f60055677a8e79acf01b27baa4390b"}, "decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"}, "earmark_parser": {:hex, :earmark_parser, "1.4.32", "fa739a0ecfa34493de19426681b23f6814573faee95dfd4b4aafe15a7b5b32c6", [:mix], [], "hexpm", "b8b0dd77d60373e77a3d7e8afa598f325e49e8663a51bcc2b88ef41838cca755"}, "ecto": {:hex, :ecto, "3.10.2", "6b887160281a61aa16843e47735b8a266caa437f80588c3ab80a8a960e6abe37", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "6a895778f0d7648a4b34b486af59a1c8009041fbdf2b17f1ac215eb829c60235"}, @@ -6,8 +7,17 @@ "makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"}, "makeup_elixir": {:hex, :makeup_elixir, "0.16.1", "cc9e3ca312f1cfeccc572b37a09980287e243648108384b97ff2b76e505c3555", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "e127a341ad1b209bd80f7bd1620a15693a9908ed780c3b763bccf7d200c767c6"}, "makeup_erlang": {:hex, :makeup_erlang, "0.1.2", "ad87296a092a46e03b7e9b0be7631ddcf64c790fa68a9ef5323b6cbb36affc72", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "f3f5a1ca93ce6e092d92b6d9c049bcda58a3b617a8d888f8e7231c85630e8108"}, + "mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"}, "nimble_parsec": {:hex, :nimble_parsec, "1.3.1", "2c54013ecf170e249e9291ed0a62e5832f70a476c61da16f6aac6dca0189f2af", [:mix], [], "hexpm", "2682e3c0b2eb58d90c6375fc0cc30bc7be06f365bf72608804fb9cffa5e1b167"}, + "phoenix": {:hex, :phoenix, "1.7.6", "61f0625af7c1d1923d582470446de29b008c0e07ae33d7a3859ede247ddaf59a", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "f6b4be7780402bb060cbc6e83f1b6d3f5673b674ba73cc4a7dd47db0322dfb88"}, + "phoenix_html": {:hex, :phoenix_html, "3.3.1", "4788757e804a30baac6b3fc9695bf5562465dd3f1da8eb8460ad5b404d9a2178", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "bed1906edd4906a15fd7b412b85b05e521e1f67c9a85418c55999277e553d0d3"}, + "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.3", "3168d78ba41835aecad272d5e8cd51aa87a7ac9eb836eabc42f6e57538e3731d", [:mix], [], "hexpm", "bba06bc1dcfd8cb086759f0edc94a8ba2bc8896d5331a1e2c2902bf8e36ee502"}, + "phoenix_template": {:hex, :phoenix_template, "1.0.1", "85f79e3ad1b0180abb43f9725973e3b8c2c3354a87245f91431eec60553ed3ef", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "157dc078f6226334c91cb32c1865bf3911686f8bcd6bcff86736f6253e6993ee"}, + "plug": {:hex, :plug, "1.14.2", "cff7d4ec45b4ae176a227acd94a7ab536d9b37b942c8e8fa6dfc0fff98ff4d80", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "842fc50187e13cf4ac3b253d47d9474ed6c296a8732752835ce4a86acdf68d13"}, + "plug_crypto": {:hex, :plug_crypto, "1.2.5", "918772575e48e81e455818229bf719d4ab4181fcbf7f85b68a35620f78d89ced", [:mix], [], "hexpm", "26549a1d6345e2172eb1c233866756ae44a9609bd33ee6f99147ab3fd87fd842"}, "telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"}, + "websock": {:hex, :websock, "0.5.2", "b3c08511d8d79ed2c2f589ff430bd1fe799bb389686dafce86d28801783d8351", [:mix], [], "hexpm", "925f5de22fca6813dfa980fb62fd542ec43a2d1a1f83d2caec907483fe66ff05"}, + "websock_adapter": {:hex, :websock_adapter, "0.5.3", "4908718e42e4a548fc20e00e70848620a92f11f7a6add8cf0886c4232267498d", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "cbe5b814c1f86b6ea002b52dd99f345aeecf1a1a6964e209d208fb404d930d3d"}, "yamerl": {:hex, :yamerl, "0.10.0", "4ff81fee2f1f6a46f1700c0d880b24d193ddb74bd14ef42cb0bcf46e81ef2f8e", [:rebar3], [], "hexpm", "346adb2963f1051dc837a2364e4acf6eb7d80097c0f53cbdc3046ec8ec4b4e6e"}, "yaml_elixir": {:hex, :yaml_elixir, "2.9.0", "9a256da867b37b8d2c1ffd5d9de373a4fda77a32a45b452f1708508ba7bbcb53", [:mix], [{:yamerl, "~> 0.10", [hex: :yamerl, repo: "hexpm", optional: false]}], "hexpm", "0cb0e7d4c56f5e99a6253ed1a670ed0e39c13fc45a6da054033928607ac08dfc"}, } diff --git a/test/type_id/phoenix_html_safe_test.exs b/test/type_id/phoenix_html_safe_test.exs new file mode 100644 index 0000000..fc34621 --- /dev/null +++ b/test/type_id/phoenix_html_safe_test.exs @@ -0,0 +1,17 @@ +defmodule TypeID.PhoenixHTMLSafeTest do + use ExUnit.Case + + test "to_iodata/1" do + assert {:ok, tid} = TypeID.from_string("test_01h4rm6n03esc96rwqtnq2fr5a") + + assert "test_01h4rm6n03esc96rwqtnq2fr5a" == + tid |> Phoenix.HTML.Safe.to_iodata() |> IO.iodata_to_binary() + end + + test "no prefix" do + assert {:ok, tid} = TypeID.from_string("01h4rm6n03esc96rwqtnq2fr5a") + + assert "01h4rm6n03esc96rwqtnq2fr5a" == + tid |> Phoenix.HTML.Safe.to_iodata() |> IO.iodata_to_binary() + end +end diff --git a/test/type_id/string_char_test.exs b/test/type_id/string_char_test.exs new file mode 100644 index 0000000..a0c217d --- /dev/null +++ b/test/type_id/string_char_test.exs @@ -0,0 +1,13 @@ +defmodule TypeID.StringCharTest do + use ExUnit.Case + + test "implicit cast to string" do + assert {:ok, tid} = TypeID.from_string("test_01h4rm6n03esc96rwqtnq2fr5a") + assert "cast? test_01h4rm6n03esc96rwqtnq2fr5a" == "cast? #{tid}" + end + + test "Kernel.to_string/1" do + assert {:ok, tid} = TypeID.from_string("test_01h4rm6n03esc96rwqtnq2fr5a") + assert "test_01h4rm6n03esc96rwqtnq2fr5a" == to_string(tid) + end +end