Syntropy

A Web Framework for Ruby

Ruby gem Tests MIT License

What is Syntropy?

| Syntropy: A tendency towards complexity, structure, order, organization of
ever more advantageous and orderly patterns.

Syntropy is a web framework for building multi-page and single-page apps.
Syntropy uses file tree-based routing, and provides controllers for a number of
common patterns, such as a SPA with client-side rendering, a standard
server-rendered MPA, a REST API etc.

Syntropy also provides tools for working with lists of items represented as
files (ala Jekyll and other static site generators), allowing you to build
read-only apps (such as a markdown blog) without using a database.

For interactive apps, Syntropy provides basic tools for working with SQLite
databases in a concurrent environment.

Syntropy is based on:

  • UringMachine - a lean mean io_uring machine for Ruby.
  • TP2 - an io_uring-based web server for concurrent Ruby apps.
  • Qeweney a uniform interface for working with HTTP requests and responses.
  • Papercraft HTML templating with plain Ruby.
  • Extralite a fast and innovative SQLite wrapper for Ruby.

Routing

Syntropy routes request by following the tree structure of the Syntropy app. A
simple example:

site/
├ _layout/
| └ default.rb
├ _articles/
| └ 2025-01-01-hello_world.md
├ api/
| └ v1.rb
├ assets/
| ├ css/
| ├ img/
| └ js/
├ about.md
├ archive.rb
├ index.rb
└ robots.txt

Syntropy knows how to serve static asset files (CSS, JS, images…) as well as
render markdown files and run modules written in Ruby.

What does a Syntropic Ruby module look like?

Consider archive.rb in the example above. We want to get a list of articles
and render it with the given layout:

# archive.rb
@@layout = import('$layout/default')

def articles
  Syntropy.stamped_file_entries('/_articles')
end

export @@layout.apply(title: 'archive') {
  div {
    ul {
      articles.each { |article|
        li { a(article.title, href: article.url) }
      }
    }
  }
}

But a module can be something completely different:

# api/v1.rb
class APIV1 < Syntropy::RPCAPI
  def initialize(db)
    @db = db
  end

  # /posts
  def all(req)
    @db[:posts].order_by(:stamp.desc).to_a
  end

  def by_id(req)
    id = req.validate_param(:id, /^{4,32}$/)
    @db[:posts].where(id: id).first
  end
end

export APIV1

Basically, the exported value can be a template, a callable or a class that
responds to the request.