2 |
3 | <%%= render "form.html", changeset: @changeset,
4 | action: <%= schema.singular %>_path(@conn, :update, @<%= schema.singular %>) %>
5 |
6 | <%%= link "Back", to: <%= schema.singular %>_path(@conn, :index) %>
7 |
--------------------------------------------------------------------------------
/lib/phoenix/template/exs_engine.ex:
--------------------------------------------------------------------------------
1 | defmodule Phoenix.Template.ExsEngine do
2 | @moduledoc """
3 | The Phoenix engine that handles the `.exs` extension.
4 | """
5 |
6 | @behaviour Phoenix.Template.Engine
7 |
8 | def compile(path, _name) do
9 | path
10 | |> File.read!
11 | |> Code.string_to_quoted!(file: path)
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/installer/templates/new/config/test.exs:
--------------------------------------------------------------------------------
1 | use Mix.Config
2 |
3 | # We don't run a server during test. If one is required,
4 | # you can enable the server option below.
5 | config :<%= app_name %>, <%= app_module %>.Endpoint,
6 | http: [port: 4001],
7 | server: false
8 |
9 | # Print only warnings and errors during test
10 | config :logger, level: :warn
11 |
--------------------------------------------------------------------------------
/installer/templates/phx_ecto/repo.ex:
--------------------------------------------------------------------------------
1 | defmodule <%= app_module %>.Repo do
2 | use Ecto.Repo, otp_app: :<%= app_name %>
3 |
4 | @doc """
5 | Dynamically loads the repository url from the
6 | DATABASE_URL environment variable.
7 | """
8 | def init(_, opts) do
9 | {:ok, Keyword.put(opts, :url, System.get_env("DATABASE_URL"))}
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/installer/templates/phx_single/config/test.exs:
--------------------------------------------------------------------------------
1 | use Mix.Config
2 |
3 | # We don't run a server during test. If one is required,
4 | # you can enable the server option below.
5 | config :<%= app_name %>, <%= endpoint_module %>,
6 | http: [port: 4001],
7 | server: false
8 |
9 | # Print only warnings and errors during test
10 | config :logger, level: :warn
11 |
--------------------------------------------------------------------------------
/installer/templates/phx_umbrella/config/dev.exs:
--------------------------------------------------------------------------------
1 | use Mix.Config
2 |
3 | # Do not include metadata nor timestamps in development logs
4 | config :logger, :console, format: "[$level] $message\n"
5 |
6 | # Set a higher stacktrace during development. Avoid configuring such
7 | # in production as building large stacktraces may be expensive.
8 | config :phoenix, :stacktrace_depth, 20
9 |
--------------------------------------------------------------------------------
/test/fixtures/cache_manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "digests": {
3 | "foo-d978852bea6530fcd197b5445ed008fd.css": {
4 | "logical_path": "foo.css",
5 | "mtime": 32132171,
6 | "size": 369053,
7 | "digest": "d978852bea6530fcd197b5445ed008fd"
8 | }
9 | },
10 | "latest": {
11 | "foo.css": "foo-d978852bea6530fcd197b5445ed008fd.css"
12 | },
13 | "version": 1
14 | }
15 |
--------------------------------------------------------------------------------
/installer/mix.exs:
--------------------------------------------------------------------------------
1 | defmodule Phx.New.Mixfile do
2 | use Mix.Project
3 |
4 | def project do
5 | [app: :phx_new,
6 | start_permanent: Mix.env == :prod,
7 | version: "1.3.0-rc.1",
8 | elixir: "~> 1.3 or ~> 1.4"]
9 | end
10 |
11 | # Configuration for the OTP application
12 | #
13 | # Type `mix help compile.app` for more information
14 | def application do
15 | [extra_applications: []]
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/installer/templates/phx_ecto/seeds.exs:
--------------------------------------------------------------------------------
1 | # Script for populating the database. You can run it as:
2 | #
3 | # mix run priv/repo/seeds.exs
4 | #
5 | # Inside the script, you can read and write to any of your
6 | # repositories directly:
7 | #
8 | # <%= app_module %>.Repo.insert!(%<%= app_module %>.SomeSchema{})
9 | #
10 | # We recommend using the bang functions (`insert!`, `update!`
11 | # and so on) as they will fail if something goes wrong.
12 |
--------------------------------------------------------------------------------
/installer/templates/ecto/seeds.exs:
--------------------------------------------------------------------------------
1 | # Script for populating the database. You can run it as:
2 | #
3 | # mix run priv/repo/seeds.exs
4 | #
5 | # Inside the script, you can read and write to any of your
6 | # repositories directly:
7 | #
8 | # <%= app_module %>.Repo.insert!(%<%= app_module %>.SomeModel{})
9 | #
10 | # We recommend using the bang functions (`insert!`, `update!`
11 | # and so on) as they will halt execution if something goes wrong.
12 |
--------------------------------------------------------------------------------
/installer/templates/phx_umbrella/apps/app_name/config/prod.secret.exs:
--------------------------------------------------------------------------------
1 | use Mix.Config
2 |
3 | # In this file, we keep production configuration that
4 | # you likely want to automate and keep it away from
5 | # your version control system.
6 | #
7 | # You should document the content of this
8 | # file or create a script for recreating it, since it's
9 | # kept out of version control and might be hard to recover
10 | # or recreate for your teammates (or you later on).
11 |
--------------------------------------------------------------------------------
/priv/templates/phoenix.gen.html/show.html.eex:
--------------------------------------------------------------------------------
1 |
17 | <%% end %>
18 |
--------------------------------------------------------------------------------
/installer/lib/mix/tasks/local.phoenix.ex:
--------------------------------------------------------------------------------
1 | defmodule Mix.Tasks.Local.Phoenix do
2 | use Mix.Task
3 |
4 | @url "https://github.com/phoenixframework/archives/raw/master/phoenix_new.ez"
5 | @shortdoc "Updates Phoenix locally"
6 |
7 | @moduledoc """
8 | Updates Phoenix locally.
9 |
10 | mix local.phoenix
11 |
12 | Accepts the same command line options as `archive.install`.
13 | """
14 | def run(args) do
15 | IO.puts :stderr, "mix local.phoenix is deprecated. Use local.phx instead."
16 | Mix.Task.run "archive.install", [@url | args]
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/installer/templates/phx_umbrella/apps/app_name_web/config/prod.secret.exs:
--------------------------------------------------------------------------------
1 | use Mix.Config
2 |
3 | # In this file, we keep production configuration that
4 | # you likely want to automate and keep it away from
5 | # your version control system.
6 | #
7 | # You should document the content of this
8 | # file or create a script for recreating it, since it's
9 | # kept out of version control and might be hard to recover
10 | # or recreate for your teammates (or you later on).
11 | config :<%= web_app_name %>, <%= endpoint_module %>,
12 | secret_key_base: "<%= prod_secret_key_base %>"
13 |
--------------------------------------------------------------------------------
/test/fixtures/digest/cleaner/cache_manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "digests": {
3 | "app-1.css": {
4 | "logical_path": "app.css",
5 | "mtime": 32132171,
6 | "size": 369053,
7 | "digest": "1"
8 | },
9 | "app-2.css": {
10 | "logical_path": "app.css",
11 | "mtime": 32132172,
12 | "size": 369053,
13 | "digest": "2"
14 | },
15 | "app-3.css": {
16 | "logical_path": "app.css",
17 | "mtime": 32132173,
18 | "size": 369053,
19 | "digest": "3"
20 | }
21 | },
22 | "latest": {
23 | "app.css": "app-3.css"
24 | },
25 | "version": 1
26 | }
27 |
--------------------------------------------------------------------------------
/installer/templates/static/brunch/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "repository": {},
3 | "license": "MIT",
4 | "scripts": {
5 | "deploy": "brunch build --production",
6 | "watch": "brunch watch --stdin"
7 | },
8 | "dependencies": {
9 | "phoenix": "file:<%= brunch_deps_prefix %><%= phoenix_path %>"<%= if html do %>,
10 | "phoenix_html": "file:<%= brunch_deps_prefix %>deps/phoenix_html"<% end %>
11 | },
12 | "devDependencies": {
13 | "babel-brunch": "6.0.6",
14 | "brunch": "2.10.7",
15 | "clean-css-brunch": "2.10.0",
16 | "css-brunch": "2.10.0",
17 | "uglify-js-brunch": "2.1.1"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/test/fixtures/digest/cleaner/latest_not_most_recent_cache_manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "digests": {
3 | "app-1.css": {
4 | "logical_path": "app.css",
5 | "mtime": 32132171,
6 | "size": 369053,
7 | "digest": "1"
8 | },
9 | "app-2.css": {
10 | "logical_path": "app.css",
11 | "mtime": 32132172,
12 | "size": 369053,
13 | "digest": "2"
14 | },
15 | "app-3.css": {
16 | "logical_path": "app.css",
17 | "mtime": 32132170,
18 | "size": 369053,
19 | "digest": "3"
20 | }
21 | },
22 | "latest": {
23 | "app.css": "app-3.css"
24 | },
25 | "version": 1
26 | }
27 |
--------------------------------------------------------------------------------
/lib/phoenix/transports/serializer.ex:
--------------------------------------------------------------------------------
1 | defmodule Phoenix.Transports.Serializer do
2 | @moduledoc """
3 | Defines a behaviour for `Phoenix.Socket.Message` serialization.
4 | """
5 |
6 | @doc "Translates a `Phoenix.Socket.Broadcast` struct to fastlane format"
7 | @callback fastlane!(Phoenix.Socket.Broadcast.t) :: term
8 |
9 | @doc "Encodes `Phoenix.Socket.Message` struct to transport representation"
10 | @callback encode!(Phoenix.Socket.Message.t | Phoenix.Socket.Reply.t) :: term
11 |
12 | @doc "Decodes iodata into `Phoenix.Socket.Message` struct"
13 | @callback decode!(iodata, options :: Keyword.t) :: Phoenix.Socket.Message.t
14 | end
15 |
--------------------------------------------------------------------------------
/priv/templates/phoenix.gen.json/view.ex:
--------------------------------------------------------------------------------
1 | defmodule <%= module %>View do
2 | use <%= base %>.Web, :view
3 |
4 | def render("index.json", %{<%= plural %>: <%= plural %>}) do
5 | %{data: render_many(<%= plural %>, <%= module %>View, "<%= singular %>.json")}
6 | end
7 |
8 | def render("show.json", %{<%= singular %>: <%= singular %>}) do
9 | %{data: render_one(<%= singular %>, <%= module %>View, "<%= singular %>.json")}
10 | end
11 |
12 | def render("<%= singular %>.json", %{<%= singular %>: <%= singular %>}) do
13 | %{id: <%= singular %>.id<%= for {k, _} <- attrs do %>,
14 | <%= k %>: <%= singular %>.<%= k %><% end %>}
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/priv/templates/phx.gen.embedded/embedded_schema.ex:
--------------------------------------------------------------------------------
1 | defmodule <%= inspect schema.module %> do
2 | use Ecto.Schema
3 | import Ecto.Changeset
4 | alias <%= inspect schema.module %>
5 |
6 | embedded_schema do
7 | <%= for {k, v} <- schema.types do %> field <%= inspect k %>, <%= inspect v %><%= schema.defaults[k] %><% end %>
8 | end
9 |
10 | @doc false
11 | def changeset(%<%= inspect schema.alias %>{} = <%= schema.singular %>, attrs) do
12 | <%= schema.singular %>
13 | |> cast(attrs, [<%= Enum.map_join(schema.attrs, ", ", &inspect(elem(&1, 0))) %>])
14 | |> validate_required([<%= Enum.map_join(schema.attrs, ", ", &inspect(elem(&1, 0))) %>])
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: elixir
2 | matrix:
3 | include:
4 | - otp_release: 18.3
5 | elixir: 1.3.2
6 | script: mix test
7 | - otp_release: 19.0
8 | elixir: 1.3.2
9 | script: mix test
10 | - otp_release: 18.3
11 | elixir: 1.4.2
12 | - otp_release: 19.0
13 | elixir: 1.4.2
14 | services:
15 | - redis-server
16 | sudo: false
17 | before_script:
18 | - mix deps.get --only test
19 | - nvm install 6.2 && nvm use 6.2
20 | script:
21 | - mix test
22 | - cd installer && mix test
23 | - cd ../ && npm install && npm test
24 | after_script:
25 | - cd $TRAVIS_BUILD_DIR
26 | - mix deps.get --only docs
27 | - MIX_ENV=docs mix inch.report
28 |
--------------------------------------------------------------------------------
/priv/templates/phoenix.gen.json/changeset_view.ex:
--------------------------------------------------------------------------------
1 | defmodule <%= base %>.ChangesetView do
2 | use <%= base %>.Web, :view
3 |
4 | @doc """
5 | Traverses and translates changeset errors.
6 |
7 | See `Ecto.Changeset.traverse_errors/2` and
8 | `<%= base %>.ErrorHelpers.translate_error/1` for more details.
9 | """
10 | def translate_errors(changeset) do
11 | Ecto.Changeset.traverse_errors(changeset, &translate_error/1)
12 | end
13 |
14 | def render("error.json", %{changeset: changeset}) do
15 | # When encoded, the changeset returns its errors
16 | # as a JSON object. So we just pass it forward.
17 | %{errors: translate_errors(changeset)}
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/installer/templates/static/brunch/gitignore:
--------------------------------------------------------------------------------
1 | # App artifacts
2 | /_build
3 | /db
4 | /deps
5 | /*.ez
6 |
7 | # Generated on crash by the VM
8 | erl_crash.dump
9 |
10 | # Static artifacts
11 | /node_modules
12 |
13 | # Since we are building assets from web/static,
14 | # we ignore priv/static. You may want to comment
15 | # this depending on your deployment strategy.
16 | /priv/static/
17 |
18 | # The config/prod.secret.exs file by default contains sensitive
19 | # data and you should not commit it into version control.
20 | #
21 | # Alternatively, you may comment the line below and commit the
22 | # secrets file as long as you replace its contents by environment
23 | # variables.
24 | /config/prod.secret.exs
25 |
--------------------------------------------------------------------------------
/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
10 |
11 | ### Environment
12 |
13 | * Elixir version (elixir -v):
14 | * Phoenix version (mix deps):
15 | * NodeJS version (node -v):
16 | * NPM version (npm -v):
17 | * Operating system:
18 |
19 | ### Expected behavior
20 |
21 |
22 | ### Actual behavior
23 |
--------------------------------------------------------------------------------
/installer/templates/phx_umbrella/apps/app_name/lib/app_name/application.ex:
--------------------------------------------------------------------------------
1 | defmodule <%= app_module %>.Application do
2 | @moduledoc """
3 | The <%= app_module %> Application Service.
4 |
5 | The <%= app_name %> system business domain lives in this application.
6 |
7 | Exposes API to clients such as the `<%= app_module%>.Web` application
8 | for use in channels, controllers, and elsewhere.
9 | """
10 | use Application
11 |
12 | def start(_type, _args) do
13 | import Supervisor.Spec, warn: false
14 |
15 | Supervisor.start_link([
16 | <%= if ecto do %>supervisor(<%= app_module %>.Repo, []),<% end %>
17 | ], strategy: :one_for_one, name: <%= app_module %>.Supervisor)
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/installer/templates/phx_umbrella/apps/app_name_web/gitignore:
--------------------------------------------------------------------------------
1 | # App artifacts
2 | /_build
3 | /db
4 | /deps
5 | /*.ez
6 |
7 | # Generate on crash by the VM
8 | erl_crash.dump
9 |
10 | # Static artifacts
11 | /node_modules
12 |
13 | # Since we are building assets from web/static,
14 | # we ignore priv/static. You may want to comment
15 | # this depending on your deployment strategy.
16 | /priv/static/
17 |
18 | # Files matching config/*.secret.exs pattern contain sensitive
19 | # data and you should not commit them into version control.
20 | #
21 | # Alternatively, you may comment the line below and commit the
22 | # secrets files as long as you replace their contents by environment
23 | # variables.
24 | /config/*.secret.exs
--------------------------------------------------------------------------------
/installer/templates/phx_umbrella/mix.exs:
--------------------------------------------------------------------------------
1 | defmodule <%= root_app_module %>.Mixfile do
2 | use Mix.Project
3 |
4 | def project do
5 | [apps_path: "apps",
6 | start_permanent: Mix.env == :prod,
7 | deps: deps()]
8 | end
9 |
10 | # Dependencies can be Hex packages:
11 | #
12 | # {:mydep, "~> 0.3.0"}
13 | #
14 | # Or git/path repositories:
15 | #
16 | # {:mydep, git: "https://github.com/elixir-lang/mydep.git", tag: "0.1.0"}
17 | #
18 | # Type "mix help deps" for more examples and options.
19 | #
20 | # Dependencies listed here are available only for this project
21 | # and cannot be accessed from applications inside the apps folder
22 | defp deps do
23 | []
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/priv/templates/phx.gen.json/changeset_view.ex:
--------------------------------------------------------------------------------
1 | defmodule <%= inspect context.web_module %>.ChangesetView do
2 | use <%= inspect context.web_module %>, :view
3 |
4 | @doc """
5 | Traverses and translates changeset errors.
6 |
7 | See `Ecto.Changeset.traverse_errors/2` and
8 | `<%= inspect context.web_module %>.ErrorHelpers.translate_error/1` for more details.
9 | """
10 | def translate_errors(changeset) do
11 | Ecto.Changeset.traverse_errors(changeset, &translate_error/1)
12 | end
13 |
14 | def render("error.json", %{changeset: changeset}) do
15 | # When encoded, the changeset returns its errors
16 | # as a JSON object. So we just pass it forward.
17 | %{errors: translate_errors(changeset)}
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/test/mix/tasks/phx.digest.clean_test.exs:
--------------------------------------------------------------------------------
1 | defmodule Mix.Tasks.Phx.Digest.CleanTest do
2 | use ExUnit.Case
3 |
4 | test "fails when the given paths are invalid" do
5 | Mix.Tasks.Phx.Digest.Clean.run(["--output", "invalid_path"])
6 |
7 | assert_received {:mix_shell, :error, ["The output path \"invalid_path\" does not exist"]}
8 | end
9 |
10 | test "removes old versions", config do
11 | output_path = Path.join("tmp", to_string(config.test))
12 | input_path = "priv/static"
13 | :ok = File.mkdir_p!(output_path)
14 |
15 | Mix.Tasks.Phx.Digest.Clean.run([input_path, "-o", output_path])
16 |
17 | msg = "Clean complete for \"#{output_path}\""
18 | assert_received {:mix_shell, :info, [^msg]}
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/installer/templates/phx_assets/brunch/gitignore:
--------------------------------------------------------------------------------
1 | # App artifacts
2 | /_build
3 | /db
4 | /deps
5 | /*.ez
6 |
7 | # Generated on crash by the VM
8 | erl_crash.dump
9 |
10 | # Generated on crash by NPM
11 | npm-debug.log
12 |
13 | # Static artifacts
14 | /assets/node_modules
15 |
16 | # Since we are building assets from assets/,
17 | # we ignore priv/static. You may want to comment
18 | # this depending on your deployment strategy.
19 | /priv/static/
20 |
21 | # Files matching config/*.secret.exs pattern contain sensitive
22 | # data and you should not commit them into version control.
23 | #
24 | # Alternatively, you may comment the line below and commit the
25 | # secrets files as long as you replace their contents by environment
26 | # variables.
27 | /config/*.secret.exs
--------------------------------------------------------------------------------
/priv/templates/phx.gen.json/fallback_controller.ex:
--------------------------------------------------------------------------------
1 | defmodule <%= inspect context.web_module %>.FallbackController do
2 | @moduledoc """
3 | Translates controller action results into valid `Plug.Conn` responses.
4 |
5 | See `Phoenix.Controller.action_fallback/1` for more details.
6 | """
7 | use <%= inspect context.web_module %>, :controller
8 |
9 | def call(conn, {:error, %Ecto.Changeset{} = changeset}) do
10 | conn
11 | |> put_status(:unprocessable_entity)
12 | |> render(<%= inspect context.web_module %>.ChangesetView, "error.json", changeset: changeset)
13 | end
14 |
15 | def call(conn, {:error, :not_found}) do
16 | conn
17 | |> put_status(:not_found)
18 | |> render(<%= inspect context.web_module %>.ErrorView, :"404")
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/lib/mix/tasks/phoenix.server.ex:
--------------------------------------------------------------------------------
1 | defmodule Mix.Tasks.Phoenix.Server do
2 | use Mix.Task
3 |
4 | @shortdoc "Starts applications and their servers"
5 |
6 | @moduledoc """
7 | Starts the application by configuring all endpoints servers to run.
8 |
9 | ## Command line options
10 |
11 | This task accepts the same command-line arguments as `run`.
12 | For additional information, refer to the documentation for
13 | `Mix.Tasks.Run`.
14 |
15 | For example, to run `phoenix.server` without checking dependencies:
16 |
17 | mix phoenix.server --no-deps-check
18 |
19 | The `--no-halt` flag is automatically added.
20 | """
21 | def run(args) do
22 | IO.puts :stderr, "mix phoenix.server is deprecated. Use phx.server instead."
23 | Mix.Tasks.Phx.Server.run(args)
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/priv/templates/phoenix.gen.model/migration.exs:
--------------------------------------------------------------------------------
1 | defmodule <%= base %>.Repo.Migrations.Create<%= scoped %> do
2 | use Ecto.Migration
3 |
4 | def change do
5 | create table(:<%= plural %><%= if binary_id do %>, primary_key: false<% end %>) do
6 | <%= if binary_id do %> add :id, :binary_id, primary_key: true
7 | <% end %><%= for {k, v} <- attrs do %> add <%= inspect k %>, <%= inspect v %><%= migration_defaults[k] %>
8 | <% end %><%= for {_, i, _, s} <- assocs do %> add <%= if(String.ends_with?(inspect(i), "_id"), do: inspect(i), else: inspect(i) <> "_id") %>, references(<%= inspect(s) %>, on_delete: :nothing<%= if binary_id do %>, type: :binary_id<% end %>)
9 | <% end %>
10 | timestamps()
11 | end
12 | <%= for index <- indexes do %>
13 | <%= index %><% end %>
14 | end
15 | end
16 |
17 |
--------------------------------------------------------------------------------
/installer/templates/phx_assets/brunch/app.js:
--------------------------------------------------------------------------------
1 | // Brunch automatically concatenates all files in your
2 | // watched paths. Those paths can be configured at
3 | // config.paths.watched in "brunch-config.js".
4 | //
5 | // However, those files will only be executed if
6 | // explicitly imported. The only exception are files
7 | // in vendor, which are never wrapped in imports and
8 | // therefore are always executed.
9 |
10 | // Import dependencies
11 | //
12 | // If you no longer want to use a dependency, remember
13 | // to also remove its path from "config.paths.watched".
14 | <%= if html do %>import "phoenix_html"<% end %>
15 |
16 | // Import local files
17 | //
18 | // Local files can be imported directly using relative
19 | // paths "./socket" or full ones "web/static/js/socket".
20 |
21 | // import socket from "./socket"
22 |
--------------------------------------------------------------------------------
/installer/templates/static/brunch/app.js:
--------------------------------------------------------------------------------
1 | // Brunch automatically concatenates all files in your
2 | // watched paths. Those paths can be configured at
3 | // config.paths.watched in "brunch-config.js".
4 | //
5 | // However, those files will only be executed if
6 | // explicitly imported. The only exception are files
7 | // in vendor, which are never wrapped in imports and
8 | // therefore are always executed.
9 |
10 | // Import dependencies
11 | //
12 | // If you no longer want to use a dependency, remember
13 | // to also remove its path from "config.paths.watched".
14 | <%= if html do %>import "phoenix_html"<% end %>
15 |
16 | // Import local files
17 | //
18 | // Local files can be imported directly using relative
19 | // paths "./socket" or full ones "web/static/js/socket".
20 |
21 | // import socket from "./socket"
22 |
--------------------------------------------------------------------------------
/installer/templates/new/web/router.ex:
--------------------------------------------------------------------------------
1 | defmodule <%= app_module %>.Router do
2 | use <%= app_module %>.Web, :router<%= if html do %>
3 |
4 | pipeline :browser do
5 | plug :accepts, ["html"]
6 | plug :fetch_session
7 | plug :fetch_flash
8 | plug :protect_from_forgery
9 | plug :put_secure_browser_headers
10 | end<% end %>
11 |
12 | pipeline :api do
13 | plug :accepts, ["json"]
14 | end<%= if html do %>
15 |
16 | scope "/", <%= app_module %> do
17 | pipe_through :browser # Use the default browser stack
18 |
19 | get "/", PageController, :index
20 | end
21 |
22 | # Other scopes may use custom stacks.
23 | # scope "/api", <%= app_module %> do
24 | # pipe_through :api
25 | # end<% else %>
26 |
27 | scope "/api", <%= app_module %> do
28 | pipe_through :api
29 | end<% end %>
30 | end
31 |
--------------------------------------------------------------------------------
/installer/templates/phx_web/router.ex:
--------------------------------------------------------------------------------
1 | defmodule <%= web_namespace %>.Router do
2 | use <%= web_namespace %>, :router<%= if html do %>
3 |
4 | pipeline :browser do
5 | plug :accepts, ["html"]
6 | plug :fetch_session
7 | plug :fetch_flash
8 | plug :protect_from_forgery
9 | plug :put_secure_browser_headers
10 | end<% end %>
11 |
12 | pipeline :api do
13 | plug :accepts, ["json"]
14 | end<%= if html do %>
15 |
16 | scope "/", <%= web_namespace %> do
17 | pipe_through :browser # Use the default browser stack
18 |
19 | get "/", PageController, :index
20 | end
21 |
22 | # Other scopes may use custom stacks.
23 | # scope "/api", <%= web_namespace %> do
24 | # pipe_through :api
25 | # end<% else %>
26 |
27 | scope "/api", <%= web_namespace %> do
28 | pipe_through :api
29 | end<% end %>
30 | end
31 |
--------------------------------------------------------------------------------
/installer/templates/new/web/gettext.ex:
--------------------------------------------------------------------------------
1 | defmodule <%= app_module %>.Gettext do
2 | @moduledoc """
3 | A module providing Internationalization with a gettext-based API.
4 |
5 | By using [Gettext](https://hexdocs.pm/gettext),
6 | your module gains a set of macros for translations, for example:
7 |
8 | import <%= app_module %>.Gettext
9 |
10 | # Simple translation
11 | gettext "Here is the string to translate"
12 |
13 | # Plural translation
14 | ngettext "Here is the string to translate",
15 | "Here are the strings to translate",
16 | 3
17 |
18 | # Domain-based translation
19 | dgettext "errors", "Here is the error message to translate"
20 |
21 | See the [Gettext Docs](https://hexdocs.pm/gettext) for detailed usage.
22 | """
23 | use Gettext, otp_app: :<%= app_name %>
24 | end
25 |
--------------------------------------------------------------------------------
/installer/templates/phx_umbrella/apps/app_name_web/lib/app_name/application.ex:
--------------------------------------------------------------------------------
1 | defmodule <%= web_namespace %>.Application do
2 | use Application
3 |
4 | def start(_type, _args) do
5 | import Supervisor.Spec
6 |
7 | # Define workers and child supervisors to be supervised
8 | children = [
9 | # Start the endpoint when the application starts
10 | supervisor(<%= endpoint_module %>, []),
11 | # Start your own worker by calling: <%= web_namespace %>.Worker.start_link(arg1, arg2, arg3)
12 | # worker(<%= web_namespace %>.Worker, [arg1, arg2, arg3]),
13 | ]
14 |
15 | # See http://elixir-lang.org/docs/stable/elixir/Supervisor.html
16 | # for other strategies and supported options
17 | opts = [strategy: :one_for_one, name: <%= web_namespace %>.Supervisor]
18 | Supervisor.start_link(children, opts)
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/installer/templates/phx_gettext/gettext.ex:
--------------------------------------------------------------------------------
1 | defmodule <%= web_namespace %>.Gettext do
2 | @moduledoc """
3 | A module providing Internationalization with a gettext-based API.
4 |
5 | By using [Gettext](https://hexdocs.pm/gettext),
6 | your module gains a set of macros for translations, for example:
7 |
8 | import <%= web_namespace %>.Gettext
9 |
10 | # Simple translation
11 | gettext "Here is the string to translate"
12 |
13 | # Plural translation
14 | ngettext "Here is the string to translate",
15 | "Here are the strings to translate",
16 | 3
17 |
18 | # Domain-based translation
19 | dgettext "errors", "Here is the error message to translate"
20 |
21 | See the [Gettext Docs](https://hexdocs.pm/gettext) for detailed usage.
22 | """
23 | use Gettext, otp_app: :<%= web_app_name %>
24 | end
25 |
--------------------------------------------------------------------------------
/installer/templates/phx_umbrella/config/config.exs:
--------------------------------------------------------------------------------
1 | # This file is responsible for configuring your application
2 | # and its dependencies with the aid of the Mix.Config module.
3 | use Mix.Config
4 |
5 | # By default, the umbrella project as well as each child
6 | # application will require this configuration file, ensuring
7 | # they all use the same configuration. While one could
8 | # configure all applications here, we prefer to delegate
9 | # back to each application for organization purposes.
10 | import_config "../apps/*/config/config.exs"
11 |
12 | # Configures Elixir's Logger
13 | config :logger, :console,
14 | format: "$time $metadata[$level] $message\n",
15 | metadata: [:request_id]
16 |
17 | # Import environment specific config. This must remain at the bottom
18 | # of this file so it overrides the configuration defined above.
19 | import_config "#{Mix.env}.exs"
20 |
--------------------------------------------------------------------------------
/test/phoenix/transports/websocket_serializer_test.exs:
--------------------------------------------------------------------------------
1 | defmodule Phoenix.Tranports.WebSocketSerializerTest do
2 | use ExUnit.Case, async: true
3 |
4 | alias Phoenix.Transports.WebSocketSerializer
5 | alias Phoenix.Socket.Message
6 |
7 | @msg_json [123, [[34, ["topic"], 34], 58, [34, ["t"], 34], 44, [34, ["ref"], 34], 58, "null", 44, [34, ["payload"], 34], 58, [34, ["m"], 34], 44, [34, ["event"], 34], 58, [34, ["e"], 34]], 125]
8 |
9 | test "encode!/1 encodes `Phoenix.Socket.Message` as JSON" do
10 | msg = %Message{topic: "t", event: "e", payload: "m"}
11 | assert WebSocketSerializer.encode!(msg) == {:socket_push, :text, @msg_json}
12 | end
13 |
14 | test "decode!/2 decodes `Phoenix.Socket.Message` from JSON" do
15 | assert %Message{topic: "t", event: "e", payload: "m"} ==
16 | WebSocketSerializer.decode!(@msg_json, opcode: :text)
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/priv/templates/phx.gen.schema/migration.exs:
--------------------------------------------------------------------------------
1 | defmodule <%= inspect schema.repo %>.Migrations.Create<%= inspect schema.module %> do
2 | use Ecto.Migration
3 |
4 | def change do
5 | create table(:<%= schema.table %><%= if schema.binary_id do %>, primary_key: false<% end %>) do
6 | <%= if schema.binary_id do %> add :id, :binary_id, primary_key: true
7 | <% end %><%= for {k, v} <- schema.attrs do %> add <%= inspect k %>, <%= inspect v %><%= schema.migration_defaults[k] %>
8 | <% end %><%= for {_, i, _, s} <- schema.assocs do %> add <%= if(String.ends_with?(inspect(i), "_id"), do: inspect(i), else: inspect(i) <> "_id") %>, references(<%= inspect(s) %>, on_delete: :nothing<%= if schema.binary_id do %>, type: :binary_id<% end %>)
9 | <% end %>
10 | timestamps()
11 | end
12 | <%= for index <- schema.indexes do %>
13 | <%= index %><% end %>
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/installer/templates/phx_umbrella/apps/app_name_web/README.md:
--------------------------------------------------------------------------------
1 | # <%= web_namespace %>
2 |
3 | To start your Phoenix server:
4 |
5 | * Install dependencies with `mix deps.get`
6 | * Create and migrate your database with `mix ecto.create && mix ecto.migrate`
7 | * Install Node.js dependencies with `cd assets && npm install`
8 | * Start Phoenix endpoint with `mix phx.server`
9 |
10 | Now you can visit [`localhost:4000`](http://localhost:4000) from your browser.
11 |
12 | Ready to run in production? Please [check our deployment guides](http://www.phoenixframework.org/docs/deployment).
13 |
14 | ## Learn more
15 |
16 | * Official website: http://www.phoenixframework.org/
17 | * Guides: http://phoenixframework.org/docs/overview
18 | * Docs: https://hexdocs.pm/phoenix
19 | * Mailing list: http://groups.google.com/group/phoenix-talk
20 | * Source: https://github.com/phoenixframework/phoenix
21 |
--------------------------------------------------------------------------------
/installer/templates/new/README.md:
--------------------------------------------------------------------------------
1 | # <%= app_module %>
2 |
3 | To start your Phoenix app:
4 |
5 | * Install dependencies with `mix deps.get`<%= if ecto do %>
6 | * Create and migrate your database with `mix ecto.create && mix ecto.migrate`<% end %><%= if brunch do %>
7 | * Install Node.js dependencies with `npm install`<% end %>
8 | * Start Phoenix endpoint with `mix phoenix.server`
9 |
10 | Now you can visit [`localhost:4000`](http://localhost:4000) from your browser.
11 |
12 | Ready to run in production? Please [check our deployment guides](http://www.phoenixframework.org/docs/deployment).
13 |
14 | ## Learn more
15 |
16 | * Official website: http://www.phoenixframework.org/
17 | * Guides: http://phoenixframework.org/docs/overview
18 | * Docs: https://hexdocs.pm/phoenix
19 | * Mailing list: http://groups.google.com/group/phoenix-talk
20 | * Source: https://github.com/phoenixframework/phoenix
21 |
--------------------------------------------------------------------------------
/priv/templates/phoenix.gen.model/model.ex:
--------------------------------------------------------------------------------
1 | defmodule <%= module %> do
2 | use <%= base %>.Web, :model
3 |
4 | schema <%= inspect plural %> do
5 | <%= for {k, _} <- attrs do %> field <%= inspect k %>, <%= inspect types[k] %><%= schema_defaults[k] %>
6 | <% end %><%= for {k, _, m, _} <- assocs do %> belongs_to <%= inspect k %>, <%= m %><%= if(String.ends_with?(inspect(k), "_id"), do: "", else: ", foreign_key: " <> inspect(k) <> "_id") %>
7 | <% end %>
8 | timestamps()
9 | end
10 |
11 | @doc """
12 | Builds a changeset based on the `struct` and `params`.
13 | """
14 | def changeset(struct, params \\ %{}) do
15 | struct
16 | |> cast(params, [<%= Enum.map_join(attrs, ", ", &inspect(elem(&1, 0))) %>])
17 | |> validate_required([<%= Enum.map_join(attrs, ", ", &inspect(elem(&1, 0))) %>])
18 | <%= for k <- uniques do %> |> unique_constraint(<%= inspect k %>)
19 | <% end %> end
20 | end
21 |
--------------------------------------------------------------------------------
/lib/phoenix/template/eex_engine.ex:
--------------------------------------------------------------------------------
1 | defmodule Phoenix.Template.EExEngine do
2 | @moduledoc """
3 | The Phoenix engine that handles the `.eex` extension.
4 | """
5 |
6 | @behaviour Phoenix.Template.Engine
7 |
8 | def compile(path, name) do
9 | EEx.compile_file(path, engine: engine_for(name), line: 1, trim: true)
10 | end
11 |
12 | defp engine_for(name) do
13 | case Phoenix.Template.format_encoder(name) do
14 | Phoenix.Template.HTML ->
15 | unless Code.ensure_loaded?(Phoenix.HTML.Engine) do
16 | raise "Could not load Phoenix.HTML.Engine to use with .html.eex templates. " <>
17 | "You can configure your own format encoder for HTML but we recommend " <>
18 | "adding phoenix_html as a dependency as it provides XSS protection."
19 | end
20 | Phoenix.HTML.Engine
21 | _ ->
22 | EEx.SmartEngine
23 | end
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/installer/templates/phx_single/README.md:
--------------------------------------------------------------------------------
1 | # <%= app_module %>
2 |
3 | To start your Phoenix server:
4 |
5 | * Install dependencies with `mix deps.get`<%= if ecto do %>
6 | * Create and migrate your database with `mix ecto.create && mix ecto.migrate`<% end %><%= if brunch do %>
7 | * Install Node.js dependencies with `cd assets && npm install`<% end %>
8 | * Start Phoenix endpoint with `mix phx.server`
9 |
10 | Now you can visit [`localhost:4000`](http://localhost:4000) from your browser.
11 |
12 | Ready to run in production? Please [check our deployment guides](http://www.phoenixframework.org/docs/deployment).
13 |
14 | ## Learn more
15 |
16 | * Official website: http://www.phoenixframework.org/
17 | * Guides: http://phoenixframework.org/docs/overview
18 | * Docs: https://hexdocs.pm/phoenix
19 | * Mailing list: http://groups.google.com/group/phoenix-talk
20 | * Source: https://github.com/phoenixframework/phoenix
21 |
--------------------------------------------------------------------------------
/priv/templates/phx.gen.channel/channel.ex:
--------------------------------------------------------------------------------
1 | defmodule <%= module %>Channel do
2 | use <%= web_module %>, :channel
3 |
4 | def join("<%= singular %>:lobby", payload, socket) do
5 | if authorized?(payload) do
6 | {:ok, socket}
7 | else
8 | {:error, %{reason: "unauthorized"}}
9 | end
10 | end
11 |
12 | # Channels can be used in a request/response fashion
13 | # by sending replies to requests from the client
14 | def handle_in("ping", payload, socket) do
15 | {:reply, {:ok, payload}, socket}
16 | end
17 |
18 | # It is also common to receive messages from the client and
19 | # broadcast to everyone in the current topic (<%= singular %>:lobby).
20 | def handle_in("shout", payload, socket) do
21 | broadcast socket, "shout", payload
22 | {:noreply, socket}
23 | end
24 |
25 | # Add authorization logic here as required.
26 | defp authorized?(_payload) do
27 | true
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/priv/templates/phoenix.gen.channel/channel.ex:
--------------------------------------------------------------------------------
1 | defmodule <%= module %>Channel do
2 | use <%= base %>.Web, :channel
3 |
4 | def join("<%= singular %>:lobby", payload, socket) do
5 | if authorized?(payload) do
6 | {:ok, socket}
7 | else
8 | {:error, %{reason: "unauthorized"}}
9 | end
10 | end
11 |
12 | # Channels can be used in a request/response fashion
13 | # by sending replies to requests from the client
14 | def handle_in("ping", payload, socket) do
15 | {:reply, {:ok, payload}, socket}
16 | end
17 |
18 | # It is also common to receive messages from the client and
19 | # broadcast to everyone in the current topic (<%= singular %>:lobby).
20 | def handle_in("shout", payload, socket) do
21 | broadcast socket, "shout", payload
22 | {:noreply, socket}
23 | end
24 |
25 | # Add authorization logic here as required.
26 | defp authorized?(_payload) do
27 | true
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/installer/templates/new/web/views/error_view.ex:
--------------------------------------------------------------------------------
1 | defmodule <%= app_module %>.ErrorView do
2 | use <%= app_module %>.Web, :view
3 |
4 | <%= if html do %>def render("404.html", _assigns) do
5 | "Page not found"
6 | end
7 |
8 | def render("500.html", _assigns) do
9 | "Internal server error"
10 | end
11 |
12 | # In case no render clause matches or no
13 | # template is found, let's render it as 500
14 | def template_not_found(_template, assigns) do
15 | render "500.html", assigns
16 | end<% else %>def render("404.json", _assigns) do
17 | %{errors: %{detail: "Page not found"}}
18 | end
19 |
20 | def render("500.json", _assigns) do
21 | %{errors: %{detail: "Internal server error"}}
22 | end
23 |
24 | # In case no render clause matches or no
25 | # template is found, let's render it as 500
26 | def template_not_found(_template, assigns) do
27 | render "500.json", assigns
28 | end<% end %>
29 | end
30 |
--------------------------------------------------------------------------------
/installer/templates/phx_web/views/error_view.ex:
--------------------------------------------------------------------------------
1 | defmodule <%= web_namespace %>.ErrorView do
2 | use <%= web_namespace %>, :view
3 |
4 | <%= if html do %>def render("404.html", _assigns) do
5 | "Page not found"
6 | end
7 |
8 | def render("500.html", _assigns) do
9 | "Internal server error"
10 | end
11 |
12 | # In case no render clause matches or no
13 | # template is found, let's render it as 500
14 | def template_not_found(_template, assigns) do
15 | render "500.html", assigns
16 | end<% else %>def render("404.json", _assigns) do
17 | %{errors: %{detail: "Page not found"}}
18 | end
19 |
20 | def render("500.json", _assigns) do
21 | %{errors: %{detail: "Internal server error"}}
22 | end
23 |
24 | # In case no render clause matches or no
25 | # template is found, let's render it as 500
26 | def template_not_found(_template, assigns) do
27 | render "500.json", assigns
28 | end<% end %>
29 | end
30 |
--------------------------------------------------------------------------------
/lib/mix/tasks/phoenix.routes.ex:
--------------------------------------------------------------------------------
1 | defmodule Mix.Tasks.Phoenix.Routes do
2 | use Mix.Task
3 |
4 | @moduledoc """
5 | Prints all routes for the default or a given router.
6 |
7 | $ mix phoenix.routes
8 | $ mix phoenix.routes MyApp.AnotherRouter
9 |
10 | The default router is inflected from the application
11 | name unless a configuration named `:namespace`
12 | is set inside your application configuration. For example,
13 | the configuration:
14 |
15 | config :my_app,
16 | namespace: My.App
17 |
18 | will exhibit the routes for `My.App.Router` when this
19 | task is invoked without arguments.
20 |
21 | Umbrella projects do not have a default router and
22 | therefore always expect a router to be given.
23 | """
24 |
25 | def run(args, base \\ Mix.Phoenix.base()) do
26 | IO.puts :stderr, "mix phoenix.router is deprecated. Use phx.router instead."
27 | Mix.Tasks.Phx.Routes.run(args, base)
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/test/fixtures/digest/priv/static/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "MyPhoenixApp",
3 | "short_name": "MyPhoenixApp",
4 | "start_url": ".",
5 | "display": "standalone",
6 | "background_color": "#F67938",
7 | "description": "A simple Phoenix app.",
8 | "icons": [{
9 | "src": "images/touch/homescreen48.png",
10 | "sizes": "48x48",
11 | "type": "image/png"
12 | }, {
13 | "src": "images/touch/homescreen72.png",
14 | "sizes": "72x72",
15 | "type": "image/png"
16 | }, {
17 | "src": "images/touch/homescreen96.png",
18 | "sizes": "96x96",
19 | "type": "image/png"
20 | }, {
21 | "src": "images/touch/homescreen144.png",
22 | "sizes": "144x144",
23 | "type": "image/png"
24 | }, {
25 | "src": "images/touch/homescreen168.png",
26 | "sizes": "168x168",
27 | "type": "image/png"
28 | }, {
29 | "src": "images/touch/homescreen192.png",
30 | "sizes": "192x192",
31 | "type": "image/png"
32 | }]
33 | }
34 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "phoenix",
3 | "version": "1.3.0-rc.1",
4 | "description": "The official JavaScript client for the Phoenix web framework.",
5 | "license": "MIT",
6 | "main": "./priv/static/phoenix.js",
7 | "repository": {
8 | "type": "git",
9 | "url": "git://github.com/phoenixframework/phoenix.git"
10 | },
11 | "author": "Chris McCord (http://www.phoenixframework.org)",
12 | "devDependencies": {
13 | "babel-brunch": "~6.0.0",
14 | "brunch": "~2.6.5",
15 | "jsdom": "9.8.3",
16 | "jsdom-global": "2.1.0",
17 | "mocha": "~2.4.4",
18 | "mock-socket": "^6.0.1",
19 | "sinon": "^1.17.6",
20 | "uglify-js-brunch": "~2.0.1"
21 | },
22 | "files": ["README.md", "LICENSE.md", "package.json", "priv/static/phoenix.js", "assets/js/phoenix.js"],
23 | "scripts": {
24 | "test": "./node_modules/.bin/mocha ./assets/test/**/*.js --compilers js:babel-register -r jsdom-global/register"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/priv/templates/phoenix.gen.channel/channel_test.exs:
--------------------------------------------------------------------------------
1 | defmodule <%= module %>ChannelTest do
2 | use <%= base %>.ChannelCase
3 |
4 | alias <%= module %>Channel
5 |
6 | setup do
7 | {:ok, _, socket} =
8 | socket("user_id", %{some: :assign})
9 | |> subscribe_and_join(<%= scoped %>Channel, "<%= singular %>:lobby")
10 |
11 | {:ok, socket: socket}
12 | end
13 |
14 | test "ping replies with status ok", %{socket: socket} do
15 | ref = push socket, "ping", %{"hello" => "there"}
16 | assert_reply ref, :ok, %{"hello" => "there"}
17 | end
18 |
19 | test "shout broadcasts to <%= singular %>:lobby", %{socket: socket} do
20 | push socket, "shout", %{"hello" => "all"}
21 | assert_broadcast "shout", %{"hello" => "all"}
22 | end
23 |
24 | test "broadcasts are pushed to the client", %{socket: socket} do
25 | broadcast_from! socket, "broadcast", %{"some" => "data"}
26 | assert_push "broadcast", %{"some" => "data"}
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/priv/templates/phx.gen.channel/channel_test.exs:
--------------------------------------------------------------------------------
1 | defmodule <%= module %>ChannelTest do
2 | use <%= web_module %>.ChannelCase
3 |
4 | alias <%= module %>Channel
5 |
6 | setup do
7 | {:ok, _, socket} =
8 | socket("user_id", %{some: :assign})
9 | |> subscribe_and_join(<%= alias %>Channel, "<%= singular %>:lobby")
10 |
11 | {:ok, socket: socket}
12 | end
13 |
14 | test "ping replies with status ok", %{socket: socket} do
15 | ref = push socket, "ping", %{"hello" => "there"}
16 | assert_reply ref, :ok, %{"hello" => "there"}
17 | end
18 |
19 | test "shout broadcasts to <%= singular %>:lobby", %{socket: socket} do
20 | push socket, "shout", %{"hello" => "all"}
21 | assert_broadcast "shout", %{"hello" => "all"}
22 | end
23 |
24 | test "broadcasts are pushed to the client", %{socket: socket} do
25 | broadcast_from! socket, "broadcast", %{"some" => "data"}
26 | assert_push "broadcast", %{"some" => "data"}
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/lib/mix/tasks/phx.server.ex:
--------------------------------------------------------------------------------
1 | defmodule Mix.Tasks.Phx.Server do
2 | use Mix.Task
3 |
4 | @shortdoc "Starts applications and their servers"
5 |
6 | @moduledoc """
7 | Starts the application by configuring all endpoints servers to run.
8 |
9 | ## Command line options
10 |
11 | This task accepts the same command-line arguments as `run`.
12 | For additional information, refer to the documentation for
13 | `Mix.Tasks.Run`.
14 |
15 | For example, to run `phx.server` without checking dependencies:
16 |
17 | mix phx.server --no-deps-check
18 |
19 | The `--no-halt` flag is automatically added.
20 | """
21 | def run(args) do
22 | Application.put_env(:phoenix, :serve_endpoints, true, persistent: true)
23 | Mix.Tasks.Run.run run_args() ++ args
24 | end
25 |
26 | defp run_args do
27 | if iex_running?(), do: [], else: ["--no-halt"]
28 | end
29 |
30 | defp iex_running? do
31 | Code.ensure_loaded?(IEx) and IEx.started?
32 | end
33 | end
34 |
--------------------------------------------------------------------------------
/test/test_helper.exs:
--------------------------------------------------------------------------------
1 | Code.require_file("support/router_helper.exs", __DIR__)
2 |
3 | # Starts web server applications
4 | Application.ensure_all_started(:cowboy)
5 |
6 | # TODO v1.4: Remove this since Elixir v1.3 will no longer be supported
7 | if Version.match?(System.version, "~> 1.3.0") do
8 | ExUnit.configure exclude: [:phoenix_new, :phx_new]
9 | end
10 |
11 | # Used whenever a router fails. We default to simply
12 | # rendering a short string.
13 | defmodule Phoenix.ErrorView do
14 | def render("404.json", %{kind: kind, reason: _reason, stack: _stack, conn: conn}) do
15 | %{error: "Got 404 from #{kind} with #{conn.method}"}
16 | end
17 |
18 | def render(template, %{conn: conn}) do
19 | unless conn.private.phoenix_endpoint do
20 | raise "no endpoint in error view"
21 | end
22 | "#{template} from Phoenix.ErrorView"
23 | end
24 | end
25 |
26 | # For mix tests
27 | Mix.shell(Mix.Shell.Process)
28 |
29 | ExUnit.start(assert_receive_timeout: 200)
30 |
--------------------------------------------------------------------------------
/priv/templates/phx.gen.json/view.ex:
--------------------------------------------------------------------------------
1 | defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>View do
2 | use <%= inspect context.web_module %>, :view
3 | alias <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>View
4 |
5 | def render("index.json", %{<%= schema.plural %>: <%= schema.plural %>}) do
6 | %{data: render_many(<%= schema.plural %>, <%= inspect schema.alias %>View, "<%= schema.singular %>.json")}
7 | end
8 |
9 | def render("show.json", %{<%= schema.singular %>: <%= schema.singular %>}) do
10 | %{data: render_one(<%= schema.singular %>, <%= inspect schema.alias %>View, "<%= schema.singular %>.json")}
11 | end
12 |
13 | def render("<%= schema.singular %>.json", %{<%= schema.singular %>: <%= schema.singular %>}) do
14 | %{id: <%= schema.singular %>.id<%= for {k, _} <- schema.attrs do %>,
15 | <%= k %>: <%= schema.singular %>.<%= k %><% end %>}
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/installer/templates/phx_single/lib/app_name/application.ex:
--------------------------------------------------------------------------------
1 | defmodule <%= app_module %>.Application do
2 | use Application
3 |
4 | # See http://elixir-lang.org/docs/stable/elixir/Application.html
5 | # for more information on OTP Applications
6 | def start(_type, _args) do
7 | import Supervisor.Spec
8 |
9 | # Define workers and child supervisors to be supervised
10 | children = [<%= if ecto do %>
11 | # Start the Ecto repository
12 | supervisor(<%= app_module %>.Repo, []),<% end %>
13 | # Start the endpoint when the application starts
14 | supervisor(<%= endpoint_module %>, []),
15 | # Start your own worker by calling: <%= app_module %>.Worker.start_link(arg1, arg2, arg3)
16 | # worker(<%= app_module %>.Worker, [arg1, arg2, arg3]),
17 | ]
18 |
19 | # See http://elixir-lang.org/docs/stable/elixir/Supervisor.html
20 | # for other strategies and supported options
21 | opts = [strategy: :one_for_one, name: <%= app_module %>.Supervisor]
22 | Supervisor.start_link(children, opts)
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/priv/templates/phx.gen.schema/schema.ex:
--------------------------------------------------------------------------------
1 | defmodule <%= inspect schema.module %> do
2 | use Ecto.Schema
3 | import Ecto.Changeset
4 | alias <%= inspect schema.module %>
5 |
6 | <%= if schema.binary_id do %>
7 | @primary_key {:id, :binary_id, autogenerate: true}
8 | @foreign_key_type :binary_id<% end %>
9 | schema <%= inspect schema.table %> do
10 | <%= for {k, v} <- schema.types do %> field <%= inspect k %>, <%= inspect v %><%= schema.defaults[k] %>
11 | <% end %><%= for {_, k, _, _} <- schema.assocs do %> field <%= inspect k %>, <%= if schema.binary_id do %>:binary_id<% else %>:id<% end %>
12 | <% end %>
13 | timestamps()
14 | end
15 |
16 | @doc false
17 | def changeset(%<%= inspect schema.alias %>{} = <%= schema.singular %>, attrs) do
18 | <%= schema.singular %>
19 | |> cast(attrs, [<%= Enum.map_join(schema.attrs, ", ", &inspect(elem(&1, 0))) %>])
20 | |> validate_required([<%= Enum.map_join(schema.attrs, ", ", &inspect(elem(&1, 0))) %>])
21 | <%= for k <- schema.uniques do %> |> unique_constraint(<%= inspect k %>)
22 | <% end %> end
23 | end
24 |
--------------------------------------------------------------------------------
/test/mix/tasks/phx.gen.presence_test.exs:
--------------------------------------------------------------------------------
1 | Code.require_file "../../../installer/test/mix_helper.exs", __DIR__
2 |
3 | defmodule Mix.Tasks.Phx.Gen.PresenceTest do
4 | use ExUnit.Case
5 | import MixHelper
6 |
7 | setup do
8 | Mix.Task.clear()
9 | :ok
10 | end
11 |
12 | test "generates presence" do
13 | in_tmp_project "generates presence", fn ->
14 | Mix.Tasks.Phx.Gen.Presence.run(["MyPresence"])
15 |
16 | assert_file "lib/phoenix/web/channels/my_presence.ex", fn file ->
17 | assert file =~ ~S|defmodule Phoenix.Web.MyPresence do|
18 | assert file =~ ~S|use Phoenix.Presence, otp_app: :phoenix|
19 | end
20 | end
21 | end
22 |
23 | test "passing no args defaults to Presence" do
24 | in_tmp_project "generates presence", fn ->
25 | Mix.Tasks.Phx.Gen.Presence.run([])
26 |
27 | assert_file "lib/phoenix/web/channels/presence.ex", fn file ->
28 | assert file =~ ~S|defmodule Phoenix.Web.Presence do|
29 | assert file =~ ~S|use Phoenix.Presence, otp_app: :phoenix|
30 | end
31 | end
32 | end
33 | end
34 |
--------------------------------------------------------------------------------
/lib/mix/tasks/phx.gen.secret.ex:
--------------------------------------------------------------------------------
1 | defmodule Mix.Tasks.Phx.Gen.Secret do
2 | @shortdoc "Generates a secret"
3 |
4 | @moduledoc """
5 | Generates a secret and prints it to the terminal.
6 |
7 | mix phx.gen.secret [length]
8 |
9 | By default, mix phoenix.gen.secret generates a key 64 characters long.
10 |
11 | The minimum value for `length` is 32.
12 | """
13 | use Mix.Task
14 |
15 | def run([]), do: run(["64"])
16 | def run([int]), do: int |> parse!() |> random_string() |> Mix.shell.info()
17 | def run([_|_]), do: invalid_args!()
18 |
19 | defp parse!(int) do
20 | case Integer.parse(int) do
21 | {int, ""} -> int
22 | _ -> invalid_args!()
23 | end
24 | end
25 |
26 | defp random_string(length) when length > 31 do
27 | :crypto.strong_rand_bytes(length) |> Base.encode64 |> binary_part(0, length)
28 | end
29 | defp random_string(_), do: Mix.raise "The secret should be at least 32 characters long"
30 |
31 | @spec invalid_args!() :: no_return()
32 | defp invalid_args! do
33 | Mix.raise "mix phx.gen.secret expects a length as integer or no argument at all"
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/test/mix/tasks/phx.gen.secret_test.exs:
--------------------------------------------------------------------------------
1 | Code.require_file "../../../installer/test/mix_helper.exs", __DIR__
2 |
3 | defmodule Mix.Tasks.Phx.Gen.SecretTest do
4 | use ExUnit.Case
5 | import Mix.Tasks.Phx.Gen.Secret
6 |
7 | test "generates a secret" do
8 | run []
9 | assert_receive {:mix_shell, :info, [secret]} when byte_size(secret) == 64
10 | end
11 |
12 | test "generates a secret with custom length" do
13 | run ["32"]
14 | assert_receive {:mix_shell, :info, [secret]} when byte_size(secret) == 32
15 | end
16 |
17 | test "raises on invalid args" do
18 | message = "mix phx.gen.secret expects a length as integer or no argument at all"
19 | assert_raise Mix.Error, message, fn -> run ["bad"] end
20 | assert_raise Mix.Error, message, fn -> run ["32bad"] end
21 | assert_raise Mix.Error, message, fn -> run ["32", "bad"] end
22 | end
23 |
24 | test "raises when length is too short" do
25 | message = "The secret should be at least 32 characters long"
26 | assert_raise Mix.Error, message, fn -> run ["0"] end
27 | assert_raise Mix.Error, message, fn -> run ["31"] end
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/priv/templates/phoenix.gen.html/index.html.eex:
--------------------------------------------------------------------------------
1 |
Listing <%= template_plural %>
2 |
3 |
4 |
5 |
6 | <%= for {k, _} <- attrs do %>
<%= Phoenix.Naming.humanize(Atom.to_string(k)) %>
7 | <% end %>
8 |
9 |
10 |
11 |
12 | <%%= for <%= singular %> <- @<%= plural %> do %>
13 |
14 | <%= for {k, _} <- attrs do %>
<%%= <%= singular %>.<%= k %> %>
15 | <% end %>
16 |
17 | <%%= link "Show", to: <%= singular %>_path(@conn, :show, <%= singular %>), class: "btn btn-default btn-xs" %>
18 | <%%= link "Edit", to: <%= singular %>_path(@conn, :edit, <%= singular %>), class: "btn btn-default btn-xs" %>
19 | <%%= link "Delete", to: <%= singular %>_path(@conn, :delete, <%= singular %>), method: :delete, data: [confirm: "Are you sure?"], class: "btn btn-danger btn-xs" %>
20 |
21 |
22 | <%% end %>
23 |
24 |
25 |
26 | <%%= link "New <%= template_singular %>", to: <%= singular %>_path(@conn, :new) %>
27 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | Copyright (c) 2014 Chris McCord
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining
6 | a copy of this software and associated documentation files (the
7 | "Software"), to deal in the Software without restriction, including
8 | without limitation the rights to use, copy, modify, merge, publish,
9 | distribute, sublicense, and/or sell copies of the Software, and to
10 | permit persons to whom the Software is furnished to do so, subject to
11 | the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be
14 | included in all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/installer/templates/new/web/templates/page/index.html.eex:
--------------------------------------------------------------------------------
1 |
2 |
<%%= gettext "Welcome to %{name}", name: "Phoenix!" %>
3 |
A productive web framework that does not compromise speed and maintainability.
37 |
--------------------------------------------------------------------------------
/RELEASE.md:
--------------------------------------------------------------------------------
1 | # Release Instructions
2 |
3 | **IMPORTANT**: when building the archive, it must be done in the minimum supported Erlang and Elixir versions.
4 |
5 | 1. Check related deps for required version bumps and compatibility (`phoenix_ecto`, `phoenix_pubsub_redis`, `phoenix_html`)
6 | 2. Bump version in related files below
7 | 3. Update `phoenix_dep` in `installer/lib/phoenix_new.ex` and `installer/lib/phx_new/generator.ex` to "~> version to be released"
8 | 4. Run tests, commit, push code
9 | 5. Publish packages and docs after pruning any extraneous uncommitted files
10 | 6. Run `MIX_ENV=prod mix archive.build` and `MIX_ENV=prod mix archive.build -o phx_new.ez` inside "installer" directory to build new installers
11 | 7. Copy new installers to "phoenixframework/archives" project
12 | 8. Test installer by generating a new app, running `mix deps.get`, and compiling
13 | 9. Start -dev version in related files below
14 | 10. Update `phoenix_dep` in `installer/lib/phoenix_new.ex` back to git
15 | 11. Publish to `npm` with `npm publish`
16 |
17 | ## Files with version
18 |
19 | * `CHANGELOG`
20 | * `mix.exs`
21 | * `installer/mix.exs`
22 | * `package.json`
23 |
--------------------------------------------------------------------------------
/installer/templates/phx_test/support/channel_case.ex:
--------------------------------------------------------------------------------
1 | defmodule <%= web_namespace %>.ChannelCase do
2 | @moduledoc """
3 | This module defines the test case to be used by
4 | channel tests.
5 |
6 | Such tests rely on `Phoenix.ChannelTest` and also
7 | import other functionality to make it easier
8 | to build common datastructures and query the data layer.
9 |
10 | Finally, if the test case interacts with the database,
11 | it cannot be async. For this reason, every test runs
12 | inside a transaction which is reset at the beginning
13 | of the test unless the test case is marked as async.
14 | """
15 |
16 | use ExUnit.CaseTemplate
17 |
18 | using do
19 | quote do
20 | # Import conveniences for testing with channels
21 | use Phoenix.ChannelTest
22 |
23 | # The default endpoint for testing
24 | @endpoint <%= endpoint_module %>
25 | end
26 | end
27 |
28 | <%= if ecto do %>
29 | setup tags do
30 | <%= adapter_config[:test_setup] %>
31 | unless tags[:async] do
32 | <%= adapter_config[:test_async] %>
33 | end
34 | :ok
35 | end
36 | <% else %>
37 | setup _tags do
38 | :ok
39 | end
40 | <% end %>
41 | end
42 |
--------------------------------------------------------------------------------
/lib/mix/tasks/compile.phoenix.ex:
--------------------------------------------------------------------------------
1 | defmodule Mix.Tasks.Compile.Phoenix do
2 | use Mix.Task
3 | @recursive true
4 |
5 | @moduledoc """
6 | Compiles Phoenix source files that support code reloading.
7 | """
8 |
9 | @doc false
10 | def run(_args) do
11 | {:ok, _} = Application.ensure_all_started(:phoenix)
12 |
13 | case touch() do
14 | [] -> :noop
15 | _ -> :ok
16 | end
17 | end
18 |
19 | @doc false
20 | def touch do
21 | Mix.Phoenix.modules
22 | |> modules_for_recompilation
23 | |> modules_to_file_paths
24 | |> Stream.map(&touch_if_exists(&1))
25 | |> Stream.filter(&(&1 == :ok))
26 | |> Enum.to_list()
27 | end
28 | defp touch_if_exists(path) do
29 | :file.change_time(path, :calendar.local_time())
30 | end
31 |
32 | defp modules_for_recompilation(modules) do
33 | Stream.filter modules, fn mod ->
34 | Code.ensure_loaded?(mod) and
35 | function_exported?(mod, :__phoenix_recompile__?, 0) and
36 | mod.__phoenix_recompile__?
37 | end
38 | end
39 |
40 | defp modules_to_file_paths(modules) do
41 | Stream.map(modules, fn mod -> mod.__info__(:compile)[:source] end)
42 | end
43 | end
44 |
--------------------------------------------------------------------------------
/test/mix/tasks/phoenix.gen.presence_test.exs:
--------------------------------------------------------------------------------
1 | Code.require_file "../../../installer/test/mix_helper.exs", __DIR__
2 |
3 | defmodule Mix.Tasks.Phoenix.Gen.PresenceTest do
4 | use ExUnit.Case
5 | import MixHelper
6 | import ExUnit.CaptureIO
7 |
8 | setup do
9 | Mix.Task.clear()
10 | :ok
11 | end
12 |
13 | test "generates presence" do
14 | in_tmp "deprecated: generates presence", fn ->
15 | capture_io(:stderr, fn ->
16 | Mix.Tasks.Phoenix.Gen.Presence.run(["MyPresence"])
17 | end)
18 |
19 | assert_file "web/channels/my_presence.ex", fn file ->
20 | assert file =~ ~S|defmodule Phoenix.MyPresence do|
21 | assert file =~ ~S|use Phoenix.Presence, otp_app: :phoenix|
22 | end
23 | end
24 | end
25 |
26 | test "passing no args defaults to Presence" do
27 | in_tmp "deprecated: generates presence", fn ->
28 | capture_io(:stderr, fn ->
29 | Mix.Tasks.Phoenix.Gen.Presence.run([])
30 | end)
31 |
32 | assert_file "web/channels/presence.ex", fn file ->
33 | assert file =~ ~S|defmodule Phoenix.Presence do|
34 | assert file =~ ~S|use Phoenix.Presence, otp_app: :phoenix|
35 | end
36 | end
37 | end
38 | end
39 |
--------------------------------------------------------------------------------
/installer/lib/mix/tasks/phx.new.web.ex:
--------------------------------------------------------------------------------
1 | defmodule Mix.Tasks.Phx.New.Web do
2 | @moduledoc """
3 | Creates a new Phoenix web project within an umbrella application.
4 |
5 | It expects the name of the otp app as the first argument and
6 | for the command to be run inside your umbrella application's
7 | apps directory:
8 |
9 | $ cd my_umbrella/apps
10 | $ mix phx.new.web APP [--module MODULE] [--app APP]
11 |
12 | This task is inteded to create a bare Phoenix project without
13 | database integration, which interfaces with your greater
14 | umbrella application(s).
15 |
16 | ## Examples
17 |
18 | mix phx.new.web hello_web
19 |
20 | Is equivalent to:
21 |
22 | mix phx.new.web hello_web --module Hello.Web
23 |
24 | Supports the same options as the `phx.new` task.
25 | See `Mix.Tasks.Phx.New` for details.
26 | """
27 | use Mix.Task
28 |
29 | def run([]) do
30 | Mix.Tasks.Help.run(["phx.new.web"])
31 | end
32 | def run([path | _] = args) do
33 | unless Phx.New.Generator.in_umbrella?(path) do
34 | Mix.raise "The web task can only be run within an umbrella's apps directory"
35 | end
36 |
37 | Mix.Tasks.Phx.New.run(args, Phx.New.Web)
38 | end
39 | end
40 |
--------------------------------------------------------------------------------
/lib/mix/tasks/phoenix.digest.ex:
--------------------------------------------------------------------------------
1 | defmodule Mix.Tasks.Phoenix.Digest do
2 | use Mix.Task
3 |
4 | @recursive true
5 |
6 | @moduledoc """
7 | Digests and compress static files.
8 |
9 | mix phoenix.digest
10 | mix phoenix.digest priv/static -o /www/public
11 |
12 | The first argument is the path where the static files are located. The
13 | `-o` option indicates the path that will be used to save the digested and
14 | compressed files.
15 |
16 | If no path is given, it will use `priv/static` as the input and output path.
17 |
18 | The output folder will contain:
19 |
20 | * the original file
21 | * the file compressed with gzip
22 | * a file containing the original file name and its digest
23 | * a compressed file containing the file name and its digest
24 | * a cache manifest file
25 |
26 | Example of generated files:
27 |
28 | * app.js
29 | * app.js.gz
30 | * app-eb0a5b9302e8d32828d8a73f137cc8f0.js
31 | * app-eb0a5b9302e8d32828d8a73f137cc8f0.js.gz
32 | * cache_manifest.json
33 | """
34 |
35 | def run(args) do
36 | IO.puts :stderr, "mix phoenix.digest is deprecated. Use phx.digest instead."
37 | Mix.Tasks.Phx.Digest.run(args)
38 | end
39 | end
40 |
--------------------------------------------------------------------------------
/lib/phoenix/transports/long_poll_serializer.ex:
--------------------------------------------------------------------------------
1 | defmodule Phoenix.Transports.LongPollSerializer do
2 | @moduledoc false
3 |
4 | @behaviour Phoenix.Transports.Serializer
5 |
6 | alias Phoenix.Socket.Reply
7 | alias Phoenix.Socket.Message
8 | alias Phoenix.Socket.Broadcast
9 |
10 | @doc """
11 | Translates a `Phoenix.Socket.Broadcast` into a `Phoenix.Socket.Message`.
12 | """
13 | def fastlane!(%Broadcast{} = msg) do
14 | %Message{topic: msg.topic,
15 | event: msg.event,
16 | payload: msg.payload}
17 | end
18 |
19 | @doc """
20 | Normalizes a `Phoenix.Socket.Message` struct.
21 |
22 | Encoding is handled downstream in the LongPoll controller.
23 | """
24 | def encode!(%Reply{} = reply) do
25 | %Message{
26 | topic: reply.topic,
27 | event: "phx_reply",
28 | ref: reply.ref,
29 | payload: %{status: reply.status, response: reply.payload}
30 | }
31 | end
32 | def encode!(%Message{} = msg), do: msg
33 |
34 | @doc """
35 | Decodes JSON String into `Phoenix.Socket.Message` struct.
36 | """
37 | def decode!(message, _opts) do
38 | message
39 | |> Poison.decode!()
40 | |> Phoenix.Socket.Message.from_map!()
41 | end
42 | end
43 |
--------------------------------------------------------------------------------
/priv/templates/phx.gen.html/index.html.eex:
--------------------------------------------------------------------------------
1 |
Listing <%= schema.human_plural %>
2 |
3 |
4 |
5 |
6 | <%= for {k, _} <- schema.attrs do %>
<%= Phoenix.Naming.humanize(Atom.to_string(k)) %>
7 | <% end %>
8 |
9 |
10 |
11 |
12 | <%%= for <%= schema.singular %> <- @<%= schema.plural %> do %>
13 |
14 | <%= for {k, _} <- schema.attrs do %>
<%%= <%= schema.singular %>.<%= k %> %>
15 | <% end %>
16 |
17 | <%%= link "Show", to: <%= schema.singular %>_path(@conn, :show, <%= schema.singular %>), class: "btn btn-default btn-xs" %>
18 | <%%= link "Edit", to: <%= schema.singular %>_path(@conn, :edit, <%= schema.singular %>), class: "btn btn-default btn-xs" %>
19 | <%%= link "Delete", to: <%= schema.singular %>_path(@conn, :delete, <%= schema.singular %>), method: :delete, data: [confirm: "Are you sure?"], class: "btn btn-danger btn-xs" %>
20 |
21 |
22 | <%% end %>
23 |
24 |
25 |
26 | <%%= link "New <%= schema.human_singular %>", to: <%= schema.singular %>_path(@conn, :new) %>
27 |
--------------------------------------------------------------------------------
/installer/templates/new/config/config.exs:
--------------------------------------------------------------------------------
1 | # This file is responsible for configuring your application
2 | # and its dependencies with the aid of the Mix.Config module.
3 | #
4 | # This configuration file is loaded before any dependency and
5 | # is restricted to this project.
6 | use Mix.Config
7 |
8 | <%= if namespaced? or ecto do %># General application configuration
9 | config :<%= app_name %><%= if namespaced? do %>,
10 | namespace: <%= app_module %><% end %><%= if ecto do %>,
11 | ecto_repos: [<%= app_module %>.Repo]<% end %>
12 |
13 | <% end %># Configures the endpoint
14 | config :<%= app_name %>, <%= app_module %>.Endpoint,
15 | url: [host: "localhost"],
16 | secret_key_base: "<%= secret_key_base %>",
17 | render_errors: [view: <%= app_module %>.ErrorView, accepts: ~w(<%= if html do %>html <% end %>json)],
18 | pubsub: [name: <%= app_module %>.PubSub,
19 | adapter: Phoenix.PubSub.PG2]
20 |
21 | # Configures Elixir's Logger
22 | config :logger, :console,
23 | format: "$time $metadata[$level] $message\n",
24 | metadata: [:request_id]
25 | <%= generator_config %>
26 | # Import environment specific config. This must remain at the bottom
27 | # of this file so it overrides the configuration defined above.
28 | import_config "#{Mix.env}.exs"
29 |
--------------------------------------------------------------------------------
/installer/templates/new/lib/app_name.ex:
--------------------------------------------------------------------------------
1 | defmodule <%= app_module %> do
2 | use Application
3 |
4 | # See http://elixir-lang.org/docs/stable/elixir/Application.html
5 | # for more information on OTP Applications
6 | def start(_type, _args) do
7 | import Supervisor.Spec
8 |
9 | # Define workers and child supervisors to be supervised
10 | children = [<%= if ecto do %>
11 | # Start the Ecto repository
12 | supervisor(<%= app_module %>.Repo, []),<% end %>
13 | # Start the endpoint when the application starts
14 | supervisor(<%= app_module %>.Endpoint, []),
15 | # Start your own worker by calling: <%= app_module %>.Worker.start_link(arg1, arg2, arg3)
16 | # worker(<%= app_module %>.Worker, [arg1, arg2, arg3]),
17 | ]
18 |
19 | # See http://elixir-lang.org/docs/stable/elixir/Supervisor.html
20 | # for other strategies and supported options
21 | opts = [strategy: :one_for_one, name: <%= app_module %>.Supervisor]
22 | Supervisor.start_link(children, opts)
23 | end
24 |
25 | # Tell Phoenix to update the endpoint configuration
26 | # whenever the application is updated.
27 | def config_change(changed, _new, removed) do
28 | <%= app_module %>.Endpoint.config_change(changed, removed)
29 | :ok
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/installer/templates/new/test/support/channel_case.ex:
--------------------------------------------------------------------------------
1 | defmodule <%= app_module %>.ChannelCase do
2 | @moduledoc """
3 | This module defines the test case to be used by
4 | channel tests.
5 |
6 | Such tests rely on `Phoenix.ChannelTest` and also
7 | import other functionality to make it easier
8 | to build and query models.
9 |
10 | Finally, if the test case interacts with the database,
11 | it cannot be async. For this reason, every test runs
12 | inside a transaction which is reset at the beginning
13 | of the test unless the test case is marked as async.
14 | """
15 |
16 | use ExUnit.CaseTemplate
17 |
18 | using do
19 | quote do
20 | # Import conveniences for testing with channels
21 | use Phoenix.ChannelTest
22 | <%= if ecto do %>
23 | alias <%= app_module %>.Repo
24 | import Ecto
25 | import Ecto.Changeset
26 | import Ecto.Query
27 | <% end %>
28 |
29 | # The default endpoint for testing
30 | @endpoint <%= app_module %>.Endpoint
31 | end
32 | end
33 |
34 | setup tags do
35 | <%= if ecto do %> <%= adapter_config[:test_setup] %>
36 |
37 | unless tags[:async] do
38 | <%= adapter_config[:test_async] %>
39 | end
40 | <% else %>
41 | _ = tags
42 | <% end %>
43 | :ok
44 | end
45 | end
46 |
--------------------------------------------------------------------------------
/test/support/router_helper.exs:
--------------------------------------------------------------------------------
1 | defmodule RouterHelper do
2 | @moduledoc """
3 | Conveniences for testing routers and controllers.
4 |
5 | Must not be used to test endpoints as it does some
6 | pre-processing (like fetching params) which could
7 | skew endpoint tests.
8 | """
9 |
10 | import Plug.Test
11 |
12 | @session Plug.Session.init(
13 | store: :cookie,
14 | key: "_app",
15 | encryption_salt: "yadayada",
16 | signing_salt: "yadayada"
17 | )
18 |
19 | defmacro __using__(_) do
20 | quote do
21 | use Plug.Test
22 | import RouterHelper
23 | end
24 | end
25 |
26 | def with_session(conn) do
27 | conn
28 | |> Map.put(:secret_key_base, String.duplicate("abcdefgh", 8))
29 | |> Plug.Session.call(@session)
30 | |> Plug.Conn.fetch_session()
31 | end
32 |
33 | def call(router, verb, path, params \\ nil, script_name \\ []) do
34 | verb
35 | |> conn(path, params)
36 | |> Plug.Conn.fetch_query_params
37 | |> Map.put(:script_name, script_name)
38 | |> router.call(router.init([]))
39 | end
40 |
41 | def action(controller, verb, action, params \\ nil) do
42 | conn = conn(verb, "/", params) |> Plug.Conn.fetch_query_params
43 | controller.call(conn, controller.init(action))
44 | end
45 | end
46 |
--------------------------------------------------------------------------------
/installer/templates/new/test/views/error_view_test.exs:
--------------------------------------------------------------------------------
1 | defmodule <%= app_module %>.ErrorViewTest do
2 | use <%= app_module %>.ConnCase, async: true
3 |
4 | # Bring render/3 and render_to_string/3 for testing custom views
5 | import Phoenix.View
6 |
7 | <%= if html do %>test "renders 404.html" do
8 | assert render_to_string(<%= app_module %>.ErrorView, "404.html", []) ==
9 | "Page not found"
10 | end
11 |
12 | test "render 500.html" do
13 | assert render_to_string(<%= app_module %>.ErrorView, "500.html", []) ==
14 | "Internal server error"
15 | end
16 |
17 | test "render any other" do
18 | assert render_to_string(<%= app_module %>.ErrorView, "505.html", []) ==
19 | "Internal server error"
20 | end<% else %>test "renders 404.json" do
21 | assert render(<%= app_module %>.ErrorView, "404.json", []) ==
22 | %{errors: %{detail: "Page not found"}}
23 | end
24 |
25 | test "render 500.json" do
26 | assert render(<%= app_module %>.ErrorView, "500.json", []) ==
27 | %{errors: %{detail: "Internal server error"}}
28 | end
29 |
30 | test "render any other" do
31 | assert render(<%= app_module %>.ErrorView, "505.json", []) ==
32 | %{errors: %{detail: "Internal server error"}}
33 | end<% end %>
34 | end
35 |
--------------------------------------------------------------------------------
/installer/templates/new/web/templates/layout/app.html.eex:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | Hello <%= app_module %>!
11 | ">
12 |
13 |
14 |
15 |