Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce suspenders:cleanup:organize_gemfile task #1181

Merged
Merged
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
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Unreleased
* Introduce `suspenders:testing` generator
* Introduce `suspenders:prerequisites` generator
* Introduce `suspenders:ci` generator
* Introduce `suspenders:cleanup:organize_gemfile` task

20230113.0 (January, 13, 2023)

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ Custom Suspenders tasks
```
bin/rails suspenders:rake
bin/rails suspenders:db:migrate
bin/rails suspenders:cleanup:organize_gemfile
```

### Email
Expand Down
1 change: 1 addition & 0 deletions lib/suspenders.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
require "suspenders/engine"
require "suspenders/railtie"
require "suspenders/generators"
require "suspenders/cleanup/organize_gemfile"

module Suspenders
# Your code goes here...
Expand Down
134 changes: 134 additions & 0 deletions lib/suspenders/cleanup/organize_gemfile.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
module Suspenders
module Cleanup
class OrganizeGemfile
def self.perform(gemfile)
new(gemfile).perform
end

attr_reader :gemfile, :current_lines, :new_lines, :new_line_markers,
:current_group, :gem_groups

def initialize(gemfile)
@gemfile = gemfile

@current_lines = File.read(gemfile).lines
@new_lines = []
@new_line_markers = []

@current_group = nil
@gem_groups = {}
end

def perform
remove_line_breaks
sort_gems_and_groups
add_gem_groups_to_gemfile
add_line_breaks
cleanup

File.open(gemfile, "w+") { _1.write new_lines.join }
end

private

def remove_line_breaks
current_lines.delete("\n")
end

def sort_gems_and_groups
current_lines.each do |line|
if line.starts_with?(/group/)
@current_group = line
end

# Consolidate gem groups
if current_group
if line.starts_with?(/end/)
@current_group = nil
elsif !line.starts_with?(/group/)
gem_groups[current_group] ||= []
gem_groups[current_group] << line
end
# Add non-grouped gems
elsif !line.starts_with?(/\n/)
new_lines << line
@current_group = nil
end
end
end

def add_gem_groups_to_gemfile
gem_groups.keys.each do |group|
gems = gem_groups[group]

gems.each_with_index do |gem, index|
if index == 0
new_lines << group
end

new_lines << gem

if gems.size == (index + 1)
new_lines << "end\n"
end
end
end
end

def add_line_breaks
new_lines.each_with_index do |line, index|
previous_line = new_lines[index - 1] if index > 0
next_line = new_lines[index + 1]
marker = index + 1

# Add line break if it's a gem and the next line is commented out
if (line.starts_with?(/\s*gem/) || line.starts_with?(/\s*\#\s*gem/)) && next_line&.starts_with?(/\s*\#/)
new_line_markers << marker
end

# Add line break if it's a commented out gem and the next line is a gem
if line.starts_with?(/\s*\#\s*gem/) && next_line&.starts_with?(/\s*gem/)
new_line_markers << marker
end

# Add line break if it's a gem with a comment and the next line is a gem
if previous_line&.starts_with?(/\s*\#/) \
&& line.starts_with?(/\s*gem/) \
&& next_line&.starts_with?(/\s*gem/) \
&& !previous_line.starts_with?(/\s*\#\s*gem/)
new_line_markers << marker
end

# Add a line break if it's /end/
if line.starts_with?(/end/)
new_line_markers << marker
end

# Add a line break if it's a gem and the next line is a group
if line.starts_with?(/gem/) && next_line&.starts_with?(/group/)
new_line_markers << marker
end

# Add line break if it's /source/ or /ruby/
if line.starts_with?(/\w/) && !line.starts_with?(/\s*(gem|group|end)/)
new_line_markers << marker
end
end

new_line_markers.each_with_index do |marker, index|
# Each time we insert, the original marker if off by 1
marker_offset = marker + index

new_lines.insert(marker_offset, "\n")
end
end

def cleanup
# Remove last line
if /\n/.match?(new_lines.last)
new_lines.pop
end
end
end
end
end
7 changes: 7 additions & 0 deletions lib/tasks/suspenders.rake
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,11 @@ namespace :suspenders do
Rake::Task["db:test:prepare"].invoke
end
end

namespace :cleanup do
desc "Organizes Gemfile"
task :organize_gemfile do
Suspenders::Cleanup::OrganizeGemfile.perform(Rails.root.join("Gemfile"))
end
end
end
4 changes: 0 additions & 4 deletions lib/tasks/suspenders_tasks.rake

This file was deleted.

85 changes: 85 additions & 0 deletions test/fixtures/files/gemfile_clean
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
source "https://rubygems.org"

ruby "3.3.0"

# Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main"
gem "rails", "~> 7.1.3", ">= 7.1.3.2"

# The original asset pipeline for Rails [https://github.com/rails/sprockets-rails]
gem "sprockets-rails"

# Use postgresql as the database for Active Record
gem "pg", "~> 1.1"

# Use the Puma web server [https://github.com/puma/puma]
gem "puma", ">= 5.0"

# Use JavaScript with ESM import maps [https://github.com/rails/importmap-rails]
gem "importmap-rails"

# Hotwire's SPA-like page accelerator [https://turbo.hotwired.dev]
gem "turbo-rails"

# Hotwire's modest JavaScript framework [https://stimulus.hotwired.dev]
gem "stimulus-rails"

# Build JSON APIs with ease [https://github.com/rails/jbuilder]
gem "jbuilder"

# Use Redis adapter to run Action Cable in production
gem "redis", ">= 4.0.1"

# Use Kredis to get higher-level data types in Redis [https://github.com/rails/kredis]
# gem "kredis"

# Use Active Model has_secure_password [https://guides.rubyonrails.org/active_model_basics.html#securepassword]
# gem "bcrypt", "~> 3.1.7"

# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem "tzinfo-data", platforms: %i[windows jruby]

# Reduces boot times through caching; required in config/boot.rb
gem "bootsnap", require: false

# Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images]
# gem "image_processing", "~> 1.2"

gem "cssbundling-rails"
gem "inline_svg"
gem "sidekiq"
gem "title"

group :development, :test do
# See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem
gem "debug", platforms: %i[mri windows]

gem "suspenders", github: "thoughtbot/suspenders", branch: "suspenders-3-0-0-web-generator"
gem "bundler-audit", ">= 0.7.0", require: false
gem "factory_bot_rails"
gem "rspec-rails", "~> 6.1.0"
gem "better_html", require: false
gem "erb_lint", require: false
gem "erblint-github", require: false
gem "standard"
end

group :development do
# Use console on exceptions pages [https://github.com/rails/web-console]
gem "web-console"

# Add speed badges [https://github.com/MiniProfiler/rack-mini-profiler]
# gem "rack-mini-profiler"

# Speed up commands on slow machines / big apps [https://github.com/rails/spring]
# gem "spring"
end

group :test do
gem "capybara_accessibility_audit"
gem "capybara_accessible_selectors", github: "citizensadvice/capybara_accessible_selectors"
gem "capybara"
gem "action_dispatch-testing-integration-capybara", github: "thoughtbot/action_dispatch-testing-integration-capybara", tag: "v0.1.1", require: "action_dispatch/testing/integration/capybara/rspec"
gem "selenium-webdriver"
gem "shoulda-matchers", "~> 6.0"
gem "webmock"
end
101 changes: 101 additions & 0 deletions test/fixtures/files/gemfile_messy
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
source "https://rubygems.org"

ruby "3.3.0"

# Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main"
gem "rails", "~> 7.1.3", ">= 7.1.3.2"

# The original asset pipeline for Rails [https://github.com/rails/sprockets-rails]
gem "sprockets-rails"

# Use postgresql as the database for Active Record
gem "pg", "~> 1.1"

# Use the Puma web server [https://github.com/puma/puma]
gem "puma", ">= 5.0"

# Use JavaScript with ESM import maps [https://github.com/rails/importmap-rails]
gem "importmap-rails"

# Hotwire's SPA-like page accelerator [https://turbo.hotwired.dev]
gem "turbo-rails"

# Hotwire's modest JavaScript framework [https://stimulus.hotwired.dev]
gem "stimulus-rails"

# Build JSON APIs with ease [https://github.com/rails/jbuilder]
gem "jbuilder"

# Use Redis adapter to run Action Cable in production
gem "redis", ">= 4.0.1"

# Use Kredis to get higher-level data types in Redis [https://github.com/rails/kredis]
# gem "kredis"

# Use Active Model has_secure_password [https://guides.rubyonrails.org/active_model_basics.html#securepassword]
# gem "bcrypt", "~> 3.1.7"

# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem "tzinfo-data", platforms: %i[windows jruby]

# Reduces boot times through caching; required in config/boot.rb
gem "bootsnap", require: false

# Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images]
# gem "image_processing", "~> 1.2"

group :development, :test do
# See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem
gem "debug", platforms: %i[mri windows]
end

group :development do
# Use console on exceptions pages [https://github.com/rails/web-console]
gem "web-console"

# Add speed badges [https://github.com/MiniProfiler/rack-mini-profiler]
# gem "rack-mini-profiler"

# Speed up commands on slow machines / big apps [https://github.com/rails/spring]
# gem "spring"
end

group :development, :test do
gem "suspenders", github: "thoughtbot/suspenders", branch: "suspenders-3-0-0-web-generator"
end

group :test do
gem "capybara_accessibility_audit"
gem "capybara_accessible_selectors", github: "citizensadvice/capybara_accessible_selectors"
end
gem "cssbundling-rails"

group :development, :test do
gem "bundler-audit", ">= 0.7.0", require: false
end
gem "inline_svg"

group :development, :test do
gem "factory_bot_rails"
end
gem "sidekiq"
gem "title"

group :development, :test do
gem "rspec-rails", "~> 6.1.0"
end

group :test do
gem "capybara"
gem "action_dispatch-testing-integration-capybara", github: "thoughtbot/action_dispatch-testing-integration-capybara", tag: "v0.1.1", require: "action_dispatch/testing/integration/capybara/rspec"
gem "selenium-webdriver"
gem "shoulda-matchers", "~> 6.0"
gem "webmock"
end

group :development, :test do
gem "better_html", require: false
gem "erb_lint", require: false
gem "erblint-github", require: false
gem "standard"
end
23 changes: 23 additions & 0 deletions test/suspenders/cleanup/organize_gemfile_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
require "test_helper"
require "tempfile"
require_relative "../../../lib/suspenders/cleanup/organize_gemfile"

module Suspenders
module Cleanup
class OrganizeGemfileTest < ActiveSupport::TestCase
test "organizes Gemfile by group" do
original = file_fixture("gemfile_messy").read
modified = file_fixture("gemfile_clean").read

Tempfile.create "Gemfile" do |gemfile|
gemfile.write original
gemfile.rewind

Suspenders::Cleanup::OrganizeGemfile.perform(gemfile.path)

assert_equal modified, gemfile.read
end
end
end
end
end