Last active
September 26, 2023 15:14
-
-
Save TylerPachal/66e9e7f42d1ff75c9a47c55deb6a7e5d to your computer and use it in GitHub Desktop.
Revisions
-
TylerPachal revised this gist
Sep 26, 2023 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -104,7 +104,7 @@ defmodule Country do end ``` Now when we compile the code, we'll get a more helpful warning preceding the warning from the Elixir compiler: ```bash $ mix compile --force -
TylerPachal revised this gist
Sep 18, 2023 . 1 changed file with 4 additions and 4 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -9,7 +9,7 @@ When you are writing macros which run at compile-time, it can be useful to emit Say you are using a text file to dynamically define function clauses. Our function will be called `official_language/1`; its only argument is the name of a country, and it returns an `:ok` tuple with a list of the countries official languages. Fortunately, for our implementation we have been provided with a `official_languages.csv` file that contains the mappings we need to perform this lookup: ```text Belgium,"Dutch,French,German" @@ -19,7 +19,7 @@ Mexico,Spanish Italy,Italian ``` Using the contents of this file to dynamically define our function with metaprogamming would look like this: ```elixir defmodule Country do @@ -74,7 +74,7 @@ warning: this clause cannot match because a previous clause at line 8 always mat ### The Solution It would be better if we emitted a more helpful error message (after identifying non-unique country keys). This can be done using [`IO.warn/1`](https://hexdocs.pm/elixir/1.12.3/IO.html#warn/1): ```elixir defmodule Country do @@ -104,7 +104,7 @@ defmodule Country do end ``` Now when we compile the code, we'll get a more helpful preceding the warning from the Elixir compiler: ```bash $ mix compile --force -
TylerPachal revised this gist
Sep 18, 2023 . 1 changed file with 16 additions and 12 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -7,7 +7,17 @@ When you are writing macros which run at compile-time, it can be useful to emit ### Example Scenario Say you are using a text file to dynamically define function clauses. Our function will be called `official_language/1`; its only argument is the name of a country, and it returns an `:ok` tuple with a list of the countries official languages. Foruntaley, for our implementation we have been provided with a `official_languages.csv` file that contains the mappings we need to perform this lookup. ```text Belgium,"Dutch,French,German" Brazil,Portugese Canada,"English,French" Mexico,Spanish Italy,Italian ``` Implementing this with metaprogamming would look like this: @@ -32,17 +42,11 @@ end _(Read more about `@external_resource` [here](https://hexdocs.pm/elixir/1.12.3/Module.html#module-external_resource))_ With the CSV file in place, you'd be able to make the following function calls: ```bash $ iex -S mix iex(1)> Country.official_language("Canada") {:ok, ["English", "French"]} @@ -54,7 +58,7 @@ iex(2)> Country.official_language("Tylerland") ### The Problem What if there was accidentally a duplicate country in your CSV file? Maybe the file contained an additional (and incorrect) line: `Brazil,Spanish`. We'd see a compiler warning, which is not helpful at narrowing down which country was the duplicate: @@ -100,7 +104,7 @@ defmodule Country do end ``` Now when we compile the code, we'll get a more helpful preceeding the warning from the Elixir compiler: ```bash $ mix compile --force -
TylerPachal revised this gist
Sep 18, 2023 . 1 changed file with 3 additions and 3 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,9 +1,9 @@ Custom Compile-Time Warnings in Elixir Using IO.warn/1 --- When you are writing macros which run at compile-time, it can be useful to emit custom compile-time warnings. [Skip down to The Solution](#the-solution) ### Example Scenario @@ -70,7 +70,7 @@ warning: this clause cannot match because a previous clause at line 8 always mat ### The Solution It would be better if we emitted a more helpful error message (after idenitfying non-unique country keys). This can be done using [`IO.warn/1`](https://hexdocs.pm/elixir/1.12.3/IO.html#warn/1). ```elixir defmodule Country do -
TylerPachal created this gist
Sep 18, 2023 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,120 @@ Custom Compile-Time warnings in Elixir --- When you are writing macros which run at compile-time, it can be useful to emit custom compile-time warnings. [Skip to the answer](#the-solution) ### Example Scenario Say you are using a text file to dynamically function clauses. Our function is called `official_language/1` and it takes the name of a country, and returns a list of its official languages (some countries have more than one!). Foruntaley, we have been provided with a `official_languages.csv` file that contains the mappings we need to perform this lookup. Implementing this with metaprogamming would look like this: ```elixir defmodule Country do @external_resource "priv/official_languages.csv" @contents File.read!("priv/official_languages.csv") rows = NimbleCSV.RFC4180.parse_string(@contents) for [country, languages] <- rows do languages_list = String.split(languages, ",") def official_language(unquote(country)) do {:ok, unquote(languages_list)} end end def official_language(_country), do: {:error, :unknown_country} end ``` _(Read more about `@external_resource` [here](https://hexdocs.pm/elixir/1.12.3/Module.html#module-external_resource))_ If you have the following `official_languages.csv` file in your `priv` repo, you'd be able to do the following function calls: ```text Belgium,"Dutch,French,German" Brazil,Portugese Canada,"English,French" Mexico,Spanish Italy,Italian ``` ```bash iex(1)> Country.official_language("Canada") {:ok, ["English", "French"]} iex(2)> Country.official_language("Tylerland") {:error, :unknown_country} ``` --- ### The Problem What if there was accidentally a duplicate country in your CSV file? Maybe the file contained an additional (and incorrect) line of `Brazil,Spanish`. We'd see a compiler warning, which is not helpful at narrowing down which country was the duplicate: ```bash $ mix compile --force Compiling 1 file (.ex) warning: this clause cannot match because a previous clause at line 8 always matches lib/country.ex:10 ``` --- ### The Solution It would be better if we emitted a more helpful error message (after idenitfying non-unique country keys). This can be done using `IO.warn/1`. ```elixir defmodule Country do @external_resource "priv/official_languages.csv" @contents File.read!("priv/official_languages.csv") rows = NimbleCSV.RFC4180.parse_string(@contents) # New part here! countries = Enum.map(rows, fn [country, _] -> country end) non_unique_countries = countries -- Enum.uniq(countries) if non_unique_countries != [] do IO.warn(""" Non-unique country in #{@external_resource}: #{inspect(non_unique_countries)} """) end for [country, languages] <- rows do languages_list = String.split(languages, ",") def official_language(unquote(country)) do {:ok, unquote(languages_list)} end end def official_language(_country), do: {:error, :unknown_country} end ``` Now when we compile the code, we'll get a more helpful warning (along with the original warning) ```bash $ mix compile --force Compiling 1 file (.ex) warning: Non-unique country in priv/official_languages.csv: ["Brazil"] lib/playground.ex:11: (module) (elixir 1.13.3) src/elixir_compiler.erl:73: :elixir_compiler.dispatch/4 (elixir 1.13.3) src/elixir_compiler.erl:58: :elixir_compiler.compile/3 (elixir 1.13.3) src/elixir_module.erl:369: :elixir_module.eval_form/6 (elixir 1.13.3) src/elixir_module.erl:105: :elixir_module.compile/5 (elixir 1.13.3) src/elixir_lexical.erl:15: :elixir_lexical.run/3 warning: this clause cannot match because a previous clause at line 19 always matches lib/playground.ex:19 ```