From 22e5816e3f2b8cc945ff46aecea039d8998ac365 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Hugo=20Bara=C3=BAna?=
Date: Fri, 10 Mar 2023 14:24:08 -0300
Subject: [PATCH 01/11] Interpolates messages with variables
---
lib/kino_slack/message_cell.ex | 22 ++++++++++++--
test/kino_slack/message_cell_test.exs | 41 +++++++++++++++++++++++++++
2 files changed, 61 insertions(+), 2 deletions(-)
diff --git a/lib/kino_slack/message_cell.ex b/lib/kino_slack/message_cell.ex
index cbdbfbe..9f523d6 100644
--- a/lib/kino_slack/message_cell.ex
+++ b/lib/kino_slack/message_cell.ex
@@ -49,6 +49,7 @@ defmodule KinoSlack.MessageCell do
@impl true
def to_source(attrs) do
required_fields = ~w(token_secret_name channel message)
+ interpolated_message = interpolate(attrs["message"])
if all_fields_filled?(attrs, required_fields) do
quote do
@@ -63,7 +64,7 @@ defmodule KinoSlack.MessageCell do
url: "/chat.postMessage",
json: %{
channel: unquote(attrs["channel"]),
- text: unquote(attrs["message"])
+ text: unquote(interpolated_message)
}
)
@@ -78,7 +79,24 @@ defmodule KinoSlack.MessageCell do
end
end
- def all_fields_filled?(attrs, keys) do
+ defp interpolate(message) do
+ ~r/(?){{[^}]+}}(?)/
+ |> Regex.split(message, on: [:before_interpolation, :after_interpolation])
+ |> Enum.map(fn message_chunk ->
+ case Regex.named_captures(~r/{{(?.*)}}/, message_chunk) do
+ %{"var_name" => var_name} ->
+ "\#{#{var_name}}"
+
+ _ ->
+ message_chunk
+ end
+ end)
+ |> Enum.join()
+ |> then(fn message -> "\"" <> message <> "\"" end)
+ |> Code.string_to_quoted!()
+ end
+
+ defp all_fields_filled?(attrs, keys) do
Enum.all?(keys, fn key -> attrs[key] not in [nil, ""] end)
end
end
diff --git a/test/kino_slack/message_cell_test.exs b/test/kino_slack/message_cell_test.exs
index 4f09576..689eb4a 100644
--- a/test/kino_slack/message_cell_test.exs
+++ b/test/kino_slack/message_cell_test.exs
@@ -48,6 +48,47 @@ defmodule KinoSlack.MessageCellTest do
assert generated_code == expected_code
end
+ test "generates source code with variable interpolation" do
+ {kino, _source} = start_smart_cell!(MessageCell, %{})
+
+ push_event(kino, "update_token_secret_name", "SLACK_TOKEN")
+ push_event(kino, "update_channel", "#slack-channel")
+ push_event(kino, "update_message", "Hello {{first_name}} {{last_name}}!")
+
+ assert_smart_cell_update(
+ kino,
+ %{
+ "token_secret_name" => "SLACK_TOKEN",
+ "channel" => "#slack-channel",
+ "message" => "Hello {{first_name}} {{last_name}}!"
+ },
+ generated_code
+ )
+
+ expected_code = ~S"""
+ req =
+ Req.new(
+ base_url: "https://slack.com/api",
+ auth: {:bearer, System.fetch_env!("LB_SLACK_TOKEN")}
+ )
+
+ response =
+ Req.post!(req,
+ url: "/chat.postMessage",
+ json: %{channel: "#slack-channel", text: "Hello #{first_name} #{last_name}!"}
+ )
+
+ case response.body do
+ %{"ok" => true} -> :ok
+ %{"ok" => false, "error" => error} -> {:error, error}
+ end
+ """
+
+ expected_code = String.trim(expected_code)
+
+ assert generated_code == expected_code
+ end
+
test "generates source code from stored attributes" do
stored_attrs = %{
"token_secret_name" => "SLACK_TOKEN",
From b3847b70e66d2d1322ef13aeec2d5a913c30c3ce Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Hugo=20Bara=C3=BAna?=
Date: Wed, 15 Mar 2023 16:17:31 -0300
Subject: [PATCH 02/11] Interpolates messages by dinamically building the
string interpolation AST
---
lib/assets/main.js | 5 ++
lib/kino_slack/message_cell.ex | 21 +------
lib/kino_slack/message_interpolator.ex | 60 +++++++++++++++++++
.../kino_slack/messsage_interpolator_test.exs | 45 ++++++++++++++
4 files changed, 112 insertions(+), 19 deletions(-)
create mode 100644 lib/kino_slack/message_interpolator.ex
create mode 100644 test/kino_slack/messsage_interpolator_test.exs
diff --git a/lib/assets/main.js b/lib/assets/main.js
index 5b20439..53fdbed 100644
--- a/lib/assets/main.js
+++ b/lib/assets/main.js
@@ -36,6 +36,11 @@ export function init(ctx, payload) {
create a Slack app and get your app's token.
+
+
+ To dynamically inject values into the query use double curly braces, like {{name}}.
+
+
diff --git a/lib/kino_slack/message_cell.ex b/lib/kino_slack/message_cell.ex
index 9f523d6..5e91cb3 100644
--- a/lib/kino_slack/message_cell.ex
+++ b/lib/kino_slack/message_cell.ex
@@ -49,7 +49,7 @@ defmodule KinoSlack.MessageCell do
@impl true
def to_source(attrs) do
required_fields = ~w(token_secret_name channel message)
- interpolated_message = interpolate(attrs["message"])
+ message_ast = KinoSlack.MessageInterpolator.interpolate(attrs["message"])
if all_fields_filled?(attrs, required_fields) do
quote do
@@ -64,7 +64,7 @@ defmodule KinoSlack.MessageCell do
url: "/chat.postMessage",
json: %{
channel: unquote(attrs["channel"]),
- text: unquote(interpolated_message)
+ text: unquote(message_ast)
}
)
@@ -79,23 +79,6 @@ defmodule KinoSlack.MessageCell do
end
end
- defp interpolate(message) do
- ~r/(?
){{[^}]+}}(?)/
- |> Regex.split(message, on: [:before_interpolation, :after_interpolation])
- |> Enum.map(fn message_chunk ->
- case Regex.named_captures(~r/{{(?.*)}}/, message_chunk) do
- %{"var_name" => var_name} ->
- "\#{#{var_name}}"
-
- _ ->
- message_chunk
- end
- end)
- |> Enum.join()
- |> then(fn message -> "\"" <> message <> "\"" end)
- |> Code.string_to_quoted!()
- end
-
defp all_fields_filled?(attrs, keys) do
Enum.all?(keys, fn key -> attrs[key] not in [nil, ""] end)
end
diff --git a/lib/kino_slack/message_interpolator.ex b/lib/kino_slack/message_interpolator.ex
new file mode 100644
index 0000000..ed272b6
--- /dev/null
+++ b/lib/kino_slack/message_interpolator.ex
@@ -0,0 +1,60 @@
+defmodule KinoSlack.MessageInterpolator do
+ def interpolate(message) do
+ ast = quote do: <<"">>
+ interpolate(message, ast)
+ end
+
+ defp interpolate("", result_ast) do
+ result_ast
+ end
+
+ defp interpolate("{{" <> rest, ast) do
+ with [inner, rest] <- String.split(rest, "}}", parts: 2),
+ {:ok, expression} <- Code.string_to_quoted(inner) do
+ ast = append_interpolation(ast, expression)
+ interpolate(rest, ast)
+ else
+ _ ->
+ <> = "{"
+ ast = append_char(ast, char)
+ ast = append_char(ast, char)
+ interpolate(rest, ast)
+ end
+ end
+
+ defp interpolate(<>, ast) do
+ new_ast = append_char(ast, char)
+ interpolate(rest, new_ast)
+ end
+
+ defp append_interpolation(ast, expression) do
+ interpolation_node = {
+ :"::",
+ [],
+ [
+ {{:., [], [Kernel, :to_string]}, [], [expression]},
+ {:binary, [], Elixir}
+ ]
+ }
+
+ {_, _, args} = ast
+ args = args ++ [interpolation_node]
+
+ {:<<>>, [], args}
+ end
+
+ defp append_char(ast, char) do
+ {_, _, args} = ast
+ last_arg = List.last(args)
+
+ new_args =
+ if is_binary(last_arg) do
+ last_string = last_arg <> <>
+ List.replace_at(args, -1, last_string)
+ else
+ args ++ [<>]
+ end
+
+ {:<<>>, [], new_args}
+ end
+end
diff --git a/test/kino_slack/messsage_interpolator_test.exs b/test/kino_slack/messsage_interpolator_test.exs
new file mode 100644
index 0000000..db422af
--- /dev/null
+++ b/test/kino_slack/messsage_interpolator_test.exs
@@ -0,0 +1,45 @@
+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)
+ {interpolated_message, _} = Code.eval_quoted(interpolated_ast, binding())
+
+ 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)
+ {interpolated_message, _} = Code.eval_quoted(interpolated_ast, binding())
+
+ assert interpolated_message == "One plus one is: 2"
+ end
+
+ test "it interpolates expressions with functinos and vars inside a message" do
+ first_name = "Hugo"
+ message = "Do you {{first_name}}, know {{1 + 1}} ?"
+
+ interpolated_ast = Interpolator.interpolate(message)
+ {interpolated_message, _} = Code.eval_quoted(interpolated_ast, binding())
+
+ assert interpolated_message == "Do you Hugo, know 2 ?"
+ end
+
+ test "it handles messags with only the beginning of interpolation syntax" do
+ first_name = "Hugo"
+ message = "hi {{ {{first_name}}"
+
+ interpolated_ast = Interpolator.interpolate(message)
+ {interpolated_message, _} = Code.eval_quoted(interpolated_ast, binding())
+
+ assert interpolated_message == "hi {{ Hugo"
+ end
+end
From fba2da6ea6d00dfff01e66f4eac094a0d4ead546 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Hugo=20Bara=C3=BAna?=
Date: Wed, 15 Mar 2023 16:20:29 -0300
Subject: [PATCH 03/11] Fixes typo in test name
---
test/kino_slack/messsage_interpolator_test.exs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/kino_slack/messsage_interpolator_test.exs b/test/kino_slack/messsage_interpolator_test.exs
index db422af..013c090 100644
--- a/test/kino_slack/messsage_interpolator_test.exs
+++ b/test/kino_slack/messsage_interpolator_test.exs
@@ -33,7 +33,7 @@ defmodule KinoSlack.MesssageInterpolatorTest do
assert interpolated_message == "Do you Hugo, know 2 ?"
end
- test "it handles messags with only the beginning of interpolation syntax" do
+ test "it handles messages with only the beginning of interpolation syntax" do
first_name = "Hugo"
message = "hi {{ {{first_name}}"
From 6c94347de0f0b720d84cfb6360ce5d0170a7eb3c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Hugo=20Bara=C3=BAna?=
Date: Thu, 16 Mar 2023 11:51:58 -0300
Subject: [PATCH 04/11] Refactor to append_string instead of append_char
---
lib/kino_slack/message_interpolator.ex | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/lib/kino_slack/message_interpolator.ex b/lib/kino_slack/message_interpolator.ex
index ed272b6..bdc1596 100644
--- a/lib/kino_slack/message_interpolator.ex
+++ b/lib/kino_slack/message_interpolator.ex
@@ -15,15 +15,13 @@ defmodule KinoSlack.MessageInterpolator do
interpolate(rest, ast)
else
_ ->
- <> = "{"
- ast = append_char(ast, char)
- ast = append_char(ast, char)
+ ast = append_string(ast, "{{")
interpolate(rest, ast)
end
end
defp interpolate(<>, ast) do
- new_ast = append_char(ast, char)
+ new_ast = append_string(ast, <>)
interpolate(rest, new_ast)
end
@@ -43,16 +41,16 @@ defmodule KinoSlack.MessageInterpolator do
{:<<>>, [], args}
end
- defp append_char(ast, char) do
+ defp append_string(ast, string) do
{_, _, args} = ast
last_arg = List.last(args)
new_args =
if is_binary(last_arg) do
- last_string = last_arg <> <>
+ last_string = last_arg <> string
List.replace_at(args, -1, last_string)
else
- args ++ [<>]
+ args ++ [string]
end
{:<<>>, [], new_args}
From 3394ac54dcb9deb7eddccc0f823824b7681e61d4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Hugo=20Bara=C3=BAna?=
Date: Thu, 16 Mar 2023 11:52:44 -0300
Subject: [PATCH 05/11] Apply suggestion
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Jonatan Kłosko
---
lib/kino_slack/message_interpolator.ex | 2 ++
1 file changed, 2 insertions(+)
diff --git a/lib/kino_slack/message_interpolator.ex b/lib/kino_slack/message_interpolator.ex
index bdc1596..62e7da0 100644
--- a/lib/kino_slack/message_interpolator.ex
+++ b/lib/kino_slack/message_interpolator.ex
@@ -1,4 +1,6 @@
defmodule KinoSlack.MessageInterpolator do
+ @moduledoc false
+
def interpolate(message) do
ast = quote do: <<"">>
interpolate(message, ast)
From fe357c13c8efbbae3668aebf58d05b526d49cd70 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Hugo=20Bara=C3=BAna?=
Date: Thu, 16 Mar 2023 11:53:10 -0300
Subject: [PATCH 06/11] Apply suggestion
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Jonatan Kłosko
---
lib/kino_slack/message_interpolator.ex | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/kino_slack/message_interpolator.ex b/lib/kino_slack/message_interpolator.ex
index 62e7da0..196431a 100644
--- a/lib/kino_slack/message_interpolator.ex
+++ b/lib/kino_slack/message_interpolator.ex
@@ -37,7 +37,7 @@ defmodule KinoSlack.MessageInterpolator do
]
}
- {_, _, args} = ast
+ {:<<>>, _, args} = ast
args = args ++ [interpolation_node]
{:<<>>, [], args}
From 6885c18bdd9107e5147a4c9384e6fdc4f396801c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Hugo=20Bara=C3=BAna?=
Date: Thu, 16 Mar 2023 14:17:32 -0300
Subject: [PATCH 07/11] Collect the interpolation AST args instead of the
interpolation AST
---
lib/kino_slack/message_interpolator.ex | 49 +++++++++++---------------
1 file changed, 21 insertions(+), 28 deletions(-)
diff --git a/lib/kino_slack/message_interpolator.ex b/lib/kino_slack/message_interpolator.ex
index 196431a..12cae9b 100644
--- a/lib/kino_slack/message_interpolator.ex
+++ b/lib/kino_slack/message_interpolator.ex
@@ -2,32 +2,32 @@ defmodule KinoSlack.MessageInterpolator do
@moduledoc false
def interpolate(message) do
- ast = quote do: <<"">>
- interpolate(message, ast)
+ args = build_interpolation_args(message, [])
+ {:<<>>, [], args}
end
- defp interpolate("", result_ast) do
- result_ast
+ defp build_interpolation_args("", args) do
+ args
end
- defp interpolate("{{" <> rest, ast) do
+ defp build_interpolation_args("{{" <> rest, args) do
with [inner, rest] <- String.split(rest, "}}", parts: 2),
{:ok, expression} <- Code.string_to_quoted(inner) do
- ast = append_interpolation(ast, expression)
- interpolate(rest, ast)
+ args = append_interpolation(args, expression)
+ build_interpolation_args(rest, args)
else
_ ->
- ast = append_string(ast, "{{")
- interpolate(rest, ast)
+ args = append_string(args, "{{")
+ build_interpolation_args(rest, args)
end
end
- defp interpolate(<>, ast) do
- new_ast = append_string(ast, <>)
- interpolate(rest, new_ast)
+ defp build_interpolation_args(<>, args) do
+ args = append_string(args, <>)
+ build_interpolation_args(rest, args)
end
- defp append_interpolation(ast, expression) do
+ defp append_interpolation(args, expression) do
interpolation_node = {
:"::",
[],
@@ -37,24 +37,17 @@ defmodule KinoSlack.MessageInterpolator do
]
}
- {:<<>>, _, args} = ast
- args = args ++ [interpolation_node]
-
- {:<<>>, [], args}
+ args ++ [interpolation_node]
end
- defp append_string(ast, string) do
- {_, _, args} = ast
+ defp append_string(args, string) do
last_arg = List.last(args)
- new_args =
- if is_binary(last_arg) do
- last_string = last_arg <> string
- List.replace_at(args, -1, last_string)
- else
- args ++ [string]
- end
-
- {:<<>>, [], new_args}
+ if is_binary(last_arg) do
+ last_string = last_arg <> string
+ List.replace_at(args, -1, last_string)
+ else
+ args ++ [string]
+ end
end
end
From 4295319982f4f00009fcbe9bfec350f5bdc654a0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Hugo=20Bara=C3=BAna?=
Date: Thu, 16 Mar 2023 14:30:10 -0300
Subject: [PATCH 08/11] Tests that the code generated by the interpolator looks
nice
---
test/kino_slack/messsage_interpolator_test.exs | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/test/kino_slack/messsage_interpolator_test.exs b/test/kino_slack/messsage_interpolator_test.exs
index 013c090..d470d47 100644
--- a/test/kino_slack/messsage_interpolator_test.exs
+++ b/test/kino_slack/messsage_interpolator_test.exs
@@ -9,8 +9,10 @@ defmodule KinoSlack.MesssageInterpolatorTest do
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 == "\"Hi \#{first_name} \#{last_name}! 🎉\""
assert interpolated_message == "Hi Hugo Baraúna! 🎉"
end
@@ -18,8 +20,10 @@ defmodule KinoSlack.MesssageInterpolatorTest 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 == "\"One plus one is: \#{1 + 1}\""
assert interpolated_message == "One plus one is: 2"
end
@@ -28,8 +32,10 @@ defmodule KinoSlack.MesssageInterpolatorTest do
message = "Do you {{first_name}}, know {{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 == "\"Do you \#{first_name}, know \#{1 + 1} ?\""
assert interpolated_message == "Do you Hugo, know 2 ?"
end
@@ -38,8 +44,10 @@ defmodule KinoSlack.MesssageInterpolatorTest do
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 == "\"hi {{ \#{first_name}\""
assert interpolated_message == "hi {{ Hugo"
end
end
From 05c4ad191b68685917ad7e417a67a47ca0a5f4e8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Hugo=20Bara=C3=BAna?=
Date: Fri, 17 Mar 2023 10:21:53 -0300
Subject: [PATCH 09/11] Improves test readability
---
test/kino_slack/messsage_interpolator_test.exs | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/test/kino_slack/messsage_interpolator_test.exs b/test/kino_slack/messsage_interpolator_test.exs
index d470d47..bd1180c 100644
--- a/test/kino_slack/messsage_interpolator_test.exs
+++ b/test/kino_slack/messsage_interpolator_test.exs
@@ -12,7 +12,7 @@ defmodule KinoSlack.MesssageInterpolatorTest do
generated_code = Macro.to_string(interpolated_ast)
{interpolated_message, _} = Code.eval_quoted(interpolated_ast, binding())
- assert generated_code == "\"Hi \#{first_name} \#{last_name}! 🎉\""
+ assert generated_code == ~S/"Hi #{first_name} #{last_name}! 🎉"/
assert interpolated_message == "Hi Hugo Baraúna! 🎉"
end
@@ -23,20 +23,20 @@ defmodule KinoSlack.MesssageInterpolatorTest do
generated_code = Macro.to_string(interpolated_ast)
{interpolated_message, _} = Code.eval_quoted(interpolated_ast, binding())
- assert generated_code == "\"One plus one is: \#{1 + 1}\""
+ assert generated_code == ~S/"One plus one is: #{1 + 1}"/
assert interpolated_message == "One plus one is: 2"
end
- test "it interpolates expressions with functinos and vars inside a message" do
- first_name = "Hugo"
- message = "Do you {{first_name}}, know {{1 + 1}} ?"
+ 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 == "\"Do you \#{first_name}, know \#{1 + 1} ?\""
- assert interpolated_message == "Do you Hugo, know 2 ?"
+ 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
@@ -47,7 +47,7 @@ defmodule KinoSlack.MesssageInterpolatorTest do
generated_code = Macro.to_string(interpolated_ast)
{interpolated_message, _} = Code.eval_quoted(interpolated_ast, binding())
- assert generated_code == "\"hi {{ \#{first_name}\""
+ assert generated_code == ~S/"hi {{ #{first_name}"/
assert interpolated_message == "hi {{ Hugo"
end
end
From bf443f1f66ab8289661c0266f9ae0e25b638b2bd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Hugo=20Bara=C3=BAna?=
Date: Fri, 17 Mar 2023 10:49:53 -0300
Subject: [PATCH 10/11] Avoids appending to the end of a list
---
lib/kino_slack/message_interpolator.ex | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/lib/kino_slack/message_interpolator.ex b/lib/kino_slack/message_interpolator.ex
index 12cae9b..725d6bc 100644
--- a/lib/kino_slack/message_interpolator.ex
+++ b/lib/kino_slack/message_interpolator.ex
@@ -2,7 +2,8 @@ defmodule KinoSlack.MessageInterpolator do
@moduledoc false
def interpolate(message) do
- args = build_interpolation_args(message, [])
+ args = build_interpolation_args(message, [""])
+ args = Enum.reverse(args)
{:<<>>, [], args}
end
@@ -13,21 +14,21 @@ defmodule KinoSlack.MessageInterpolator do
defp build_interpolation_args("{{" <> rest, args) do
with [inner, rest] <- String.split(rest, "}}", parts: 2),
{:ok, expression} <- Code.string_to_quoted(inner) do
- args = append_interpolation(args, expression)
+ args = add_interpolation(args, expression)
build_interpolation_args(rest, args)
else
_ ->
- args = append_string(args, "{{")
+ args = add_string(args, "{{")
build_interpolation_args(rest, args)
end
end
defp build_interpolation_args(<>, args) do
- args = append_string(args, <>)
+ args = add_string(args, <>)
build_interpolation_args(rest, args)
end
- defp append_interpolation(args, expression) do
+ defp add_interpolation(args, expression) do
interpolation_node = {
:"::",
[],
@@ -37,17 +38,16 @@ defmodule KinoSlack.MessageInterpolator do
]
}
- args ++ [interpolation_node]
+ [interpolation_node | args]
end
- defp append_string(args, string) do
- last_arg = List.last(args)
+ defp add_string(args, string) do
+ [head | tail] = args
- if is_binary(last_arg) do
- last_string = last_arg <> string
- List.replace_at(args, -1, last_string)
+ if is_binary(head) do
+ [head <> string | tail]
else
- args ++ [string]
+ [string | args]
end
end
end
From b449bb1c4a66ba2e501a7041d5668087417f6208 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Hugo=20Bara=C3=BAna?=
Date: Fri, 17 Mar 2023 14:58:26 -0300
Subject: [PATCH 11/11] Refactors Interpolator to use a buffer for the string
chunk being processed
---
lib/kino_slack/message_interpolator.ex | 36 ++++++++++----------------
1 file changed, 14 insertions(+), 22 deletions(-)
diff --git a/lib/kino_slack/message_interpolator.ex b/lib/kino_slack/message_interpolator.ex
index 725d6bc..0867529 100644
--- a/lib/kino_slack/message_interpolator.ex
+++ b/lib/kino_slack/message_interpolator.ex
@@ -2,33 +2,32 @@ defmodule KinoSlack.MessageInterpolator do
@moduledoc false
def interpolate(message) do
- args = build_interpolation_args(message, [""])
+ args = build_interpolation_args(message, "", [])
args = Enum.reverse(args)
{:<<>>, [], args}
end
- defp build_interpolation_args("", args) do
- args
+ defp build_interpolation_args("", buffer, acc) do
+ prepend_buffer(buffer, acc)
end
- defp build_interpolation_args("{{" <> rest, args) do
+ defp build_interpolation_args("{{" <> rest, buffer, acc) do
with [inner, rest] <- String.split(rest, "}}", parts: 2),
{:ok, expression} <- Code.string_to_quoted(inner) do
- args = add_interpolation(args, expression)
- build_interpolation_args(rest, args)
+ acc = prepend_buffer(buffer, acc)
+ acc = prepend_interpolation(expression, acc)
+ build_interpolation_args(rest, "", acc)
else
_ ->
- args = add_string(args, "{{")
- build_interpolation_args(rest, args)
+ build_interpolation_args(rest, <>, acc)
end
end
- defp build_interpolation_args(<>, args) do
- args = add_string(args, <>)
- build_interpolation_args(rest, args)
+ defp build_interpolation_args(<>, buffer, acc) do
+ build_interpolation_args(rest, <>, acc)
end
- defp add_interpolation(args, expression) do
+ defp prepend_interpolation(expression, acc) do
interpolation_node = {
:"::",
[],
@@ -38,16 +37,9 @@ defmodule KinoSlack.MessageInterpolator do
]
}
- [interpolation_node | args]
+ [interpolation_node | acc]
end
- defp add_string(args, string) do
- [head | tail] = args
-
- if is_binary(head) do
- [head <> string | tail]
- else
- [string | args]
- end
- end
+ defp prepend_buffer("", acc), do: acc
+ defp prepend_buffer(buffer, acc), do: [buffer | acc]
end