is a single-file static-site generator in 150 lines of ruby [WIP]
It's distinguishing characteristic is that it's archicture
& system design philosophy (over)emphasizes simplicity to an unsual degree,
even more so than program correctness.Read more:
- The New Jersey style/Worse is Better by Richard Gabrielle
- Locality of Behaviour, Carson Gross
Instead of installing X
/Y
publishing framework on your system,
it inverts the process by embedding the "framework" in the site itself.
- create a repo & drop
nix.rb
into it - run
nix.rb --init
- add posts & pages as markdown
git push
... which publishes automatically on Github Pages.
- unit tests
- data should be pruned outside of this readme
- code docs
anyone with repository access can edit/publish the site by simply cloning the repo,
add/edit posts and re-pushing to main
.
Usage: nix [options]
nix --init create sample blog
nix --build build static HTML
nix --watch rebuild on file change
- docs
- unit tests
- create a Github repo with enabled pages.
- drop the nix.rb file in it.
- Run
ruby nix.rb --init
to generate a sample site - push to
main
branch
... which publishes a barebones site consistent with the 1kb philosophy at: <user>.github.io/<repo>
- write markdown in
posts/
andpages/
- push to
main
branch
Say you have a repo with the following structure:
repo
┣━nix.rb
┗━README.md
generate a minimal sample blog:
ruby nix.rb --init
posts include syntax highlighting, just wrap them in code fences (```) as usual:
const hello = 'world'
moving on..
build to static HTML, at
/build
ruby nix.rb --build
# build ok!
or even better:
rebuild automatically on file change
ruby nix.rb --watch
Just push to main
.
An autogenerated Github workflow will run nix --build
to compile
everything once-more & deploy at: https://username.github.io/repo-name.
/build
directory is recompiled onpush
so you can safely.gitignore
it entirely.
just make sure each page or post has:
- an
h1
title on the 1st line - an
empty line
on the 2nd line - a
<date>
on the 3rd, ie.2024-10-18
the rest is up to you.
example:
# Some pretentious post title
2024-12-20
> A sentence should contain no unnecessary words, a paragraph no unnecessary
> sentences, for the same reason that a drawing should have no unnecessary lines
> and a machine no unnecessary parts. This requires not that the writer make all
> his sentences short, or that he avoid all detail and treat his subjects only
> in outline, but that every word tell
The Elements of Style by William Strunk Jr (1918) ...
nix
is just a single-file; it's max 150 lines of code & it includes everything
necessary to develop and publish a ridicously minimal yet functional
blog site.
grab it from this repo directly, or just curl
it:
curl -O https://raw.githubusercontent.com/nicholaswmin/nix/main/nix.rb
apart from Ruby 3.3 there's nothing to install;
nor any commands to run. You don't need to run gem install
.
It's not available as a gem
either;
This is intentional
Don't use absolute paths to reference assets.
Github Pages has a well-known quirk of serving from a non-root path, applicable to all static-site generators.
this won't work:
<img src="/public/felix.svg"></img>
<img src="/felix.svg"></img>
use relative paths instead:
<img src="../../felix.svg"></img>
even better, use {{root_url)}
:
<img src="{{root_path}}/felix.svg"></img>
<!-- auto expands to <img src="../../felix.svg"></img> -->
it's rewritten automatically & resolves to the correct root regardless of the
page position, so it's less error-prone than manually writing relative paths.
same in markdown:
[1]: {{root_url}}felix.svg
in case you're extending
nix
:
root_url
is also available as a method
which has the same effect:
root_url('felix.svg')
# ../../felix.svg
more context:
class CustomPage < HTMLPage
# omitted ...
def render(ctx)
super +
"<link rel=\"stylesheet\" href=\"#{root_url('highlight.css')}\"><link>"
end
end
This project is actually part of a weekly workshop I was invited to do in an SME. It's an actual project that you can use but it's primary purpose was illustrative.
The idea behind it closely mimics wruby, a static-site generator that generates sites that are under 1kb.
While the whole thing looks more like a code-golfing joke than anything substantial, it's philosophy is based around serious ideas that emerged in MIT and Berkley around the 80s(?), regarding software architecture design.
Despite their similarities, under the hood wruby
is written entirely
procedurally.
There is a clear lack of architecture and you can more or less describe it as a cooking recipe.
What I've done is take wruby and rewrite it's core ideas in an Object-Oriented paradigm; in an effort to make the code more "modern" and "extensible"; in effect I've proved the entire point of the argument, the tendency to introduce unnecessary complexity on our own.
nix
is using a lot of ideas supposedly considered "Best Practices".
Data is moved around in a functional manner; the API is implemented in a fluent
prose with clear hierarchical organisation into classes/types.
Additionally, there's a clear and intentional Separation of Concerns between persistence code and logic code; the purpose of this is to make it amerable to unit-testing.
wruby
has absolutely none of the above.
it's really just a bunch of functions glued together.
It's not possible to extend it without pulling out your hair but nor is
there any indication that it's purpose was to be extensible.
wruby is actually one of the few projects that I sat through reading it's entire source-code without getting bored or distracted, because it is just that simple.
Both projects are written in Ruby.
Both projects are based on material from the following essays:
- Worse is Better, Richard P. Gabriel
- Is Worse Really Better?, Richard P. Gabriel
- [Locality of Behavior][loc], Carson Gross
- Chesterson's Fence: A lesson in thinking
From the Unix-Haters handbook
Simson Garfinkel
[...] Literature that Unix succeeded because of its technical superiority. This is not true. Unix was evolutionarily superior to its competitors, but not technically superior. Unix became a commercial success because it was a virus. Its sole evolutionary advantage was its small size, simple design, and resulting portability.
The New Jersey style of software architecture design
vs the MIT/Stanford approachRichard P. Gabriel, 1991
[... ] I and just about every designer of Common Lisp and CLOS has had extreme exposure to the MIT/Stanford style of design. The essence of this style can be captured by the phrase The Right Thing. To such a designer it is important to get all of the following characteristics right:
the design must be simple, both in implementation and interface. It is more important for the interface to be simple than the implementation.
The design must be correct in all observable aspects. Incorrectness is simply not allowed.
The design must not be inconsistent. A design is allowed to be slightly less simple and less complete to avoid inconsistency. Consistency is as important as correctness.
The design must cover as many important situations as is practical. All reasonably expected cases must be covered. Simplicity is not allowed to overly reduce completeness.
[...] The Worse is Better philosophy is only slightly different:
The design must be simple, both in implementation and interface.
It is more important for the implementation to be simple than the interface. Simplicity is the most important consideration in a design.The design must be correct in all observable aspects. It is slightly better to be simple than correct.
The design must not be overly inconsistent.
Consistency can be sacrificed for simplicity in some cases, but it is better to drop those parts of the design that deal with less common circumstances than to introduce either implementational complexity or inconsistency.nt as correctness.Completeness -- the design must cover as many important situations as is practical. All reasonably expected cases should be covered. Completeness can be sacrificed in favor of any other quality. In fact, compzleteness must be sacrificed whenever implementation simplicity is jeopardized. Consistency can be sacrificed to achieve completeness if simplicity is retained; especially worthless is consistency of interface.
I have intentionally caricatured the worse-is-better philosophy to convince you that it is obviously a bad philosophy and that the New Jersey approach is a bad approach.
[...] However, I believe that worse-is-better, even in its strawman form, has better survival characteristics than the-right-thing, and that the New Jersey approach when used for software is a better approach than the MIT approach[...]