Add Nix flake for reproducible dev and CI/CD

- flake.nix pins the full toolchain (asciidoctor + pdf/epub3/diagram/
  mathematical, plantuml, graphviz, jre, vale, epubcheck) via bundlerEnv
- Gemfile/Gemfile.lock/gemset.nix lock the Ruby gems; work around the
  vendored mtex2MML cmake_minimum_required incompatibility
- 'nix build' produces book.pdf + book.epub; 'nix develop' gives a shell
  where all existing make targets work
- CI/CD workflows now install Nix and build/lint/validate through the flake
- devcontainer uses Nix; add .envrc for direnv; document in README

Co-authored-by: Shelley <shelley@exe.dev>
This commit is contained in:
Dunya Kirkali
2026-08-08 15:36:51 +00:00
committed by Dunya Kirkali
parent c0c95fdff5
commit 0f64b1133e
13 changed files with 822 additions and 31 deletions

View File

@@ -1,11 +1,19 @@
{ {
"image": "asciidoctor/docker-asciidoctor:latest", "image": "nixpkgs/devcontainer@sha256:423dabf2e17c6710bf9bb6160bf1c63be33c73672d31c884dcc47238f42f4eba",
"features": {
"ghcr.io/devcontainers/features/nix:1": {
"extraNixConfig": "experimental-features = nix-command flakes"
}
},
"onCreateCommand": "nix develop --command true",
"customizations": { "customizations": {
"vscode": { "vscode": {
"extensions": [ "extensions": [
"asciidoctor.asciidoctor-vscode", "asciidoctor.asciidoctor-vscode",
"ms-vscode.makefile-tools", "ms-vscode.makefile-tools",
"chrischinchilla.vale-vscode" "chrischinchilla.vale-vscode",
"jnoortheen.nix-ide",
"mkhl.direnv"
] ]
} }
} }

3
.envrc Normal file
View File

@@ -0,0 +1,3 @@
# Enable a reproducible dev environment with direnv + nix.
# Run `direnv allow` once; the flake dev shell then loads automatically.
use flake

View File

@@ -23,6 +23,7 @@ Odum
Peitgen Peitgen
Polina Polina
Rainforest Rainforest
rainforests
Romanesco Romanesco
Saupe Saupe
Slimbach Slimbach

View File

@@ -4,32 +4,22 @@ on:
workflow_dispatch: workflow_dispatch:
jobs: jobs:
pdf: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container:
image: asciidoctor/docker-asciidoctor
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Generate PDF - name: Install Nix
run: make output/book.pdf uses: cachix/install-nix-action@630ae543ea3a38a9a4166f03376c02c50f408342 # v31.11.0
- name: Build book (PDF + EPUB)
run: nix build .#book -L
- name: Archive PDF - name: Archive PDF
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: pdf name: pdf
path: output/book.pdf path: result/book.pdf
epub:
runs-on: ubuntu-latest
container:
image: asciidoctor/docker-asciidoctor
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Generate EPUB
run: make output/book.epub
- name: Archive EPUB - name: Archive EPUB
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: epub name: epub
path: output/book.epub path: result/book.epub

View File

@@ -12,17 +12,27 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Install Nix
uses: cachix/install-nix-action@630ae543ea3a38a9a4166f03376c02c50f408342 # v31.11.0
- name: Count words - name: Count words
run: make count run: nix develop --command make count
lint: lint:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Install Asciidoctor
run: sudo apt-get install -y asciidoctor
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Install Nix
uses: cachix/install-nix-action@630ae543ea3a38a9a4166f03376c02c50f408342 # v31.11.0
- name: Vale - name: Vale
uses: errata-ai/vale-action@reviewdog run: nix develop --command make lint
with: build:
files: source/ runs-on: ubuntu-latest
fail_on_error: true steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Nix
uses: cachix/install-nix-action@630ae543ea3a38a9a4166f03376c02c50f408342 # v31.11.0
- name: Build book (PDF + EPUB)
run: nix build .#book -L
- name: Validate EPUB
run: nix develop --command epubcheck result/book.epub

3
.gitignore vendored
View File

@@ -1,3 +1,6 @@
.DS_Store .DS_Store
.vscode .vscode
output/ output/
result
result-*
.direnv/

10
Gemfile Normal file
View File

@@ -0,0 +1,10 @@
source "https://rubygems.org"
gem "asciidoctor"
gem "asciidoctor-pdf"
gem "asciidoctor-epub3"
gem "asciidoctor-diagram"
gem "asciidoctor-mathematical"
gem "rouge"
gem "coderay"
gem "pygments.rb"

114
Gemfile.lock Normal file
View File

@@ -0,0 +1,114 @@
GEM
remote: https://rubygems.org/
specs:
Ascii85 (2.0.1)
addressable (2.9.0)
public_suffix (>= 2.0.2, < 8.0)
afm (1.0.0)
asciidoctor (2.0.26)
asciidoctor-diagram (3.2.1)
asciidoctor (>= 1.5.7, < 3.x)
rexml
asciidoctor-epub3 (2.3.0)
asciidoctor (~> 2.0)
gepub (~> 1.0.0)
mime-types (~> 3.0)
sass
asciidoctor-mathematical (0.3.5)
asciidoctor (~> 2.0)
asciimath (~> 2.0)
mathematical (~> 1.6.0)
asciidoctor-pdf (2.3.24)
asciidoctor (~> 2.0)
concurrent-ruby (~> 1.3)
matrix (~> 0.4)
prawn (~> 2.4.0)
prawn-icon (~> 3.0.0)
prawn-svg (~> 0.34.0)
prawn-table (~> 0.2.0)
prawn-templates (~> 0.1.0)
treetop (~> 1.6.0)
ttfunk (~> 1.7.0)
asciimath (2.0.6)
coderay (1.1.3)
concurrent-ruby (1.3.8)
css_parser (1.22.0)
addressable
ffi (1.17.4)
gepub (1.0.17)
nokogiri (>= 1.8.2, < 2.0)
rubyzip (> 1.1.1, < 2.4)
hashery (2.1.2)
logger (1.7.0)
mathematical (1.6.20)
ruby-enum (>= 0.4, < 2.0)
matrix (0.4.3)
mime-types (3.7.0)
logger
mime-types-data (~> 3.2025, >= 3.2025.0507)
mime-types-data (3.2026.0701)
mini_portile2 (2.8.9)
nokogiri (1.19.4)
mini_portile2 (~> 2.8.2)
racc (~> 1.4)
pdf-core (0.9.0)
pdf-reader (2.15.1)
Ascii85 (>= 1.0, < 3.0, != 2.0.0)
afm (>= 0.2.1, < 2)
hashery (~> 2.0)
ruby-rc4
ttfunk
polyglot (0.3.5)
prawn (2.4.0)
pdf-core (~> 0.9.0)
ttfunk (~> 1.7)
prawn-icon (3.0.0)
prawn (>= 1.1.0, < 3.0.0)
prawn-svg (0.34.2)
css_parser (~> 1.6)
matrix (~> 0.4.2)
prawn (>= 0.11.1, < 3)
rexml (~> 3.2)
prawn-table (0.2.2)
prawn (>= 1.3.0, < 3.0.0)
prawn-templates (0.1.2)
pdf-reader (~> 2.0)
prawn (~> 2.2)
public_suffix (7.0.5)
pygments.rb (5.0.0)
logger (~> 1.7)
racc (1.8.1)
rb-fsevent (0.11.2)
rb-inotify (0.11.1)
ffi (~> 1.0)
rexml (3.4.4)
rouge (5.1.0)
strscan (~> 3.1)
ruby-enum (1.1.0)
ruby-rc4 (0.1.5)
rubyzip (2.3.2)
sass (3.7.4)
sass-listen (~> 4.0.0)
sass-listen (4.0.0)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
strscan (3.1.8)
treetop (1.6.18)
polyglot (~> 0.3)
ttfunk (1.7.0)
PLATFORMS
ruby
DEPENDENCIES
asciidoctor
asciidoctor-diagram
asciidoctor-epub3
asciidoctor-mathematical
asciidoctor-pdf
coderay
pygments.rb
rouge
BUNDLED WITH
2.6.9

View File

@@ -1,8 +1,6 @@
SOURCE_FOLDER := source SOURCE_FOLDER := source
SHELL := /bin/bash SHELL := bash
.PHONY: all count clean lint
ASCIIDOC_FILES := $(wildcard $(SOURCE_FOLDER)/*.adoc) ASCIIDOC_FILES := $(wildcard $(SOURCE_FOLDER)/*.adoc)

View File

@@ -17,6 +17,7 @@ Contributions to Letterpress are welcome! If you have suggestions, improvements,
This Project makes use of the following tools: This Project makes use of the following tools:
- [Nix](https://nixos.org/) (flakes) for reproducible builds and dev environments
- [GNU Make](https://www.gnu.org/software/make/) - [GNU Make](https://www.gnu.org/software/make/)
- [Asciidoctor](https://asciidoctor.org/) - [Asciidoctor](https://asciidoctor.org/)
@@ -24,6 +25,7 @@ This Project makes use of the following tools:
Everything you need to get started is included in the package Everything you need to get started is included in the package
- Nix flake: Reproducible toolchain for local dev and CI/CD
- Devcontainers: Allows you to build your book locally - Devcontainers: Allows you to build your book locally
- GitHub Workflows: Allows you to build your book on GitHub CI - GitHub Workflows: Allows you to build your book on GitHub CI
@@ -32,8 +34,42 @@ Everything you need to get started is included in the package
- Content - Content
- Images - Images
## Development environment
Letterpress ships a [Nix flake](flake.nix) that pins the entire toolchain
(Asciidoctor, asciidoctor-pdf/epub3/diagram/mathematical, PlantUML, Graphviz,
a JRE, Vale and EPUBCheck). This is the same environment used in CI, so builds
are reproducible everywhere.
### Enter the dev shell
```bash
nix develop
```
This drops you into a shell with every tool on `PATH`, so all the `make`
commands below just work. If you use [direnv](https://direnv.net/), run
`direnv allow` once and the environment loads automatically.
### Build the book with Nix
You can build the book directly, without entering a shell, and get a `result`
symlink containing `book.pdf` and `book.epub`:
```bash
nix build # builds both PDF and EPUB into ./result
ls result/
```
Under the hood this runs the same `make` targets described below inside the
pinned environment.
## Commands ## Commands
The `make` commands below assume the toolchain is available. The easiest way to
get it is the Nix dev shell (`nix develop`); alternatively install the tools
yourself.
### Generate ### Generate
In order to generate the PDF and the EPUB versions of the book you can just run: In order to generate the PDF and the EPUB versions of the book you can just run:
@@ -62,7 +98,7 @@ make count
### Validate EPUB ### Validate EPUB
letterpress can validate the generated EPUB with [EPUBCheck](https://www.w3.org/publishing/epubcheck/). Once you've installed EPUBCheck on your machine you can run it with: Letterpress can validate the generated EPUB with [EPUBCheck](https://www.w3.org/publishing/epubcheck/). EPUBCheck is provided by the Nix dev shell (or install it yourself), then run:
```bash ```bash
make epubcheck make epubcheck
@@ -80,7 +116,7 @@ make clean
### Linting ### Linting
letterpress comes with [vale](https://vale.sh/). Once you've installed vale on your machine you can run it with: Letterpress comes with [vale](https://vale.sh/). Vale is provided by the Nix dev shell (or install it yourself), then run:
```bash ```bash
make lint make lint

61
flake.lock generated Normal file
View File

@@ -0,0 +1,61 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1785967620,
"narHash": "sha256-IItrdb7Puk05RqOBWZYFC5X6Wl1sJmCfh5MWVHw5iMM=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "b7c2ada94fe99c15b0dbcf4d11fd7850b957a436",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

83
flake.nix Normal file
View File

@@ -0,0 +1,83 @@
{
description = "letterpress - a self-publishing book template built on Asciidoctor";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = import nixpkgs { inherit system; };
# Ruby gem environment pinned by Gemfile.lock + gemset.nix.
# The native `mathematical` gem (pulled in by asciidoctor-mathematical)
# needs a bunch of C libraries + bison/flex to build its bundled lasem.
gems = pkgs.bundlerEnv {
name = "letterpress-gems";
ruby = pkgs.ruby_3_4;
gemdir = ./.;
# nixpkgs' defaultGemConfig already knows how to build the tricky
# native `mathematical` gem (bison/flex/cmake + rpath fixups). We only
# extend it: the gem vendors an mtex2MML whose CMakeLists declares an
# ancient cmake_minimum_required that modern cmake rejects, so allow it.
gemConfig = pkgs.defaultGemConfig // {
mathematical = attrs:
(pkgs.defaultGemConfig.mathematical attrs) // {
CMAKE_POLICY_VERSION_MINIMUM = "3.5";
};
};
};
# Everything needed to render the book: the gem env plus the external
# binaries asciidoctor-diagram shells out to (plantuml -> java + graphviz).
runtimeInputs = with pkgs; [
gems
gems.wrappedRuby
gnumake
plantuml
graphviz
jre
vale
epubcheck
];
book = pkgs.stdenv.mkDerivation {
pname = "letterpress-book";
version = "0.1.0";
src = ./.;
nativeBuildInputs = runtimeInputs;
# asciidoctor-diagram caches into $HOME
buildPhase = ''
export HOME=$TMPDIR
make all
'';
installPhase = ''
mkdir -p $out
cp -r output/* $out/
'';
};
in
{
packages = {
default = book;
book = book;
gems = gems;
};
devShells.default = pkgs.mkShell {
packages = runtimeInputs ++ (with pkgs; [ bundix ]);
shellHook = ''
echo "letterpress dev shell"
echo " make build PDF + EPUB"
echo " make output/book.pdf"
echo " make output/book.epub"
echo " make lint run vale"
echo " make epubcheck validate EPUB"
'';
};
formatter = pkgs.nixpkgs-fmt;
});
}

474
gemset.nix Normal file
View File

@@ -0,0 +1,474 @@
{
addressable = {
dependencies = ["public_suffix"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1by7h2lwziiblizpd5yx87jsq8ppdhzvwf08ga34wzqgcv1nmpvz";
type = "gem";
};
version = "2.9.0";
};
afm = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0ia5iw9xvvy1igaxsa08vvv4b5ry9ipyr18917pi8w0y4kvddm2v";
type = "gem";
};
version = "1.0.0";
};
Ascii85 = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0nmyxpngg5rycyryhq9l9hapz1y3iqyflskyksxkqm0832a5vjqm";
type = "gem";
};
version = "2.0.1";
};
asciidoctor = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1hbin3j8wynl2fpqa3d6vb932pyngyfn8j2q6gbbn1n23z7srqqn";
type = "gem";
};
version = "2.0.26";
};
asciidoctor-diagram = {
dependencies = ["asciidoctor" "rexml"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "113658j129myfg5y41zf94pkkfy8ysqvxdr2da2gf9x6y98x0cp4";
type = "gem";
};
version = "3.2.1";
};
asciidoctor-epub3 = {
dependencies = ["asciidoctor" "gepub" "mime-types" "sass"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0n4c7silsc37gapsvkzm2l7fwa9gi28cif7mzd27lkzbkdsv4k0i";
type = "gem";
};
version = "2.3.0";
};
asciidoctor-mathematical = {
dependencies = ["asciidoctor" "asciimath" "mathematical"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1lxfq7qn3ql642pva6jh3h1abm9j9daxg5icfn1h73k6cjsmcisp";
type = "gem";
};
version = "0.3.5";
};
asciidoctor-pdf = {
dependencies = ["asciidoctor" "concurrent-ruby" "matrix" "prawn" "prawn-icon" "prawn-svg" "prawn-table" "prawn-templates" "treetop" "ttfunk"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0ldh43ps15dpnrgqaybyq2py9cn1m14q2z6djgg22fyl698yaxih";
type = "gem";
};
version = "2.3.24";
};
asciimath = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0b5h65vas9fj4k85gw18cf6pgqbdxfjzj63632rdkngabar67zlq";
type = "gem";
};
version = "2.0.6";
};
coderay = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0jvxqxzply1lwp7ysn94zjhh57vc14mcshw1ygw14ib8lhc00lyw";
type = "gem";
};
version = "1.1.3";
};
concurrent-ruby = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1qfi2ns3zwkgq616fc127xiqhan7g7m7gqpwriwcr34nds1vxwdj";
type = "gem";
};
version = "1.3.8";
};
css_parser = {
dependencies = ["addressable"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1ha0bcz71z48ahdvc0dp71apnbqnnpgffq0dac2q65y68259hx7j";
type = "gem";
};
version = "1.22.0";
};
ffi = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1kqasqvy8d7r09ri4n6bkdwbk63j7afd9ilsw34nzlgh0qp69ldw";
type = "gem";
};
version = "1.17.4";
};
gepub = {
dependencies = ["nokogiri" "rubyzip"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0fiwnfgvyrhgywnqvfvr3ird8p4xda6nvvqwvvfpnhvsyhrxswlc";
type = "gem";
};
version = "1.0.17";
};
hashery = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0qj8815bf7q6q7llm5rzdz279gzmpqmqqicxnzv066a020iwqffj";
type = "gem";
};
version = "2.1.2";
};
logger = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "00q2zznygpbls8asz5knjvvj2brr3ghmqxgr83xnrdj4rk3xwvhr";
type = "gem";
};
version = "1.7.0";
};
mathematical = {
dependencies = ["ruby-enum"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0y103dvfjswm5r0xafyjrw6ybvz1qrqfa4lvpk9gdhbzwpaiwy4r";
type = "gem";
};
version = "1.6.20";
};
matrix = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0nscas3a4mmrp1rc07cdjlbbpb2rydkindmbj3v3z5y1viyspmd0";
type = "gem";
};
version = "0.4.3";
};
mime-types = {
dependencies = ["logger" "mime-types-data"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0mjyxl7c0xzyqdqa8r45hqg7jcw2prp3hkp39mdf223g4hfgdsyw";
type = "gem";
};
version = "3.7.0";
};
mime-types-data = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "03vkd9g09jnxsp8mdacvjbplrrqfl5l26n50kd4kdn49zghi326d";
type = "gem";
};
version = "3.2026.0701";
};
mini_portile2 = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "12f2830x7pq3kj0v8nz0zjvaw02sv01bqs1zwdrc04704kwcgmqc";
type = "gem";
};
version = "2.8.9";
};
nokogiri = {
dependencies = ["mini_portile2" "racc"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1d9safb4dly6qmc2g06444l0zifby52yy6j1a5fa1g4j3ihm3jah";
type = "gem";
};
version = "1.19.4";
};
pdf-core = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1fz0yj4zrlii2j08kaw11j769s373ayz8jrdhxwwjzmm28pqndjg";
type = "gem";
};
version = "0.9.0";
};
pdf-reader = {
dependencies = ["Ascii85" "afm" "hashery" "ruby-rc4" "ttfunk"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1kk8f1f5kkdwsbskv0vikcwx5xaivv19y9zl97x1fcaam23akihq";
type = "gem";
};
version = "2.15.1";
};
polyglot = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1bqnxwyip623d8pr29rg6m8r0hdg08fpr2yb74f46rn1wgsnxmjr";
type = "gem";
};
version = "0.3.5";
};
prawn = {
dependencies = ["pdf-core" "ttfunk"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1g9avv2rprsjisdk137s9ljr05r7ajhm78hxa1vjsv0jyx22f1l2";
type = "gem";
};
version = "2.4.0";
};
prawn-icon = {
dependencies = ["prawn"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1xdnjik5zinnkjavmybbh2s52wzcpb8hzaqckiv0mxp0vs0x9j6s";
type = "gem";
};
version = "3.0.0";
};
prawn-svg = {
dependencies = ["css_parser" "matrix" "prawn" "rexml"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "143sfwadbdrgi57am8ikalryjijdyl82h2sdc1cns3wl6b9pkzxg";
type = "gem";
};
version = "0.34.2";
};
prawn-table = {
dependencies = ["prawn"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1nxd6qmxqwl850icp18wjh5k0s3amxcajdrkjyzpfgq0kvilcv9k";
type = "gem";
};
version = "0.2.2";
};
prawn-templates = {
dependencies = ["pdf-reader" "prawn"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1w9irn3rllm992c6j7fsx81gg539i7yy8zfddyw7q53hnlys0yhi";
type = "gem";
};
version = "0.1.2";
};
public_suffix = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "08znfv30pxmdkjyihvbjqbvv874dj3nybmmyscl958dy3f7v12qs";
type = "gem";
};
version = "7.0.5";
};
"pygments.rb" = {
dependencies = ["logger"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0vpg920w2ic9hqlznzpv8njv0nv8n1av7cnvrq95sjqbvahb1crk";
type = "gem";
};
version = "5.0.0";
};
racc = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0byn0c9nkahsl93y9ln5bysq4j31q8xkf2ws42swighxd4lnjzsa";
type = "gem";
};
version = "1.8.1";
};
rb-fsevent = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1zmf31rnpm8553lqwibvv3kkx0v7majm1f341xbxc0bk5sbhp423";
type = "gem";
};
version = "0.11.2";
};
rb-inotify = {
dependencies = ["ffi"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0vmy8xgahixcz6hzwy4zdcyn2y6d6ri8dqv5xccgzc1r292019x0";
type = "gem";
};
version = "0.11.1";
};
rexml = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0hninnbvqd2pn40h863lbrn9p11gvdxp928izkag5ysx8b1s5q0r";
type = "gem";
};
version = "3.4.4";
};
rouge = {
dependencies = ["strscan"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0ljlr1da64kx3mimpzb4x2yczk08b0sg04h2ji3m2zxb88l66z5p";
type = "gem";
};
version = "5.1.0";
};
ruby-enum = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1ds98s00askf8lmmc40w9yp852avmq9f84c7djy15sqpar65x1dx";
type = "gem";
};
version = "1.1.0";
};
ruby-rc4 = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "00vci475258mmbvsdqkmqadlwn6gj9m01sp7b5a3zd90knil1k00";
type = "gem";
};
version = "0.1.5";
};
rubyzip = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0grps9197qyxakbpw02pda59v45lfgbgiyw48i0mq9f2bn9y6mrz";
type = "gem";
};
version = "2.3.2";
};
sass = {
dependencies = ["sass-listen"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0p95lhs0jza5l7hqci1isflxakz83xkj97lkvxl919is0lwhv2w0";
type = "gem";
};
version = "3.7.4";
};
sass-listen = {
dependencies = ["rb-fsevent" "rb-inotify"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0xw3q46cmahkgyldid5hwyiwacp590zj2vmswlll68ryvmvcp7df";
type = "gem";
};
version = "4.0.0";
};
strscan = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "17k75zrwf4ag9yl9wjjkcb90zrm4r5jigdzv3zr5jm9239hxpqma";
type = "gem";
};
version = "3.1.8";
};
treetop = {
dependencies = ["polyglot"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1nl3q5ai7ikaa5sjdbspfa4njbrdvf7898zkplmalln6y4r3y153";
type = "gem";
};
version = "1.6.18";
};
ttfunk = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "15iaxz9iak5643bq2bc0jkbjv8w2zn649lxgvh5wg48q9d4blw13";
type = "gem";
};
version = "1.7.0";
};
}