Release 2.1 with revoke_all and fixes

Release 2.1 with revoke_all and fixes

defmodule Guardian.DB.Mixfile do
  use Mix.Project

  @version "2.1.0"
  @source_url "https://github.com/ueberauth/guardian_db"

  def project do
    [
      name: "Guardian.DB",
      app: :guardian_db,
      version: @version,
      description: "DB tracking for token validity",
      elixir: "~> 1.4 or ~> 1.5",
      elixirc_paths: elixirc_paths(Mix.env()),
      package: package(),
      docs: docs(),
      build_embedded: Mix.env() == :prod,
      start_permanent: Mix.env() == :prod,
      aliases: aliases(),
      deps: deps(),
      test_coverage: [tool: ExCoveralls],
      preferred_cli_env: [
        coveralls: :test,
        "coveralls.html": :test,
        "coveralls.json": :test
      ]
    ]
  end

  def application do
    [extra_applications: [:logger]]
  end

  defp elixirc_paths(:test), do: ["lib", "test/support"]
  defp elixirc_paths(_), do: ["lib"]

  defp deps do
    [
      {:guardian, "~> 1.0 or ~> 2.0"},
      {:ecto, "~> 3.0"},
      {:ecto_sql, "~> 3.1"},
      {:postgrex, "~> 0.13", optional: true},

      # Tools
      {:dialyxir, ">= 0.0.0", only: [:dev], runtime: false},
      {:credo, ">= 0.0.0", only: [:dev, :test], runtime: false},
      {:excoveralls, ">= 0.0.0", only: [:test], runtime: false},
      {:ex_doc, ">= 0.0.0", only: [:dev], runtime: false},
      {:inch_ex, ">= 0.0.0", only: [:dev], runtime: false}
    ]
  end

  defp package do
    [
      maintainers: ["Daniel Neighman", "Sean Callan", "Sonny Scroggin"],
      licenses: ["MIT"],
      links: %{GitHub: @source_url},
      files: [
        "lib",
        "CHANGELOG.md",
        "LICENSE",
        "mix.exs",
        "README.md",
        "priv/templates"
      ]
    ]
  end

  defp docs do
    [
      main: "readme",
      homepage_url: @source_url,
      source_ref: "v#{@version}",
      source_url: @source_url,
      extras: ["README.md"]
    ]
  end

  defp aliases do
    [
      test: [
        "ecto.drop --quiet",
        "ecto.create --quiet",
        "guardian.db.gen.migration",
        "ecto.migrate",
        "test"
      ]
    ]
  end
end

defmodule Guardian.DB.Mixfile do
  use Mix.Project

  @version "2.0.3"
  @source_url "https://github.com/ueberauth/guardian_db"

  def project do
    [
      name: "Guardian.DB",
      app: :guardian_db,
      version: @version,
      description: "DB tracking for token validity",
      elixir: "~> 1.4 or ~> 1.5",
      elixirc_paths: elixirc_paths(Mix.env()),
      package: package(),
      docs: docs(),
      build_embedded: Mix.env() == :prod,
      start_permanent: Mix.env() == :prod,
      aliases: aliases(),
      deps: deps(),
      test_coverage: [tool: ExCoveralls],
      preferred_cli_env: [
        coveralls: :test,
        "coveralls.html": :test,
        "coveralls.json": :test
      ]
    ]
  end

  def application do
    [extra_applications: [:logger]]
  end

  defp elixirc_paths(:test), do: ["lib", "test/support"]
  defp elixirc_paths(_), do: ["lib"]

  defp deps do
    [
      {:guardian, "~> 1.0 or ~> 2.0"},
      {:ecto, "~> 3.0"},
      {:ecto_sql, "~> 3.1"},
      {:postgrex, "~> 0.13", optional: true},

      # Tools
      {:dialyxir, ">= 0.0.0", only: [:dev], runtime: false},
      {:credo, ">= 0.0.0", only: [:dev, :test], runtime: false},
      {:excoveralls, ">= 0.0.0", only: [:test], runtime: false},
      {:ex_doc, ">= 0.0.0", only: [:dev], runtime: false},
      {:inch_ex, ">= 0.0.0", only: [:dev], runtime: false}
    ]
  end

  defp package do
    [
      maintainers: ["Daniel Neighman", "Sean Callan", "Sonny Scroggin"],
      licenses: ["MIT"],
      links: %{GitHub: @source_url},
      files: [
        "lib",
        "CHANGELOG.md",
        "LICENSE",
        "mix.exs",
        "README.md",
        "priv/templates"
      ]
    ]
  end

  defp docs do
    [
      main: "readme",
      homepage_url: @source_url,
      source_ref: "v#{@version}",
      source_url: @source_url,
      extras: ["README.md"]
    ]
  end

  defp aliases do
    [
      test: [
        "ecto.drop --quiet",
        "ecto.create --quiet",
        "guardian.db.gen.migration",
        "ecto.migrate",
        "test"
      ]
    ]
  end
end


Release 1.4.3

Release 1.4.3


Adding hex package info

Adding hex package info

https://hex.pm/packages/spell
http://hexdocs.pm/spell/0.0.1/

Resolves #11, #13


Cleanup mix.exs

Cleanup mix.exs


Bump version to 0.4.0

Bump version to 0.4.0

defmodule Credo.Mixfile do
  use Mix.Project

  def project do
    [
      app: :credo,
      version: "0.4.0",
      elixir: "~> 1.1",
      escript: [main_module: Credo.CLI],
      build_embedded: Mix.env == :prod,
      start_permanent: Mix.env == :prod,
      deps: deps,
      test_coverage: [tool: Coverex.Task],
      name: "Credo",
      description: "A static code analysis tool for the Elixir language with a focus on code consistency and teaching.",
      package: package
    ]
  end

  defp package do
    [
      files: [".credo.exs", ".template.check.ex", "lib", "mix.exs",
              "README.md", "LICENSE"],
      maintainers: ["René Föhring"],
      licenses: ["MIT"],
      links: %{"GitHub" => "https://github.com/rrrene/credo"},
    ]
  end

  def application do
    [mod: {Credo, []}, applications: [:bunt, :logger]]
  end

  defp deps do
    [
      {:bunt, "~> 0.1.6"},
      {:inch_ex, "~> 0.4", only: [:dev, :test]},
      {:coverex, "~> 1.4.1", only: :test}
    ]
  end
end

defmodule Credo.Mixfile do
  use Mix.Project

  def project do
    [
      app: :credo,
      version: "0.4.0-beta5",
      elixir: "~> 1.1",
      escript: [main_module: Credo.CLI],
      build_embedded: Mix.env == :prod,
      start_permanent: Mix.env == :prod,
      deps: deps,
      test_coverage: [tool: Coverex.Task],
      name: "Credo",
      description: "A static code analysis tool for the Elixir language with a focus on code consistency and teaching.",
      package: package
    ]
  end

  defp package do
    [
      files: [".credo.exs", ".template.check.ex", "lib", "mix.exs",
              "README.md", "LICENSE"],
      maintainers: ["René Föhring"],
      licenses: ["MIT"],
      links: %{"GitHub" => "https://github.com/rrrene/credo"},
    ]
  end

  def application do
    [mod: {Credo, []}, applications: [:bunt, :logger]]
  end

  defp deps do
    [
      {:bunt, "~> 0.1.6"},
      {:inch_ex, "~> 0.4", only: [:dev, :test]},
      {:coverex, "~> 1.4.1", only: :test}
    ]
  end
end


add def package to mix.exs

add def package to mix.exs

defmodule PlugOffline.Mixfile do
  use Mix.Project

  def project do
    [app: :plug_offline,
     version: "0.0.1",
     elixir: "~> 1.2",
     build_embedded: Mix.env == :prod,
     start_permanent: Mix.env == :prod,
     name: "PlugOffline",
     source_url: "https://github.com/bonyiii/plug_offline",
     package: package,
     deps: deps]
  end

  # Configuration for the OTP application
  #
  # Type "mix help compile.app" for more information
  def application do
    [applications: [:logger]]
  end

  # Dependencies can be Hex packages:
  #
  #   {:mydep, "~> 0.3.0"}
  #
  # Or git/path repositories:
  #
  #   {:mydep, git: "https://github.com/elixir-lang/mydep.git", tag: "0.1.0"}
  #
  # Type "mix help deps" for more examples and options
  defp deps do
    [{:plug, "~> 1.1"}]
  end

  defp description do
    """
    This package provides cache manifest file with digest and
    file or inline assets helper for .eex templates.
    """
  end

  defp package do
    [
      maintainers: ["bonyiii"],
      licenses: ["Apache 2.0"],
      links: %{"GitHub" => "https://github.com/bonyiii/plug_offline"}
    ]
  end
end

defmodule PlugOffline.Mixfile do
  use Mix.Project

  def project do
    [app: :plug_offline,
     version: "0.0.1",
     elixir: "~> 1.0",
     build_embedded: Mix.env == :prod,
     start_permanent: Mix.env == :prod,
     deps: deps]
  end

  # Configuration for the OTP application
  #
  # Type "mix help compile.app" for more information
  def application do
    [applications: [:logger]]
  end

  # Dependencies can be Hex packages:
  #
  #   {:mydep, "~> 0.3.0"}
  #
  # Or git/path repositories:
  #
  #   {:mydep, git: "https://github.com/elixir-lang/mydep.git", tag: "0.1.0"}
  #
  # Type "mix help deps" for more examples and options
  defp deps do
    [{:plug, "~> 1.1"}]
  end
end


version 0.10.9

version 0.10.9


Bump version to 0.8.0-rc6

Bump version to 0.8.0-rc6


mix file

mix file

defmodule Expyplot.Mixfile do
  use Mix.Project

  @version "1.0.0"

  def project do
    [app: :expyplot,
     version: @version,
     elixir: "~> 1.4",
     build_embedded: Mix.env == :prod,
     start_permanent: Mix.env == :prod,
     deps: deps(),
     docs: docs(),
     package: package(),
     description: description(),
    ]
  end

  # Configuration for the OTP application
  #
  # Type "mix help compile.app" for more information
  def application do
    # Specify extra applications you'll use from Erlang/Elixir
    [extra_applications: [:logger],
     mod: {Expyplot, []},
    ]
  end

  # Dependencies can be Hex packages:
  #
  #   {:my_dep, "~> 0.3.0"}
  #
  # Or git/path repositories:
  #
  #   {:my_dep, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
  #
  # Type "mix help deps" for more examples and options
  defp deps do
    [
      {:statistics, "~> 0.4.1"},
      {:earmark, "~> 0.1"},
      {:ex_doc, "~> 0.11"},
    ]
  end

  defp docs do
    [main: "Expyplot.Plot"]
  end

  defp package do
    [
      files: ["lib", "mix.exs", "README.md", "config", "priv", "examples", "LICENSE"],
      maintainers: ["Max Strange"],
      licenses: ["MIT"],
      links: %{"GitHub" => "https://github.com/MaxStrange/expyplot"}
    ]
  end

  defp description do
    """
    Python's matplotlib.pyplot ported to Elixir. Inspired by https://github.com/JordiPolo/explot

    This library provides a fairly transparent wrapper for matplotlib.pyplot.
    """
  end
end

defmodule Expyplot.Mixfile do
  use Mix.Project

  def project do
    [app: :expyplot,
     version: "1.0.0",
     elixir: "~> 1.4",
     build_embedded: Mix.env == :prod,
     start_permanent: Mix.env == :prod,
     deps: deps(),
     docs: docs(),
    ]
  end

  # Configuration for the OTP application
  #
  # Type "mix help compile.app" for more information
  def application do
    # Specify extra applications you'll use from Erlang/Elixir
    [extra_applications: [:logger],
     mod: {Expyplot, []},
    ]
  end

  # Dependencies can be Hex packages:
  #
  #   {:my_dep, "~> 0.3.0"}
  #
  # Or git/path repositories:
  #
  #   {:my_dep, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
  #
  # Type "mix help deps" for more examples and options
  defp deps do
    [
      {:statistics, "~> 0.4.1"},
      {:earmark, "~> 0.1"},
      {:ex_doc, "~> 0.11"},
    ]
  end

  defp docs do
    [main: "Expyplot.Plot"]
  end
end


Typo and wording fixes in docs (#3093)

Typo and wording fixes in docs (#3093)

defmodule Phoenix.View do
  @moduledoc """
  Defines the view layer of a Phoenix application.

  This module is used to define the application's main view, which
  serves as the base for all other views and templates.

  The view layer also contains conveniences for rendering templates,
  including support for layouts and encoders per format.

  ## Examples

  Phoenix defines the view template at `lib/your_app_web.ex`:

      defmodule YourAppWeb do
        # ...

        def view do
          quote do
            use Phoenix.View, root: "lib/your_app_web/templates", namespace: "web"

            # Import convenience functions from controllers
            import Phoenix.Controller, only: [get_flash: 1, get_flash: 2, view_module: 1]

            # Use all HTML functionality (forms, tags, etc)
            use Phoenix.HTML

            import YourAppWeb.ErrorHelpers
            import YourAppWeb.Gettext

            # Alias the Helpers module as Routes
            alias  YourAppWeb.Router.Helpers, as: Routes
          end
        end

        # ...
      end

  You can use the definition above to define any view in your application:

      defmodule YourApp.UserView do
        use YourAppWeb, :view
      end

  Because we have defined the template root to be "lib/your_app_web/templates", `Phoenix.View`
  will automatically load all templates at "your_app_web/templates/user" and include them
  in the `YourApp.UserView`. For example, imagine we have the template:

      # your_app_web/templates/user/index.html.eex
      Hello <%= @name %>

  The `.eex` extension maps to a template engine which tells Phoenix how
  to compile the code in the file into Elixir source code. After it is
  compiled, the template can be rendered as:

      Phoenix.View.render(YourApp.UserView, "index.html", name: "John Doe")
      #=> {:safe, "Hello John Doe"}

  ## Rendering

  The main responsibility of a view is to render a template.

  A template has a name, which also contains a format. For example,
  in the previous section we have rendered the "index.html" template:

      Phoenix.View.render(YourApp.UserView, "index.html", name: "John Doe")
      #=> {:safe, "Hello John Doe"}

  When a view renders a template, the result returned is an inner
  representation specific to the template format. In the example above,
  we got: `{:safe, "Hello John Doe"}`. The safe tuple annotates that our
  template is safe and that we don't need to escape its contents because
  all data has already been encoded. Let's try to inject custom code:

      Phoenix.View.render(YourApp.UserView, "index.html", name: "John
Doe")
      #=> {:safe, "Hello John
Doe"}

  This inner representation allows us to render and compose templates easily.
  For example, if you want to render JSON data, we could do so by adding a
  "show.json" entry to `render/2` in our view:

      defmodule YourApp.UserView do
        use YourApp.View

        def render("show.json", %{user: user}) do
          %{name: user.name, address: user.address}
        end
      end

  Notice that in order to render JSON data, we don't need to explicitly
  return a JSON string! Instead, we just return data that is encodable to
  JSON.

  Both JSON and HTML formats will be encoded only when passing the data
  to the controller via the `render_to_iodata/3` function. The
  `render_to_iodata/3` function uses the notion of format encoders to convert a
  particular format to its string/iodata representation.

  Phoenix ships with some template engines and format encoders, which
  can be further configured in the Phoenix application. You can read
  more about format encoders in `Phoenix.Template` documentation.
  """
  alias Phoenix.{Template}

  @doc """
  When used, defines the current module as a main view module.

  ## Options

    * `:root` - the template root to find templates
    * `:path` - the optional path to search for templates within the `:root`.
      Defaults to the underscored view module name. A blank string may
      be provided to use the `:root` path directly as the template lookup path
    * `:namespace` - the namespace to consider when calculating view paths
    * `:pattern` - the wildcard pattern to apply to the root
      when finding templates. Default `"*"`

  The `:root` option is required while the `:namespace` defaults to the
  first nesting in the module name. For instance, both `MyApp.UserView`
  and `MyApp.Admin.UserView` have namespace `MyApp`.

  The `:namespace` and `:path` options are used to calculate template
  lookup paths. For example, if you are in `MyApp.UserView` and the
  namespace is `MyApp`, templates are expected at `Path.join(root, "user")`.
  On the other hand, if the view is `MyApp.Admin.UserView`,
  the path will be `Path.join(root, "admin/user")` and so on. For
  explicit root path locations, the `:path` option can be provided instead.
  The `:root` and `:path` are joined to form the final lookup path.
  A blank string may be provided to use the `:root` path directly as the
  template lookup path.

  Setting the namespace to `MyApp.Admin` in the second example will force
  the template to also be looked up at `Path.join(root, "user")`.
  """
  defmacro __using__(opts) do
    %{module: module} = __CALLER__

    if Module.get_attribute(module, :view_resource) do
      raise ArgumentError,
            "use Phoenix.View is being called twice in the module #{module}. " <>
              "Make sure to call it only once per module"
    else
      view_resource = String.to_atom(Phoenix.Naming.resource_name(module, "View"))
      Module.put_attribute(module, :view_resource, view_resource)
    end

    quote do
      import Phoenix.View
      use Phoenix.Template, Phoenix.View.__template_options__(__MODULE__, unquote(opts))

      @before_compile Phoenix.View
      @view_resource String.to_atom(Phoenix.Naming.resource_name(__MODULE__, "View"))

      @doc """
      Renders the given template locally.
      """
      def render(template, assigns \\ %{})

      def render(module, template) when is_atom(module) do
        Phoenix.View.render(module, template, %{})
      end

      def render(template, _assigns) when not is_binary(template) do
        raise ArgumentError, "render/2 expects template to be a string, got: #{inspect template}"
      end

      def render(template, assigns) when not is_map(assigns) do
        render(template, Enum.into(assigns, %{}))
      end

      @doc "The resource name, as an atom, for this view"
      def __resource__, do: @view_resource
    end
  end

  @anno (if :erlang.system_info(:otp_release) >= '19' do
    [generated: true]
  else
    [line: -1]
  end)

  @doc false
  defmacro __before_compile__(_env) do
    # We are using @anno because we don't want warnings coming from
    # render/2 to be reported in case the user has defined a catch-all
    # render/2 clause.
    quote @anno do
      # Catch-all clause for rendering.
      def render(template, assigns) do
        render_template(template, assigns)
      end
    end
  end

  @doc """
  Renders a template.

  It expects the view module, the template as a string, and a
  set of assigns.

  Notice that this function returns the inner representation of a
  template. If you want the encoded template as a result, use
  `render_to_iodata/3` instead.

  ## Examples

      Phoenix.View.render(YourApp.UserView, "index.html", name: "John Doe")
      #=> {:safe, "Hello John Doe"}

  ## Assigns

  Assigns are meant to be user data that will be available in templates.
  However, there are keys under assigns that are specially handled by
  Phoenix, they are:

    * `:layout` - tells Phoenix to wrap the rendered result in the
      given layout. See next section

  The following assigns are reserved, and cannot be set directly:

    * `@view_module` - The view module being rendered
    * `@view_template` - The `@view_module`'s template being rendered

  ## Layouts

  Templates can be rendered within other templates using the `:layout`
  option. `:layout` accepts a tuple of the form
  `{LayoutModule, "template.extension"}`.

  To render the template within the layout, simply call `render/3`
  using the `@view_module` and `@view_template` assigns:

      <%= render(@view_module, @view_template, assigns) %>

  """
  def render(module, template, assigns) do
    assigns
    |> to_map()
    |> Map.pop(:layout, false)
    |> render_within(module, template)
  end

  defp render_within({false, assigns}, module, template) do
    assigns = Map.merge(assigns, %{view_module: module,
                                   view_template: template})
    module.render(template, assigns)
  end

  defp render_within({layout, assigns}, inner_mod, inner_tpl) do
    assigns = Map.merge(assigns, %{view_module: inner_mod, view_template: inner_tpl})
    render_layout(layout, assigns)
  end

  defp render_layout({layout_mod, layout_tpl}, assigns)
       when is_atom(layout_mod) and is_binary(layout_tpl) do
    layout_mod.render(layout_tpl, assigns)
  end

  defp render_layout(layout, _assigns) do
    raise ArgumentError, """
    invalid value for reserved key :layout in View.render/3 assigns

    :layout accepts a tuple of the form {LayoutModule, "template.extension"}

    got: #{inspect(layout)}
    """
  end

  @doc """
  Renders a template only if it exists.

  Same as `render/3`, but returns `nil` instead of raising.
  Useful for dynamically rendering templates in the layout that may or
  may not be implemented by the `@view_module` view.

  ## Examples

  Consider the case where the application layout allows views to dynamically
  render a section of script tags in the head of the document. Some views
  may wish to inject certain scripts, while others will not.

        <%= render_existing @view_module, "scripts.html", assigns %>

  Then the module for the `@view_module` view can decide to provide scripts with
  either a precompiled template, or by implementing the function directly, ie:

      def render("scripts.html", _assigns) do
        ~E()
      end

  To use a precompiled template, create a `scripts.html.eex` file in the `templates`
  directory for the corresponding view you want it to render for. For example,
  for the `UserView`, create the `scripts.html.eex` file at `your_app_web/templates/user/`.

  ## Rendering based on controller template

  In some cases, you might need to render based on the template.
  For these cases, `@view_template` can pair with
  `render_existing/3` for per-template based content, ie:

        <%= render_existing @view_module, "scripts." <> @view_template, assigns %>

      def render("scripts.show.html", _assigns) do
        ~E()
      end
      def render("scripts.index.html", _assigns) do
        ~E()
      end

  """
  def render_existing(module, template, assigns \\ []) do
    render(module, template, put_in(assigns[:__phx_render_existing__], {module, template}))
  end

  @doc """
  Renders a collection.

  A collection is any enumerable of structs. This function
  returns the rendered collection in a list:

      render_many users, UserView, "show.html"

  is roughly equivalent to:

      Enum.map(users, fn user ->
        render(UserView, "show.html", user: user)
      end)

  The underlying user is passed to the view and template as `:user`,
  which is inferred from the view name. The name of the key
  in assigns can be customized with the `:as` option:

      render_many users, UserView, "show.html", as: :data

  is roughly equivalent to:

      Enum.map(users, fn user ->
        render(UserView, "show.html", data: user)
      end)

  """
  def render_many(collection, view, template, assigns \\ %{}) do
    assigns = to_map(assigns)
    Enum.map(collection, fn resource ->
      render view, template, assign_resource(assigns, view, resource)
    end)
  end

  @doc """
  Renders a single item if not nil.

  The following:

      render_one user, UserView, "show.html"

  is roughly equivalent to:

      if user != nil do
        render(UserView, "show.html", user: user)
      end

  The underlying user is passed to the view and template as
  `:user`, which is inflected from the view name. The name
  of the key in assigns can be customized with the `:as` option:

      render_one user, UserView, "show.html", as: :data

  is roughly equivalent to:

      if user != nil do
        render(UserView, "show.html", data: user)
      end

  """
  def render_one(resource, view, template, assigns \\ %{})
  def render_one(nil, _view, _template, _assigns), do: nil
  def render_one(resource, view, template, assigns) do
    assigns = to_map(assigns)
    render view, template, assign_resource(assigns, view, resource)
  end

  defp to_map(assigns) when is_map(assigns), do: assigns
  defp to_map(assigns) when is_list(assigns), do: :maps.from_list(assigns)

  defp assign_resource(assigns, view, resource) do
    as = Map.get(assigns, :as) || view.__resource__
    Map.put(assigns, as, resource)
  end

  @doc """
  Renders the template and returns iodata.
  """
  def render_to_iodata(module, template, assign) do
    render(module, template, assign) |> encode(template)
  end

  @doc """
  Renders the template and returns a string.
  """
  def render_to_string(module, template, assign) do
    render_to_iodata(module, template, assign) |> IO.iodata_to_binary
  end

  defp encode(content, template) do
    if encoder = Template.format_encoder(template) do
      encoder.encode_to_iodata!(content)
    else
      content
    end
  end

  @doc false
  def __template_options__(module, opts) do
    root = opts[:root] || raise(ArgumentError, "expected :root to be given as an option")
    path = opts[:path]

    namespace =
      if given = opts[:namespace] do
        given
      else
        module
        |> Module.split()
        |> Enum.take(1)
        |> Module.concat()
      end

    root_path = Path.join(root, path || Template.module_to_template_root(module, namespace, "View"))
    [root: root_path] ++ Keyword.take(opts, [:pattern, :template_engines])
  end
end

defmodule Phoenix.View do
  @moduledoc """
  Defines the view layer of a Phoenix application.

  This module is used to define the application's main view, which
  serves as the base for all other views and templates.

  The view layer also contains conveniences for rendering templates,
  including support for layouts and encoders per format.

  ## Examples

  Phoenix defines the view template at `lib/your_app_web.ex`:

      defmodule YourAppWeb do
        # ...

        def view do
          quote do
            use Phoenix.View, root: "lib/your_app_web/templates", namespace: "web"

            # Import convenience functions from controllers
            import Phoenix.Controller, only: [get_flash: 1, get_flash: 2, view_module: 1]

            # Use all HTML functionality (forms, tags, etc)
            use Phoenix.HTML

            import YourAppWeb.ErrorHelpers
            import YourAppWeb.Gettext

            # Alias the Helpers module as Routes
            alias  YourAppWeb.Router.Helpers, as: Routes
          end
        end

        # ...
      end

  We can use the definition above to define any view in your application:

      defmodule YourApp.UserView do
        use YourAppWeb, :view
      end

  Because we have defined the template root to be "lib/your_app_web/templates", `Phoenix.View`
  will automatically load all templates at "your_app_web/templates/user" and include them
  in the `YourApp.UserView`. For example, imagine we have the template:

      # your_app_web/templates/user/index.html.eex
      Hello <%= @name %>

  The `.eex` extension maps to a template engine which tells Phoenix how
  to compile the code in the file into Elixir source code. After it is
  compiled, the template can be rendered as:

      Phoenix.View.render(YourApp.UserView, "index.html", name: "John Doe")
      #=> {:safe, "Hello John Doe"}

  ## Rendering

  The main responsibility of a view is to render a template.

  A template has a name, which also contains a format. For example,
  in the previous section we have rendered the "index.html" template:

      Phoenix.View.render(YourApp.UserView, "index.html", name: "John Doe")
      #=> {:safe, "Hello John Doe"}

  When a view renders a template, the result returned is an inner
  representation specific to the template format. In the example above,
  we got: `{:safe, "Hello John Doe"}`. The safe tuple annotates that our
  template is safe and that we don't need to escape its contents because
  all data has already been encoded. Let's try to inject custom code:

      Phoenix.View.render(YourApp.UserView, "index.html", name: "John
Doe")
      #=> {:safe, "Hello John
Doe"}

  This inner representation allows us to render and compose templates easily.
  For example, if you want to render JSON data, we could do so by adding a
  "show.json" entry to `render/2` in our view:

      defmodule YourApp.UserView do
        use YourApp.View

        def render("show.json", %{user: user}) do
          %{name: user.name, address: user.address}
        end
      end

  Notice that in order to render JSON data, we don't need to explicitly
  return a JSON string! Instead, we just return data that is encodable to
  JSON.

  Both JSON and HTML formats will be encoded only when passing the data
  to the controller via the `render_to_iodata/3` function. The
  `render_to_iodata/3` function uses the notion of format encoders to convert a
  particular format to its string/iodata representation.

  Phoenix ships with some template engines and format encoders, which
  can be further configured in the Phoenix application. You can read
  more about format encoders in `Phoenix.Template` documentation.
  """
  alias Phoenix.{Template}

  @doc """
  When used, defines the current module as a main view module.

  ## Options

    * `:root` - the template root to find templates
    * `:path` - the optional path to search for templates within the `:root`.
      Defaults to the underscored view module name. A blank string may
      be provided to use the `:root` path directly as the template lookup path
    * `:namespace` - the namespace to consider when calculating view paths
    * `:pattern` - the wildcard pattern to apply to the root
      when finding templates. Default `"*"`

  The `:root` option is required while the `:namespace` defaults to the
  first nesting in the module name. For instance, both `MyApp.UserView`
  and `MyApp.Admin.UserView` have namespace `MyApp`.

  The `:namespace` and `:path` options are used to calculate template
  lookup paths. For example, if you are in `MyApp.UserView` and the
  namespace is `MyApp`, templates are expected at `Path.join(root, "user")`.
  On the other hand, if the view is `MyApp.Admin.UserView`,
  the path will be `Path.join(root, "admin/user")` and so on. For
  explicit root path locations, the `:path` option can instead be provided.
  The `:root` and `:path` are joined to form the final lookup path.
  A blank string may be provided to use the `:root` path directly as the
  template lookup path.

  Setting the namespace to `MyApp.Admin` in the second example will force
  the template to also be looked up at `Path.join(root, "user")`.
  """
  defmacro __using__(opts) do
    %{module: module} = __CALLER__

    if Module.get_attribute(module, :view_resource) do
      raise ArgumentError,
            "use Phoenix.View is being called twice in the module #{module}. " <>
              "Make sure to call it only per module"
    else
      view_resource = String.to_atom(Phoenix.Naming.resource_name(module, "View"))
      Module.put_attribute(module, :view_resource, view_resource)
    end

    quote do
      import Phoenix.View
      use Phoenix.Template, Phoenix.View.__template_options__(__MODULE__, unquote(opts))

      @before_compile Phoenix.View
      @view_resource String.to_atom(Phoenix.Naming.resource_name(__MODULE__, "View"))

      @doc """
      Renders the given template locally.
      """
      def render(template, assigns \\ %{})

      def render(module, template) when is_atom(module) do
        Phoenix.View.render(module, template, %{})
      end

      def render(template, _assigns) when not is_binary(template) do
        raise ArgumentError, "render/2 expects template to be a string, got: #{inspect template}"
      end

      def render(template, assigns) when not is_map(assigns) do
        render(template, Enum.into(assigns, %{}))
      end

      @doc "The resource name, as an atom, for this view"
      def __resource__, do: @view_resource
    end
  end

  @anno (if :erlang.system_info(:otp_release) >= '19' do
    [generated: true]
  else
    [line: -1]
  end)

  @doc false
  defmacro __before_compile__(_env) do
    # We are using @anno because we don't want warnings coming from
    # render/2 to be reported in case the user has defined a catch all
    # render/2 clause.
    quote @anno do
      # Catch-all clause for rendering.
      def render(template, assigns) do
        render_template(template, assigns)
      end
    end
  end

  @doc """
  Renders a template.

  It expects the view module, the template as a string, and a
  set of assigns.

  Notice this function returns the inner representation of a
  template. If you want the encoded template as a result, use
  `render_to_iodata/3` instead.

  ## Examples

      Phoenix.View.render(YourApp.UserView, "index.html", name: "John Doe")
      #=> {:safe, "Hello John Doe"}

  ## Assigns

  Assigns are meant to be user data that will be available in templates.
  However, there are keys under assigns that are specially handled by
  Phoenix, they are:

    * `:layout` - tells Phoenix to wrap the rendered result in the
      given layout. See next section

  The following assigns are reserved, and cannot be set directly:

    * `@view_module` - The view module being rendered
    * `@view_template` - The `@view_module`'s template being rendered

  ## Layouts

  Templates can be rendered within other templates using the `:layout`
  option. `:layout` accepts a tuple of the form
  `{LayoutModule, "template.extension"}`.

  To render the template within the layout, simply call `render/3`
  using the `@view_module` and `@view_template` assign:

      <%= render(@view_module, @view_template, assigns) %>

  """
  def render(module, template, assigns) do
    assigns
    |> to_map()
    |> Map.pop(:layout, false)
    |> render_within(module, template)
  end

  defp render_within({false, assigns}, module, template) do
    assigns = Map.merge(assigns, %{view_module: module,
                                   view_template: template})
    module.render(template, assigns)
  end

  defp render_within({layout, assigns}, inner_mod, inner_tpl) do
    assigns = Map.merge(assigns, %{view_module: inner_mod, view_template: inner_tpl})
    render_layout(layout, assigns)
  end

  defp render_layout({layout_mod, layout_tpl}, assigns)
       when is_atom(layout_mod) and is_binary(layout_tpl) do
    layout_mod.render(layout_tpl, assigns)
  end

  defp render_layout(layout, _assigns) do
    raise ArgumentError, """
    invalid value for reserved key :layout in View.render/3 assigns

    :layout accepts a tuple of the form {LayoutModule, "template.extension"}

    got: #{inspect(layout)}
    """
  end

  @doc """
  Renders a template only if it exists.

  Same as `render/3`, but returns `nil` instead of raising.
  Useful for dynamically rendering templates in the layout that may or
  may not be implemented by the `@view_module` view.

  ## Examples

  Consider the case where the application layout allows views to dynamically
  render a section of script tags in the head of the document. Some views
  may wish to inject certain scripts, while others will not.

        <%= render_existing @view_module, "scripts.html", assigns %>

  Then the module for the `@view_module` view can decide to provide scripts with
  either a precompiled template, or by implementing the function directly, ie:

      def render("scripts.html", _assigns) do
        ~E()
      end

  To use a precompiled template, create a `scripts.html.eex` file in the `templates`
  directory for the corresponding view you want it to render for. For example,
  for the `UserView`, create the `scripts.html.eex` file at `your_app_web/templates/user/`.

  ## Rendering based on controller template

  In some cases, you might need to render based on the template.
  For these cases, `@view_template` can pair with
  `render_existing/3` for per-template based content, ie:

        <%= render_existing @view_module, "scripts." <> @view_template, assigns %>

      def render("scripts.show.html", _assigns) do
        ~E()
      end
      def render("scripts.index.html", _assigns) do
        ~E()
      end

  """
  def render_existing(module, template, assigns \\ []) do
    render(module, template, put_in(assigns[:__phx_render_existing__], {module, template}))
  end

  @doc """
  Renders a collection.

  A collection is any enumerable of structs. This function
  returns the rendered collection in a list:

      render_many users, UserView, "show.html"

  is roughly equivalent to:

      Enum.map(users, fn user ->
        render(UserView, "show.html", user: user)
      end)

  The underlying user is passed to the view and template as `:user`,
  which is inferred from the view name. The name of the key
  in assigns can be customized with the `:as` option:

      render_many users, UserView, "show.html", as: :data

  is roughly equivalent to:

      Enum.map(users, fn user ->
        render(UserView, "show.html", data: user)
      end)

  """
  def render_many(collection, view, template, assigns \\ %{}) do
    assigns = to_map(assigns)
    Enum.map(collection, fn resource ->
      render view, template, assign_resource(assigns, view, resource)
    end)
  end

  @doc """
  Renders a single item if not nil.

  The following:

      render_one user, UserView, "show.html"

  is roughly equivalent to:

      if user != nil do
        render(UserView, "show.html", user: user)
      end

  The underlying user is passed to the view and template as
  `:user`, which is inflected from the view name. The name
  of the key in assigns can be customized with the `:as` option:

      render_one user, UserView, "show.html", as: :data

  is roughly equivalent to:

      if user != nil do
        render(UserView, "show.html", data: user)
      end

  """
  def render_one(resource, view, template, assigns \\ %{})
  def render_one(nil, _view, _template, _assigns), do: nil
  def render_one(resource, view, template, assigns) do
    assigns = to_map(assigns)
    render view, template, assign_resource(assigns, view, resource)
  end

  defp to_map(assigns) when is_map(assigns), do: assigns
  defp to_map(assigns) when is_list(assigns), do: :maps.from_list(assigns)

  defp assign_resource(assigns, view, resource) do
    as = Map.get(assigns, :as) || view.__resource__
    Map.put(assigns, as, resource)
  end

  @doc """
  Renders the template and returns iodata.
  """
  def render_to_iodata(module, template, assign) do
    render(module, template, assign) |> encode(template)
  end

  @doc """
  Renders the template and returns a string.
  """
  def render_to_string(module, template, assign) do
    render_to_iodata(module, template, assign) |> IO.iodata_to_binary
  end

  defp encode(content, template) do
    if encoder = Template.format_encoder(template) do
      encoder.encode_to_iodata!(content)
    else
      content
    end
  end

  @doc false
  def __template_options__(module, opts) do
    root = opts[:root] || raise(ArgumentError, "expected :root to be given as an option")
    path = opts[:path]

    namespace =
      if given = opts[:namespace] do
        given
      else
        module
        |> Module.split()
        |> Enum.take(1)
        |> Module.concat()
      end

    root_path = Path.join(root, path || Template.module_to_template_root(module, namespace, "View"))
    [root: root_path] ++ Keyword.take(opts, [:pattern, :template_engines])
  end
end


Update documentation slightly, and add `assign`

defmodule Swoosh.Email do
  @moduledoc """
  Defines an Email.

  This module defines a `Swoosh.Email` struct and the main functions for composing an email.  As it is the contract for
  the public APIs of Swoosh it is a good idea to make use of these functions rather than build the struct yourself.

  ## Email fields

  * `from` - the email address of the sender, example: `{"Tony Stark", "tony@stark.com"}`
  * `to` - the email address for the recipient(s), example: `[{"Steve Rogers", "steve@rogers.com"}]`
  * `subject` - the subject of the email, example: `"Hello, Avengers!"`
  * `cc` - the intended carbon copy recipient(s) of the email, example: `[{"Bruce Banner", "hulk@smash.com"}]`
  * `bcc` - the intended blind carbon copy recipient(s) of the email, example: `[{"Janet Pym", "wasp@avengers.com"}]`
  * `text_body` - the content of the email in plaintext, example: `"Hello"`
  * `html_body` - the content of the email in HTML, example: `"<h1>Hello</h1>"`
  * `reply_to` - the email address that should receive replies, example: `{"Clints Barton", "hawk@eye.com"}`
  * `headers` - a map of headers that should be included in the email, example: `%{"X-Accept-Language" => "en-us, en"}`
  * `assigns` - a map of values that correspond with any template variables, example: `%{"first_name" => "Bruce"}`

  ## Private

  This key is reserved for use with adapters, libraries and frameworks.

  * `private` - a map of values that are for use by libraries/frameworks, example: `%{phoenix_template: "welcome.html.eex"}`

  ## Provider options

  This key allow users to make use of provider-specific functionality by passing along addition parameters.

  * `provider_options` - a map of values that are specific to adapter provider, example: `%{async: true}`

  ## Examples

      email =
        %Swoosh.Email{}
        |> to("tony@stark.com")
        |> from("bruce@banner.com")
        |> text_body("Welcome to the Avengers")

  The composable nature makes it very easy to continue expanding upon a given Email.

      email =
        email
        |> cc({"Steve Rogers", "steve@rogers.com"})
        |> cc("wasp@avengers.com")
        |> bcc(["thor@odinson.com", {"Henry McCoy", "beast@avengers.com"}])
        |> html_body("
Special Welcome
")
  """

  defstruct subject: "", from: nil, to: [], cc: [], bcc: [], text_body: nil,
            html_body: nil, attachments: nil, reply_to: nil, headers: %{},
            private: %{}, assigns: %{}, provider_options: %{}

  @doc """
  Sets a recipient in the `from` field.

  The recipient must be either; a tuple specifying the name and address of the recipient; a string specifying the
  address of the recipient.

  ## Examples

      iex> %Swoosh.Email{} |> from({"Steve Rogers", "steve@rogers.com"})
      %Swoosh.Email{assigns: %{}, attachments: nil, bcc: [], cc: [], from: {"Steve Rogers", "steve@rogers.com"},
       headers: %{}, html_body: nil, private: %{}, provider_options: %{},
       reply_to: nil, subject: "", text_body: nil, to: []}

      iex> %Swoosh.Email{} |> from("steve@rogers.com")
      %Swoosh.Email{assigns: %{}, attachments: nil, bcc: [], cc: [], from: {"", "steve@rogers.com"},
       headers: %{}, html_body: nil, private: %{}, provider_options: %{},
       reply_to: nil, subject: "", text_body: nil, to: []}
  """
  def from(%__MODULE__{} = email, from) do
    from = format_recipient(from)
    %{email | from: from}
  end

  @doc """
  Sets a recipient in the `reply_to` field.

  The recipient must be either; a tuple specifying the name and address of the recipient; a string specifying the
  address of the recipient.

  ## Examples

      iex> %Swoosh.Email{} |> reply_to({"Steve Rogers", "steve@rogers.com"})
      %Swoosh.Email{assigns: %{}, attachments: nil, bcc: [], cc: [], from: nil,
       headers: %{}, html_body: nil, private: %{}, provider_options: %{},
       reply_to: {"Steve Rogers", "steve@rogers.com"}, subject: "", text_body: nil, to: []}

      iex> %Swoosh.Email{} |> reply_to("steve@rogers.com")
      %Swoosh.Email{assigns: %{}, attachments: nil, bcc: [], cc: [], from: nil,
       headers: %{}, html_body: nil, private: %{}, provider_options: %{},
       reply_to: {"", "steve@rogers.com"}, subject: "", text_body: nil, to: []}
  """
  def reply_to(%__MODULE__{} = email, reply_to) do
    reply_to = format_recipient(reply_to)
    %{email | reply_to: reply_to}
  end

  @doc """
  Sets the `subject` field.

  The subject must be a string that contains the subject.

  ## Examples

      iex> %Swoosh.Email{} |> subject("Hello, Avengers!")
      %Swoosh.Email{assigns: %{}, attachments: nil, bcc: [],
       cc: [], from: nil, headers: %{}, html_body: nil,
       private: %{}, provider_options: %{}, reply_to: nil, subject: "Hello, Avengers!",
       text_body: nil, to: []}
  """
  def subject(email, subject), do: %{email|subject: subject}

  @doc """
  Sets the `text_body` field.

  The text body must be a string that containing the plaintext content.

  ## Examples

      iex> %Swoosh.Email{} |> text_body("Hello")
      %Swoosh.Email{assigns: %{}, attachments: nil, bcc: [],
       cc: [], from: nil, headers: %{}, html_body: nil,
       private: %{}, provider_options: %{}, reply_to: nil, subject: "",
       text_body: "Hello", to: []}
  """
  def text_body(email, text_body), do: %{email|text_body: text_body}

  @doc """
  Sets the `html_body` field.

  The HTML body must be a string that containing the HTML content.

  ## Examples

      iex> %Swoosh.Email{} |> html_body("
Hello
")
      %Swoosh.Email{assigns: %{}, attachments: nil, bcc: [],
       cc: [], from: nil, headers: %{}, html_body: "
Hello
",
       private: %{}, provider_options: %{}, reply_to: nil, subject: "",
       text_body: nil, to: []}
  """
  def html_body(email, html_body), do: %{email|html_body: html_body}

  @doc """
  Adds new recipients in the `bcc` field.

  The recipient must be; a tuple specifying the name and address of the recipient; a string specifying the
  address of the recipient; or an array comprised of a combination of either.

      iex> %Swoosh.Email{} |> bcc("steve@rogers.com")
      %Swoosh.Email{assigns: %{}, attachments: nil, bcc: [{"", "steve@rogers.com"}],
       cc: [], from: nil, headers: %{}, html_body: nil,
       private: %{}, provider_options: %{}, reply_to: nil, subject: "",
       text_body: nil, to: []}
  """
  def bcc(%__MODULE__{bcc: bcc} = email, recipients) when is_list(recipients) do
    recipients =
      recipients
      |> Enum.map(&format_recipient(&1))
      |> Enum.concat(bcc)
    %{email | bcc: recipients}
  end
  def bcc(%__MODULE__{} = email, recipient) do
    bcc(email, [recipient])
  end

  @doc """
  Puts new recipients in the `bcc` field.

  It will replace any previously added `bcc` recipients.
  """
  def put_bcc(%__MODULE__{} = email, recipients) when is_list(recipients) do
    recipients =
      recipients
      |> Enum.map(&format_recipient(&1))
    %{email | bcc: recipients}
  end
  def put_bcc(%__MODULE__{} = email, recipient) do
    put_bcc(email, [recipient])
  end

  @doc """
  Adds new recipients in the `cc` field.

  The recipient must be; a tuple specifying the name and address of the recipient; a string specifying the
  address of the recipient; or an array comprised of a combination of either.

  ## Examples

      iex> %Swoosh.Email{} |> cc("steve@rogers.com")
      %Swoosh.Email{assigns: %{}, attachments: nil, bcc: [],
       cc: [{"", "steve@rogers.com"}], from: nil, headers: %{}, html_body: nil,
       private: %{}, provider_options: %{}, reply_to: nil, subject: "",
       text_body: nil, to: []}
  """
  def cc(%__MODULE__{cc: cc} = email, recipients) when is_list(recipients) do
    recipients =
      recipients
      |> Enum.map(&format_recipient(&1))
      |> Enum.concat(cc)
    %{email | cc: recipients}
  end
  def cc(%__MODULE__{} = email, recipient) do
    cc(email, [recipient])
  end

  @doc """
  Puts new recipients in the `cc` field.

  It will replace any previously added `cc` recipients.
  """
  def put_cc(%__MODULE__{} = email, recipients) when is_list(recipients) do
    recipients =
      recipients
      |> Enum.map(&format_recipient(&1))
    %{email | cc: recipients}
  end
  def put_cc(%__MODULE__{} = email, recipient) do
    put_cc(email, [recipient])
  end

  @doc """
  Adds new recipients in the `to` field.

  The recipient must be; a tuple specifying the name and address of the recipient; a string specifying the
  address of the recipient; or an array comprised of a combination of either.

  ## Examples

      iex> %Swoosh.Email{} |> to("steve@rogers.com")
      %Swoosh.Email{assigns: %{}, attachments: nil, bcc: [],
       cc: [], from: nil, headers: %{}, html_body: nil,
       private: %{}, provider_options: %{}, reply_to: nil, subject: "",
       text_body: nil, to: [{"", "steve@rogers.com"}]}
  """
  def to(%__MODULE__{to: to} = email, recipients) when is_list(recipients) do
    recipients =
      recipients
      |> Enum.map(&format_recipient(&1))
      |> Enum.concat(to)
    %{email | to: recipients}
  end
  def to(%__MODULE__{} = email, recipient) do
    to(email, [recipient])
  end

  @doc """
  Puts new recipients in the `to` field.

  It will replace any previously added `to` recipients.
  """
  def put_to(%__MODULE__{} = email, recipients) when is_list(recipients) do
    recipients =
      recipients
      |> Enum.map(&format_recipient(&1))
    %{email | to: recipients}
  end
  def put_to(%__MODULE__{} = email, recipient) do
    put_to(email, [recipient])
  end

  @doc """
  Adds a new `header` in the email.

  The name and value must be specified as strings.

  ## Examples

      iex> %Swoosh.Email{} |> header("X-Magic-Number", "7")
      %Swoosh.Email{assigns: %{}, attachments: nil, bcc: [], cc: [], from: nil,
       headers: %{"X-Magic-Number" => "7"}, html_body: nil, private: %{},
       provider_options: %{}, reply_to: nil, subject: "", text_body: nil, to: []}
  """
  def header(%__MODULE__{headers: headers} = email, name, value) when is_binary(name) and is_binary(value) do
    headers = headers |> Map.put(name, value)
    Map.put(email, :headers, headers)
  end
  def header(%__MODULE__{}, name, value) do
    raise ArgumentError, message:
    """
    header/3 expects the header name and value to be strings.

    Instead it got:
      name: `#{inspect name}`.
      value: `#{inspect value}`.
    """
  end

  @doc """
  Stores a new **private** key and value in the email.

  This store is meant to be for libraries/framework usage. The name should be
  specified as an atom, the value can be any term.

  ## Examples

      iex> email.private[:phoenix_template]
      nil
      iex> email = put_private(email, :phoenix_template, "welcome.html")
      iex> email.private[:phoenix_template]
      "welcome.html"
  """
  def put_private(%__MODULE__{private: private} = email, key, value) when is_atom(key) do
    %{email | private: Map.put(private, key, value)}
  end

  @doc """
  Stores a new **provider_option** key and value in the email.

  This store is meant for adapter usage, to aid provider-specific functionality.
  The name should be specified as an atom, the value can be any term.

  ## Examples

      iex> email.provider_options[:async]
      nil
      iex> email = put_provider_option(email, :async, true)
      iex> email.provider_options[:async]
      true
  """
  def put_provider_option(%__MODULE__{provider_options: provider_options} = email, key, value) when is_atom(key) do
    %{email | provider_options: Map.put(provider_options, key, value)}
  end

  @doc """
  Stores a new variable key and value in the email.

  This store is meant for variables used in templating. The name should be specified as an atom, the value can be any
  term.

  ## Examples

      iex> email.assigns[:first_name]
      nil
      iex> email = assign(email, :first_name, "Steve")
      iex> email.assigns[:first_name]
      "Steve"
  """
  def assign(%__MODULE__{assigns: assigns} = email, key, value) when is_atom(key) do
    %{email | assigns: Map.put(assigns, key, value)}
  end

  defp format_recipient({name, address} = recipient) when is_binary(name) and is_binary(address) and recipient != "" do
    recipient
  end
  defp format_recipient(recipient) when is_binary(recipient) and recipient != "" do
    {"", recipient}
  end
  defp format_recipient(invalid) do
    raise ArgumentError, message:
    """
    The recipient `#{inspect invalid}` is invalid.

    Recipients must be a string representing an email address like
    `foo@bar.com` or a two-element tuple `{name, address}`, where
    name and address are strings.
    """
  end
end

defmodule Swoosh.Email do
  @moduledoc """
  Defines an Email.

  This module defines a `Swoosh.Email` struct and the main functions for composing an email.  As it is the contract for
  the public APIs of Swoosh it is a good idea to make use of these functions rather than build the struct yourself.

  ## Email fields

  * `from` - the email address of the sender, example: `{"Tony Stark", "tony@stark.com"}`
  * `to` - the email address for the recipient(s), example: `[{"Steve Rogers", "steve@rogers.com"}]`
  * `subject` - the subject of the email, example: `"Hello, Avengers!"`
  * `cc` - the intended carbon copy recipient(s) of the email, example: `[{"Bruce Banner", "hulk@smash.com"}]`
  * `bcc` - the intended blind carbon copy recipient(s) of the email, example: `[{"Janet Pym", "wasp@avengers.com"}]`
  * `text_body` - the content of the email in plaintext, example: `"Hello"`
  * `html_body` - the content of the email in HTML, example: `"<h1>Hello</h1>"`
  * `reply_to` - the email address that should receive replies, example: `{"Clints Barton", "hawk@eye.com"}`
  * `headers` - a map of headers that should be included in the email, example: `%{"X-Accept-Language" => "en-us, en"}`
  * `assigns` - a map of values that correspond with any template variables, example: `%{"first_name" => "Bruce"}`

  ## Private

  This key is reserved for use with adapters, libraries and frameworks.

  * `private` - a map of values that are for use by libraries/frameworks, example: `%{phoenix_template: "welcome.html.eex"}`

  ## Provider options

  This key allow users to make use of provider-specific functionality by passing along addition parameters.

  * `provider_options` - a map of values that are specific to adapter provider, example: `%{async: true}`

  ## Examples

      email =
        %Swoosh.Email{}
        |> to("tony@stark.com")
        |> from("bruce@banner.com")
        |> text_body("Welcome to the Avengers")

  The composable nature makes it very easy to continue expanding upon a given Email.

      email =
        email
        |> cc({"Steve Rogers", "steve@rogers.com"})
        |> cc("wasp@avengers.com")
        |> bcc(["thor@odinson.com", {"Henry McCoy", "beast@avengers.com"}])
        |> html_body("
Special Welcome
")
  """

  defstruct subject: "", from: nil, to: [], cc: [], bcc: [], text_body: nil,
            html_body: nil, attachments: nil, reply_to: nil, headers: %{},
            private: %{}, assigns: %{}, provider_options: %{}

  @doc """
  Sets a recipient in the `from` field.

  The recipient must be either; a tuple specifying the name and address of the recipient; a string specifying the
  address of the recipient.

  ## Examples

      iex> %Swoosh.Email{} |> from({"Steve Rogers", "steve@rogers.com"})
      %Swoosh.Email{assigns: %{}, attachments: nil, bcc: [], cc: [], from: {"Steve Rogers", "steve@rogers.com"},
       headers: %{}, html_body: nil, private: %{}, provider_options: %{},
       reply_to: nil, subject: "", text_body: nil, to: []}

      iex> %Swoosh.Email{} |> from("steve@rogers.com")
      %Swoosh.Email{assigns: %{}, attachments: nil, bcc: [], cc: [], from: {"", "steve@rogers.com"},
       headers: %{}, html_body: nil, private: %{}, provider_options: %{},
       reply_to: nil, subject: "", text_body: nil, to: []}
  """
  def from(%__MODULE__{} = email, from) do
    from = format_recipient(from)
    %{email | from: from}
  end

  @doc """
  Sets a recipient in the `reply_to` field.

  The recipient must be either; a tuple specifying the name and address of the recipient; a string specifying the
  address of the recipient.

  ## Examples

        iex> %Swoosh.Email{} |> reply_to({"Steve Rogers", "steve@rogers.com"})
        %Swoosh.Email{assigns: %{}, attachments: nil, bcc: [], cc: [], from: nil,
         headers: %{}, html_body: nil, private: %{}, provider_options: %{},
         reply_to: {"Steve Rogers", "steve@rogers.com"}, subject: "", text_body: nil, to: []}

        iex> %Swoosh.Email{} |> reply_to("steve@rogers.com")
        %Swoosh.Email{assigns: %{}, attachments: nil, bcc: [], cc: [], from: nil,
         headers: %{}, html_body: nil, private: %{}, provider_options: %{},
         reply_to: {"", "steve@rogers.com"}, subject: "", text_body: nil, to: []}
  """
  def reply_to(%__MODULE__{} = email, reply_to) do
    reply_to = format_recipient(reply_to)
    %{email | reply_to: reply_to}
  end

  @doc """
  Sets the `subject` field.

  The subject must be a string that contains the subject.

  ## Examples

        iex> %Swoosh.Email{} |> subject("Hello, Avengers!")
        %Swoosh.Email{assigns: %{}, attachments: nil, bcc: [],
        cc: [], from: nil, headers: %{}, html_body: nil,
         private: %{}, provider_options: %{}, reply_to: nil, subject: "Hello, Avengers!",
         text_body: nil, to: []}
  """
  def subject(email, subject), do: %{email|subject: subject}

  @doc """
  Sets the `text_body` field.

  The text body must be a string that containing the plaintext content.

  ## Examples

      iex> %Swoosh.Email{} |> text_body("Hello")
      %Swoosh.Email{assigns: %{}, attachments: nil, bcc: [],
       cc: [], from: nil, headers: %{}, html_body: nil,
       private: %{}, provider_options: %{}, reply_to: nil, subject: "",
       text_body: "Hello", to: []}
  """
  def text_body(email, text_body), do: %{email|text_body: text_body}

  @doc """
  Sets the `html_body` field.

  The HTML body must be a string that containing the HTML content.

  ## Examples

      iex> %Swoosh.Email{} |> html_body("
Hello
")
      %Swoosh.Email{assigns: %{}, attachments: nil, bcc: [],
       cc: [], from: nil, headers: %{}, html_body: "
Hello
",
       private: %{}, provider_options: %{}, reply_to: nil, subject: "",
       text_body: nil, to: []}
  """
  def html_body(email, html_body), do: %{email|html_body: html_body}

  @doc """
  Adds new recipients in the `bcc` field.

  The recipient must be; a tuple specifying the name and address of the recipient; a string specifying the
  address of the recipient; or an array comprised of a combination of either.

        iex> %Swoosh.Email{} |> bcc("steve@rogers.com")
        %Swoosh.Email{assigns: %{}, attachments: nil, bcc: [{"", "steve@rogers.com"}],
         cc: [], from: nil, headers: %{}, html_body: nil,
         private: %{}, provider_options: %{}, reply_to: nil, subject: "",
         text_body: nil, to: []}
  """
  def bcc(%__MODULE__{bcc: bcc} = email, recipients) when is_list(recipients) do
    recipients =
      recipients
      |> Enum.map(&format_recipient(&1))
      |> Enum.concat(bcc)
    %{email | bcc: recipients}
  end
  def bcc(%__MODULE__{} = email, recipient) do
    bcc(email, [recipient])
  end

  @doc """
  Puts new recipients in the `bcc` field.

  It will replace any previously added `bcc` recipients.
  """
  def put_bcc(%__MODULE__{} = email, recipients) when is_list(recipients) do
    recipients =
      recipients
      |> Enum.map(&format_recipient(&1))
    %{email | bcc: recipients}
  end
  def put_bcc(%__MODULE__{} = email, recipient) do
    put_bcc(email, [recipient])
  end

  @doc """
  Adds new recipients in the `cc` field.

  The recipient must be; a tuple specifying the name and address of the recipient; a string specifying the
  address of the recipient; or an array comprised of a combination of either.

  ## Examples

        iex> %Swoosh.Email{} |> cc("steve@rogers.com")
        %Swoosh.Email{assigns: %{}, attachments: nil, bcc: [],
         cc: [{"", "steve@rogers.com"}], from: nil, headers: %{}, html_body: nil,
         private: %{}, provider_options: %{}, reply_to: nil, subject: "",
         text_body: nil, to: []}
  """
  def cc(%__MODULE__{cc: cc} = email, recipients) when is_list(recipients) do
    recipients =
      recipients
      |> Enum.map(&format_recipient(&1))
      |> Enum.concat(cc)
    %{email | cc: recipients}
  end
  def cc(%__MODULE__{} = email, recipient) do
    cc(email, [recipient])
  end

  @doc """
  Puts new recipients in the `cc` field.

  It will replace any previously added `cc` recipients.
  """
  def put_cc(%__MODULE__{} = email, recipients) when is_list(recipients) do
    recipients =
      recipients
      |> Enum.map(&format_recipient(&1))
    %{email | cc: recipients}
  end
  def put_cc(%__MODULE__{} = email, recipient) do
    put_cc(email, [recipient])
  end

  @doc """
  Adds new recipients in the `to` field.

  The recipient must be; a tuple specifying the name and address of the recipient; a string specifying the
  address of the recipient; or an array comprised of a combination of either.

  ## Examples

        iex> %Swoosh.Email{} |> to("steve@rogers.com")
        %Swoosh.Email{assigns: %{}, attachments: nil, bcc: [],
         cc: [], from: nil, headers: %{}, html_body: nil,
         private: %{}, provider_options: %{}, reply_to: nil, subject: "",
         text_body: nil, to: [{"", "steve@rogers.com"}]}
  """
  def to(%__MODULE__{to: to} = email, recipients) when is_list(recipients) do
    recipients =
      recipients
      |> Enum.map(&format_recipient(&1))
      |> Enum.concat(to)
    %{email | to: recipients}
  end
  def to(%__MODULE__{} = email, recipient) do
    to(email, [recipient])
  end

  @doc """
  Puts new recipients in the `to` field.

  It will replace any previously added `to` recipients.
  """
  def put_to(%__MODULE__{} = email, recipients) when is_list(recipients) do
    recipients =
      recipients
      |> Enum.map(&format_recipient(&1))
    %{email | to: recipients}
  end
  def put_to(%__MODULE__{} = email, recipient) do
    put_to(email, [recipient])
  end

  @doc """
  Adds a new `header` in the email.

  The name and value must be specified as strings.

  ## Examples

      iex> %Swoosh.Email{} |> header("X-Magic-Number", "7")
      %Swoosh.Email{assigns: %{}, attachments: nil, bcc: [], cc: [], from: nil,
       headers: %{"X-Magic-Number" => "7"}, html_body: nil, private: %{},
       provider_options: %{}, reply_to: nil, subject: "", text_body: nil, to: []}
  """
  def header(%__MODULE__{headers: headers} = email, name, value) when is_binary(name) and is_binary(value) do
    headers = headers |> Map.put(name, value)
    Map.put(email, :headers, headers)
  end
  def header(%__MODULE__{}, name, value) do
    raise ArgumentError, message:
    """
    header/3 expects the header name and value to be strings.

    Instead it got:
      name: `#{inspect name}`.
      value: `#{inspect value}`.
    """
  end

  @doc """
  Stores a new **private** key and value in the email.

  This store is meant to be for libraries/framework usage. The name should be
  specified as an atom, the value can be any term.

  ## Examples

      iex> %Swoosh.Email{} |> put_private(:phoenix_template, "welcome.html")
      %Swoosh.Email{assigns: %{}, attachments: nil, bcc: [], cc: [], from: nil,
       headers: %{}, html_body: nil, private: %{phoenix_template: "welcome.html"},
       provider_options: %{}, reply_to: nil, subject: "", text_body: nil, to: []}
  """
  def put_private(%__MODULE__{private: private} = email, key, value) when is_atom(key) do
    %{email | private: Map.put(private, key, value)}
  end

  @doc """
  Stores a new **provider_option** key and value in the email.

  This store is meant for adapter usage, to aid provider-specific functionality.
  The name should be specified as an atom, the value can be any term.

  ## Examples

      iex> %Swoosh.Email{} |> put_provider_option(:async, true)
      %Swoosh.Email{assigns: %{}, attachments: nil, bcc: [], cc: [], from: nil,
       headers: %{}, html_body: nil, private: %{}, provider_options: %{async: true},
       reply_to: nil, subject: "", text_body: nil, to: []}
  """
  def put_provider_option(%__MODULE__{provider_options: provider_options} = email, key, value) when is_atom(key) do
    %{email | provider_options: Map.put(provider_options, key, value)}
  end

  defp format_recipient({name, address} = recipient) when is_binary(name) and is_binary(address) and recipient != "" do
    recipient
  end
  defp format_recipient(recipient) when is_binary(recipient) and recipient != "" do
    {"", recipient}
  end
  defp format_recipient(invalid) do
    raise ArgumentError, message:
    """
    The recipient `#{inspect invalid}` is invalid.

    Recipients must be a string representing an email address like
    `foo@bar.com` or a two-element tuple `{name, address}`, where
    name and address are strings.
    """
  end
end


Fix typo

Fix typo

defmodule Mix.Tasks.Nerves.Clean do
  use Mix.Task
  import Mix.Nerves.IO

  @shortdoc "Clean artifacts for a Nerves package"

  @moduledoc """
  Cleans the build artifacts and fetched sources for given dependencies

  Since this is a destructive action, cleaning of dependencies
  only occurs when one of the following are specified:
    * `dep1 dep2` - the names of Nerves dependencies to be cleaned, separated by spaces
    * `--all` - cleans all Nerves dependencies
  """

  @switches [all: :boolean]

  def run(argv) do
    debug_info "Clean Start"
    {opts, packages, _} = OptionParser.parse(argv, switches: @switches)
    Mix.Tasks.Nerves.Env.run([])

    packages =
      case packages do
        [] ->
          if opts[:all] do
            Nerves.Env.packages
          else
            Mix.raise """
            You must specify the Nerves dependencies to clean, seperated by spaces
            Example:
              mix nerves.clean nerves_system_rpi3
            Or by passing --all
              mix nerves.clean --all
            """
          end
        packages ->
          packages
          |> Enum.map(&String.to_existing_atom/1)
          |> Enum.map(&Nerves.Env.package/1)
      end
      debug_info "Clean End"
    Nerves.Env.clean(packages)
  end

end

defmodule Mix.Tasks.Nerves.Clean do
  use Mix.Task
  import Mix.Nerves.IO

  @shortdoc "Clean artifacts for a Nerves package"

  @moduledoc """
  Cleans the build artifacts and fetches sources for given dependencies

  Since this is a destructive action, cleaning of dependencies
  only occurs when one of the following are specified:
    * `dep1 dep2` - the names of Nerves dependencies to be cleaned, separated by spaces
    * `--all` - cleans all Nerves dependencies
  """

  @switches [all: :boolean]

  def run(argv) do
    debug_info "Clean Start"
    {opts, packages, _} = OptionParser.parse(argv, switches: @switches)
    Mix.Tasks.Nerves.Env.run([])

    packages =
      case packages do
        [] ->
          if opts[:all] do
            Nerves.Env.packages
          else
            Mix.raise """
            You must specify the Nerves dependencies to clean, seperated by spaces
            Example:
              mix nerves.clean nerves_system_rpi3
            Or by passing --all
              mix nerves.clean --all
            """
          end
        packages ->
          packages
          |> Enum.map(&String.to_existing_atom/1)
          |> Enum.map(&Nerves.Env.package/1)
      end
      debug_info "Clean End"
    Nerves.Env.clean(packages)
  end

end


Improve GraphqlController

Improve GraphqlController

defmodule MicrocrawlerWebapp.GraphqlController do
  use MicrocrawlerWebapp.Web, :controller

  def index(conn, %{"query" => query}) do
    res = GraphQL.execute(MicrocrawlerWebapp.TestSchema.schema, query)
    case res do
        {:ok, data} -> json conn, data
        {:error, reasons} -> json conn, %{:errors => reasons}
    end
  end

  def index(conn, params) do
    IO.inspect params
    json conn, %{}
  end
end

defmodule MicrocrawlerWebapp.GraphqlController do
  use MicrocrawlerWebapp.Web, :controller

  def index(conn, %{"query" => query}) do
    {:ok, data} = GraphQL.execute(MicrocrawlerWebapp.TestSchema.schema, query)
    json conn, data
  end

  def index(conn, params) do
    IO.inspect params
    json conn, %{id: 1}
  end
end


inspect query

inspect query

defmodule Pan.SearchFrontendController do
  use Pan.Web, :controller
  require Logger

  def new(conn, params) do
    size = 10
    from = unless params["page"] in ["", nil] do
             (String.to_integer(params["page"]) - 1) * size
           else
             0
           end

    page = round((from + 10) / size)

    query = [index: "/panoptikum_" <> Application.get_env(:pan, :environment),
             search: [size: size, from: from,
               query: [
                 function_score: [
                   query: [match: [_all: [query: params["search"]["searchstring"]]]],
                   boost_mode: "multiply",
                   functions: [
                     %{filter: [term: ["_type": "categories"]], weight: 0},
                     %{filter: [term: ["_type": "podcasts"]], weight: 1},
                     %{filter: [term: ["_type": "personas"]], weight: 0},
                     %{filter: [term: ["_type": "episodes"]], weight: 0},
                     %{filter: [term: ["_type": "users"]], weight: 0}]]]]]
    IO.inspect query

    case Tirexs.Query.create_resource(query) do
      {:ok, 200, %{hits: hits, took: took}} ->
        total = Enum.min([hits.total, 10000])
        render(conn, "new.html", searchstring: params["search"]["searchstring"],
                                 hits: hits, took: took, from: from, size: size, page: page,
                                 total: total)
      {:error, 500, %{error: %{caused_by: %{reason: reason}}}} ->
        render(conn, "error.html")
        raise reason
    end
  end
end

defmodule Pan.SearchFrontendController do
  use Pan.Web, :controller
  require Logger

  def new(conn, params) do
    size = 10
    from = unless params["page"] in ["", nil] do
             (String.to_integer(params["page"]) - 1) * size
           else
             0
           end

    page = round((from + 10) / size)

    query = [index: "/panoptikum_" <> Application.get_env(:pan, :environment),
             search: [size: size, from: from,
               query: [
                 function_score: [
                   query: [match: [_all: [query: params["search"]["searchstring"]]]],
                   boost_mode: "multiply",
                   functions: [
                     %{filter: [term: ["_type": "categories"]], weight: 0},
                     %{filter: [term: ["_type": "podcasts"]], weight: 1},
                     %{filter: [term: ["_type": "personas"]], weight: 0},
                     %{filter: [term: ["_type": "episodes"]], weight: 0},
                     %{filter: [term: ["_type": "users"]], weight: 0}]]]]]

    case Tirexs.Query.create_resource(query) do
      {:ok, 200, %{hits: hits, took: took}} ->
        total = Enum.min([hits.total, 10000])
        render(conn, "new.html", searchstring: params["search"]["searchstring"],
                                 hits: hits, took: took, from: from, size: size, page: page,
                                 total: total)
      {:error, 500, %{error: %{caused_by: %{reason: reason}}}} ->
        render(conn, "error.html")
        raise reason
    end
  end
end


Tests for env(k, v)

Tests for env(k, v)


Minor change to user skill controller test (#141)

defmodule CodeCorps.UserSkillControllerTest do
  use CodeCorps.ConnCase

  alias CodeCorps.UserSkill
  alias CodeCorps.Repo

  setup do
    conn =
      %{build_conn | host: "api."}
      |> put_req_header("accept", "application/vnd.api+json")
      |> put_req_header("content-type", "application/vnd.api+json")

    {:ok, conn: conn}
  end

  defp attributes do
    %{}
  end

  defp relationships(user, skill) do
    %{
      "user" => %{
        "data" => %{
          "type" => "user",
          "id" => user.id
        }
      },
      "skill" => %{
        "data" => %{
          "type" => "skill",
          "id" => skill.id
        }
      },
    }
  end

  test "lists all entries on index", %{conn: conn} do
    conn = get conn, user_skill_path(conn, :index)
    assert json_response(conn, 200)["data"] == []
  end

  test "filters resources on index", %{conn: conn} do
    elixir = insert(:skill, title: "Elixir")
    phoenix = insert(:skill, title: "Phoenix")
    rails = insert(:skill, title: "Rails")

    user = insert(:user)
    user_skill_1 = insert(:user_skill, user: user, skill: elixir)
    user_skill_2 = insert(:user_skill, user: user, skill: phoenix)
    insert(:user_skill, user: user, skill: rails)

    conn = get conn, "user-skills/?filter[id]=#{user_skill_1.id},#{user_skill_2.id}"
    data = json_response(conn, 200)["data"]
    [first_result, second_result | _] = data
    assert length(data) == 2
    assert first_result["id"] == "#{user_skill_1.id}"
    assert second_result["id"] == "#{user_skill_2.id}"
  end

  test "shows chosen resource", %{conn: conn} do
    skill = insert(:skill)
    user = insert(:user)
    user_skill = insert(:user_skill, user: user, skill: skill)
    conn = get conn, user_skill_path(conn, :show, user_skill)
    data = json_response(conn, 200)["data"]
    assert data["id"] == "#{user_skill.id}"
    assert data["type"] == "user-skill"
    assert data["relationships"]["user"]["data"]["id"] == "#{user.id}"
    assert data["relationships"]["skill"]["data"]["id"] == "#{skill.id}"
  end

  test "does not show resource and instead throw error when id is nonexistent", %{conn: conn} do
    assert_error_sent 404, fn ->
      get conn, user_skill_path(conn, :show, -1)
    end
  end

  test "creates and renders resource when data is valid", %{conn: conn} do
    user = insert(:user)
    skill = insert(:skill, title: "test-skill")

    conn = post conn, user_skill_path(conn, :create), %{
      "meta" => %{},
      "data" => %{
        "type" => "user-skill",
        "attributes" => attributes,
        "relationships" => relationships(user, skill)
      }
    }

    json = json_response(conn, 201)

    id = json["data"]["id"] |> String.to_integer
    user_skill = UserSkill |> Repo.get!(id)

    assert json["data"]["id"] == "#{user_skill.id}"
    assert json["data"]["type"] == "user-skill"
    assert json["data"]["relationships"]["user"]["data"]["id"] == "#{user.id}"
    assert json["data"]["relationships"]["skill"]["data"]["id"] == "#{skill.id}"
  end

  test "does not create resource and renders errors when data is invalid", %{conn: conn} do
    conn = post conn, user_skill_path(conn, :create), %{
      "meta" => %{},
      "data" => %{
        "type" => "user-skill",
        "attributes" => attributes,
      }
    }

    assert json_response(conn, 422)["errors"] != %{}
  end

  test "deletes resource", %{conn: conn} do
    skill = insert(:skill, title: "test-skill")
    user = insert(:user)
    user_skill = insert(:user_skill, user: user, skill: skill)
    response = delete conn, user_skill_path(conn, :delete, user_skill)

    assert response.status == 204
  end
end

defmodule CodeCorps.UserSkillControllerTest do
  use CodeCorps.ConnCase

  alias CodeCorps.UserSkill
  alias CodeCorps.Repo

  setup do
    conn =
      %{build_conn | host: "api."}
      |> put_req_header("accept", "application/vnd.api+json")
      |> put_req_header("content-type", "application/vnd.api+json")

    {:ok, conn: conn}
  end

  defp attributes do
    %{}
  end

  defp relationships(user, skill) do
    %{
      user: %{data: %{id: user.id}},
      skill: %{data: %{id: skill.id}}
    }
  end

  test "lists all entries on index", %{conn: conn} do
    conn = get conn, user_skill_path(conn, :index)
    assert json_response(conn, 200)["data"] == []
  end

  test "filters resources on index", %{conn: conn} do
    elixir = insert(:skill, title: "Elixir")
    phoenix = insert(:skill, title: "Phoenix")
    rails = insert(:skill, title: "Rails")

    user = insert(:user)
    user_skill_1 = insert(:user_skill, user: user, skill: elixir)
    user_skill_2 = insert(:user_skill, user: user, skill: phoenix)
    insert(:user_skill, user: user, skill: rails)

    conn = get conn, "user-skills/?filter[id]=#{user_skill_1.id},#{user_skill_2.id}"
    data = json_response(conn, 200)["data"]
    [first_result, second_result | _] = data
    assert length(data) == 2
    assert first_result["id"] == "#{user_skill_1.id}"
    assert second_result["id"] == "#{user_skill_2.id}"
  end

  test "shows chosen resource", %{conn: conn} do
    skill = insert(:skill)
    user = insert(:user)
    user_skill = insert(:user_skill, user: user, skill: skill)
    conn = get conn, user_skill_path(conn, :show, user_skill)
    data = json_response(conn, 200)["data"]
    assert data["id"] == "#{user_skill.id}"
    assert data["type"] == "user-skill"
    assert data["relationships"]["user"]["data"]["id"] == "#{user.id}"
    assert data["relationships"]["skill"]["data"]["id"] == "#{skill.id}"
  end

  test "does not show resource and instead throw error when id is nonexistent", %{conn: conn} do
    assert_error_sent 404, fn ->
      get conn, user_skill_path(conn, :show, -1)
    end
  end

  test "creates and renders resource when data is valid", %{conn: conn} do
    user = insert(:user)
    skill = insert(:skill, title: "test-skill")

    conn = post conn, user_skill_path(conn, :create), %{
      "meta" => %{},
      "data" => %{
        "type" => "user-skill",
        "attributes" => attributes,
        "relationships" => relationships(user, skill)
      }
    }

    json = json_response(conn, 201)

    id = json["data"]["id"] |> String.to_integer
    user_skill = UserSkill |> Repo.get!(id)

    assert json["data"]["id"] == "#{user_skill.id}"
    assert json["data"]["type"] == "user-skill"
    assert json["data"]["relationships"]["user"]["data"]["id"] == "#{user.id}"
    assert json["data"]["relationships"]["skill"]["data"]["id"] == "#{skill.id}"
  end

  test "does not create resource and renders errors when data is invalid", %{conn: conn} do
    conn = post conn, user_skill_path(conn, :create), %{
      "meta" => %{},
      "data" => %{
        "type" => "user-skill",
        "attributes" => attributes,
      }
    }

    assert json_response(conn, 422)["errors"] != %{}
  end

  test "deletes resource", %{conn: conn} do
    skill = insert(:skill, title: "test-skill")
    user = insert(:user)
    user_skill = insert(:user_skill, user: user, skill: skill)
    response = delete conn, user_skill_path(conn, :delete, user_skill)

    assert response.status == 204
  end
end


Add typespects to Database.Patch

Add typespects to Database.Patch

defmodule BorsNG.Database.Patch do
  @moduledoc """
  Corresponds to a pull request in GitHub.

  A closed patch may not be r+'ed,
  nor can a patch associated with a completed batch be r+'ed again,
  though a patch may be merged and r+'ed at the same time.
  """

  use BorsNG.Database.Model

  @type t :: %__MODULE__{}
  @type id :: pos_integer

  schema "patches" do
    belongs_to :project, Project
    field :into_branch, :string
    field :pr_xref, :integer
    field :title, :string
    field :body, :string
    field :commit, :string
    field :open, :boolean, default: true
    field :priority, :integer, default: 0
    belongs_to :author, User
    timestamps()
  end

  @spec changeset(t | Ecto.Changeset.t, map) :: Ecto.Changeset.t
  @doc """
  Builds a changeset based on the `struct` and `params`.
  """
  def changeset(struct, params \\ %{}) do
    struct
    |> cast(params, [
      :pr_xref,
      :title,
      :body,
      :commit,
      :project_id,
      :author_id,
      :open,
      :into_branch,
      :priority])
    |> unique_constraint(:pr_xref, name: :patches_pr_xref_index)
  end

  @spec all_for_batch(Batch.id) :: Ecto.Queryable.t
  def all_for_batch(batch_id) do
    from p in Patch,
      join: l in LinkPatchBatch, on: l.patch_id == p.id,
      where: l.batch_id == ^batch_id,
      order_by: [desc: p.pr_xref]
  end

  @spec all_links_not_err() :: Ecto.Queryable.t
  defp all_links_not_err do
    from l in LinkPatchBatch,
      join: b in Batch,
      on: l.batch_id == b.id and b.state != ^:error and b.state != ^:canceled
  end

  @spec all(:awaiting_review) :: Ecto.Queryable.t
  def all(:awaiting_review) do
    all = all_links_not_err()
    from p in Patch,
      left_join: l in subquery(all), on: l.patch_id == p.id,
      where: is_nil(l.batch_id),
      where: p.open,
      order_by: [desc: p.pr_xref]
  end

  @spec all_for_project(Project.id, :open | :awaiting_review) :: Ecto.Queryable.t
  def all_for_project(project_id, :open) do
    from p in Patch,
      where: p.open,
      where: p.project_id == ^project_id,
      order_by: [desc: p.pr_xref]
  end

  def all_for_project(project_id, :awaiting_review) do
    from p in Patch.all(:awaiting_review),
      where: p.project_id == ^project_id,
      order_by: [desc: p.pr_xref]
  end

  @spec dups_in_batches() :: Ecto.Queryable.t
  def dups_in_batches do
    all = all_links_not_err()
    from p in Patch,
      left_join: l in subquery(all), on: l.patch_id == p.id,
      where: p.open,
      group_by: p.id,
      having: count(p.id) > 1
  end

  @spec ci_skip?(t) :: boolean()
  def ci_skip?(patch) do
    rexp =  ~r/\[ci skip\]\[skip ci\]\[skip netlify\]/
    title = patch.title || ""
    body = patch.body || ""
    String.match?(title, rexp) or String.match?(body, rexp)
  end
end

defmodule BorsNG.Database.Patch do
  @moduledoc """
  Corresponds to a pull request in GitHub.

  A closed patch may not be r+'ed,
  nor can a patch associated with a completed batch be r+'ed again,
  though a patch may be merged and r+'ed at the same time.
  """

  use BorsNG.Database.Model

  @type t :: %Patch{}
  @type id :: pos_integer

  schema "patches" do
    belongs_to :project, Project
    field :into_branch, :string
    field :pr_xref, :integer
    field :title, :string
    field :body, :string
    field :commit, :string
    field :open, :boolean, default: true
    field :priority, :integer, default: 0
    belongs_to :author, User
    timestamps()
  end

  @doc """
  Builds a changeset based on the `struct` and `params`.
  """
  def changeset(struct, params \\ %{}) do
    struct
    |> cast(params, [
      :pr_xref,
      :title,
      :body,
      :commit,
      :project_id,
      :author_id,
      :open,
      :into_branch,
      :priority])
    |> unique_constraint(:pr_xref, name: :patches_pr_xref_index)
  end

  def all_for_batch(batch_id) do
    from p in Patch,
      join: l in LinkPatchBatch, on: l.patch_id == p.id,
      where: l.batch_id == ^batch_id,
      order_by: [desc: p.pr_xref]
  end

  defp all_links_not_err do
    from l in LinkPatchBatch,
      join: b in Batch,
      on: l.batch_id == b.id and b.state != ^:error and b.state != ^:canceled
  end

  def all(:awaiting_review) do
    all = all_links_not_err()
    from p in Patch,
      left_join: l in subquery(all), on: l.patch_id == p.id,
      where: is_nil(l.batch_id),
      where: p.open,
      order_by: [desc: p.pr_xref]
  end

  def all_for_project(project_id, :open) do
    from p in Patch,
      where: p.open,
      where: p.project_id == ^project_id,
      order_by: [desc: p.pr_xref]
  end

  def all_for_project(project_id, :awaiting_review) do
    from p in Patch.all(:awaiting_review),
      where: p.project_id == ^project_id,
      order_by: [desc: p.pr_xref]
  end

  def dups_in_batches do
    all = all_links_not_err()
    from p in Patch,
      left_join: l in subquery(all), on: l.patch_id == p.id,
      where: p.open,
      group_by: p.id,
      having: count(p.id) > 1
  end

  @spec ci_skip?(%Patch{}) :: boolean()
  def ci_skip?(patch) do
    rexp =  ~r/\[ci skip\]\[skip ci\]\[skip netlify\]/
    title = patch.title || ""
    body = patch.body || ""
    String.match?(title, rexp) or String.match?(body, rexp)
  end
end