Reality check your library idea

I’ve been playing with Macro’s after reading Metaprogramming Elixir by @chrismccord.

As a result :phx_alt_routes was born, albeit in a private repository. First I want to validate the concept. It already works with dead views and live views. Simply by

  • creating one config module (adapter)
  • replacing alias MyWebApp.Router.Helpers with use MyWebApp.AltRoutes.Router.Helpers, MyWebApp.Router.Helpers in my_web_app.ex
  • adding Phx.AltRoutes.MountHelper to the :live_view set.
  • adding Phx.AltRoutes.Plug to the connection plug set

Phx.AltRoutes.Router

Provides a set of macros for generating alternative Phoenix routes with configurable assignments.

When a Gettext module is defined in the configuration, the alt_scope/2 macro uses it to build the alternative routes using the Gettext module. This allows routes to be translated along with other Gettext messages.

To summarize the process.

  • The alt_scope/2 macro splits the path of every nested route.
  • The segments are extracted into routes.po files using mix gettext.extract.
  • The individual segments are translated
  • The translations are used to create additional alternative routes with path {prefix}/{translated_segment1}/{translated_segment2}/ and helper {prefix}_{original_helper}
  • For every alternative route the configured bindings are added to assigns and session.
  • A few helper assignments are also added, which can be used by Phx.AltRoutes.Router.Helpers

Example

Given this configuration:

defmodule MyAppWeb.Phx.AltRoutes do
  use Phx.AltRoutes,
    routes: %{
      "dutch" => %{
        path_prefix: "nl",
        bindings: %{locale: "nl_NL"},
      },
      "english" => %{
        path_prefix: "en",
        bindings: %{ocale: "en_GB"},
      },
    },
    gettext_module: MyAppWeb.Gettext

To generate alternative routes for routes, those routes are nested in a alt_scope.

defmodule MyAppWeb.Router do
  use Phoenix.Router
  alt_scope MyAppWeb.Phx.AltRoutes do
    get "/users/:id/edit", UserController, :edit
    get "/users/show/:id", UserController, :show
  end
end

This will generate routes.po files including the entries for users, edit and show. You can translate the segments. The macro expand the routes during compile time with alternative variants. The example above is equal to:

defmodule MyAppWeb.Router do
  use Phoenix.Router
  scope "/" do
    get "/users/:id/edit", UserController, :edit
    get "/users/show/:id", UserController, :show

  scope "/en" do
    get "/users/:id/edit", UserController, :edit, assigns: %{locale: "en_GB", helper_prefix: "en"}, session: %{"locale": "en_GB", helper_prefix: "en"}, as: :en_user_edit_path
    get "/users/show/:id", UserController, :show, assigns: %{locale: "en_GB", helper_prefix: "en"}, session: %{"locale": "en_GB", helper_prefix: "en"} , as: :en_user_show_path
  end

  scope "/nl" do
    get "/gebruikers/:id/bewerken", UserController, :edit, assigns: %{locale: "nl_NL", helper_prefix: "nl"}, session: %{"locale": "nl_NL", helper_prefix: "nl"}, as: :nl_user_edit_path
    get "/gebruikers/tonen/:id", UserController, :show, :edit, assigns: %{locale: "nl_NL", helper_prefix: "nl"}, session: %{"locale": "nl_NL", helper_prefix: "nl"}, as: :nl_user_show_path
  end
end

The routes can be nested, which makes it easy to create /region/sub-region/ routes.

Phx.AltRoutes.Router.Helpers

Provides a macro that wraps Phoenix.Router.Helpers functions in order to generates the correct alternative route. It uses the helper_prefix assignment added to the session by Phx.AltRoutes.Router.

Thinking of it…the assignments can probably be fetched using only the helper_prefix key…

4 Likes