Current section
Files
Jump to
Current section
Files
lib/phoenix_playground.ex
defmodule PhoenixPlayground do
@moduledoc """
Phoenix Playground makes it easy to create single-file Phoenix applications.
"""
@doc """
Starts Phoenix Playground.
This functions starts Phoenix with a LiveView (`:live`), a controller (`:controller`),
or a router (`:router`).
## Options
* `:live` - a LiveView module.
* `:controller` - a controller module.
* `:plug` - a plug.
* `:port` - port to listen on, defaults to: `4000`.
* `:open_browser` - whether to open the browser on start, defaults to `true`.
* `:child_specs` - child specs to run in Phoenix Playground supervision tree. The playground
Phoenix endpoint is automatically added and is always the last child spec. Defaults to `[]`.
"""
def start(options) do
options = Keyword.put_new(options, :file, get_file())
options =
if router = options[:router] do
IO.warn("setting :router is deprecated in favour of setting :plug")
options
|> Keyword.delete(:router)
|> Keyword.put(:plug, router)
else
options
end
if plug = options[:plug] do
Application.put_env(:phoenix_playground, :plug, plug)
end
case Supervisor.start_child(PhoenixPlayground.Application, {PhoenixPlayground, options}) do
{:ok, pid} ->
{:ok, pid}
{:error, {:already_started, pid}} ->
{:ok, pid}
other ->
other
end
end
defp get_file do
{:current_stacktrace, stacktrace} = Process.info(self(), :current_stacktrace)
get_file(stacktrace)
end
defp get_file([
{PhoenixPlayground, :start, 1, _},
{_, :__FILE__, 1, meta} | _
]) do
Path.expand(Keyword.fetch!(meta, :file))
end
defp get_file([_ | rest]) do
get_file(rest)
end
defp get_file([]) do
nil
end
@doc false
def child_spec(options) do
%{
id: __MODULE__,
start: {__MODULE__, :start_link, [options]},
type: :supervisor
}
end
@doc false
def start_link(options) do
options =
Keyword.validate!(options, [
:live,
:controller,
:plug,
:file,
child_specs: [],
port: 4000,
open_browser: true
])
{child_specs, options} = Keyword.pop!(options, :child_specs)
{type, module} =
cond do
live = options[:live] ->
{:live, live}
controller = options[:controller] ->
{:controller, controller}
options[:plug] ->
{:plug, :fetch_from_env}
true ->
raise "missing :live, :controller, or :plug"
end
if options[:open_browser] do
Application.put_env(:phoenix, :browser_open, true)
end
path = options[:file] || to_string(module.__info__(:compile)[:source])
basename = Path.basename(path)
# PhoenixLiveReload requires Hex
Application.ensure_all_started(:hex)
Application.ensure_all_started(:phoenix_live_reload)
Application.put_env(:phoenix_live_reload, :dirs, [
Path.dirname(path)
])
options =
[
type: type,
module: module,
basename: basename
] ++ Keyword.take(options, [:port])
children =
child_specs ++
[
{Phoenix.PubSub, name: PhoenixPlayground.PubSub},
{PhoenixPlayground.Reloader, path},
{PhoenixPlayground.Endpoint, options}
]
System.no_halt(true)
Supervisor.start_link(children, strategy: :one_for_one)
end
end