Gemfile Organize
Input
- TARGET = first arg or
Gemfilein cwd - Read TARGET, parse:
source,ruby,gemdeclarations, groups, inline comments
Categories (assignment table)
| Category | Gem patterns |
|---|---|
| Server | puma, unicorn, thin, falcon |
| GraphQL | graphql*, apollo*, graphiql* |
| Databases | pg*, mysql*, sqlite*, redis*, mongo*, activerecord*, active_record*, sequel, connection_pool, with_advisory_lock, store_model, attr_json |
| Background Jobs | sidekiq*, resque*, delayed_job*, good_job, solid_queue, activejob, active_job* |
| Authentication & Authorization | devise*, omniauth*, doorkeeper*, rodauth*, pundit, cancan*, action_policy, jwt, bcrypt |
| Feature Flags | flipper*, rollout, unleash |
| Caching | solid_cache, dalli, redis-rails, bootsnap |
| Monitoring | appsignal, newrelic*, datadog*, scout_apm, rollbar, sentry*, bugsnag, honeybadger, judoscale*, rails_autoscale* |
| Upload & Storage | shrine, carrierwave, paperclip, active_storage*, aws-sdk*, google-cloud-storage, fog*, image_processing, mini_magick, ruby-vips |
| External APIs & Services | stripe, braintree, paddle, twilio*, sendgrid*, mailgun*, postmark*, slack-*, octokit, savon, httparty, faraday, typhoeus, intacct, quickbooks*, xero* |
| Ruby Extensions | amazing_print, awesome_print, oj, multi_json, alba, blueprinter, dry-*, hashie, hash_dot, countries, money*, phonelib, chronic, ice_cube, business_time, holidays, shale, nokogiri, ox |
| PDF Generation | prawn*, wicked_pdf, pdfkit, hexapdf, ttfunk, matrix |
| XLSX/CSV Generation | caxlsx, axlsx*, roo*, spreadsheet, csv, smarter_csv |
| Frontend Dependencies | turbo-rails, stimulus-rails, hotwire*, importmap*, jsbundling*, cssbundling*, propshaft, sprockets*, tailwindcss*, bootstrap*, view_component*, inertia* |
| Admin & Backoffice | avo*, activeadmin, rails_admin, administrate, trestle |
| Rails Extensions & Tools (default) | aasm, state_machines*, friendly_id, hashid*, sequenced, pagy, kaminari, will_paginate, paranoia, discard, acts_as_paranoid, audited, paper_trail, logidze, rack-*, lograge*, most *-rails gems, anything uncategorized |
Group-only categories (kept inside group blocks, not top-level):
| Category | Gem patterns |
|---|---|
| Testing | rspec*, minitest*, capybara*, factory_bot*, faker, ffaker, vcr, webmock, shoulda*, simplecov, codecov, database_cleaner* |
| Development Tools | rubocop*, standard, brakeman, annotate, bullet, pry*, byebug, debug, letter_opener*, guard*, ruby-lsp*, solargraph |
Output Format
source "https://rubygems.org"
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
ruby file: '.ruby-version'
gem 'rails', '~> 7.x'
# Server
#########################
gem 'puma'
# Databases
#########################
gem 'pg'
gem 'redis'
# [Continue for each non-empty category, in table order]
group :production do
# ...
end
group :development, :test do
# ...
end
group :development do
# ...
end
group :test do
# ...
end
group :tools do
# ...
end
Preservation Rules
- Keep gem options intact:
github:,source:,require:,branch:,path: - Preserve version constraints:
'~> 1.0','>= 2.0' - Keep inline comments:
gem 'foo' # comment - Preserve special blocks like
git_source - Sort gems alphabetically within each section
- Only emit category headers for non-empty sections
- Uncategorized gems → "Rails Extensions & Tools"
Workflow
- Read TARGET → parse declarations
- For each gem: assign to category by pattern match (first match wins, table order)
- Build organized output (top-level categories, then groups)
- Compute diff vs current TARGET
- Show summary:
Organized N gems into M categories: - Category: K gems ... Uncategorized → Rails Extensions & Tools: - gem_a - gem_b - AskUserQuestion → options:
Show diff|Apply changes|Cancel - If Apply → write
TARGET.backup, then overwrite TARGET