Papercraft

Introduction

Overview

Getting Started

Community

Basic Usage

Writing Templates

Rendering Templates

HTML Elements

Built-in Methods

Template Composition

Component Templates

Working with Layouts

Advanced Usage

Deferred Rendering

Extending Papercraft

Papercraft Internals

How Papercraft Works

Writing Templates

Papercraft templates are expressed as Ruby lambdas. Ruby lambdas are simply anonymous functions, and use the following syntax:

->(...) { ... }

A lambda is defined by using the arrow operator -> followed by optional arguments, and finally a body inside curly brackets { }.

Template Arguments

A lambda can take 0 or more arguments. You can define lambda arguments just like you would in a Ruby method:

# no arguments:
-> { }

# positional arguments:
->(foo, bar) { }

# keyword arguments:
->(foo:, bar:) { }

# mix of positional and keyword arguments:
->(foo, bar, baz:) { }

# default values
->(foo, bar = 1, baz: 2) { }

# rest arguments
->(foo, bar, *rest) { }

# explicit block argument:
->(foo, &block) { }

The Template Body

The template body is simply a sequence of Ruby statements. HTML tags are emitted by making receiver-less method calls:

-> {
  h1 "Title"
  h2 "Sub-title"
  p "Some text"
}

You can express any kind of logic or loops inside your templates, right along your HTML tags:

->(items) {
  h1 "Title"
  if items
    ul {
      items.each {
        li it.title
      }
    }
  end
}

Template Constants

Since Ruby lambdas are merely expressions, you’d want to assign them to a constant in order to be able to reference them later:

# assign to a constant:
Foo = -> { h1 "Hi" }

As you’ll see further on, assigning templates to constants allows us to use them as sub-templates, or components, inside other templates.

Templates as Pure Functions

While Ruby lambdas can also act as closures (that is, capturing the local binding along with the local variables and any instance variables,) Papercraft encourages passing all dynamic data used inside the template as explicit arguments. So, by convention, you should avoid using any local variables defined outside the template or any instance variables inside your templates, and instead define them as arguments:

# instead of this:
foo = "foo"
-> { h1 foo }.render

# do this:
->(foo) { h1 foo }.render("foo")