Skip to content

Repository files navigation

Bandoola

Build PDF documents from plain Ruby, styling elements with a Tailwind-inspired class vocabulary. No runtime dependencies.

class Invoice < Bandoola::View
  def view_template
    div(class: "p-8 bg-slate-100 rounded-lg") do
      text(class: "text-3xl font-bold") { "Bandoola" }
      text(class: "text-base text-slate-600 mt-2") { "PDFs, the Tailwind way." }
    end
  end
end

invoice = Invoice.new
invoice.render          # build the PDF (also returns the bytes)
invoice.write("out.pdf")

Installation

bundle add bandoola

Elements

Inside view_template you build a tree of elements. Each takes a class: (a space-separated string or an array of tokens) and, where it makes sense, a block.

  • div(class:) { … } — a block-level box that lays out the elements inside it.
  • text(class:) { "…" } — a run of text; the block returns the string. It wraps to its box width, and embedded newlines start new lines.
  • img(src:, class:) — an image; src is a path to an SVG or JPEG.

Elements flow like HTML blocks: each fills its container's width and stacks below the previous one, unless a width class makes it share a row (and reflow).

Styling

The class names follow Tailwind; see their docs for the full scales. What Bandoola understands today:

Concern Classes
Padding / margin p-4, px-2, pt-1, m-4, mx-2, …
Width / height w-32, w-1/2, w-full, h-16, h-1/2, h-full
Border width border-1border-16
Border radius rounded, rounded-smrounded-3xl, rounded-full
Background bg-cyan-100, bg-slate-800, bg-black, bg-white
Border color border-blue-600 (needs a border width to show)
Text color text-rose-500, text-white
Font family font-sans, font-serif, font-mono, font-<registered>
Font weight font-lightfont-black
Text size text-xstext-9xl

Sizes and spacing are points (1px ≈ 1pt). Notes:

  • div has no fill or border by default — add bg-*, border-*, or rounded-*.
  • Colors work on the full Tailwind palette plus black/white; a color with no shade (bg-cyan) uses 500.
  • A div's font-* family and weight are inherited by the text inside it; text size is set per text element.

Fonts

font-sans/serif/mono map to the standard PDF fonts (Helvetica, Times, Courier), which cover Western European text. Register a TrueType font for anything else:

class Doc < Bandoola::View
  register_font :gowun, "fonts/GowunDodum-Regular.ttf"
  # or per weight: register_font :gowun, regular: "…-Regular.ttf", bold: "…-Bold.ttf"

  def view_template
    text(class: "font-gowun") { "Räksmörgås · 안녕하세요" }
  end
end

Embedded fonts render any Unicode they have glyphs for (Identity-H encoding) and are subset to just the glyphs you use — a few KB rather than the whole file. Opt out with compact_fonts false if you'd rather keep the original glyph ids. You can register several fonts in one document and use whichever fits each script.

Headers, footers & pages

Define header and footer alongside view_template for content that repeats at the top and bottom of every page. When the body is taller than one page it splits automatically, and page_number / page_count are available inside the header and footer.

class Report < Bandoola::View
  def header = text(class: "font-bold mb-4") { "Quarterly Report" }
  def footer = text(class: "text-sm mt-4") { "Page #{page_number} of #{page_count}" }

  def view_template
    50.times { |i| div(class: "p-2 mb-2 border-1") { text { "Row #{i + 1}" } } }
  end
end

Give the header an mb-* (and the footer an mt-*, or use my-*) for some air between them and the body. Pages break between top-level elements — an element isn't split across a page boundary.

Page size

The default page is A4. Override the geometry per view:

class Wide < Bandoola::View
  def width  = 1190
  def height = 842
  def margin = 48
end

Command line

Render a file that defines a view straight to a PDF:

bundle exec bandoola doc.rb > doc.pdf

Development

bin/setup to install dependencies, rake test to run the tests, bin/console for a prompt. Running rake test also regenerates the inspectable example PDFs under tmp/pdf_samples/.

Status

Bandoola is pre-release and the API may shift. It is not a browser — there's no cascade, no flexbox, line breaking is greedy (no hyphenation or justification), and a class either does what's listed above or is ignored. I add things as I need them, so coverage is deliberately partial; PRs and issues that fill a gap are welcome.

License

Available as open source under the MIT License.

About

A nice way to render PDF files in Ruby

Resources

Stars

5 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages