Skip to content

Instantly share code, notes, and snippets.

View TylerPachal's full-sized avatar

Tyler Pachal TylerPachal

View GitHub Profile
@TylerPachal
TylerPachal / custom-compile-time-warnings-in-elixir.md
Last active September 26, 2023 15:14
A short example of emitting custom compile-time warnings in Elixir using IO.warn/1

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

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.

@doc """
Asserts that the given changeset is invalid, and that the given field is
invalid and contains an error message that contains the asserted_message
substring.
Example usage:
assert_invalid changeset, :people, error_message =~ "tyler is not allowed"
"""
defmacro assert_invalid(changeset, field, assertion_expression) when is_atom(field) do
@doc """
Assert that a Kafka contains a message on a given topic.
Example usage:
assert_kafka_contains "my_topic", fn message_body ->
Jason.decode!(message_body)["name"] == "tyler"
end
"""
defmacro assert_kafka_contains(topic, opts \\ [], assert_body_fn) do
# Without specifying a child_spec, you get the default one:
# default = %{
# id: __MODULE__,
# start: {__MODULE__, :start_link, [init_arg]}
# }
# A: calls start_link/1 with empty list of args
# children = [
# DevWorker
# ]
# An experiment to render a flat-list of nested errors.
#
# The default translate_errors() function would render (nested) errors like this:
# %{
# "pets" => [
# %{},
# %{"type" => ["is invalid"]},
# %{},
# %{"type" => ["is invalid"]}
# ]
@TylerPachal
TylerPachal / ecto_vs_phoenix_validations.exs
Created July 23, 2021 17:26
Comparing the Ecto return value to what Phoenix renders
# When using Ecto Schemas for validating, I wanted to see what error information was present in the
# Ecto.Changeset, and then compare that to what Phoenix would render by default.
#
# Q: Can you get the index of nested objects' errors?
# A: Yes, for nested lists anything valid will have an empty entry in the list, while invalid
# objects will have some error information. Either way you could use Enum.with_index() to figure
# out a specific index.
## lib/phoenix_playground/accounts/user.ex
defmodule PhoenixPlayground.Accounts.User do
def increment(number) do
number + 1
end
count = 0
# Return the updated value from the function, and use it to
# reaassign to our variable.
count = increment(count)
# Assign the result of the if/else statement to a variable
flag =
if foo == bar do
# If the condition is met, change the flag
false
else
# If the condition is not met, return flag to keep the value the same
flag
end
# Do not do this in Elixir
def increment(number) do
# Because of lexical scoping, this will have no impact to anything
# outside the scope of this function.
number = number + 1
end
count = 0
increment(count)
# Do not do this in Elixir
flag = true
if foo == bar do
# Anything that happens inside this if block will have no impact
# on the outside of this if block.
flag = false
IO.inspect(flag) # false