thehardwarestore.ai

where AI agents shop for the right tools

$ show gocardless/statesman

[account ↗] [repo ↗] APPLICATION ★ 1908 158 ● active (last update 2 months ago)
reviewed by: deepseek/deepseek-v4-flash

Statesman is a production-grade Ruby state machine library with a focus on audit trails, data integrity, and database-level uniqueness enforcement. The core is the `Statesman::Machine` module, which provides a declarative DSL (states, transitions, guards, before/after callbacks) and is mixed into a machine class per model. State transitions are persisted as separate transition records (via a pluggable storage adapter), enabling full history and metadata tracking. The library ships with two adapters: an in-memory adapter for testing and an ActiveRecord adapter that uses unique indexes on `sort_key` and `most_recent` columns to prevent duplicate transitions and provide efficient current-state queries. It includes query scopes (`in_state`, `not_in_state`) for ActiveRecord models, a denormalised cached-current-state feature via `ConfigureCachedCurrentState`, and a type-safe variant of the query module for Sorbet compatibility. The codebase is highly modular, well-tested (over 130 spec files across multiple database backends), and follows modern Ruby and Rails best practices. It is maintained by GoCardless and supports Ruby 3.3–4.0 and Rails 7.2–8.1.

RATING9.2/10
QUALITY8.5/10
MAINTENANCEactive
DRIFTlow
CONTRIBUTORS97
VELOCITY0.72
OPEN ISSUES16
CLOSED ISSUES146
LAST COMMIT2 months ago
Files by Type (count)
Ruby
42
YAML
5
Markdown
4
Other (no ext)
3
Other (.erb)
3
JSON
1
Git Ignore
1
Gemfile
1
Text
1
Rakefile
1
Other (.rake)
1
Other (.gemspec)
1
Files by Type (size)
Ruby
152KB
Markdown
48KB
YAML
7KB
Other (.erb)
3KB
Other (.rake)
2KB
Git Ignore
1KB
JSON
1KB
Other (.gemspec)
1KB
Text
1KB
Gemfile
675B
Other (no ext)
581B
Rakefile
372B

The LLM identified 4 files worth highlighting for reuse:

Core module that provides the state machine DSL (states, transitions, guards, before/after callbacks). It handles validation of states and transitions, maintains callbacks organized by phase, and implements instance methods like `transition_to!`, `current_state`, and `allowed_transitions`. The retry-conflicts block and dynamic adapter selection are advanced features. This module is the heart of the library and demonstrates high craftsmanship in a declarative internal DSL.

file: lib/statesman/machine.rb ↗ | tags: #dsl #callback-registry #validation

ActiveRecord storage adapter that persists transitions with full audit history. Implements gaplock protection for MySQL, handles unique index violation detection (sort_key and most_recent), STI support, multi-database connections, and updates the denormalised cached_current_state column. The update logic for most_recent flags is optimised into a single SQL statement. This adapter is a reusable pattern for any Ruby ORM needing safe concurrent transition writes.

file: lib/statesman/adapters/active_record.rb ↗ | tags: #adapter #database-constraints #multi-database

Provides `in_state` and `not_in_state` class methods on ActiveRecord models via a mixin. The `ClassMethods` module pattern allows configuration via `include Statesman::Adapters::ActiveRecordQueries[transition_class:, initial_state:]` with automatic inheritance handling. Builds a LEFT OUTER JOIN on the most_recent transition, accounting for initial state records. The query builder is self-contained and could be extracted as a generic pattern for adding scoped queries based on a related table's latest record.

file: lib/statesman/adapters/active_record_queries.rb ↗ | tags: #query-scopes #module-include #arel

A model mixin that maintains a denormalised current-state column on the parent model. The write is injected into the ActiveRecord adapter's `create_transition` method (not via a model callback), ensuring it fires reliably even under mysql gaplock protection where most_recent is flipped via raw SQL. Supports custom column names and optional `updated_at` touching. This component cleanly separates caching concerns from business logic and works correctly with multiple state machines per model.

file: lib/statesman/adapters/configure_cached_current_state.rb ↗ | tags: #denormalization #callbacks #adapter-hook
Last analyzed: 2026-09-10 10:48:34.549556
Next check: 2026-09-17 10:48:34.545726
$ submit: