diff --git a/README.md b/README.md index 4c26797..a3ad823 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ end Documentation can be found at [https://hexdocs.pm/language_list](https://hexdocs.pm/language_list). -## Usage: +## Usage Standard requests will return a list of maps or strings. @@ -113,6 +113,6 @@ nil ``` -## TODO: +## TODO -[] add native language names to json file. +[ ] add native language names to json file. diff --git a/lib/language_list.ex b/lib/language_list.ex index 22ea85d..a917ff4 100644 --- a/lib/language_list.ex +++ b/lib/language_list.ex @@ -18,12 +18,15 @@ defmodule LanguageList do def all_data do file_path = Application.app_dir(:language_list, "priv/languages.json") + decoders = [ + object_push: fn key, value, acc -> [{String.to_existing_atom(key), value} | acc] end + ] + with {:ok, file} <- File.read(file_path), - {:ok, languages} <- Poison.decode(file, keys: :atoms) - do - languages - else - _ -> raise "Could not read internal languages.json file!" + {languages, :ok, ""} <- JSON.decode(file, :ok, decoders) do + languages + else + _ -> raise "Could not read internal languages.json file!" end end @@ -51,7 +54,7 @@ defmodule LanguageList do @doc false def all_common_data!, do: all_common_data() - @doc""" + @doc """ Returns list of all language names. ## Examples @@ -131,5 +134,4 @@ defmodule LanguageList do {:ok, result} end end - end diff --git a/mix.exs b/mix.exs index 4aecd26..0b43793 100644 --- a/mix.exs +++ b/mix.exs @@ -4,14 +4,18 @@ defmodule LanguageList.MixProject do def project do [ app: :language_list, - version: "2.0.0", - elixir: "~> 1.12", + version: "3.0.0", + elixir: "~> 1.18", start_permanent: Mix.env() == :prod, description: description(), package: package(), deps: deps(), name: "language_list", - source_url: "https://github.com/GunnarPDX/language_list" + source_url: "https://github.com/GunnarPDX/language_list", + docs: [ + main: "readme", + extras: ["README.md"] + ] ] end @@ -25,8 +29,7 @@ defmodule LanguageList.MixProject do # Run "mix help deps" to learn about dependencies. defp deps do [ - {:poison, "~> 3.1"}, - {:ex_doc, ">= 0.0.0", only: :dev, runtime: false} + {:ex_doc, "~> 0.34", only: :dev, runtime: false, warn_if_outdated: true} ] end @@ -43,7 +46,7 @@ defmodule LanguageList.MixProject do # This option is only needed when you don't want to use the OTP application name name: "language_list", # These are the default files included in the package - files: ~w(lib priv .formatter.exs mix.exs README* LICENSE*), + files: ~w(lib priv .formatter.exs mix.exs README* LICENSE* usage-rules.md), licenses: ["MIT"], links: %{"GitHub" => "https://github.com/GunnarPDX/language_list"} ] diff --git a/mix.lock b/mix.lock index 5fcd076..1bf6bab 100644 --- a/mix.lock +++ b/mix.lock @@ -1,10 +1,10 @@ %{ - "earmark_parser": {:hex, :earmark_parser, "1.4.12", "b245e875ec0a311a342320da0551da407d9d2b65d98f7a9597ae078615af3449", [:mix], [], "hexpm", "711e2cc4d64abb7d566d43f54b78f7dc129308a63bc103fbd88550d2174b3160"}, - "ex_doc": {:hex, :ex_doc, "0.24.2", "e4c26603830c1a2286dae45f4412a4d1980e1e89dc779fcd0181ed1d5a05c8d9", [:mix], [{:earmark_parser, "~> 1.4.0", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "e134e1d9e821b8d9e4244687fb2ace58d479b67b282de5158333b0d57c6fb7da"}, + "earmark_parser": {:hex, :earmark_parser, "1.4.44", "f20830dd6b5c77afe2b063777ddbbff09f9759396500cdbe7523efd58d7a339c", [:mix], [], "hexpm", "4778ac752b4701a5599215f7030989c989ffdc4f6df457c5f36938cc2d2a2750"}, + "ex_doc": {:hex, :ex_doc, "0.39.3", "519c6bc7e84a2918b737aec7ef48b96aa4698342927d080437f61395d361dcee", [:mix], [{:earmark_parser, "~> 1.4.44", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "0590955cf7ad3b625780ee1c1ea627c28a78948c6c0a9b0322bd976a079996e1"}, "jason": {:hex, :jason, "1.2.2", "ba43e3f2709fd1aa1dce90aaabfd039d000469c05c56f0b8e31978e03fa39052", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "18a228f5f0058ee183f29f9eae0805c6e59d61c3b006760668d8d18ff0d12179"}, - "makeup": {:hex, :makeup, "1.0.5", "d5a830bc42c9800ce07dd97fa94669dfb93d3bf5fcf6ea7a0c67b2e0e4a7f26c", [:mix], [{:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cfa158c02d3f5c0c665d0af11512fed3fba0144cf1aadee0f2ce17747fba2ca9"}, - "makeup_elixir": {:hex, :makeup_elixir, "0.15.1", "b5888c880d17d1cc3e598f05cdb5b5a91b7b17ac4eaf5f297cb697663a1094dd", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.1", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "db68c173234b07ab2a07f645a5acdc117b9f99d69ebf521821d89690ae6c6ec8"}, - "makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"}, - "nimble_parsec": {:hex, :nimble_parsec, "1.1.0", "3a6fca1550363552e54c216debb6a9e95bd8d32348938e13de5eda962c0d7f89", [:mix], [], "hexpm", "08eb32d66b706e913ff748f11694b17981c0b04a33ef470e33e11b3d3ac8f54b"}, + "makeup": {:hex, :makeup, "1.2.1", "e90ac1c65589ef354378def3ba19d401e739ee7ee06fb47f94c687016e3713d1", [:mix], [{:nimble_parsec, "~> 1.4", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "d36484867b0bae0fea568d10131197a4c2e47056a6fbe84922bf6ba71c8d17ce"}, + "makeup_elixir": {:hex, :makeup_elixir, "1.0.1", "e928a4f984e795e41e3abd27bfc09f51db16ab8ba1aebdba2b3a575437efafc2", [: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", "7284900d412a3e5cfd97fdaed4f5ed389b8f2b4cb49efc0eb3bd10e2febf9507"}, + "makeup_erlang": {:hex, :makeup_erlang, "1.0.2", "03e1804074b3aa64d5fad7aa64601ed0fb395337b982d9bcf04029d68d51b6a7", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "af33ff7ef368d5893e4a267933e7744e46ce3cf1f61e2dccf53a111ed3aa3727"}, + "nimble_parsec": {:hex, :nimble_parsec, "1.4.2", "8efba0122db06df95bfaa78f791344a89352ba04baedd3849593bfce4d0dc1c6", [:mix], [], "hexpm", "4b21398942dda052b403bbe1da991ccd03a053668d147d53fb8c4e0efe09c973"}, "poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm", "fec8660eb7733ee4117b85f55799fd3833eb769a6df71ccf8903e8dc5447cfce"}, } diff --git a/test/language_list_test.exs b/test/language_list_test.exs index 183897c..fd7cc9e 100644 --- a/test/language_list_test.exs +++ b/test/language_list_test.exs @@ -3,48 +3,48 @@ defmodule LanguageListTest do # doctest LanguageList test "get all data" do - assert values = LanguageList.all_data + assert values = LanguageList.all_data() assert Enum.count(values) > 0 end test "get all data without :ok/:error" do - assert LanguageList.all_data! |> Enum.count() > 0 + assert LanguageList.all_data!() |> Enum.count() > 0 end test "test get all common data" do - assert values = LanguageList.all_common_data + assert values = LanguageList.all_common_data() assert Enum.count(values) > 0 end test "test get all common data without :ok/:error" do - assert LanguageList.all_common_data! |> Enum.count() > 0 + assert LanguageList.all_common_data!() |> Enum.count() > 0 end test "make sure all_common_data returns only common data" do - values = LanguageList.all_common_data + values = LanguageList.all_common_data() assert Enum.find(values, fn x -> x.common != true end) == nil end test "get language names" do - assert values = LanguageList.languages + assert values = LanguageList.languages() assert Enum.count(values) > 0 end test "get language names without :ok/:error" do - assert LanguageList.languages! |> Enum.count() > 0 + assert LanguageList.languages!() |> Enum.count() > 0 end test "get common language names" do - assert values = LanguageList.common_languages + assert values = LanguageList.common_languages() assert Enum.count(values) > 0 end test "get common language names without :ok/:error" do - assert LanguageList.common_languages! |> Enum.count() > 0 + assert LanguageList.common_languages!() |> Enum.count() > 0 end test "common languages only" do - values = LanguageList.common_languages! + values = LanguageList.common_languages!() assert Enum.find(values, fn x -> x == "Corsican" end) == nil assert Enum.find(values, fn x -> x == "Aragonese" end) == nil assert Enum.find(values, fn x -> x == "Guarani" end) == nil @@ -58,33 +58,58 @@ defmodule LanguageListTest do end test "find by language name" do - assert LanguageList.find("Icelandic", :name) == {:ok, %{common: true, iso_639_1: "is", iso_639_3: "isl", name: "Icelandic"}} + assert LanguageList.find("Icelandic", :name) == + {:ok, %{common: true, iso_639_1: "is", iso_639_3: "isl", name: "Icelandic"}} + assert LanguageList.find("name does not exist", :name) == {:error, "No matches found"} end test "find by name without :ok/:error" do - assert LanguageList.find!("Icelandic", :name) == %{common: true, iso_639_1: "is", iso_639_3: "isl", name: "Icelandic"} + assert LanguageList.find!("Icelandic", :name) == %{ + common: true, + iso_639_1: "is", + iso_639_3: "isl", + name: "Icelandic" + } + assert LanguageList.find!("name does not exist", :name) == nil end test "find by iso-1" do - assert LanguageList.find("pt", :iso_639_1) == {:ok, %{common: true, iso_639_1: "pt", iso_639_3: "por", name: "Portuguese"}} - assert LanguageList.find("iso code does not exist", :iso_639_1) == {:error, "No matches found"} + assert LanguageList.find("pt", :iso_639_1) == + {:ok, %{common: true, iso_639_1: "pt", iso_639_3: "por", name: "Portuguese"}} + + assert LanguageList.find("iso code does not exist", :iso_639_1) == + {:error, "No matches found"} end test "find by iso-1 without :ok/:error" do - assert LanguageList.find!("pt", :iso_639_1) == %{common: true, iso_639_1: "pt", iso_639_3: "por", name: "Portuguese"} + assert LanguageList.find!("pt", :iso_639_1) == %{ + common: true, + iso_639_1: "pt", + iso_639_3: "por", + name: "Portuguese" + } + assert LanguageList.find!("iso code does not exist", :iso_639_1) == nil end test "find by iso-3" do - assert LanguageList.find("pt", :iso_639_1) == {:ok, %{common: true, iso_639_1: "pt", iso_639_3: "por", name: "Portuguese"}} - assert LanguageList.find("iso code does not exist", :iso_639_1) == {:error, "No matches found"} + assert LanguageList.find("pt", :iso_639_1) == + {:ok, %{common: true, iso_639_1: "pt", iso_639_3: "por", name: "Portuguese"}} + + assert LanguageList.find("iso code does not exist", :iso_639_1) == + {:error, "No matches found"} end test "find by iso-3 without :ok/:error" do - assert LanguageList.find!("por", :iso_639_3) == %{common: true, iso_639_1: "pt", iso_639_3: "por", name: "Portuguese"} + assert LanguageList.find!("por", :iso_639_3) == %{ + common: true, + iso_639_1: "pt", + iso_639_3: "por", + name: "Portuguese" + } + assert LanguageList.find!("iso code does not exist", :iso_639_3) == nil end - end diff --git a/usage-rules.md b/usage-rules.md new file mode 100644 index 0000000..7375140 --- /dev/null +++ b/usage-rules.md @@ -0,0 +1,47 @@ +# LanguageList Usage Rules + +## Data Structure + +Language data is returned as maps with these keys: +- `:name` - Language name (e.g., "Portuguese") +- `:iso_639_1` - Two-letter ISO code (e.g., "pt") +- `:iso_639_3` - Three-letter ISO code (e.g., "por") +- `:common` - Boolean indicating if commonly used + +## API Functions + +- `all_data/0` - Returns list of all language maps +- `all_common_data/0` - Returns list of common language maps only +- `languages/0` - Returns list of all language names as strings +- `common_languages/0` - Returns list of common language names as strings +- `find/2` - Returns `{:ok, map}` or `{:error, msg}` +- `find!/2` - Returns map or `nil` (no tuple wrapper) + +## Search Keys + +`find/2` and `find!/2` accept only these keys: +- `:name` - Search by language name +- `:iso_639_1` - Search by 2-letter code +- `:iso_639_3` - Search by 3-letter code + +## Common Mistakes + +- **Wrong**: `LanguageList.find("en", :iso_639_2)` - Invalid key +- **Right**: `LanguageList.find("en", :iso_639_1)` - Use `:iso_639_1` or `:iso_639_3` + +- **Wrong**: Expecting `find!/2` to raise on not found +- **Right**: `find!/2` returns `nil` when not found, not an exception + +## Examples + +```elixir +# Get Portuguese by ISO code +{:ok, lang} = LanguageList.find("pt", :iso_639_1) +lang.name # => "Portuguese" + +# Direct access without tuple +lang = LanguageList.find!("Portuguese", :name) + +# Filter common languages +LanguageList.common_languages() # => ["Afrikaans", "Arabic", ...] +```