Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions skills/ruby_with_tdd/green/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---
description: TDD green phase — write the minimum code to pass the current failing test and stop. Use after /red.
allowed-tools: Bash Read Edit Write
---

## YOUR ONLY JOB RIGHT NOW: make the failing test pass with the least possible code.

Nothing more. No error handling that has no test. No alternate paths that have no test. No guard clauses that have no test. No helper methods that have no test.

---

## What to do

1. Read the current failing test output carefully. Understand **exactly** what assertion is failing.
2. Write the **bare minimum** code that satisfies that assertion. Hardcoding a return value is acceptable — the next test will force you to generalize.
3. Run the **full suite** (not just the new test) to confirm nothing regressed.
4. Verify every new line of implementation is required by the current test:
- Temporarily remove or trivialize each piece (delete a guard, change a string to `'x'`).
- Confirm a test goes red. If nothing goes red, the code is untested — delete it.
5. Show the passing output.
6. **STOP.**

Your final message must be exactly this format:
> **Green.** `[one-sentence summary of what you implemented]`
> Ready for `/refactor`.

---

## What you must NOT do

- Do not add code that anticipates the next test.
- Do not add error handling, fallbacks, or guards unless the current failing test demands them.
- Do not add requires or dependencies beyond what the current implementation needs.
- Do not refactor or rename anything — that is `/refactor`'s job.
- Do not proceed to refactor on your own.

---

## The hardcode test

Ask yourself: "Could this test pass if I just returned a hardcoded value?"

If yes, consider whether a hardcoded value is more honest. The next test will expose the hardcode and force real logic. A hardcoded green is always better than speculative real logic.
42 changes: 42 additions & 0 deletions skills/ruby_with_tdd/red/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
description: TDD red phase — write exactly one failing test and stop. Use after /ruby to begin a TDD cycle, or after /refactor to start the next one.
allowed-tools: Bash Read Edit Write
---

## YOUR ONLY JOB RIGHT NOW: write one failing test.

Nothing else. No implementation. No skeleton classes. No speculative requires. No "just to make it load" stubs.

---

## What to do

1. Write **exactly one `it` block** — the smallest test that captures the next required behavior.
2. Add only the requires the test itself needs to run.
3. Run the test.
4. Confirm it fails **for the right reason**: the assertion must fail, not a load error or syntax error. If it fails to load, create the minimum skeleton (empty class/method definition, nothing more) to let the test reach the assertion, then re-run.
5. Show the failure output.
6. **STOP.**

Your final message must be exactly this format:
> **Red.** `[one-sentence description of what failed and why]`
> Ready for `/green`.

---

## What you must NOT do

- Do not write any implementation code.
- Do not write more than one test.
- Do not add requires, constants, or class definitions beyond what is needed to reach the failing assertion.
- Do not explain what the implementation will look like.
- Do not ask clarifying questions about future tests.
- Do not proceed to green on your own, even if it seems obvious.

---

## Reminders

- A partial test (method call with no assertion) is enough to go red. Add the assertion after confirming the call works.
- The test description (`it '...'`) must read as a complete sentence describing behavior, not implementation.
- If the test is hard to write, that is a design signal — raise it before writing code.
50 changes: 50 additions & 0 deletions skills/ruby_with_tdd/refactor/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
description: TDD refactor phase — improve structure and run RuboCop on changed files, without changing behavior. Use after /green.
allowed-tools: Bash Read Edit Write
---

## YOUR ONLY JOB RIGHT NOW: improve the code without changing what it does.

No new behavior. No new tests. No bug fixes that weren't already covered by passing tests.

---

## What to do

1. Apply Clean Code discipline to everything written in this cycle:
- Names explain intent — rename anything unclear.
- Methods do one thing — extract if needed.
- No speculative abstractions — only simplify what exists.
- No dead code.
2. Run RuboCop on every file you touched:
```bash
bundle exec rubocop <changed files>
```
3. Fix all offenses. Re-run the suite after each fix to stay green.
4. Show the final RuboCop output and test output.
5. **STOP.**

Your final message must be exactly this format:
> **Refactor done.** `[one-sentence summary of what changed, or "no changes needed"]`
> RuboCop: clean. Tests: N passing.
> Ready for `/red` on the next behavior.

---

## What you must NOT do

- Do not add new functionality.
- Do not add new tests (unless a refactor reveals untested behavior — flag it and stop).
- Do not add `rubocop:disable` comments except for confirmed false positives with an explanation.
- Do not change method signatures or public interfaces without flagging it.
- Do not proceed to the next red on your own.

---

## Clean Code quick reference

- **Names**: verb phrases for methods, predicate form for booleans, nouns for classes. No abbreviations.
- **Methods**: one responsibility, short enough to read without scrolling.
- **Arguments**: more than three is a smell. No boolean flags.
- **Comments**: only justify the WHY. Never restate what the code already says.
- **Structure**: delete dead code. Three similar lines before abstracting.
96 changes: 96 additions & 0 deletions skills/ruby_with_tdd/ruby/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
---
description: Drive Ruby work using TDD, Clean Code, and expressive naming. Run RuboCop on every change. Use when the user wants to write clean, well-tested Ruby with red-green-refactor and linting discipline.
allowed-tools: Bash Read Edit Write
---

## How to use these skills

TDD happens in three separate commands. Each one does exactly one thing:

- `/red` — write one failing test, run it, stop
- `/green` — write the minimum code to pass it, run the suite, stop
- `/refactor` — clean up and lint, stop

Start a cycle with `/red`. Do not proceed to the next command until you have the output from the previous one.

---

## The Standard

Every change must satisfy three things before it is done:
1. Tests are green.
2. RuboCop reports no offenses on changed files.
3. The code reads like well-written prose — names explain intent, methods do one thing, nothing is surprising.

---

## Object-Oriented Programming

- **Encapsulation** — hide internal state. Expose only what callers need. Prefer private methods and instance variables over public accessors.
- **Abstraction** — expose what a thing does, not how it does it. Names and interfaces should describe intent; implementation details stay hidden.
- **Inheritance** — use for genuine is-a relationships only. Prefer composition when the goal is code reuse rather than a true type hierarchy.
- **Polymorphism** — design so callers don't need to know which concrete class they're working with. Use duck typing in Ruby — if it responds to the right methods, it works.
- **Tell, don't ask** — tell objects to do things rather than querying their state and deciding for them. Keep decision logic inside the object that owns the data.
- **Law of Demeter** — only talk to your immediate collaborators. A chain like `a.b.c.d` is a smell; the object in the middle should expose the behavior you need directly.

---

## SOLID Principles

- **Single Responsibility** — a class or module does one thing. If you need "and" to describe what it does, split it.
- **Open/Closed** — extend behavior by adding new classes, not by modifying existing ones. Prefer composition over conditionals inside a class.
- **Liskov Substitution** — subclasses must be substitutable for their parent without changing program correctness. Don't override methods in ways that violate the parent's contract.
- **Interface Segregation** — don't force callers to depend on methods they don't use. Small, focused interfaces beat large, general ones.
- **Dependency Inversion** — depend on abstractions, not concretions. Inject dependencies rather than instantiating them inside a class.

---

## Clean Code Rules

**Names**
- Names must explain intent. If a name needs a comment to clarify it, the name is wrong.
- Methods: verb phrases (`decrypt_cookie`, `user_id_from_header`). Booleans: predicate form (`ignored?`, `valid?`). Classes: nouns.
- No abbreviations unless the abbreviation is more familiar than the full word (e.g. `url`, `id`).

**Methods**
- One method, one responsibility. If you need "and" to describe what it does, split it.
- Short. If a method doesn't fit comfortably in view, it is doing too much.
- No surprise side effects. A method named `get_x` must not mutate state or trigger I/O.

**Arguments**
- Fewer is better. More than three arguments is a design smell — consider a parameter object.
- No boolean flags as arguments. A flag argument means the method does two things.

**Comments**
- No comments that restate what the code already says.
- A comment is only justified when it explains WHY — a hidden constraint, a non-obvious invariant, a workaround for a specific external behavior.

**Structure**
- Delete dead code. Version control has it if you need it back.
- Duplication: two similar things may just be similar. Three identical things need abstraction.
- Don't abstract prematurely. Three similar lines is better than a wrong abstraction.

---

## RuboCop Rules

- Run RuboCop on every file you touch before declaring a cycle done.
- Fix all offenses — do not add `rubocop:disable` comments unless the offense is a confirmed false positive, and explain why inline.
- If RuboCop and Clean Code conflict, fix the code so both are satisfied rather than suppressing the cop.

---

## Collaboration

- Do not avoid conflict. If you disagree with the user's approach — on naming, design, test strategy, or anything else — say so directly and explain why. State your honest position once, clearly. If the user pushes back, engage with their reasoning rather than capitulating to avoid friction. Changing your position is fine; changing it just because the user pushed is not.

---

## Shared Rules (enforced across all three commands)

- Prefer RSpec unless the project already uses Minitest — follow what exists.
- One assertion per test where possible. Descriptive `it` names that read as sentences.
- Never define tests inside a loop. Use `shared_examples` with `include_examples` instead.
- Prefer real classes over test doubles. Doubles that mock an entire chain hide whether the real API is being used correctly.
- Never mock the class under test. If a method needs to be isolated, extract it into a collaborator and mock that instead.
- If the user asks to skip a step, decline and explain why the discipline matters.