Behavioral verification for Ruby
Change the code.
Keep the behavior.
Your legacy code has a lot to teach its replacement. Capture what it does, then check the new implementation against the same behavior.
Legacy APIRecord once
# An instance method
slugifier = Legacy::Slugifier.new
slugifier.call("Hello World")
# => "hello-world"
Replacement APIVerify independently
# A module. A keyword argument.
Replacement::Slugs.generate(
text: "Hello World"
)
# => "hello-world"
- "Hello World"
- "hello-world"
- " Hi! "
- "hi"
- ""
- ArgumentError: "blank"
The replacement can change shape. The recorded behavior stays the reference.
Ruby 3.1+ MIT licensed
Behavior is more
than a return value.
Keep the details that callers depend on, including the ones a happy-path test can miss.
- Arguments
- Return values
- Errors
- Yields
- Mutations
- State
- External calls
Keep the evidence.
Leave the legacy.
Record while the old environment still runs. A portable Specification Bundle becomes the reference for everything that comes next.
-
1
Capture the original
Define the public boundary and run your RSpec or Minitest suite. Combine recorded traces and source evidence into a checked bundle.
record + synthesize
-
2
Map the replacement
Use a small Ruby adapter to connect recorded operations to your new API. Classes, method names, and argument shapes can all change.
.bparity/adapter.rb
-
3
Check what changed
Verify with just the bundle, adapter, and replacement. Inspect differences and declared waivers in Markdown, JSON, JUnit XML, or HTML.
bparity verify
Know what passed.
And what was checked.
Start with recorded examples. Add property checks, finite-domain exploration, model comparison, or Z3 proofs when the required inputs are available.
Every formal result reports its scope, assumptions, and exclusions. Inconclusive results stay inconclusive.
Read the assurance limits- F0
Trace replay
The recorded examples match.
- F1
Contract & property checks
Executed inputs satisfy declared predicates.
- F2
Bounded exhaustive comparison
No difference within the reported finite domain.
- F3
Finite-state model comparison
The projected learned models conform.
- F4
Translation-validated Z3 proof
No difference in the supported pure fragment, under reported assumptions.
Give your rewrite
a reference point.
Start in the legacy environment, while its dependencies still work.
Follow the quick startgem "bparity", github: "ydah/bparity", branch: "main"
bundle install
bundle package --all
bundle exec bparity init --timecapsule
Next, define your boundary, record the suite, and map your replacement. The quick start walks through each step.