.\" Automatically generated by Pod::Man 2.27 (Pod::Simple 3.28) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is turned on, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{ . if \nF \{ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "Poet::Manual::Intro 3pm" .TH Poet::Manual::Intro 3pm "2014-02-26" "perl v5.18.2" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" Poet::Manual::Intro \- A gentle introduction to Poet .SH "WHAT IS POET?" .IX Header "WHAT IS POET?" Poet is a modern Perl web framework for Mason developers. It uses \&\s-1PSGI\s0/Plack for server integration, Mason for request routing and templating, and a selection of best-of-breed \s-1CPAN\s0 modules for caching, logging and configuration. .SH "INSTALLATION" .IX Header "INSTALLATION" If you don't yet have cpanminus (\f(CW\*(C`cpanm\*(C'\fR), get it here . Then run .PP .Vb 1 \& cpanm \-S \-\-notest Poet .Ve .PP Omit the \*(L"\-S\*(R" if you don't have root, in which case cpanminus will install Poet and prereqs into \f(CW\*(C`~/perl5\*(C'\fR. .PP Omit the \*(L"\-\-notest\*(R" if you want to run all the installation tests. Note that this will take about four times as long. .SH "SETUP" .IX Header "SETUP" You should now have a \f(CW\*(C`poet\*(C'\fR app installed: .PP .Vb 2 \& % which poet \& /usr/local/bin/poet .Ve .PP Run this to create your initial environment: .PP .Vb 6 \& % poet new MyApp \& my_app/.poet_root \& my_app/bin/app.psgi \& my_app/bin/get.pl \& ... \& Now run \*(Aqmy_app/bin/run.pl\*(Aq to start your server. .Ve .PP The app name must be a valid Perl class name, generally either \f(CW\*(C`CamelCase\*(C'\fR (\f(CW\*(C`MyApp\*(C'\fR) or an all-uppercase acronym (\f(CW\*(C`TLA\*(C'\fR). The directory, if not specified with \-d, will be formed from the app name, but lowercased and underscored. .SH "ENVIRONMENT" .IX Header "ENVIRONMENT" In Poet, your entire web site lives within a single directory hierarchy called the \fIenvironment\fR. It contains subdirectories for configuration, libraries, Mason components (templates), static files, etc. .PP Here are the subdirectories that are generated for you. If you don't need some of these directories, feel free to delete them. The only ones really required by Poet are \f(CW\*(C`conf\*(C'\fR, \f(CW\*(C`comps\*(C'\fR and \f(CW\*(C`lib\*(C'\fR. .IP "\(bu" 4 \&\f(CW\*(C`bin\*(C'\fR \- executable scripts .IP "\(bu" 4 \&\f(CW\*(C`comps\*(C'\fR \- Mason components (templates) .IP "\(bu" 4 \&\f(CW\*(C`conf\*(C'\fR \- configuration files .IP "\(bu" 4 \&\f(CW\*(C`data\*(C'\fR \- data not checked into version control, such as cache and object files .IP "\(bu" 4 \&\f(CW\*(C`db\*(C'\fR \- database related files such as your schema .IP "\(bu" 4 \&\f(CW\*(C`lib\*(C'\fR \- app-specific libraries and Poet subclasses .IP "\(bu" 4 \&\f(CW\*(C`logs\*(C'\fR \- logs from web server and from explicit logging statements .IP "\(bu" 4 \&\f(CW\*(C`static\*(C'\fR \- static web files \- css, images, js .IP "\(bu" 4 \&\f(CW\*(C`t\*(C'\fR \- unit tests .SS "Initializing Poet" .IX Subsection "Initializing Poet" Any web server or script must initialize Poet before it can use any of Poet's features. This is accomplished by with \f(CW\*(C`Poet::Script\*(C'\fR: .PP .Vb 2 \& #!/usr/local/bin/perl \& use Poet::Script qw($conf $poet); .Ve .PP You'll see this in \f(CW\*(C`bin/run.pl\*(C'\fR, for example, the script you use to start your webserver. The \f(CW\*(C`use Poet::Script\*(C'\fR line does several things: .IP "\(bu" 4 Searches upwards from the script for the environment root (as marked by the \&\f(CW\*(C`.poet_root\*(C'\fR file). .IP "\(bu" 4 Reads and parses your configuration. .IP "\(bu" 4 Unshifts onto \f(CW@INC\fR the lib/ subdirectory of your environment, so that you can \&\f(CW\*(C`use\*(C'\fR your application modules. .IP "\(bu" 4 Imports the specified \fIquick vars\fR \- in this case \f(CW$conf\fR and \f(CW$poet\fR \- as well as some default utilities into the script namespace. More information about these below. .SS "Relocatable environments" .IX Subsection "Relocatable environments" Ideally your environment will be \fIrelocatable\fR \*(-- if you move your environment to a different root, or checkout a second copy of it in a different root, things should just work. .PP To achieve this you should never refer to exact environment directory paths in your code; instead you'll call Poet methods that return them. e.g. instead of this: .PP .Vb 1 \& system("/path/to/environment/bin/myscript.pl"); .Ve .PP you'll do this: .PP .Vb 1 \& system($poet\->bin_path("myscript.pl")); .Ve .PP (More information about this \f(CW$poet\fR variable below.) .SS "App name" .IX Subsection "App name" Your app name, e.g. \f(CW\*(C`MyApp\*(C'\fR, is where you are expected to put app-specific subclasses. For example if you have a DBIx::Class schema, you'd create it under \f(CW\*(C`MyApp::Schema\*(C'\fR in the file \f(CW\*(C`lib/MyApp/Schema.pm\*(C'\fR. .PP The app name is also where Poet will look for subclasses of its own classes. .SH "CONFIGURATION AND LAYERS" .IX Header "CONFIGURATION AND LAYERS" Poet configuration files are kept in the \f(CW\*(C`conf\*(C'\fR subdirectory. The files are in \&\s-1YAML\s0 form and are merged in a particular order to create a single configuration hash. (If you want to use something other than \&\s-1YAML\s0 you can customize this.) .PP Configuration files come in three varieties: \f(CW\*(C`global\*(C'\fR, \f(CW\*(C`layer\*(C'\fR, and \f(CW\*(C`local\*(C'\fR, in order from least to highest precedence. .IP "Global" 4 .IX Item "Global" \&\fIGlobal\fR configuration applies to all instances of your environment, and is typically checked into version control. .Sp Your generated environment includes a \f(CW\*(C`conf/global.cfg\*(C'\fR. This is simplest to start out with, but as a site scales in size and number of developers, you can split out your global configuration into multiple files in \&\f(CW\*(C`conf/global/*.cfg\*(C'\fR. .IP "Layer" 4 .IX Item "Layer" \&\fILayers\fR allow you to have different configuration for different contexts. With all but the simplest site you'll have at least two layers: \fIdevelopment\fR (the internal environment where you develop) and \fIproduction\fR (the live site). Later on, you might want a \fIstaging\fR environment (which looks like production except for a different data source, etc.). .Sp In general you can have as many layers as you like. Each layer has a corresponding configuration file in \f(CW\*(C`conf/layer/*.cfg\*(C'\fR; only one layer file will be loaded per environment. We recommend that these files all be checked into version control as well, so that changes to each layer are tracked. .Sp Note: \fIlayer\fR is analagous to Plack's \fIenvironment\fR concept. And in fact, \&\f(CW\*(C`bin/run.pl\*(C'\fR passes the layer to plackup's <\-E> option. .IP "Local" 4 .IX Item "Local" \&\f(CW\*(C`conf/local.cfg\*(C'\fR contains configuration local to this specific environment instance. This is where the current layer must be defined. It is also the only configuration file that must exist, and the only one that should \fInot\fR be checked into version control. .Sp You can also specify an extra local file via \f(CW$ENV{POET_EXTRA_CONF_FILE}\fR. .PP There are a variety of ways to access configuration: .PP .Vb 2 \& my $value = $conf\->get(\*(Aqkey\*(Aq, \*(Aqdefault\*(Aq); \& my $value = $conf\->get_or_die(\*(Aqkey\*(Aq); \& \& my $listref = $conf\->get_list(\*(Aqkey\*(Aq, [\*(Aqdefault\*(Aq]); \& my $hashref = $conf\->get_hash(\*(Aqkey\*(Aq, {\*(Aqdefault\*(Aq => 5}); \& my $bool = $conf\->get_boolean(\*(Aqkey\*(Aq); .Ve .PP See below for more information about this \f(CW$conf\fR variable, and see Poet::Conf for more information on specifying and accessing configuration. .SS "Development versus live mode" .IX Subsection "Development versus live mode" Although you may have as many layers as you like, Poet also maintains a more limited binary notion of \fIdevelopment mode\fR versus \fIlive mode\fR. By default, you're in development mode iff layer equals 'development', and in live mode otherwise. .PP You can use these boolean methods to determine which mode you're in at runtime: .PP .Vb 2 \& $conf\->is_development \& $conf\->is_live .Ve .PP These are mutually exclusive (exactly one is always true). .PP Poet uses development/live mode to determine things like .IP "\(bu" 4 whether to turn on automatic server restarting .IP "\(bu" 4 whether to display errors in the browser .IP "\(bu" 4 whether to enable debugging utilities .PP You can customize how mode is determined by subclassing Poet::Conf. .SH "SERVER RUNNER AND MIDDLEWARE" .IX Header "SERVER RUNNER AND MIDDLEWARE" \&\f(CW\*(C`poet new\*(C'\fR generates \f(CW\*(C`bin/run.pl\*(C'\fR and \f(CW\*(C`bin/app.psgi\*(C'\fR for you. .PP \&\f(CW\*(C`bin/run.pl\*(C'\fR is a wrapper around plackup, which starts your server. It has a few sensible defaults, such as setting up autorestart in development mode and using an access log in live mode. It will also take a few options from configuration, e.g. .PP .Vb 3 \& server: \& host: 127.0.0.1 \& port: 5000 .Ve .PP If you are using something other than plackup (e.g. Server::Starter) then you'll have to adapt this into your own startup script. .PP \&\f(CW\*(C`bin/app.psgi\*(C'\fR defines your \s-1PSGI\s0 app. It's the place to add Plack middleware, or change the configuration of the default middleware. For example, to enable basic authentication with an \&\f(CW\*(C`conf/.htpasswd\*(C'\fR file, add this to app.psgi: .PP .Vb 1 \& enable "Auth::Htpasswd", file => $poet\->conf_path(\*(Aq.htpasswd\*(Aq); .Ve .SH "QUICK VARS AND UTILITIES" .IX Header "QUICK VARS AND UTILITIES" Poet makes it easy to import certain variables (known as \*(L"quick vars\*(R") and utility sets into any module or script in your environment. You've seen two examples of quick vars above: \f(CW$conf\fR, the global configuration variable, and \&\f(CW$poet\fR, the global environment object. .PP In a script, this looks like: .PP .Vb 2 \& #!/usr/local/bin/perl \& use Poet::Script qw($conf :file); .Ve .PP In a module, this looks like: .PP .Vb 2 \& package MyApp::Foo; \& use Poet qw($cache $poet); .Ve .PP And every Mason component automatically gets this on top: .PP .Vb 1 \& use Poet qw($conf $poet :web); .Ve .PP Debug utilities are automatically imported without having to specify a tag. .PP See Poet::Import for a complete list of quick vars and utility sets. .SH "HANDLING HTTP REQUESTS" .IX Header "HANDLING HTTP REQUESTS" \&\s-1HTTP\s0 requests are handled with \s-1PSGI\s0/Plack and Mason. .PP A persistent Mason interpreter is created at server startup, with component root set to the \f(CW\*(C`comps\*(C'\fR subdirectory. (See Poet::Mason for other default settings and how to configure them.) .PP When an \s-1HTTP\s0 request comes in, Poet .IP "\(bu" 4 Constructs a Poet::Plack::Request object from the plack environment. This is a thin subclass of Plack::Request and provides information such as the \s-1URL\s0 and incoming \s-1HTTP\s0 headers. It is made available in Mason components as \f(CW\*(C`$m\->req\*(C'\fR. .IP "\(bu" 4 Constructs an empty Poet::Plack::Response object. This is a thin subclass of Plack::Response, and you may use it to set things such as the \s-1HTTP\s0 status and headers. It is made available in Mason components as \f(CW\*(C`$m\->res\*(C'\fR. .IP "\(bu" 4 Calls \f(CW\*(C`$interp\->run\*(C'\fR with the \s-1URL\s0 and the \s-1GET/POST\s0 parameters. So for example, a \s-1URL\s0 like .Sp .Vb 1 \& /foo/bar?a=5&b=6 .Ve .Sp would result in .Sp .Vb 1 \& $interp\->run("/foo/bar", a=>5, b=>6); .Ve .Sp From there Mason will choose a component to dispatch to \- see Mason::Manual::RequestDispatch and Mason::Plugin::RouterSimple. .SS "Generating content with Mason" .IX Subsection "Generating content with Mason" Mason is a full-featured templating system and beyond our ability to summarize here. Recommended reading: .IP "\(bu" 4 Poet::Manual::Tutorial, especially starting here .IP "\(bu" 4 Mason::Manual::Components .IP "\(bu" 4 Mason::Manual::Syntax .SS "Success and failure results" .IX Subsection "Success and failure results" If the Mason request finishes successfully, the Mason output becomes the plack response body, the status code is set to 200 if it hasn't already been set, and the content type is set to \f(CW\*(C`text/html\*(C'\fR (or the specified default content type) if it hasn't already been set. .PP If the top-level component path cannot be found, the status code is set to 404. .PP If any other kind of runtime error occurs in development mode, it will be nicely displayed in the browser via StackTrace middleware. Outside of development it will be logged and sent as a 500 error response. .PP You can call \f(CW\*(C`$m\->redirect\*(C'\fR and \f(CW\*(C`$m\->not_found\*(C'\fR to generate redirect and not_found results from a component. These are documented in Poet::Mason. .SS "Multiple values for parameters" .IX Subsection "Multiple values for parameters" If there are multiple values for a \s-1GET\s0 or \s-1POST\s0 parameter, generally only the last value will be kept, as per Hash::MultiValue. However, if the corresponding attribute in the page component is declared an \&\f(CW\*(C`ArrayRef\*(C'\fR, then all values will be kept and passed in as an arrayref. For example, if the page component \f(CW\*(C`/foo/bar.mc\*(C'\fR has these declarations: .PP .Vb 6 \& <%class> \& has \*(Aqa\*(Aq; \& has \*(Aqb\*(Aq => (isa => "Int"); \& has \*(Aqc\*(Aq => (isa => "ArrayRef"); \& has \*(Aqd\*(Aq => (isa => "ArrayRef[Int]"); \& .Ve .PP then this \s-1URL\s0 .PP .Vb 1 \& /foo/bar?a=1&a=2&b=3&b=4&c=5&c=6&d=7&d=8 .Ve .PP would result in .PP .Vb 1 \& $interp\->run("/foo/bar", a=>2, b=>4, c=>[5,6], d => [7,8]); .Ve .PP You can always get the original Hash::MultiValue object from \f(CW\*(C`$m\->request_args\*(C'\fR. e.g. .PP .Vb 3 \& my $hmv = $m\->request_args; \& # get all values for \*(Aqe\*(Aq \& $hmv\->get_all(\*(Aqe\*(Aq); .Ve .SH "LOGGING" .IX Header "LOGGING" Poet uses the Log::Log4perl engine for logging, but with a much simpler configuration for the common cases. (If you want to use something other than Log4perl you can customize this.) .PP Once you have a \f(CW$log\fR variable, logging looks like: .PP .Vb 1 \& $log\->error("an error occurred"); \& \& $log\->debugf("arguments are: %s", \e@_) \& if $log\->is_debug(); .Ve .PP By default, all logs go to \f(CW\*(C`logs/poet.log\*(C'\fR with a reasonable set of metadata such as timestamp. .PP See Poet::Log for more information. .SH "CACHING" .IX Header "CACHING" Poet uses \s-1CHI\s0 for caching, providing access to a wide variety of cache backends (memory, files, memcached, etc.) You can configure caching differently for different namespaces. .PP Once you have a \f(CW$cache\fR variable, caching looks like: .PP .Vb 5 \& my $customer = $cache\->get($name); \& if ( !defined $customer ) { \& $customer = get_customer_from_db($name); \& $cache\->set( $name, $customer, "10 minutes" ); \& } .Ve .PP or .PP .Vb 3 \& my $customer2 = $cache\->compute($name2, "10 minutes", sub { \& get_customer_from_db($name2) \& }); .Ve .PP By default, everything is cached in files under \f(CW\*(C`data/chi\*(C'\fR. .PP See Poet::Cache for more information. .SH "SEE ALSO" .IX Header "SEE ALSO" Poet .SH "AUTHOR" .IX Header "AUTHOR" Jonathan Swartz .SH "COPYRIGHT AND LICENSE" .IX Header "COPYRIGHT AND LICENSE" This software is copyright (c) 2012 by Jonathan Swartz. .PP This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.