WWW::Twilio::TwiML(3)

πŸ“¦
version 1.05 Β· 4 versions
, in epel 9

🌸 NAME 🌸

WWW::Twilio::TwiML β€” Light and fast TwiML generator πŸ’– (and yes bestie, this is the WWW::Twilio::TwiML(3) manual β€” lowkey iconic).


✨ SYNOPSIS ✨

use WWW::Twilio::TwiML;

my $t = new WWW::Twilio::TwiML;
$t->Response->Dial("+1234567890");
print $t->to_string;

πŸ¦‹ DESCRIPTION πŸ¦‹

WWW::Twilio::TwiML makes Twilio-compatible TwiML documents. You can build a document by creating and nesting one element at a time, or by chaining objects together. Elements can hold attributes, text content, or other elements. ✨

TwiML is XML, so technically you could generate it with XML::LibXML or any number of other XML parsers/generators. But philosophically, WWW::Twilio::TwiML is an economical TwiML generator: it has a small footprint (TwiML documents are typically small and simple), and it's meant to make TwiML creation straightforward and moderately fun. πŸŽ€

WWW::Twilio::TwiML's primary aim is economy of expression. So any method you call on a TwiML object (except the ones described below) will create new TwiML objects named after the method you called. Chain those method calls and you can make robust TwiML documents with very little code. no cap. πŸ’…

🌈 new( key => value, ... ) 🌈

Creates a new TwiML object. With no arguments, it makes a root for your TwiML document. You can also call new with name, content, or attributes arguments to create unattached elements. 🫢

The following examples all create this TwiML document using different calling styles:

<?xml version="1.0" encoding="UTF-8" ?>
<Response>
  <Say voice="man">Kilroy was here</Say>
</Response>

The upside-down, piecemeal, verbose way:

my $say = new WWW::Twilio::TwiML;
$say->name('Say');
$say->content("Kilroy was here");
$say->attributes({voice => "man"});

my $resp = new WWW::Twilio::TwiML;
$resp->name('Response');
$resp->content($say);

my $tw = new WWW::Twilio::TwiML;
$tw->content($resp);
print $tw->to_string;

The same thing, with a little more powerful constructor:

my $say = new WWW::Twilio::TwiML(name => 'Say',
                                 content => "Kilroy was here",
                                 attributes => {voice => "man"});

my $tw = new WWW::Twilio::TwiML;
$tw->Response->add_child($say);
print $tw->to_string;

The concise way:

my $tw = new WWW::Twilio::TwiML;
$tw->Response->Say({voice => "man"}, "Kilroy was here");
print $tw->to_string;

And the obligatory one-liner (spread across 4 lines for readability):

print WWW::Twilio::TwiML->new
  ->Response
  ->Say({voice => "man"}, "Kilroy was here")
  ->root->to_string;

What you don't see in the latter two examples is that both Response and Say create and return objects with the names Response and Say respectively. When you call them this way, methods can chain, so you get compact but still readable expressions. πŸ’–

🌟 Any TwiML Verb( string | { attributes } ) 🌟

Constructor shortcuts! TwiML verbs are described at <http://www.twilio.com/docs/api/twiml>. Some examples include Response, Say, Play, Gather, Record, Sms, Dial, Number, Client, Conference, Hangup, Redirect, Reject, and Pause (this list may be out of date with respect to the official documentation).

See Twilio's documentation for usage for these and other TwiML verbs.

The (any TwiML verb) shortcut is a constructor of a TwiML object. When you call (any TwiML verb) on an existing TwiML object, here's what happens:

  • A new object is created and named by the method you called. E.g., if you called:
$tw->Response;

a TwiML object named 'Response' will be created.

  • The newly created object is attached to its parent (the object called to create it).
  • The parent object has the new object added to its list of children.

Those last two items mean the objects are "chained" to each other. Chaining objects lets you write concise expressions that create TwiML documents. We could add another object to the chain:

$tw->Response
  ->Say("I'm calling you.")
    ->parent
  ->Dial("+17175558309");

The parent method returns the Say object's parent (Response object), and we chain a Dial object from it. The resulting $tw object returns:

<?xml version="1.0" encoding="UTF-8" ?>
<Response>
  <Say>I&apos;m calling you.</Say>
  <Dial>+17175558309</Dial>
</Response>

πŸ’œ name( string ) πŸ’œ

Gives a name to an element. This is what gets used when the element is printed out. If you're generally chaining objects, you won't use this method often. πŸ™ˆ

$elem->name('Dial');
$elem->content("+1234567890");

becomes:

<Dial>+1234567890</Dial>

When no string is supplied, the name of the object is returned.

print $elem->name . "\n";

The element name may also be given with new, or it's implicit when you call the constructor by the name of the element you want to create. ✨

πŸ“ content( string | object ) πŸ“

Sets the content of an element. A TwiML object's content can be either a string or a listref of objects, but not both. If the argument is another WWW::Twilio::TwiML object, the content of the element (if any) will be replaced with the object. Any other argument gets treated as string content. πŸ’…

my $say = new WWW::Twilio::TwiML(name => 'Say');
$say->content("Eat at Joe's!");  ## a string as content

becomes:

<Say>Eat at Joe&apos;s!</Say>

Now we can add $say to another element:

my $parent = new WWW::Twilio::TwiML(name => 'Response');
$parent->content($say);  ## an object as content

which becomes:

<Response>
  <Say>Eat at Joe&apos;s!</Say>
</Response>

When no argument is supplied, the existing contents are returned.

my $content = $elem->content;
if( ref($content) ) {
  for my $obj ( @$content ) {
    ## do something with each $obj
  }
}

else {
  print $content . "\n";  ## assuming a string here
}

πŸŽ€ add_child( object ) πŸŽ€

Adds an element to the content of the TwiML object. Returns a reference to the added object. Unlike content, add_child does not replace the existing content β€” it appends an object to the existing content. Also unlike content, add_child is not appropriate to use for setting text content of an element. 🫢

my $tw = new WWW::Twilio::TwiML;
my $resp = $tw->Response;
$resp->add_child(new WWW::Twilio::TwiML(name => 'Say',
                                        content => 'Soooey!'));

my $email = uri_escape('biff@example.com');
my $msg = uri_escape("Heeer piiiig!");
my $url = "http://twimlets.com/voicemail?Email=$email&Message=$msg";
$resp->add_child(new WWW::Twilio::TwiML(name => 'Redirect',
                                        content => $url));

print $tw->to_string({'Content-type' => 'text/xml'});

becomes:

Content-type: text/xml

<?xml version="1.0" encoding="UTF-8" ?>
<Response>
  <Say>Soooey!</Say>
  <Redirect>http://twimlets.com/voicemail?Email=\
  biff%40example.com&amp;Message=Heeer%20piiiig!</Redirect>
</Response>

🌈 attributes({ key => value }) 🌈

Sets attributes for an element. If a hash reference is not supplied, a hashref of the existing attributes is returned. πŸ’–

my $elem = new WWW::Twilio::TwiML(name => 'Say');
$elem->attributes({voice => 'woman'});
$elem->content("gimme another donut");

becomes:

<Say voice="woman">gimme another donut</Say>

πŸ‘‘ root πŸ‘‘

Returns a handle to the root object. 🫢

print WWW::Twilio::TwiML->new
  ->Response
  ->Say("All men are brothers,")
    ->parent
  ->Say("Like Jacob and Esau.")
  ->root->to_string;

prints:

<?xml version="1.0" encoding="UTF-8" ?>
<Response>
  <Say>All men are brothers,</Say>
  <Say>Like Jacob and Esau.</Say>
</Response>

root is a convenient way to get a handle to the root TwiML object when you're ready to print. ✨

🧚 to_string( { header => value } ) 🧚

Returns the object as a string. Unnamed (root) elements will include the XML declaration entity. If a hashref is supplied, those will be emitted as RFC 822 headers followed by a blank line. πŸ’…

Example:

print WWW::Twilio::TwiML->new->to_string;

prints:

<?xml version="1.0" encoding="UTF-8" ?>

while this:

print WWW::Twilio::TwiML->new
  ->Response
  ->Say("plugh")
  ->root->to_string;

prints:

<?xml version="1.0" encoding="UTF-8" ?>
<Response>
  <Say>plugh</Say>
</Response>

If we forget the call to root in the previous example, like this:

print WWW::Twilio::TwiML->new
  ->Response
  ->Say("plugh")
  ->to_string;

we get:

<Say>plugh</Say>

because to_string is being applied to the object created by Say, not $tw. 😭

By specifying a hashref, you can add RFC 822 headers to your documents:

$tw = new WWW::Twilio::TwiML;
$tw->Response->Say('Arf!');
$tw->to_string({'Content-type' => 'text/xml'});

which returns:

Content-type: text/xml

<?xml version="1.0" encoding="UTF-8" ?>
<Response>
  <Say>Arf!</Say>
</Response>

πŸ¦‹ parent( object ) πŸ¦‹

Sets the parent of the object; this gets done automatically by add_child and content. When no arguments are given, the existing parent object is returned. πŸ’œ

Because WWW::Twilio::TwiML objects chain, parent is useful for getting the previous object so you can add more content to it:

WWW::Twilio::TwiML->new
  ->Response
  ->Gather({action => "/process_gather.cgi", method => "GET"})
    ->Say("Please enter your account number.")
      ->parent  ## Say's parent, Gather
    ->parent    ## Gather's parent, Response
  ->Say("We didn't receive any input. Goodbye!");

becomes:

<Response>
  <Gather action="/process_gather.cgi" method="GET">
    <Say>Please enter your account number.</Say>
  </Gather>
  <Say>We didn't receive any input. Goodbye!</Say>
</Response>

A note on readability: the author recommends indenting multi-line chains to show the parent-child relationship. Each time parent is invoked, the next line should be outdented, as illustrated above. 🌸

πŸŽ€ PACKAGE VARIABLES

okay so you can totally steer how WWW::Twilio::TwiML behaves in a couple of ways, and it's all done by setting package variables. They're all described right here, bestie. ✨

Newlines

you can change the default newline from "\n" to literally anything else by setting the $NL package variable. it's giving customizable:

local $WWW::Twilio::TwiML::NL = "\r\n";

Strict mode

so here's the tea πŸ«– β€” WWW:Twilio::TwiML can generate well-formed but invalid TwiML documents. like, it looks fine but it's lowkey wrong. WWW::Twilio::TwiML uses autoloaded methods to figure out the name of TwiML elements (Response, Say, Dial, Redirect, etc.); which means if you typo a method name, your TwiML is gonna be incorrect:

$tw->Response->Saay('plugh');

Saay is not a valid Twilio TwiML tag, and you will not know it until Twilio's TwiML parser attempts to handle your TwiML document. 😭 brutal, i know.

but!! you can enable strict checks on the TwiML elements at runtime by setting two package variables:

  • $STRICT β€” when true, WWW::Twilio::TwiML's autoloader will look up the unhandled method call in the %TAGS package variable (below). if the method name is not in that hash, the autoloader will die with an "Undefined subroutine" error.
  • %TAGS β€” empty by default. when $STRICT is true, this hash will be consulted to determine whether a method call is a valid TwiML tag or not.

for example:

local $WWW::Twilio::TwiML::STRICT = 1;
local %WWW::Twilio::TwiML::TAGS = (Response => 1, Say => 1, Dial => 1);

now any methods invoked on WWW::Twilio::TwiML objects that are not Response, Say, or Dial will die with an error. e.g.:

WWW::Twilio::TwiML->Response->Saay("Let's play Twister!");

generates the following fatal error:

Undefined subroutine Saay at line 1.

you may wish to use the fast hash creation with hash slices (the author learned this syntax from Damian Conway at a conference some years ago β€” it's faster than map over an array for building hashes). iconic tip ngl πŸ’…:

## TwiML verbs taken from http://www.twilio.com/docs/api/twiml
my @tags = qw(Response Say Play Gather Record Sms Dial Number
              Client Conference Hangup Redirect Reject Pause);

local @WWW::Twilio::TwiML::TAGS{@tags} = (1) x @tags;
local $WWW::Twilio::TwiML::STRICT = 1;

## all method calls in this scope are now strict
...

✨ EXAMPLES ✨

this section demonstrates a few things you can do with WWW::Twilio::TwiML. let's get into it. πŸ¦‹

Example 1

$t = new WWW::Twilio::TwiML;
$t->Response->Say({voice => "woman"}, "This is Jenny");
print $t->to_string({'Content-type' => 'text/xml'});

Output:

Content-type: text/xml

<?xml version="1.0" encoding="UTF-8" ?>
<Response>
  <Say voice="woman">This is Jenny</Say>
</Response>

Examples from twilio.com

the following examples are from twilio.com's TwiML documentation, listed by the primary verb they implement. assume a TwiML object $tw for each of these examples has already been created:

my $tw = new WWW::Twilio::TwiML;

and consequently each example would be printed with:

print $tw->to_string;

see the t/twilio.t test file distributed with this package for additional context for these examples. πŸ‘‘

Say

$tw->Response
  ->Say({voice => "woman", loop => "2"}, "Hello");

Play

$tw->Response
  ->Play("http://foo.com/cowbell.mp3");

Gather

$tw->Response
  ->Gather({action => "/process_gather.cgi", method => "GET"})
    ->Say("Enter something, or not")
      ->parent
    ->parent
  ->Redirect({method => "GET"}, "/process_gather.cgi?Digits=TIMEOUT");

Record

$tw->Response
  ->Say("Please leave a message at the beep. \
         Press the star key when finished.")
    ->parent
  ->Record({action => "http://foo.edu/handleRecording.cgi",
            method => "GET",
            maxLength => "20",
            finishOnKey => "*"});
    ->parent
  ->Say("I did not receive a recording");

Sms

$tw->Response
  ->Say("Our store is located at 123 East St.")
    ->parent
  ->Sms({action => "/smsHandler.cgi", method => "POST"},
        "Store location: 123 East St.");

Dial

$tw->Response
  ->Dial
    ->Number("858-987-6543")->parent
    ->Number("415-123-4567")->parent
    ->Number("619-765-4321");

Conference

$tw->Response
  ->Dial
    ->Conference({startConferenceOnEnter => "true",
                  endConferenceOnExit => "true"},
                 "1234");

Hangup

$tw->Response->Hangup;

Redirect

$tw->Response
  ->Dial("415-123-4567")->parent
  ->Redirect("http://www.foo.com/nextInstructions");

Reject

$tw->Response
  ->Reject({reason => "busy"});

Pause

$tw->Response
  ->Pause({length => 5})->parent
  ->Say("Hi there.");

Other examples

other examples may be found in the t directory that came with this package, also available on CPAN. 🧚


🌈 COMPATIBILITY

WWW::Twilio::TwiML will likely be forward compatible with all future revisions of Twilio's TwiML language. why? because method calls are constructors which generate TwiML objects on the fly. it just works. periodt.

like, for example, say Twilio began to support a Belch verb (if only!), we could take advantage of it immediately by simply calling a Belch method like this:

my $tw = new WWW::Twilio::TwiML;
$tw->Response->Belch('Braaaaaap!');
print $tw->to_string;

because there is no Belch method, WWW::Twilio::TwiML assumes you want to create a node by that name and makes one for you:

<?xml version="1.0" encoding="UTF-8" ?>
<Response>
  <Belch>Braaaaaap!</Belch>
</Response>

if the $STRICT package variable is enabled, all we need to do is add Belch to our %TAGS hash and we're good to go. 🫢


πŸ‘€ SEE ALSO

  • WWW::Twilio::API

πŸ’– AUTHOR

Scott Wiersdorf, <scott@perlcode.org>


Copyright (C) 2011 by Scott Wiersdorf

this library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.1 or, at your option, any later version of Perl 5 you may have available.


and that's the whole page, bestie! πŸ¦‹ this one's perl v5.32.1, dated 2022-01-21, and it's the WWW::Twilio::TwiML(3) manpage β€” go forth and generate some absolutely iconic TwiML. slay πŸ’…βœ¨

πŸ“¦ where this page comes from