A

Appendix A: Ruby Project Lifecycle

en/appendix_a_project_lifecycle

merged appendix page

Ruby Project Lifecycle and Core Tooling ๏ธ

Why this appendix exists ๐Ÿ’ก

A student can understand Ruby syntax and still feel lost when working in a real project. The missing knowledge is often not "more language features." It is the operational flow around the language:

  • Which command comes first?
  • How do I know which Ruby version I am using?
  • How do I install dependencies safely?
  • Why do some projects use bundle exec everywhere?
  • How do I look up documentation without opening a browser?
  • When should I care about documentation generators, linters, task runners, and debuggers?

This appendix teaches Ruby tools through the story of a real project lifecycle, from "I have an empty directory" to "I am working in repeated sprint cycles with a maintainable codebase."

Main learning outcomes ๐ŸŽฏ

By the end of this appendix, students should be able to:

  • explain the roles of ruby, gem, bundle, ri, and rbenv;
  • start a Ruby project in a reproducible way;
  • understand when to use gem install versus bundle add;
  • run Ruby code directly from the command line and check syntax quickly;
  • use ri for local API lookup during development;
  • understand where rake, rubocop, rdoc, yard, and rdbg fit in project life;
  • troubleshoot common environment problems without guessing blindly.

Teaching philosophy ๐Ÿงญ

This appendix does not teach tools as an alphabetical catalog.

It teaches them in the order a real developer tends to need them:

  1. choose the Ruby version;
  2. confirm the interpreter works;
  3. create the project;
  4. add dependencies;
  5. start the test loop;
  6. look up docs while coding;
  7. automate repeated tasks;
  8. keep style and docs consistent;
  9. debug runtime behavior;
  10. troubleshoot environment drift.

That order matters. When students learn tools in project order, the purpose of each tool becomes obvious.

Files in this appendix ๐Ÿ—‚๏ธ

  • story.md: the detailed project-life-cycle narrative
  • cheatsheet.md: commands in first-use order
  • sprint_flow.md: how the tools fit into daily sprint work
  • troubleshooting.md: common failures and diagnostic order
  • addons.md: tools that are useful later, after the basics are stable

What this appendix is not ๐Ÿšซ

It is not:

  • a full RubyGems manual;
  • a complete Bundler reference;
  • a shell tutorial;
  • a replacement for official docs.

It is a practical survival guide for students moving from "I can write Ruby" to "I can work inside a Ruby project responsibly."

The Ruby Project Lifecycle Story

Stage 0: Before the project exists ๐ŸŒ…

Before a Ruby project has code, it already has one invisible dependency: the Ruby interpreter itself.

If the wrong Ruby version is active, every later step becomes unstable:

  • gems may install into the wrong location;
  • native extensions may fail;
  • scripts may behave differently;
  • your machine may not match the project's intended environment.

This is why project lifecycle starts with the runtime, not with source files.

Tools introduced here

  • ruby
  • which
  • rbenv

Commands

ruby -v
which ruby
rbenv versions
rbenv local 3.4.8
rbenv which ruby
story.md
bash

What each command tells you

ruby -v

  • shows the active Ruby version
  • use this whenever a project expects a specific version

which ruby

  • shows which executable your shell will actually run
  • this is critical when version managers are involved

rbenv versions

  • lists installed versions and shows which one is active

rbenv local 3.4.8

  • writes the local project version
  • this means "when I am in this directory, use Ruby 3.4.8"

rbenv which ruby

  • tells you exactly which Ruby binary rbenv resolved

Real-life situation

You clone a Ruby project and bundle install fails with a strange native extension error. A common cause is not the gem itself. The common cause is that your shell is using the wrong Ruby.

So the first debugging question is not:

  • "Why is Bundler broken?"

It is:

  • "Which Ruby am I actually using?"

That is why version management comes first.

Stage 1: Try Ruby before creating the project ๐Ÿงช

Before making a project skeleton, verify that the interpreter and shell workflow are working. This keeps environment issues separate from project issues.

Tools introduced here

  • ruby
  • irb

Commands

ruby -e 'puts "hello from ruby"'
ruby -e 'puts [1, 2, 3].map { |n| n * 2 }.inspect'
irb
story.md
bash

Why this stage matters

ruby -e is a fast smoke test:

  • the interpreter runs
  • the shell quoting works
  • you can evaluate small expressions quickly

irb is your live Ruby scratchpad:

  • test an expression
  • inspect how a method behaves
  • experiment before editing a file

Real-life situation

You are unsure whether String#gsub or Array#zip behaves the way you remember. Instead of guessing or editing production code blindly, you can use irb for quick validation.

Example:

irb
irb(main):001> %w[Ana Bob].zip([88, 76])
=> [["Ana", 88], ["Bob", 76]]
story.md
ruby

That is a real daily workflow, not a beginner trick.

Stage 2: Create the project ๐Ÿ“

Now that Ruby itself works, create the project directory and initialize dependency management immediately.

Tools introduced here

  • bundle

Commands

mkdir my_ruby_project
cd my_ruby_project
bundle init
story.md
bash

What happens here

bundle init

  • creates a Gemfile
  • marks the project as a dependency-managed Ruby project

This is one of the most important habits in Ruby work:

  • do not start by installing random gems globally and hoping the project will work later
  • start by declaring project dependencies

Real-life situation

If you skip Bundler and only run gem install rspec, your machine may work, but a teammate's machine might not. Bundler is what turns "my machine" into "the project environment."

Stage 3: Run files and check syntax โ–ถ๏ธ

After the project exists, you need a few commands for direct file execution and fast feedback.

Commands

ruby app.rb
ruby -c app.rb
ruby -Ilib script.rb
story.md
bash

Why these matter

ruby app.rb

  • run a Ruby file directly

ruby -c app.rb

  • check syntax without running the program
  • very useful when debugging syntax errors quickly

ruby -Ilib script.rb

  • add directories to the load path
  • useful in small scripts where you want require to find local project files

Real-life situation

A student changes several methods and now gets a syntax error. They do not need the whole test suite to discover that. ruby -c gives a fast answer before deeper testing.

Stage 4: Add dependencies the project way ๐Ÿ“ฆ

Now the project needs libraries.

Tools introduced here

  • gem
  • bundle

Core idea

There are two separate concerns:

  1. the machine-level gem system
  2. the project's declared dependency set

Students must learn the difference.

Machine-level commands

gem -v
gem list
gem env
gem which rake
story.md
bash

These help you inspect the RubyGems environment.

Project-level commands

bundle add rspec
bundle install
bundle info rspec
story.md
bash

What these mean

bundle add rspec

  • adds the gem to the project's Gemfile
  • preferred over random global installation for project dependencies

bundle install

  • resolves and installs dependencies for the current project

bundle info rspec

  • shows where Bundler resolved the gem from

Real-life situation

Suppose csv works on one machine and not another. A student might think:

  • "Ruby is inconsistent."

But the real question is:

  • "Was csv declared for the project, or was it only present on one machine?"

That is exactly the kind of confusion Bundler is meant to prevent.

Stage 5: Start the first test loop โœ…

This is the moment the project becomes real development work.

Commands

bundle exec rspec
bundle exec rspec spec/my_spec.rb
bundle exec rspec spec/my_spec.rb:12
story.md
bash

Why bundle exec matters

bundle exec

  • ensures the command runs inside the project's dependency context
  • avoids accidentally using a gem version from outside the project

Students often resist bundle exec early because it feels repetitive. It is worth teaching early because it solves a real project problem.

Real-life situation

You have multiple versions of RSpec installed across projects. Running rspec directly might use the wrong executable. Running bundle exec rspec uses the project's declared dependency resolution.

That is not stylistic preference. That is environment correctness.

Stage 6: Use documentation while coding ๐Ÿ“š

Once sprint work begins, students need fast ways to look up Ruby APIs.

Tools introduced here

  • ri

Commands

ri Array#map
ri Enumerable#reduce
ri String#gsub
ri File
story.md
bash

Why ri matters

ri is the local documentation reader for Ruby APIs.

It is useful because:

  • it is fast
  • it works without opening a browser
  • it reinforces the habit of looking up behavior precisely

Real-life situation

A student knows map exists but forgets whether reduce needs an initial value or what String#gsub returns. ri gives the answer in the middle of implementation, which is how professionals actually use docs.

Stage 7: Turn repeated commands into project tasks ๐Ÿ”

Once a project has a repeated workflow, raw shell commands are no longer enough.

Tools introduced here

  • rake

Commands

bundle exec rake -T
bundle exec rake
story.md
bash

Why rake matters

rake is Ruby's traditional task runner.

Use it when a project has repeated actions such as:

  • running test suites
  • generating docs
  • cleaning build artifacts
  • seeding local data
  • custom project tasks

Real-life situation

A team keeps telling everyone:

  • "Run these four commands in this exact order."

That is usually a sign the project wants a task runner.

Stage 8: Keep style consistent โœจ

As the codebase grows, readability and consistency need automation.

Tools introduced here

  • rubocop

Commands

bundle exec rubocop
bundle exec rubocop -A
story.md
bash

Why rubocop matters

rubocop helps teams:

  • apply consistent style
  • catch some simple smells
  • reduce code-review noise about formatting

It is not a substitute for design review, but it is useful because it automates repetitive feedback.

Real-life situation

Without a formatter/linter, code review gets filled with:

  • spacing changes
  • quote-style debates
  • layout arguments

That wastes human attention that should be spent on logic and design.

Stage 9: Document the project for humans ๐Ÿ“

Once code is shared, others need more than passing tests. They need readable API docs.

Tools introduced here

  • rdoc
  • yard

Commands

rdoc
yard doc
yard server --reload
yard stats --list-undoc
story.md
bash

Difference between ri, rdoc, and yard

ri

  • read local Ruby docs

rdoc

  • generate documentation from Ruby source comments

yard

  • a widely used Ruby documentation tool with richer project-doc workflows

Why this stage comes later

Students should first understand:

  • how to write code
  • how to run tests
  • how to use docs

Only then does it make sense to ask them to generate and maintain docs for others.

Real-life situation

A service object is being reused across several scripts. Passing tests prove it works, but they do not explain:

  • expected input shape
  • return structure
  • side effects

That is where documentation tools become practical.

Stage 10: Debug execution, not just source code ๐Ÿž

As projects grow, printed output is sometimes not enough.

Tools introduced here

  • rdbg

Commands

rdbg app.rb
rdbg -c -- bundle exec rspec
story.md
bash

Why rdbg matters

A debugger helps when:

  • recursion behaves unexpectedly
  • database state differs from expectations
  • a closure captures the wrong value
  • a test passes data through too many layers to inspect easily with puts

Real-life situation

A recursive traversal duplicates some paths only in one edge case. Adding print statements everywhere becomes noisy. A debugger lets you inspect the call stack and current values more precisely.

Stage 11: Mature project add-ons ๐ŸŒณ

After the core lifecycle is stable, students may meet supporting tools such as:

  • simplecov
  • bundler-audit
  • ruby-lsp
  • solargraph

These are important, but they are not the first tools a student should learn.

They belong after the core project loop is already understood.

Sprint Flow: How These Tools Fit Daily Work

The repeated loop ๐Ÿ”

Once a Ruby project is alive, the daily loop is usually:

  1. confirm the environment
  2. install or sync dependencies if needed
  3. run one test or one spec file
  4. change code
  5. re-run the tests
  6. look up Ruby behavior when uncertain
  7. lint or format before finishing

That loop is where the tools stop being "commands to memorize" and become part of real project practice.

A realistic sprint example ๐Ÿงช

Imagine you are implementing a topic exercise or a new project feature.

Step 1: Confirm the runtime

ruby -v
which ruby
sprint_flow.md
bash

Why:

  • avoids working for 20 minutes in the wrong Ruby version

Step 2: Sync dependencies

bundle install
sprint_flow.md
bash

Why:

  • ensures your project dependencies match the Gemfile and lockfile

Step 3: Run only the relevant tests

bundle exec rspec spec/my_spec.rb
sprint_flow.md
bash

Why:

  • faster feedback
  • easier focus on one problem at a time

Step 4: Inspect docs mid-implementation

ri Enumerable#filter_map
sprint_flow.md
bash

Why:

  • lets you answer one concrete question without leaving your flow

Step 5: Check syntax fast if needed

ruby -c lib/my_class.rb
sprint_flow.md
bash

Why:

  • useful if the failure looks like a syntax issue rather than a logic issue

Step 6: Run the linter before considering the work finished

bundle exec rubocop
sprint_flow.md
bash

Why:

  • reduce avoidable review comments

When rake enters the sprint loop ๐Ÿ› ๏ธ

If the project has repeatable workflows, a team often stops writing raw commands in README files and starts formalizing them as tasks.

Examples:

  • bundle exec rake test
  • bundle exec rake docs
  • bundle exec rake setup

That is a sign the project is maturing operationally.

When rdbg enters the sprint loop ๐Ÿž

Use the debugger when:

  • the failing state is deep in recursion;
  • you need to inspect intermediate values;
  • print debugging is becoming messy;
  • a query result, block, or lambda is behaving unexpectedly.

In those cases, rdbg is not advanced decoration. It is a time-saving inspection tool.

Project Lifecycle Cheatsheet โšก

1. Check the runtime first ๐Ÿ”Ž

ruby -v
which ruby
rbenv versions
rbenv local 3.4.8
rbenv which ruby
cheatsheet.md
bash

2. Try Ruby quickly ๐Ÿงช

ruby -e 'puts "hello"'
ruby -e 'puts [1, 2, 3].map { |n| n * 2 }.inspect'
irb
cheatsheet.md
bash

3. Create the project ๐Ÿ“

mkdir my_ruby_project
cd my_ruby_project
bundle init
cheatsheet.md
bash

4. Run files and syntax-check โ–ถ๏ธ

ruby app.rb
ruby -c app.rb
ruby -Ilib script.rb
cheatsheet.md
bash

5. Add dependencies ๐Ÿ“ฆ

bundle add rspec
bundle install
bundle info rspec
cheatsheet.md
bash

6. Inspect gem environment ๐Ÿ’Ž

gem -v
gem list
gem env
gem which rake
cheatsheet.md
bash

7. Start the test loop โœ…

bundle exec rspec
bundle exec rspec spec/my_spec.rb
bundle exec rspec spec/my_spec.rb:12
cheatsheet.md
bash

8. Read docs while coding ๐Ÿ“š

ri Array#map
ri Enumerable#reduce
ri String#gsub
ri File
cheatsheet.md
bash

9. Use project tasks ๐Ÿ”

bundle exec rake -T
bundle exec rake
cheatsheet.md
bash

10. Keep style consistent โœจ

bundle exec rubocop
bundle exec rubocop -A
cheatsheet.md
bash

11. Generate docs ๐Ÿ“

rdoc
yard doc
yard server --reload
yard stats --list-undoc
cheatsheet.md
bash

12. Debug runtime behavior ๐Ÿž

rdbg app.rb
rdbg -c -- bundle exec rspec
cheatsheet.md
bash

Troubleshooting Guide

The most important rule โš ๏ธ

Do not guess randomly.

Check the environment in a fixed order.

Diagnostic order ๐Ÿฉบ

  1. Which Ruby is active?
  2. Which executable is the shell using?
  3. Is the dependency declared for the project?
  4. Did you run the command through Bundler?
  5. Is the gem installed but not available on PATH?
  6. Is there a native extension or default-gem packaging problem?

Problem: wrong Ruby version ๐Ÿ”ข

Symptoms:

  • gem install path looks strange
  • native gems fail unexpectedly
  • project works in one terminal tab but not another

Check:

ruby -v
which ruby
rbenv versions
rbenv which ruby
troubleshooting.md
bash

Interpretation:

  • if ruby -v does not match the project expectation, fix the version first

Problem: gem command works, project command fails ๐Ÿ“ฆ

Symptoms:

  • gem list rspec shows RSpec
  • bundle exec rspec still fails

Check:

bundle info rspec
bundle install
troubleshooting.md
bash

Interpretation:

  • the gem may exist globally but not be resolved for the project

Problem: executable not found ๐Ÿšซ

Symptoms:

  • bundle or rubocop or yard is "not found"

Check:

which bundle
gem env
troubleshooting.md
bash

Interpretation:

  • the gem may be installed, but the executable directory is not on PATH
  • or the version manager shell integration is incomplete

Problem: Ruby says a standard library feature is missing ๐Ÿงฉ

Symptoms:

  • cannot load such file -- csv
  • cannot load such file -- erb

Interpretation:

Recent Ruby versions may package some formerly-default pieces as separately installed gems.

What to do:

  • add the dependency to the project Gemfile
  • install it through Bundler or the project bootstrap

Problem: native extension build failure ๐Ÿ—๏ธ

Symptoms:

  • gems like sqlite3 fail while building
  • compiler or header errors appear

Check:

gem env
ruby -v
pkg-config --modversion sqlite3
troubleshooting.md
bash

Interpretation:

  • often caused by missing system headers or a mismatched Ruby environment

Problem: command works outside the project but fails inside it ๐Ÿงญ

Symptoms:

  • ruby -e works
  • project scripts fail

Interpretation:

  • the issue is likely project dependency resolution, not the Ruby interpreter itself

Check:

bundle install
bundle exec rspec
troubleshooting.md
bash

Problem: documentation command does not show what you expect ๐Ÿ“š

Symptoms:

  • ri output looks sparse
  • yard docs are incomplete

Interpretation:

  • ri reads installed docs for Ruby/core APIs
  • yard depends on comment quality in your project

In other words:

  • ri is for consuming docs
  • yard is for publishing docs

Add-On Tools and Why They Matter Later

These tools are valuable, but they are not first-line tools for a beginner. Students should meet them after the core Ruby project loop is already familiar.

simplecov ๐Ÿ“Š

Use when:

  • the team wants test coverage reports

Why it matters:

  • helps identify untested areas

Why it comes later:

  • coverage is useful only after students can already run and trust tests

bundler-audit ๐Ÿ”’

Use when:

  • the project needs dependency vulnerability checks

Why it matters:

  • dependency security becomes part of real project maintenance

Why it comes later:

  • students first need to understand ordinary dependency management

ruby-lsp or solargraph ๐Ÿง 

Use when:

  • editor integration matters more
  • students want inline hover docs, completion, and navigation

Why they matter:

  • improve day-to-day editing experience

Why they come later:

  • editor tooling should support understanding, not replace it

reek ๐Ÿ‘ƒ

Use when:

  • a team wants smell-oriented feedback beyond formatting

Why it matters:

  • encourages design conversation

Why it comes later:

  • students should first learn the language and project flow before smell taxonomy

brakeman ๐Ÿ›ก๏ธ

Use when:

  • the project uses Rails

Why it matters:

  • security scanning for Rails applications

Why it comes later:

  • not relevant to every Ruby project

The broader lesson ๐Ÿงญ

Ruby projects grow in layers:

  1. runtime
  2. project setup
  3. dependencies
  4. tests
  5. docs and style
  6. debugging
  7. ecosystem support tools

Students should know that these add-ons exist, but they should not be buried under too many tools before the core workflow feels natural.