The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Bigtop::Docs::Syntax - An introduction to Bigtop syntax description

Intro

This document explains the basic structure of a bigtop file.

Note that you might find Bigtop::Docs::Cookbook useful depending on the complexity of your questions and how you like to use docs. For a full list of Bigtop keywords, see Bigtop::Docs::FullKeywords. A shorter version is available in Bigtop::Docs::QuickKeywords. To know what each backend does, and how to configure them, see Bigtop::Docs::AutoBackends. All of those, except the cookbook, are generated from the official source of Bigtop keywords (Bigtop::Keywords) and so are up to date.

Other docs are available, including docs on tentmaker. See Bigtop::Docs::TOC for a complete list of documentation.

Anatomy of a Bigtop File

Bigtop files are designed to be easy to write and to read (by you and the computer). There is a basic structure based on brace delimited blocks, but it's not complicated like a programming language. It's a descriptive language. There is no flow of control. That means that you can put things in whatever order you like, except that config comes first and some recipients of the generated files may care about order. For instance, your command line SQL tool probably expects to see the definition for a table before it sees any foreign keys pointing to that table. These orderings are usually fairly intuitive, especially when that other program complains about missing definitions, etc. (Further, if you use "Kickstart Syntax", Bigtop will adjust the order to account for foreign keys.)

The following skeleton is the smallest legal bigtop file which describes almost nothing (and will do nothing if you feed it to bigtop):

    config {}
    app App::Name {}

config Section

At the top level there are two sections in a Bigtop file. The order is enforced. First comes config. It lists things that make the output specific. In it, there are statements and backend blocks. Each statement can take exactly one value. If there are any characters that Perl wouldn't like in an identifier, enclose the value in back ticks, a.k.a. backquotes, (the quote usually found under tilde, not the ones on the same key with double quotes).

The available config statements are described briefly in Bigtop::Docs::QuickKeywords and in more detail in Bigtop::Docs::FullKeywords. There are two keywords which have been deprecated and so do not appear there. These are sometimes useful for testing, so I've described them here:

base_dir

Deprecated.

Optional, defaults to the current directory. Ignored with a warning except in create mode.

A path to where the app will be built. Enclose paths in backquotes. Example:

    base_dir `/home/phil/play`;
app_dir

Deprecated.

Optional, defaults to the h2xs style directory name for your app. Ignored with a warning except in create mode.

A path relative to base_dir where Build.PL, Changes, README, etc. will live. For example, if your app block looks like this:

    app MyNS::Apps::Name

the default will be MyNS-Apps-Name under the base_dir. If you wanted extra nesting you could say:

    app_dir `MyNS/Apps/Name`;

then bigtop would make those intervening directories for you.

In addition to these hard coded keys, there are backend blocks which depend on what Bigtop:: modules you have installed. These typically generate files on the disk, which could be Perl modules, httpd.confs, etc.

The system is simplistic and best described by an example. Suppose you list

    SomeType  SomeBackend {}

in the config section. Bigtop will assume the following (yes, I know how dangerous assumptions can be):

  • You have a package called Bigtop::Backend::SomeType::SomeBackend, defined in the usual way, which is installed on your system. (i.e. There is a file called SomeBackend.pm which defines the package Bigtop::Backend::SomeType::SomeBackend, which lives in the path Bigtop/Backend/SomeType/SomeBackend.pm, relative to an @INC member.)

  • That package has a method called gen_SomeType which does whatever backends of this type should do (it might make .pm files, .conf files, .sql files etc.). This allows bigtop to call gen_SomeType when the user types:

        bigtop file.bigtop SomeType

The distribution comes with a number of these Bigtop::Backends. [ See Bigtop::Docs::AuotBackends for a list. ] If you write a useful one, please send it in so we can include it in a future release. For advice on writing one, see Bigtop::Docs::Modules.

As a user, you can mark a file as not to be generated by saying:

    SomeType SomeBackend { no_gen 1; }

This serves as a reminder that you generated SomeType in the past, but have messed with the result (even though you were probably warned not to). But, more importantly, it allows SomeBackend to register the keywords it handles, so their absence doesn't generate parse errors.

Most backends also honor the template statement. If you say:

    SomeType SomeModule { template my_template.tt; }

Bigtop::Backend::SomeType::SomeModule will use my_template.tt instead of the one hard coded inside it. Note that the template must be directly usable by Template Toolit. Further, it needs to define the same blocks as the backend's normal template. It's usually best to start by copying the template from the here doc in backend into a file, then modify it.

That is all there is to the config section. A typical one looks like this:

    config {
        # engine          MP13;
        engine          MP20;
        template_engine TT;
        Init            Std             {}
        SQL             Postgres        {}
        Control         Gantry          {}
        Model           GantryDBIxClass {}
    }

Note that one engine statement is commented out. A comment is any line whose first non-whitespace character is a pound sign.

app Section

The app section is far more interesting than the config section. This is where you describe the data in your application and how you want the user to view and manipulate it. This is the heart of the Bigtop file. Theoretically, you can completely recast the app (say by exchanging Postgres for mysql, Catalyst for Gantry, mod_perl 1.3 for mod_perl 2.0, etc.) without changing the app section. Whether you can do that in practice depends on whether there are backends for the system you want to move to (if you are interested in writing backends, see Bigtop::Docs::Modules for some pointers). Reality also impinges on this ideal. Some backends understand different keywords, because they work with different concepts.

In the app section, there are two key components:

Blocks

Most blocks look like this:

    block_type Name {
        ... statements or blocks
    }

Controller and method blocks are exceptions. These have a type property (the type is required for methods, but is optional for controllers):

    method name is stub { ... }

The legal values of this property are specified in the Bigtop::Backend::Control:: backend you choose. See it's docs for a list of the types and what they mean, but the trivial type, stub, is always supported.

Statements

Some examples of statements:

    label          Description;
    label          `First Name`;
    header_options Add => `$site->location . q!/add!`;
    cols           first_name, last_name, age;

A statement is a legal keyword followed by a value and terminated with a semi-colon. Legal values are numbers, valid Perl idents (including colons), anything you enclose in backward quotes (see 'A Note About Quotes in Strings' if you need to embed quotes in strings), and comma separated lists of the above.

Note that we sometimes use => instead of comma, they mean substantially different things. Only use => when told to. Always use the => when told to. Here's the difference. In the grammar, comma is the separator for items in a list, while the fat comma (=>) forms a pair which becomes a single element in the list. If your backend is expecting two items and it gets one pair instead, it will be sorely confused. Likewise, if your backend is expecting a pair, but you give it two items separated by comma, it will be just as confused. This is different from the way Perl treats the fat comma. Remember: in Bigtop a fat comma makes a pair a comma never does.

Which keywords are legal depends on which backends you are using. Whether a particular keyword's value will work is up to the backend and to whatever program ends up receiving what the backend produced.

A Note About Quotes in Strings:

You can put whatever you like into backquoted strings (as long as you don't like backquotes). But if you put quotes in such strings, you may need to escape them in some way. For example, if the string is a label for html presentation, your backend will likely take your:

    label `Customer's Name`;

and make it something like:

    some_display_function('Customer's Name');

This will not work, since the generated Perl now has an extra single quote. Usually you avoid this by protecting the quote like this:

    label `Customer\'s Name';

This results in the correct final output:

    some_display_function('Customer\'s Name');

You must read the backend documentation to find out what will happen to the value you provide, but the above is typical.

In particular, if the statement's value is Perl code, you probably want to use q or qq operators for quoting instead of single or double quotes. Otherwise, tentmaker may become confused about your values, since it must embed them in Javascript enabled HTML.

[ Note for those who read tests as examples: In the tests you will see quotes protected by two backslashes. This is because the tests use here documents to build Bigtop input. The first backslash is eaten by the heredoc processor. Since you will supply input from file (at least most of the time), you should not need two backslashes. ]

The general structure of the app section is:

    app App::Name { }

In fact, that is a valid specification, but it doesn't do much (you could generate Init for such an app, but that would do slightly less than h2xs).

Inside the braces there are statements and blocks. Again, the statements are described in Bigtop::Docs::QuickKeywords and Bigtop::Docs::FullKeywords.

Currently there are five legal block types at the app level: sequence, config, table, join_table, and controller. These are described below.

There are also several literal statements which dump their string values directly to generated output files. See Bigtop::Docs::QuickKeywords or Bigtop::Docs::FullKeywords for a list of legal literal types and explanations of where their output goes.

sequence

(understood by Bigtop::Backend::SQL::*, Bigtop::Backend::Model::*, and some Bigtop::Backend::Control::* modules)

If you are going to generate default id's from sequences in PostgreSQL, use this to declare the sequence. Give the sequence a name and a block:

    sequence address_seq {}

Currently the block must be empty (but it might eventually allow you to specify things like starting value, increment, etc.).

config

(understood by Bigtop::Backend::Conf::*, Bigtop::Backend::HttpdConf::*, and Bigtop::Backend::CGI::*)

[ For historical reasons set_vars can be used as a synonym for config. That use is deprecated. ]

This allows you to dump config parameters into your Gantry::Conf instance config file, PerlSetVar statements into the root location for your app in your httpd.conf, or the equivalent in your CGI dispatching script or stand alone server. Simply list the name of a variable and its value in each statement (remember to use backquotes):

    config {
        dbconn `dbi:Pg:dbname=yourdb` => no_accessor;
        dbuser `some_user`            => no_accessor;

        smtp_host `smtp.example.com`;
    }

If you tag the statement with => no_accessor, the controller backend will skip making an accessor for the variable (thus assuming that your framework is handling it). It will also omit fishing the parameter from the config info into the site object in the controller's generated init method.

Note that all the backends which understand config blocks allow a gen_root statement in their backend block in the bigtop config section. It will manufacture a root parameter with a relative path to the generated html templates.

You can have multiple config blocks. One of them must have either no name (as shown above), or be called 'base'. The others can named with any valid Perl ident. A second config block might look like this:

    config prod {
        dbconn `dbi:Pg:dbname=proddb;host=ourdb.example.com`;
    }

This results in a second conf instance for Gantry::Conf and alternate files for other approaches (like two cgi scritps or two files ready for inclusion in httpd.conf).

All of the config values are inherited from the unnamed config block. Parameters defined in a named config block override or augment those inherited values.

table

(understood by Bigtop::Backend::SQL::*, Bigtop::Backend::Model::*, and Bigtop::Backend::Control::*)

The general structure of a table is:

    table name { }

Inside you can list either statements or field blocks.

    field name { }

The field block can contain only statements.

join_table

Join tables are used to connect two other tables in a many-to-many relationship. For example, a book can have multiple authors while an author can have multiple books. A joining table for this set-up has two foreign keys one to author and the other to book.

Join table blocks have statements and allow field blocks just as other tables do.

controller
    controller Control::Module [ is type ] { ... }

The type is optional and defaults to stub. Nothing special happens for stubs.

Controllers allow statements and literal statements. They also contain method and config blocks (see below).

There are four controller types:

AutoCRUD

(understood by Bigtop::Backend::Control::Gantry)

The Gantry Control backend puts Gantry::Plugins::AutoCRUD into your use list (so don't put it there yourself, or it will appear twice in the output).

CRUD

(understood by Bigtop::Backend::Control::Gantry)

Puts Gantry::Plugins::CRUD in your use list (so don't put it there yourself). Also generates a mass of code stubs to get you started with semi-automated CRUD. See "How do I use Gantry's CRUD?" in Gantry::Docs::FAQ for details.

stub

(understood by Bigtop::Backend::Control::*)

This has no effect and is provided solely for symmetry.

This is the default, so:

    controller MySpecialOne is stub {
    }

is exactly equivalent to

    controller MySpecialOne {
    }
base_controller

You may have one base_controller in your bigtop file. Use it if you want to include non-default things in the apps's base module. To replace the default behavior, you need at least this:

    controller is base_controller {
        method do_main is base_links {
            title `Your Choice`;
        }
        method site_links is links {}
    }

Once you do that, you should put any app level location or uses statement inside the block. You may not use rel_location inside a base controller, but most other statements will work as they would for any other controller. Further, there is no restriction on methods types in either base controllers or regular controllers.

It is unwise to include multiple base controllers, no error will be reported, but strange things will surely happen.

There are two blocks for controllers:

config

(part of the grammar understood by Bigtop::Backend::Conf::General, Bigtop::Backend::Control::Gantry and Bigtop::Backend::HttpdConf::Gantry)

[ For historical reasons set_vars can be used as a synonym for config. That use is deprecated. ]

This block works like the app level config block, but dumps its variables into the location for the controller. The same rules for named blocks apply. There must be an unnamed block (well, you could call it 'base'). Other blocks need names, and their names should match the app level named blocks (if there are any). Then parameters in the named blocks augment or override the ones in the base block.

method
    method name is type { ... }

What goes in the block is controlled by the type (and how the backend treats it). Everything in the block must be a statement.

AUTHOR

Phil Crow <crow.phil@gmail.com>