Skip to content

Instantly share code, notes, and snippets.

@coryodaniel
Created December 18, 2019 19:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save coryodaniel/bbaa6f9cb71dbbe4abd32f098e9635a8 to your computer and use it in GitHub Desktop.
Save coryodaniel/bbaa6f9cb71dbbe4abd32f098e9635a8 to your computer and use it in GitHub Desktop.
Elixir `func` type safe-ish
ExUnit.start()
defmodule TypeSafeish do
defmacro func({:"::", _metadata, func_head}, do: block) do
[method_spec, return_spec] = func_head
{func_name, _metadata, [args_specs]} = method_spec
args = for {arg, _spec} <- args_specs, do: Macro.var(arg, nil)
specs = for {_arg, {spec, _metadata, _addl}} <- args_specs, do: Macro.var(spec, nil)
quote do
@spec unquote(func_name)(unquote_splicing(specs)) :: unquote(return_spec)
def unquote(func_name)(unquote_splicing(args)) do
unquote(block)
end
end
end
end
defmodule Hacksy do
@moduledoc """
Documentation for Hacksy.
"""
import TypeSafeish
def good_demo do
add(7, 3)
is_forty_two(42)
is_forty_two([43, 42])
end
def bad_demo do
is_forty_two(:foo)
end
@doc "Adds two numbers"
func add(n: integer, m: integer) :: integer do
n + m
end
@doc "Checks if a number is 42"
func is_forty_two(n: integer()) :: boolean() do
n == 42
end
# func is_forty_two(list_n: list(integer())) :: list(boolean()) do
# Enum.map(list_n, fn n -> n == 42 end)
# end
# func hello(%{"name" => name} = person) :: String.t() do
# name
# end
end
defmodule HacksyTest do
use ExUnit.Case
test "creates single arity functions" do
assert Hacksy.is_forty_two(42)
end
test "creates multi arity functions" do
assert 7 == Hacksy.add(3, 4)
end
test "handles nested types" do
assert [true, false] == Hacksy.is_forty_two([42, 43])
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment