Patterns
Because sometimes you want a tiny *sparkle* of magic.
Patterns is an anti-framework for shaping plain Elixir code into tidy little systems.
It gives you small, composable building blocks for the parts of an app that tend to get repetitive:
- query DSLs
- middleware
- scoped context
- delegation helpers
- tiny conventions you keep rewriting from project to project
Patterns is for the little bits of structure you keep rebuilding.
The query helpers, wrapper functions, scoped context, and tiny APIs that make a codebase feel like itself.
Just a few cursed cute tools that stay out of the way and make your own modules feel a little more intentional.
Installation
def deps do
[
{:patterns, "~> 0.0.1"}
]
endWhy Patterns?
Because there is a sweet spot between “copy-paste this again” and “adopt an entire platform.”
Patterns is for codebases that want:
- plain modules with sprinkles of magic
- teeny tiny DSLs that get out of your way
- pretty patterns that still feel like your code
- APIs that feel nice without getting weird about it
Write the Elixir you want to write. Patterns just helps it stay pretty.
What's Inside?
Utilities
A couple of tiny tools for library-ish code:
defdelegate_all/1for when yes, actually, you do want to delegate the whole public surface.with_ctx/2andctx/1for scoped process-local context when a DSL needs to know where it is.
Queryable
Patterns.Queryable gives Ecto schemas one tidy query/2 entrypoint for contexts, resolvers, dataloaders, and tests.
Think of it like a more powerful Repo.get_by/2 that works on any query, with good defaults for the boring stuff:
Post.query(title: "Hello")
Post.query([published: true, order_by: [desc: :published_at]])
Post.query(comments: [author_id: user.id])Middleware
Patterns.Middleware wraps plain functions with explicit @middleware annotations.
Use it to extend existing functions and APIs: do a lil' auth check here, a lil' logging there.
@middleware Blog.Middlewares.AuthorizeEditor
def edit_post(post, attrs) do
Blog.Posts.update(post, attrs)
end
@middleware [Blog.Middlewares.AuthorizeEditor, Blog.Middlewares.RecordAuditLog]
def create_post(attrs) do
Blog.Posts.create(attrs)
endStatus
v0.0.1 is the first release. Tiny, useful, and still allowed to be a little cursed.
Development
Patterns uses Nix for the project shell and CI tooling.
If you use direnv:
direnv allowIf you prefer entering the shell manually:
nix developThen run the usual checks:
mix local.hex --force
mix local.rebar --force
mix deps.get
mix test
mix lint
MIX_ENV=prod mix hex.build
CI runs the same checks through the Nix shell, with nix flake check covering repo-level hooks and formatting.
License
MIT