This project is a RubyGem managed with the kettle-rb toolchain.
Minimum Supported Ruby: See the gemspec required_ruby_version constraint.
Local Development Ruby: See .tool-versions for the version used in local development (typically the latest stable Ruby).
Gemfiles are split into modular components under gemfiles/modular/. Each component handles a specific concern (coverage, style, debug, etc.). The main Gemfile loads these modular components via eval_gemfile.
Gemfiles in the project, including modular ones, can utilize a *_local.gemfile counterpart pattern enabled via an ENV flag. This uses nomono to load sibling gems in the same workspace.
CRITICAL: The canonical project environment lives in mise.toml, with local overrides in .env.local loaded via dotenvy.
mise.toml or .env.local, mise may require trust to be refreshed before commands can load the project environment. Until that trust step is handled, commands can appear hung or produce no output, which can look like terminal access is broken.
Recovery rule: If a mise exec command goes silent or appears hung, assume mise trust is the first thing to check. Recover by running:
mise trust -C /path/to/project
mise exec -C /path/to/project -- bundle exec rspecDo this before spending time on unrelated debugging; in this workspace pattern, silent mise commands are usually a trust problem first.
✅ CORRECT — Run self-contained commands with mise exec:
mise exec -C /path/to/project -- bundle exec rspec✅ CORRECT — If you need shell syntax first, load the environment in the same command:
eval "$(mise env -C /path/to/project -s bash)" && bundle exec rspec❌ WRONG — Do not rely on a previous command changing directories:
cd /path/to/project
bundle exec rspec❌ WRONG — A chained cd does not give directory-change hooks time to update the environment:
cd /path/to/project && bundle exec rspec✅ PREFERRED — Use internal tools:
grep_searchinstead ofgrepcommandfile_searchinstead offindcommandread_fileinstead ofcatcommandlist_dirinstead oflscommandreplace_string_in_fileorcreate_fileinstead ofsed/ manual editing
❌ AVOID when possible:
run_in_terminalfor information gathering
Only use terminal for:
- Running tests (
bundle exec rspec) - Installing dependencies (
bundle install) - Simple commands that do not require much shell escaping
- Running scripts (prefer writing a script over a complicated command with shell escaping)
When you do run tests, keep the full output visible so you can inspect failures completely.
This gem is part of the kettle-rb ecosystem. Key development tools:
| Tool | Purpose |
|---|---|
kettle-dev |
Development dependency: Rake tasks, release tooling, CI helpers |
kettle-test |
Test infrastructure: RSpec helpers, stubbed_env, timecop |
kettle-jem |
Template management and gem scaffolding |
| Executable | Purpose |
|---|---|
kettle-release |
Full gem release workflow |
kettle-pre-release |
Pre-release validation |
kettle-changelog |
Changelog generation |
kettle-dvcs |
DVCS (git) workflow automation |
kettle-commit-msg |
Commit message validation |
kettle-check-eof |
EOF newline validation |
lib/
├── <gem_namespace>/ # Main library code
│ └── version.rb # Version constant (managed by kettle-release)
spec/
├── fixtures/ # Test fixture files (NOT auto-loaded)
├── support/
│ ├── classes/ # Helper classes for specs
│ └── shared_contexts/ # Shared RSpec contexts
├── spec_helper.rb # RSpec configuration (loaded by .rspec)
gemfiles/
├── modular/ # Modular Gemfile components
│ ├── coverage.gemfile # SimpleCov dependencies
│ ├── debug.gemfile # Debugging tools
│ ├── documentation.gemfile # YARD/documentation
│ ├── optional.gemfile # Optional dependencies
│ ├── rspec.gemfile # RSpec testing
│ ├── style.gemfile # RuboCop/linting
│ └── x_std_libs.gemfile # Extracted stdlib gems
├── ruby_*.gemfile # Per-Ruby-version Appraisal Gemfiles
└── Appraisal.root.gemfile # Root Gemfile for Appraisal builds
.git-hooks/
├── commit-msg # Commit message validation hook
├── prepare-commit-msg # Commit message preparation
├── commit-subjects-goalie.txt # Commit subject prefix filters
└── footer-template.erb.txt # Commit footer ERB template
Always make commands self-contained. Use mise exec -C /home/pboling/src/kettle-rb/prism-merge -- ... so the command gets the project environment in the same invocation.
If the command is complicated write a script in local tmp/ and then run the script.
Full suite spec runs:
mise exec -C /path/to/project -- bundle exec rspecFor single file, targeted, or partial spec runs the coverage threshold must be disabled.
Use the K_SOUP_COV_MIN_HARD=false environment variable to disable hard failure:
mise exec -C /path/to/project -- env K_SOUP_COV_MIN_HARD=false bundle exec rspec spec/path/to/spec.rbmise exec -C /path/to/project -- bin/rake coverage
mise exec -C /path/to/project -- bin/kettle-soup-cover -dKey ENV variables (set in mise.toml, with local overrides in .env.local):
K_SOUP_COV_DO=true– Enable coverageK_SOUP_COV_MIN_LINE– Line coverage thresholdK_SOUP_COV_MIN_BRANCH– Branch coverage thresholdK_SOUP_COV_MIN_HARD=true– Fail if thresholds not met
mise exec -C /path/to/project -- bundle exec rake reek
mise exec -C /path/to/project -- bundle exec rubocop-gradualbin/kettle-pre-release # Validate everything before release
bin/kettle-release # Full release workflowTemplate updates preserve custom code wrapped in freeze blocks:
# kettle-jem:freeze
# ... custom code preserved across template runs ...
# kettle-jem:unfreezeGemfiles are split into modular components under gemfiles/modular/. Each component handles a specific concern (coverage, style, debug, etc.). The main Gemfile loads these modular components via eval_gemfile.
CRITICAL: All constructors and public API methods that accept keyword arguments MUST include **options as the final parameter for forward compatibility.
- Uses
kettle-testfor RSpec helpers (stubbed_env, block_is_expected, silent_stream, timecop) - Uses
Dir.mktmpdirfor isolated filesystem tests - Spec helper is loaded by
.rspec— never addrequire "spec_helper"to spec files
before do
stub_env("MY_ENV_VAR" => "value")
end
before do
hide_env("HOME", "USER")
endUse dependency tags to conditionally skip tests when optional dependencies are not available:
RSpec.describe SomeClass, :prism_merge do
# Skipped if prism-merge is not available
end- NEVER pipe test output through
head/tail— Run tests without truncation so you can inspect the full output.