-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Interpolates messages with variables (#4)
- Loading branch information
1 parent
1c8f123
commit cadccbd
Showing
5 changed files
with
147 additions
and
2 deletions.
There are no files selected for viewing
This file contains 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 characters
This file contains 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 characters
This file contains 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 characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
defmodule KinoSlack.MessageInterpolator do | ||
@moduledoc false | ||
|
||
def interpolate(message) do | ||
args = build_interpolation_args(message, "", []) | ||
args = Enum.reverse(args) | ||
{:<<>>, [], args} | ||
end | ||
|
||
defp build_interpolation_args("", buffer, acc) do | ||
prepend_buffer(buffer, acc) | ||
end | ||
|
||
defp build_interpolation_args("{{" <> rest, buffer, acc) do | ||
with [inner, rest] <- String.split(rest, "}}", parts: 2), | ||
{:ok, expression} <- Code.string_to_quoted(inner) do | ||
acc = prepend_buffer(buffer, acc) | ||
acc = prepend_interpolation(expression, acc) | ||
build_interpolation_args(rest, "", acc) | ||
else | ||
_ -> | ||
build_interpolation_args(rest, <<buffer::binary, "{{">>, acc) | ||
end | ||
end | ||
|
||
defp build_interpolation_args(<<char, rest::binary>>, buffer, acc) do | ||
build_interpolation_args(rest, <<buffer::binary, char>>, acc) | ||
end | ||
|
||
defp prepend_interpolation(expression, acc) do | ||
interpolation_node = { | ||
:"::", | ||
[], | ||
[ | ||
{{:., [], [Kernel, :to_string]}, [], [expression]}, | ||
{:binary, [], Elixir} | ||
] | ||
} | ||
|
||
[interpolation_node | acc] | ||
end | ||
|
||
defp prepend_buffer("", acc), do: acc | ||
defp prepend_buffer(buffer, acc), do: [buffer | acc] | ||
end |
This file contains 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 characters
This file contains 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 characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
defmodule KinoSlack.MesssageInterpolatorTest do | ||
use ExUnit.Case, async: true | ||
|
||
alias KinoSlack.MessageInterpolator, as: Interpolator | ||
|
||
test "it interpolates variables inside a message" do | ||
first_name = "Hugo" | ||
last_name = "Baraúna" | ||
message = "Hi {{first_name}} {{last_name}}! 🎉" | ||
|
||
interpolated_ast = Interpolator.interpolate(message) | ||
generated_code = Macro.to_string(interpolated_ast) | ||
{interpolated_message, _} = Code.eval_quoted(interpolated_ast, binding()) | ||
|
||
assert generated_code == ~S/"Hi #{first_name} #{last_name}! 🎉"/ | ||
assert interpolated_message == "Hi Hugo Baraúna! 🎉" | ||
end | ||
|
||
test "it interpolates expressons inside a message" do | ||
message = "One plus one is: {{1 + 1}}" | ||
|
||
interpolated_ast = Interpolator.interpolate(message) | ||
generated_code = Macro.to_string(interpolated_ast) | ||
{interpolated_message, _} = Code.eval_quoted(interpolated_ast, binding()) | ||
|
||
assert generated_code == ~S/"One plus one is: #{1 + 1}"/ | ||
assert interpolated_message == "One plus one is: 2" | ||
end | ||
|
||
test "it interpolates funtion calls inside a message" do | ||
sum = fn a, b -> a + b end | ||
message = "1 + 1 is: {{sum.(1, 1)}}" | ||
|
||
interpolated_ast = Interpolator.interpolate(message) | ||
generated_code = Macro.to_string(interpolated_ast) | ||
{interpolated_message, _} = Code.eval_quoted(interpolated_ast, binding()) | ||
|
||
assert generated_code == ~S/"1 + 1 is: #{sum.(1, 1)}"/ | ||
assert interpolated_message == "1 + 1 is: 2" | ||
end | ||
|
||
test "it handles messages with only the beginning of interpolation syntax" do | ||
first_name = "Hugo" | ||
message = "hi {{ {{first_name}}" | ||
|
||
interpolated_ast = Interpolator.interpolate(message) | ||
generated_code = Macro.to_string(interpolated_ast) | ||
{interpolated_message, _} = Code.eval_quoted(interpolated_ast, binding()) | ||
|
||
assert generated_code == ~S/"hi {{ #{first_name}"/ | ||
assert interpolated_message == "hi {{ Hugo" | ||
end | ||
end |