Understanding Elixir and Plug syntax

I am studying some code from http://www.brianstorti.com/getting-started-with-plug-elixir/ and have some observations.

defmodule MyPipeline do
  # We use Plug.Builder to have access to the plug/2 macro.
  # This macro can receive a function or a module plug and an
  # optional parameter that will be passed unchanged to the 
  # given plug.
  use Plug.Builder

  plug Plug.Logger
  plug :extract_name
  plug :greet, %{my_option: "Hello"}

  def extract_name(%Plug.Conn{request_path: "/" <> name} = conn, opts) do
    assign(conn, :name, name)
  end

  def greet(conn, opts) do
    conn
    |> send_resp(200, "#{opts[:my_option]}, #{conn.assigns.name}")
  end
end

The plug is called in iex by Plug.Adapters.Cowboy.http MyPipeline, %{} as a opposed to the first one in the Plug docs Plug.Adapters.Cowboy.http MyPlug, [].

  1. Does this mean that the %{} is a means of passing a parameter to the plug(an empty map in this case), whereas the [] means you are passing no parameters to the plug or that it takes no parameters?

  2. Does the expression Plug.Adapters.Cowboy.http mean that every item to the right of a dot is a submodule, making Adapters a submodule of Plug and Cowboy a submodule of the adapters which uses the Cowboy package, and http a submodule of the Cowboy package?

  3. I take it that in the expression %Plug.Conn{}, Conn is a struct defined in the Plug package. Why wouldn’t it be right to write it as Plug.%Conn{}

  4. In the case of the code below does it that the extract_name function would not be called if the request did not match "/" <> name? i.e. a plug will not be executed if it pattern it is matched on is not part of the request?

    def extract_name(%Plug.Conn{request_path: “/” <> name} = conn, opts) do
    assign(conn, :name, name)
    end

Thanks

When a plug is init’d its init/2 function is called if a module or the second argument is it, the second argument is the second argument, so for the call plug :greet, %{my_option: "Hello"} then greet’s second argument will be %{my_option: "Hello"}, it can be whatever the plug wants, so a map, a list, an integer, whatever. :slight_smile:

To be ‘technical’, the EVM has no such thing as submodules, the Plug.Adapters.Cowboy is a module name, dots and all. Elixir gives you functionality that emulates submodules via dots though, so in essence you can consider it yes, except in this cast http is not a submodule but a function on Plug.Adapters.Cowboy since it starts with a lower-case char.

Because that would basically be doing %Conn{} then calling it on the Plug module. In Elixir a string of initially upper-cased atoms are all combined into a single atom, and ‘that’ can then be called with a trailing dot to access the module and whatever is after that is what is accessed. Basically if Plug.%Conn{} compiled (I doubt it does but not tried) it would be trying to call a function named %Conn on the module Plug with the argument of the empty tuple {} or something like that, but since I doubt it compiled, eh… ^.^

If you surround code in standard markdown code fences (``` on empty lines before and after the code) it will format properly. :slight_smile:

The extract name function will still be called, however if the argument does not match what is specified there then it will go to the next same-named/arity function, if no more then it throws an exception. :slight_smile:

2 Likes