Why I'm getting nil on second argument of `Kernel.<>()`?

I’m trying to build a telegram bot with Nadia, and I thought that would be a good idea, to wrap some functionalities with macros, for studying purposes!

Here’re my macros:

#router.ex
defmodule Lovelace.Router
  [...]
  defp generate_command(command, handler) do
    quote do
      def do_match_message(
            %{
              message: %{
                text: "/" <> unquote(command)
              }
            } = var!(update)
          ) do
        handle_message(unquote(handler), [var!(update)])
      end

      def do_match_message(
            %{
              message: %{
                text: "/" <> unquote(command) <> " " <> _
              }
            } = var!(update)
          ) do
        handle_message(unquote(handler), [var!(update)])
      end

      def do_match_message(
            %{
              message: %{
                text: "/" <> unquote(command) <> "@" <> unquote(@bot_name)
              }
            } = var!(update)
          ) do
        handle_message(unquote(handler), [var!(update)])
      end

      def do_match_message(
            %{
              message: %{
                text: "/" <> unquote(command) <> "@" <> unquote(@bot_name) <> " " <> _
              }
            } = var!(update)
          ) do
        handle_message(unquote(handler), [var!(update)])
      end
    end
  end

    # Helpers

  def handle_message({module, function}, update)
      when is_atom(function) and is_list(update) do
    Task.start(fn ->
      apply(module, function, [hd(update)])
    end)
  end

  def handle_message({module, function}, update)
      when is_atom(function) do
    Task.start(fn ->
      apply(module, function, [update])
    end)
  end

  def handle_message(function, _update)
      when is_function(function) do
    Task.start(fn ->
      function.()
    end)
  end

  def handle_message(_, _), do: nil

  ## Command

  defmacro command(commands, do: function)
           when is_list(commands) do
    Enum.map(commands, fn command ->
      generate_command(command, function)
    end)
  end

  defmacro command(command, do: function) do
    generate_command(command, function)
  end

  defmacro command(commands, module, function)
           when is_list(commands) do
    Enum.map(commands, fn command ->
      generate_command(command, {module, function})
    end)
  end

  defmacro command(command, module, function) do
    generate_command(command, {module, function})
  end
  [...]
end

And I’m using as:

#commands.ex
defmodule Lovelace.Commands do
  @moduledoc """
  Define all bot's commands
  """

  use Lovelace.Router
  use Lovelace.Commander

  import Lovelace.Helpers

  alias Lovelace.Commands.Outside
 
  command "welcome" do
    Logger.log(:info, "Command /welcome")

    ~s(Seja bem vindo ao grupo de Ciência da Computação! )
    |> Kernel.<>(
      ~s|Leia as regras do grupo no pinado e visite nosso GitHub(https://github.com/cciuenf) |
    )
    |> Kernel.<>(~s(Digite /ajuda para ver mais comandos!))
    |> send_message()
  end
end

However, when compiling, I’m geeting:

Compiling 2 files (.ex)

== Compilation error in file lib/lovelace/commands.ex ==
** (ArgumentError) expected binary argument in <> operator but got: nil
    (elixir 1.11.3) lib/kernel.ex:1821: Kernel.wrap_concatenation/3
    (elixir 1.11.3) lib/kernel.ex:1812: Kernel.extract_concatenations/2
    (elixir 1.11.3) lib/kernel.ex:1808: Kernel.extract_concatenations/2
    (elixir 1.11.3) expanding macro: Kernel.<>/2
    lib/lovelace/commands.ex:13: Lovelace.Commands.do_match_message/1

The Error is thrown on

command "welcome"...

in the commands.ex file!

But I ain’t finding where is the error… Could you help me?

This one works for me:

defmodule Demo do
  def f1() do
    ~s(Seja bem vindo ao grupo de Ciência da Computação! )
    |> Kernel.<>(
      ~s|Leia as regras do grupo no pinado e visite nosso GitHub(https://github.com/cciuenf) |
    )
    |> Kernel.<>(~s(Digite /ajuda para ver mais comandos!))
  end
end

Demo.f1 inside the iex REPL returns the concatenated string for me. On which line in your source are you getting the compilation error? #13 looks like an empty line to me.

Sorry, I didn’t specified where is the error! I changed the question!

You changed the bigger code block at the start of your post but that doesn’t tell me where the error is. It still says line 13 in your last coding block, which points at the empty line immediately after Logger.log.

Check this out:

    lib/lovelace/commands.ex:13: Lovelace.Commands.do_match_message/1

Notice the 13 in there. But line 13 is empty. Weird.

Can you make one single small module and test with it?

The commands.ex file block here was incomplete, I completed! But I’ll also try to reproduce on another module!

Pasting a bunch of coding blocks (some rather big) doesn’t help much when you have a narrow problem. For such scenarios where more code is involved you’d get much more help if you just made a small GitHub project and linked to it here. :slight_smile:

For now, just make one module that demonstrates the problem and we can discuss that.

It’s in 2 places:

and

Looks like you don’t have set @bot_name in Lovelace.Router or by mistake you called unquote for it.

1 Like

Thank you! The error wasn’t so specific so I didn’t thought about my Application.compile_env/2 on the beggining of router.ex