Skip to content

Commit

Permalink
Improve docs and cleanup Radius.Dict module (#8)
Browse files Browse the repository at this point in the history
  • Loading branch information
tverlaan committed Jun 14, 2023
1 parent fdb3329 commit 6a5b710
Show file tree
Hide file tree
Showing 6 changed files with 142 additions and 35 deletions.
74 changes: 41 additions & 33 deletions lib/radius/dict.ex
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
defmodule Radius.Dict do
alias Radius.Dict.Parser
@moduledoc """
Parses dictionaries and generates lookup functions and helper macro's.
The helper macro's give the benefit of compile time checks and faster encoding without losing
readability.
"""
require Radius.Dict.Helpers
alias Radius.Dict.EntryNotFoundError
alias Radius.Dict.Helpers
alias Radius.Dict.Parser

defmacro __using__(_) do
quote do
Expand Down Expand Up @@ -59,39 +67,41 @@ defmodule Radius.Dict do
end
)

for attribute <- attributes do
attr_fun_name = "attr_#{attribute.name}" |> String.replace("-", "_") |> String.to_atom()
Helpers.define_attribute_doc_helpers()

defmacro unquote(attr_fun_name)(), do: unquote(attribute.id)
defmacro unquote(attr_fun_name)(val), do: {unquote(attribute.id), val}
def attribute_by_id(unquote(attribute.id)), do: unquote(Macro.escape(attribute))
def attribute_by_name(unquote(attribute.name)), do: unquote(Macro.escape(attribute))
for attribute <- attributes do
Helpers.define_attribute_functions(attribute)

Check warning on line 73 in lib/radius/dict.ex

View workflow job for this annotation

GitHub Actions / Build and test

this clause cannot match because a previous clause at line 73 always matches

Check warning on line 73 in lib/radius/dict.ex

View workflow job for this annotation

GitHub Actions / Build and test

this clause cannot match because a previous clause at line 73 always matches

Check warning on line 73 in lib/radius/dict.ex

View workflow job for this annotation

GitHub Actions / Build and test

this clause cannot match because a previous clause at line 73 always matches

Check warning on line 73 in lib/radius/dict.ex

View workflow job for this annotation

GitHub Actions / Build and test

this clause cannot match because a previous clause at line 73 always matches

Check warning on line 73 in lib/radius/dict.ex

View workflow job for this annotation

GitHub Actions / Build and test

this clause cannot match because a previous clause at line 73 always matches

Check warning on line 73 in lib/radius/dict.ex

View workflow job for this annotation

GitHub Actions / Build and test

this clause cannot match because a previous clause at line 73 always matches

Check warning on line 73 in lib/radius/dict.ex

View workflow job for this annotation

GitHub Actions / Build and test

this clause cannot match because a previous clause at line 73 always matches

Check warning on line 73 in lib/radius/dict.ex

View workflow job for this annotation

GitHub Actions / Build and test

this clause cannot match because a previous clause at line 73 always matches

Check warning on line 73 in lib/radius/dict.ex

View workflow job for this annotation

GitHub Actions / Build and test

this clause cannot match because a previous clause at line 73 always matches

Check warning on line 73 in lib/radius/dict.ex

View workflow job for this annotation

GitHub Actions / Build and test

this clause cannot match because a previous clause at line 73 always matches
end

for val <- values do
val_fun_name = "val_#{val.attr}_#{val.name}" |> String.replace("-", "_") |> String.to_atom()
Helpers.define_value_doc_helpers()

defmacro unquote(val_fun_name)(), do: unquote(val.value)
def value_by_value(unquote(val.attr), unquote(val.value)), do: unquote(Macro.escape(val))
def value_by_name(unquote(val.attr), unquote(val.name)), do: unquote(Macro.escape(val))
for val <- values do
Helpers.define_value_functions(val)
end

@doc """
Get vendor struct based on vendor id
"""
@doc group: :lookup
def vendor_by_id(attr_id)

@doc """
Get vendor struct based on vendor name
"""
@doc group: :lookup
def vendor_by_name(attr_name)

for vendor <- vendors do
mod = Module.concat(__MODULE__, :"Vendor#{String.replace(vendor.name, "-", "_")}")
mod = Module.concat(__MODULE__, Helpers.safe_name("Vendor#{vendor.name}"))
[tl, ll] = Keyword.get(vendor.opts, :format) || [1, 1]
vendor_data = %{id: vendor.id, name: vendor.name, format: {tl, ll}, module: mod}
def vendor_by_id(unquote(vendor.id)), do: unquote(Macro.escape(vendor_data))
def vendor_by_name(unquote(vendor.name)), do: unquote(Macro.escape(vendor_data))

attribute_funs =
for attribute <- vendor.attributes do
attr_fun_name = "attr_#{attribute.name}" |> String.replace("-", "_") |> String.to_atom()

quote location: :keep do
defmacro unquote(attr_fun_name)(), do: unquote(attribute.id)
defmacro unquote(attr_fun_name)(val), do: {unquote(attribute.id), val}
def attribute_by_id(unquote(attribute.id)), do: unquote(Macro.escape(attribute))
def attribute_by_name(unquote(attribute.name)), do: unquote(Macro.escape(attribute))
quote do
unquote(Helpers.generate_attribute_functions(Macro.escape(attribute)))
end
end

Expand All @@ -100,22 +110,13 @@ defmodule Radius.Dict do
value_funs =
if Enum.count(vendor.attributes ++ vendor.values) < elixir_compiler_limit do
for val <- vendor.values do
val_fun_name =
"val_#{val.attr}_#{val.name}" |> String.replace("-", "_") |> String.to_atom()

quote location: :keep do
defmacro unquote(val_fun_name)(), do: unquote(val.value)

def value_by_value(unquote(val.attr), unquote(val.value)),
do: unquote(Macro.escape(val))

def value_by_name(unquote(val.attr), unquote(val.name)),
do: unquote(Macro.escape(val))
quote do
unquote(Helpers.generate_value_functions(Macro.escape(val)))
end
end
else
for {attr, vals} <- Enum.group_by(vendor.values, & &1.attr) do
val_fun_name = "val_#{attr}" |> String.replace("-", "_") |> String.to_atom()
val_fun_name = Helpers.safe_name("val_#{attr}")

quote location: :keep do
defmacro unquote(val_fun_name)(val_name),
Expand Down Expand Up @@ -143,7 +144,14 @@ defmodule Radius.Dict do
end

IO.puts("Compiling #{mod}")
Module.create(mod, attribute_funs ++ value_funs, Macro.Env.location(__ENV__))

value_doc_funs = if value_funs == [], do: [], else: [Helpers.generate_value_doc_helpers()]

module_body =
[Helpers.generate_attribute_doc_helpers()] ++
attribute_funs ++ value_funs ++ value_doc_funs

Module.create(mod, module_body, Macro.Env.location(__ENV__))
end

def attribute_by_id(id), do: raise(EntryNotFoundError, type: :attribute, key: id)
Expand Down
78 changes: 78 additions & 0 deletions lib/radius/dict/helpers.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
defmodule Radius.Dict.Helpers do
@moduledoc false
defmacro define_attribute_doc_helpers() do
generate_attribute_doc_helpers()
end

defmacro define_attribute_functions(attribute) do
generate_attribute_functions(attribute)
end

defmacro define_value_doc_helpers() do
generate_value_doc_helpers()
end

defmacro define_value_functions(val) do
generate_value_functions(val)
end

def generate_attribute_doc_helpers() do
quote do
@doc """
Get attribute struct based on attribute id
"""
@doc group: :lookup
def attribute_by_id(attr_id)

@doc """
Get attribute struct based on attribute name
"""
@doc group: :lookup
def attribute_by_name(attr_name)
end
end

def generate_attribute_functions(attribute) do
quote bind_quoted: [attribute: attribute] do
attr_fun_name = "attr_#{attribute.name}" |> String.replace("-", "_") |> String.to_atom()

@doc group: :attributes
defmacro unquote(attr_fun_name)(), do: unquote(attribute.id)
@doc group: :attributes
defmacro unquote(attr_fun_name)(val), do: {unquote(attribute.id), val}
def attribute_by_id(unquote(attribute.id)), do: unquote(Macro.escape(attribute))
def attribute_by_name(unquote(attribute.name)), do: unquote(Macro.escape(attribute))
end
end

def generate_value_doc_helpers() do
quote do
@doc """
Get value struct based on attribute name and value name
"""
@doc group: :lookup
def value_by_name(attr_name, value_name)

@doc """
Get value struct based on attribute name and the value
"""
@doc group: :lookup
def value_by_value(attr_name, value)
end
end

def generate_value_functions(val) do
quote bind_quoted: [val: val] do
val_fun_name = "val_#{val.attr}_#{val.name}" |> String.replace("-", "_") |> String.to_atom()

@doc group: :values
defmacro unquote(val_fun_name)(), do: unquote(val.value)
def value_by_value(unquote(val.attr), unquote(val.value)), do: unquote(Macro.escape(val))
def value_by_name(unquote(val.attr), unquote(val.name)), do: unquote(Macro.escape(val))
end
end

def safe_name(name) do
name |> String.replace("-", "_") |> String.to_atom()
end
end
3 changes: 2 additions & 1 deletion lib/radius/dict/parser.ex
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# Default for opts on `parse_bin/2` manually removed to get rid of warning
# Generated from lib/radius/dict/parser.ex.exs, do not edit.
# Generated at 2023-06-06 13:43:01Z.
# Generated at 2023-06-12 12:12:16Z.

defmodule Radius.Dict.Parser do
@moduledoc false
def parse(binary) do
{:ok, _, "", ctx, _, _} =
parse_bin(binary, context: [attributes: [], values: [], prepend_key: []])
Expand Down
1 change: 1 addition & 0 deletions lib/radius/dict/parser.ex.exs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
defmodule Radius.Dict.Parser do
@moduledoc false
def parse(binary) do
{:ok, _, "", ctx, _, _} =
parse_bin(binary, context: [attributes: [], values: [], prepend_key: []])
Expand Down
1 change: 1 addition & 0 deletions lib/radius/util.ex
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
defmodule Radius.Util do
@moduledoc false
require Logger
import Bitwise

Expand Down
20 changes: 19 additions & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ defmodule RadiusProxy.Mixfile do
app: :elixir_radius,
version: "2.0.0",
elixir: "~> 1.12",
deps: deps(),
name: "Radius",
description: desc(),
package: package(),
deps: deps()
source_url: "https://github.com/bearice/elixir-radius",
docs: docs()
]
end

Expand Down Expand Up @@ -52,4 +55,19 @@ defmodule RadiusProxy.Mixfile do
links: %{"Github" => "https://github.com/bearice/elixir-radius"}
]
end

defp docs() do
[
main: "README",
extras: ["README.md"],
groups_for_modules: [
"Vendor Dictionaries": ~r/Radius\.Dict\.Vendor.+/
],
groups_for_docs: [
"Lookup Functions": &(&1[:group] == :lookup),
Attributes: &(&1[:group] == :attributes),
Values: &(&1[:group] == :values)
]
]
end
end

0 comments on commit 6a5b710

Please sign in to comment.