Back to documentation
# PODNAME: Statocles::Help::Develop
# ABSTRACT: How Statocles works and how to write Statocles modules

=head1 DESCRIPTION

This is a high-level overview of how Statocles works: Which modules are responsible
for which tasks.

=head1 OVERVIEW

Statocles has a small workflow:

=over 4

=item *

User creates L<Documents|Statocles::Document>.

=item *

L<Stores|Statocles::Store> read and write documents.

=item *

L<Applications|Statocles::App> use Stores to read documents and create
L<Pages|Statocles::Page>.

=item *

L<Sites|Statocles::Site> collect a set of Applications.

=item *

Sites have a L<Themes|Statocles::Theme> that builds
L<Templates|Statocles::Template> that are given to Pages.

=item *

Finally, the Site writes the Page to a L<Deploy|Statocles::Deploy>.

=back

=head1 DOCUMENTS

A L<document|Statocles::Document> is the main content of the site. The user does
all the work with documents: adding, editing, and removing documents.

The default store reads documents in a Markdown format with a YAML header,
easily editable with any text editor. A sample document looks like:

    ---
    title: This is a title
    author: preaction
    ---
    # This is the markdown content

    This is a paragraph

The document format is described in the L<Statocles::Store> documentation
under L<Frontmatter Document Format|Statocles::Store/"Frontmatter
Document Format">.

=head1 STORES

A L<Statocles::Store> reads and writes documents and pages. The default store
reads documents in YAML and writes pages to a file, but stores could read
documents as JSON, or from a Mongo database, and write pages to a database, or
wherever you want!

=over 4

=item L<Statocles::Store>

Read documents from the filesystem.

=back

=head1 APPLICATIONS

An application is the module that will take the documents the user provides and
turn them into the pages that can be written out to the filesystem.

=over 4

=item L<Statocles::App::Basic>

Basic markdown documents are turned into pages with no special arrangement. Also
allows for collateral images and other files.

=item L<Statocles::App::Blog>

A simple blogging application.

=item L<Statocles::App::Static>

Static files, like images and other site collateral, are copied into the site
with no processing whatsoever.

=back

=head1 PAGES

A L<Statocles::Page> is collected information ready to be rendered into HTML
(or whatever). Statocles Applications generate pages from the documents that
the user provides. One document may generate multiple pages, and pages may have
multiple formats like HTML or RSS.

=over 4

=item L<Statocles::Page::Document>

This page renders a single document. This is used for the main page of a blog
post, for example.

=item L<Statocles::Page::List>

This page renders a list of other pages (not documents). This is used for index
pages and feed pages.

=item L<Statocles::Page::Plain>

This page adds a layout, but does not require a document. Good if you've already
got HTML.

=item L<Statocles::Page::File>

This page is used for non-rendered static files like images. No processing is
done.

=back

=head1 SITES

A L<Statocles::Site> manages a bunch of applications, writing and deploying the
resulting pages.

The site controls the entire workflow, reading pages from the applications and
writing them to the appropriate deploy.

=head1 THEMES

A L<Statocles::Theme> creates L<Statocles::Template> objects using L<Mojo::Template>.

If you want to use Template Toolkit or Text::Xslate, you would create a new
Theme class that provides a different Template object.

=head1 DEPLOYS

Deploying the site may involve a simple file copy, but it could also involve a
Git repository, an FTP site, or a database.

=over 4

=item L<Statocles::Deploy::File>

Copy the site's files to a given local path.

=item L<Statocles::Deploy::Git>

Copy the files to a git repository and push them out. This is how a Github Pages
site is deployed.

=back

=head1 PLUGINS

Plugins are used to add template functions and respond to events in the
Statocles workflow. For example, when a site is built, an event is fired
containing all the built pages. Then, the
L<Statocles::Plugin::LinkCheck> plugin can search all the pages for
broken links. For another example, the L<Statocles::Plugin::Highlight>
plugin adds the C<highlight> function to all the templates in the site.

Plugins consume the L<Statocles::Plugin role|Statocles::Plugin> and must
implement the C<register> method to add themselves where they need to be
added.

    # Statocles::Plugin::LinkCheck
    sub register {
        my ( $self, $site ) = @_;
        $site->on( build => sub { $self->check_pages( @_ ) } );
    }

    sub check_pages { ... }

When the C<build> event fires, the LinkCheck method C<check_pages> will be called,
with the event object given as the argument.

Plugins are added to the Site object's C<plugins> attribute:

    # site.yml
    site:
        class: Statocles::Site
        args:
            plugins:
                link_check:
                    $class: 'Statocles::Plugin::LinkCheck'

=head2 Event Handlers

Instead of making an entire Statocles::Plugin, we can respond only to
certain events using Beam::Wire's event handling API.

In this example, we're going to enable the same LinkCheck plugin as
above, but manually using a C<build> event handler:

    # site.yml
    site:
        class: Statocles::Site
        on:
            - build:
                $class: Statocles::Plugin::LinkCheck
                $sub: check_pages

=head1 ROLES

If you want to add some custom behavior to any of the site's objects, the
configuration file (L<made with Beam::Wire|Beam::Wire>) allows you to compose
one or more L<roles|Moo::Role> into the objects in your site.

    # lib/My/Readme.pm
    package My::Readme;

    use Moo::Role;
    around build => sub {
        my ( $orig, $self, @args ) = @_;

        # Call the original build method
        my @pages = $orig->$self( @args );

        # Add a readme file
        push @pages, Statocles::Page::Plain->new(
            path => '/README',
            content => 'Please read me!',
        );

        return @pages;
    };

    # site.yml
    site:
        class: Statocles::Site
        with: 'My::Readme'

Using roles can help change behaviors that are otherwise not available to
L<plugins|/PLUGINS>.