Current section

Files

Jump to
texas lib mix tasks texas.ify.ex
Raw

lib/mix/tasks/texas.ify.ex

defmodule Mix.Tasks.Texas.Ify do
use Mix.Task
@shortdoc "Take an existing Phoenix project and Texasify it"
@moduledoc """
Adds Texas hooks into the current Phoenix application (assumed to be create with `mix phx.new`).
This will modify the following files as described, so it is wise to commit your changes prior to
running this command:
- `./assets/js/app.js` - (adds `texasjs` dependency and instantiates a new Texas socket)
- `./lib/<your_app>_web/channels/user_socket.ex` - adds `use Texas.Socket` after `use Phoenix.Socket`
- `./config/config.exs` - Specifies endpoint and router modules and configures templating engine to compile .texas files
- `./lib/<your_app>_web/router.ex` - Adds the `Texas.Plug` to your browser pipeline
- `./lib/<your_app>_web.ex/` - imports `Texas.Controller` into your app's controller template
# - `./lib/<your_app>_web/controllers/page_controller.ex` - Renders views with `texas_render`
# - Renames `index.html.eex` to `index.html.texas`
Usage:
mix texas.ify
"""
@impl true
def run(_args) do
# TODO: Check for Phoenix version?
Mix.shell().info("Texasifying this project")
app = Mix.Project.config()[:app]
app_js = "./assets/js/app.js"
[user_socket] = Path.wildcard("./lib/*_web/channels/user_socket.ex")
config = "./config/config.exs"
[router] = Path.wildcard("./lib/*_web/router.ex")
app_name =
config
|> File.stream!()
|> Enum.find(& String.contains?(&1, "Endpoint") && String.contains?(&1, inspect app))
|> String.split(",")
|> Enum.at(1)
|> String.trim()
[web_templates] = Path.wildcard("./lib/#{to_string(app)}_web.ex")
Mix.shell().info("- Adding texasjs socket to app.js")
# If user hasn't uncommented the socket import in app.js, do it for them
replace_in_file(app_js, "// import socket", "import socket", false)
insert_into_file(app_js, "import socket from \"./socket\"", "import Texas from \"texasjs\"\nnew Texas(socket)")
Mix.shell().info("Adding Texas into the backend socket")
insert_into_file(user_socket, "use Phoenix.Socket", " use Texas.Socket")
Mix.shell().info("Added Texas stuff to config.exs")
insert_into_file(config, "use Mix.Config", """
config :phoenix, :template_engines,
texas: Texas.TemplateEngine
config :texas, pubsub: #{app_name}.Endpoint
config :texas, router: #{app_name}.Router
""")
Mix.shell().info("Adding Texas to the browser pipeline")
insert_into_file(router, " pipeline :browser do", " end", " plug Texas.Plug")
Mix.shell().info("Adding Texas to the controller template")
insert_into_file(web_templates, "use Phoenix.Controller", "import", " import Texas.Controller")
Mix.shell().info("Done!")
end
defp replace_in_file(path, text, replacement_text, check? \\ true) do
input = File.read!(path)
unless String.contains?(input, replacement_text) and check? do
text = String.replace(input, text, replacement_text)
File.write!(path, text)
end
end
defp insert_into_file(path, previous_line, text_to_add) do
replace_in_file(path, previous_line, "#{previous_line}\n#{text_to_add}")
end
defp insert_into_file(path, section_start, section_end, text_to_add) do
unless String.contains?(File.read!(path), text_to_add) do
f = File.stream!(path)
{pre, rest} = Enum.split_while(f, & not String.contains?(&1, section_start))
{section, end_and_beyond} = Enum.split_while(rest, & not String.contains?(&1, section_end))
out = pre ++ [section] ++ [text_to_add] ++ ["\n"] ++ [end_and_beyond] |> Enum.join()
File.write!(path, out)
end
end
end