defmodule TwiML do
@moduledoc """
Generate complex TwiML documents for Twilio in an elegant Elixir way.
> #### Note {: .warning}
>
> Please refer to the [official TwiML
> documentation](https://www.twilio.com/docs/voice/twiml) to verify that the
> TwiML verb actually supports content or the given attributes.
#{"README.md" |> File.read!() |> String.split("<!-- MDOC !-->") |> Enum.fetch!(1)}
"""
# The nesting and duplication is intentionally as it improves comparing the
# verbs with the official TwiML at https://www.twilio.com/docs/voice/twiml
use TwiML.Magic,
verbs: [
[:connect, :autopilot, :siprec, :stream, :virtual_agent],
[
:dial,
:application,
:client,
[:identity, :parameter],
:conference,
:number,
:queue,
:sim,
:sip
],
:enqueue,
:gather,
:hangup,
:leave,
:pause,
[:pay, :prompt, :parameter],
:play,
:record,
:redirect,
:refer,
:reject,
:say,
:siprec,
:stream
]
import TwiML.Camelize, only: [camelize: 2]
@external_resource "README.md"
@typedoc """
A TwiML document contains one or more TwiML verbs. These verbs can have
attributes and can wrap nested TwiML verbs.
"""
@type t :: [{atom(), keyword(), content() | t()}]
@typedoc """
Content which can be used within a TwiML verb. Refer to the `XmlBuilder`
documentation for more information.
"""
@type content :: binary() | {:safe, binary()} | {:cdata, binary()} | {:iodata, binary()}
@doc """
Generates a XML document from the provided verbs and arguments. For the
supported `opts`, please refer to the documentation of
`XmlBuilder.generate/2`.
## Examples
iex> TwiML.say("Hello world")
...> |> TwiML.to_xml(format: :none)
~s(<?xml version="1.0" encoding="UTF-8"?><Response><Say>Hello world</Say></Response>)
"""
@doc helper: true
def to_xml(verbs, opts \\ []) do
:Response
|> XmlBuilder.document(verbs)
|> XmlBuilder.generate(opts)
end
defp build_verb(verb, attrs, children) do
verb =
verb
|> Atom.to_string()
|> String.capitalize()
attrs =
attrs
|> Enum.reject(&is_nil(elem(&1, 1)))
|> Enum.map(fn {k, v} -> {camelize(k, :lower), v} end)
{verb, attrs, children}
end
@doc """
Generates a comment.
## Examples
iex> TwiML.comment("Blocked because of insufficient funds")
...> |> TwiML.to_xml(format: :none)
~s(<?xml version="1.0" encoding="UTF-8"?><Response><!-->Blocked because of insufficient funds</!--></Response>)
"""
@doc helper: true
def comment(text) do
[{"!--", [], text}]
end
@doc """
Appends a comment to the TwiML.
## Examples
iex> TwiML.reject() |> TwiML.comment("Blocked because of insufficient funds") |> TwiML.to_xml(format: :none)
~s(<?xml version="1.0" encoding="UTF-8"?><Response><Reject/><!-->Blocked because of insufficient funds</!--></Response>)
"""
@doc helper: true
def comment(verbs, text) do
verbs ++ [comment(text)]
end
end