Last active
July 9, 2024 15:01
-
-
Save josevalim/7432084 to your computer and use it in GitHub Desktop.
Revisions
-
José Valim revised this gist
Jan 20, 2015 . 1 changed file with 11 additions and 21 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,3 +1,4 @@ # Elixir v1.0 defmodule Rules do defmacro __using__(_) do quote do @@ -13,39 +14,28 @@ defmodule Rules do condition = Macro.escape(condition) block = Macro.escape(block) quote do @rules [{unquote(condition), unquote(block)}|@rules] end end defmacro __before_compile__(env) do rules = Module.get_attribute(env.module, :rules) arg = quote do: arg # Compile each rule to a ->. # # Later we will inject those clauses into a cond. rules = Enum.flat_map rules, fn {condition, block} -> condition = add_arg(condition, arg) quote do: (unquote(condition) -> unquote(block)) end quote do def run_rules(arg) do # Make the argument available in the block as the "number" var. # This is usually seen as bad practice but here it goes as an example. var!(number) = arg cond do: unquote(rules) end end end @@ -54,12 +44,12 @@ defmodule Rules do # implicitly receives an argument. So we go into each node, # taking into account "and/or" operators and pipe the arg as # the first argument. defp add_arg({op, meta, [left, right]}, arg) when op in [:and, :or] do {op, meta, [add_arg(left, arg), add_arg(right, arg)]} end defp add_arg(other, arg) do Macro.pipe(arg, other, 0) end end @@ -92,4 +82,4 @@ end Sample.run_rules(1) Sample.run_rules(5) Sample.run_rules(50) Sample.run_rules(150) -
josevalim revised this gist
Nov 13, 2013 . 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 @@ -55,7 +55,7 @@ defmodule Rules do # taking into account "and/or" operators and pipe the arg as # the first argument. defp add_arg({ op, meta, [left, right] }, arg) when op in [:and, :or] do { op, meta, [add_arg(left, arg), add_arg(right, arg)] } end defp add_arg(other, arg) do -
josevalim revised this gist
Nov 12, 2013 . 1 changed file with 12 additions and 5 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 @@ -22,16 +22,22 @@ defmodule Rules do arg = quote do: arg # Compile each rule to a clause in cond. # Each clause in a cond: # # left -> right # # Compiles to an AST node in the format: # # { [left], meta, right } # # We will do the same here. rules = lc { condition, block } inlist rules do condition = add_arg(condition, arg) { [condition], [], block } end # Now we pack all clauses/rules together in # a -> node which we will pass to cond. arrow = { :->, [], rules } quote do @@ -46,8 +52,9 @@ defmodule Rules do # A rule is writen as "foo and bar" but each item in the rule # implicitly receives an argument. So we go into each node, # taking into account "and/or" operators and pipe the arg as # the first argument. defp add_arg({ op, meta, [left, right] }, arg) when op in [:and, :or] do { :and, meta, [add_arg(left, arg), add_arg(right, arg)] } end -
josevalim revised this gist
Nov 12, 2013 . 1 changed file with 2 additions and 0 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,6 +7,8 @@ defmodule Rules do end end # Store each rules in the @rules attribute so we can # compile them all at once later defmacro rule(condition, do: block) do condition = Macro.escape(condition) block = Macro.escape(block) -
josevalim created this gist
Nov 12, 2013 .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,86 @@ defmodule Rules do defmacro __using__(_) do quote do import unquote(__MODULE__) @before_compile unquote(__MODULE__) @rules [] end end defmacro rule(condition, do: block) do condition = Macro.escape(condition) block = Macro.escape(block) quote do @rules [{ unquote(condition), unquote(block) }|@rules] end end defmacro __before_compile__(env) do rules = Module.get_attribute(env.module, :rules) arg = quote do: arg # Compile each rule to a clause in cond. # Each clause has the ast in the format: # # { args, meta, block } # rules = lc { condition, block } inlist rules do condition = add_arg(condition, arg) { [condition], [], block } end # The -> in "cond do: (... -> ...)" is represented by this node: arrow = { :->, [], rules } quote do def run_rules(arg) do # Make the argument available in the block as the "number" var. # This is usually seen as bad practice but here it goes as an example. var!(number) = arg cond do: unquote(arrow) end end end # A rule is writen as "foo and bar" but each item in the rule # implicitly receives an argument. So we go into each node, # taking into account "and" and pipe the arg as the first argument. defp add_arg({ :and, meta, [left, right] }, arg) do { :and, meta, [add_arg(left, arg), add_arg(right, arg)] } end defp add_arg(other, arg) do Macro.pipe(arg, other) end end defmodule Sample do use Rules rule is_one do IO.puts "A" end rule is_more_than_one and is_less_than_ten do IO.puts "B" end rule is_more_than(10) and is_less_than(99) do IO.puts "C" end rule is_more_than(100) do IO.puts "D: #{number}" end defp is_one(x), do: x == 1 defp is_more_than_one(x), do: x > 1 defp is_less_than_ten(x), do: x < 10 defp is_more_than(x, y), do: x > y defp is_less_than(x, y), do: x < y end Sample.run_rules(1) Sample.run_rules(5) Sample.run_rules(50) Sample.run_rules(150)