Write idiomatic, explicit and predictable Ruby. Metaprogramming only when the API gain is clear. Web/MVC: skill ruby-on-rails.
Tooling
- Ruby 3.4+ in new code; respect
.ruby-version/.tool-versionsof the repo. - Bundler:
Gemfile+Gemfile.lock;bundle execfor the project's binaries. rakefor tasks; RuboCop if the project already uses it — do not impose new cops on a feature.- YJIT enabled in production when the runtime allows it.
Organization
lib/
my_gem.rb
my_gem/
bin/
test/ # ou spec/
my_gem.gemspec # se gem
Apps (not Rails):
lib/my_app/
cli.rb
domain/
exe/my_app
- Files/constants in the autoload path match (
my_app/user.rb→MyApp::User). - Thin public API at the module root; internals in submodules.
Language
- Keyword arguments in new APIs; avoid opaque options hash (
opts = {}) unless for compatibility. Data.definefor immutable value objects;Structonly if the project already uses it.- Pattern matching (
case/in) for closed payloads (known hashes/JSON). Enumerableinstead offor;each_with_object,filter_map,tally.- Frozen string literals:
# frozen_string_literal: trueat the top if the project adopts it. ||=for simple memoization; be careful with falsy values (false/nil).- Prefer
require_relativeinternally;requirefor gems.
User = Data.define(:id, :email)
def parse_status(payload)
case payload
in { status: "ok", id: String => id }
[:ok, id]
in { status: "error", message: message }
[:error, message]
end
end
Errors
- Exceptions for exceptional failures; tagged return (
Success/Failureor[:ok, x]) when the caller always handles it. - Hierarchy
class NotFound < Error; do notraise "string"in libs. rescuespecific (rescue JSON::ParserError); neverrescue nil/rescue Exception.- I/O edges (HTTP, FS, process) rescue and translate; domain core remains pure when possible.
Concurrency
- Ractors/threads only with an explicit model; the GIL still limits CPU-bound work in threads.
- Fibers /
asyncif the project already uses it; do not introduce a parallel runtime in an isolated function. - Timeout on external I/O; do not assume the gem does this.
Gems and APIs
- Minimal dependencies; avoid abandoned gems or ones that overlap stdlib (
net-http,json,pathname). - Conscious version constraints (
~>); do not>= 0. - Monkey patches /
refinewith scope; no reopening core classes in apps.
Tests
- RSpec or Minitest — whichever the project uses.
- Test public API behavior, not private internals.
- Fakes/stubs at the edges (HTTP); avoid mocking everything.
bundle exec rspec/rake testin the changed scope.
Anti-patterns
method_missing/define_methodfor a single shortcut- Hash
{"id" => , "Id" =>}mixing string/symbol withoutActiveSupport(and even then avoid it) eval,class_evalin user input- Assuming Rails (
ActiveRecord,params,app/models) in this skill rescue StandardErrorswallowing bugs- Mutating constants and class variables as global state
Integration with other skills
- Web MVC / Rails API:
ruby-on-rails - Container:
docker
Completion criteria
- Idiomatic Ruby; keywords and domain types (
Data/structs) clear - Typed errors or explicit returns at the boundaries
- Consistent Gemfile; no new dead deps
- Critical path tests passing
- No unjustified metaprogramming