Skip to content

Instantly share code, notes, and snippets.

@cpjk
Last active September 15, 2015 16:07
Show Gist options
  • Save cpjk/ae19c0039119dd09185b to your computer and use it in GitHub Desktop.
Save cpjk/ae19c0039119dd09185b to your computer and use it in GitHub Desktop.
defmodule Abilities do
defmacro __using__(_opts) do
quote do
Module.register_attribute __MODULE__, :rules, accumulate: true
@before_compile unquote(__MODULE__)
end
end
def gather_rules(rules) do
rules
# first option
|> Enum.reduce %{}, fn ({struct_name, rule}, rules_map) ->
rules_map
|> Map.fetch(struct_name)
|> case do
{:ok, rules} ->
rules_map |> Map.put(struct_name, rules ++ [rule])
:error ->
rules_map |> Map.put(struct_name, [rule])
end
end
end
def build_impls(rules_map) do
ast = quote do
end
rules_map
|> Enum.reduce ast, fn ({struct_name, rules_list}, acc_ast) ->
rules_list
defimpl_ast = quote do
defimpl Canada.Can, for: unquote(struct_name) do
complete_defimpl_ast = rules_list
|> Enum.reduce defimpl_ast, fn(rule, acc_impl_ast) ->
quote do
unquote(acc_impl_ast)
unquote(rule)
end
end
end
end
end
end
defmacro __before_compile__(_) do
# group all of the rules together by model
quote do
@rules
|> Abilities.gather_rules
|> Abilities.build_impls
# ...
end
end
defmacro can(user, actions, targets, when: condition) do
{_,_,[{_,_,[user_struct]}, _]} = user
rule_ast = quote do
def can?(unquote(user), unquote(actions), unquote(targets)) when unquote(condition), do: true
end
model_ast = quote do: user_struct
quote do
@rules {unquote(rule_ast), unquote(rule_ast)}
end
end
defmacro can(user, actions, targets) do
{_,_,[{_,_,[user_struct]}, _]} = user
rule_ast = quote do
def can?(unquote(user), unquote(actions), unquote(targets)), do: true
end
model_ast = quote do: user_struct
quote do
@rules {unquote(model_ast), unquote(rule_ast)}
end
end
end
require Abilities
defmodule User do
defstruct id: 1, dude_id: 1
end
defmodule M do
use Abilities
Abilities.can(%User{id: id}, :post, %User{}, when: id in [1,2])
Abilities.can(%User{id: id}, :post, %User{}, when: id in [1,2])
Abilities.can(%User{id: id}, :post, %User{}, when: id in [1,2])
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment