-
-
Notifications
You must be signed in to change notification settings - Fork 528
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
A gem
action
#1066
A gem
action
#1066
Conversation
For too long we have [suffered] under the tyranny of Rails' mediocre `gem` action! But Rails 6 took it a step too far: it [no longer] supports a `destroy` generator. [suffered]: #915 [no longer]:#1061 (comment) So it's high time we make our own. In the process, encode the rules we like to see: keep gems alphabetical, and use the `group` block syntax instead of the `:group` argument. When inserting a gem, we have to consider two cases: do we have a group specification? If we don't have a group name, insert it alphabetically before the first non-indented `gem "..."` declaration. If we do have a group name, find the block for that group and insert it alphabetically. But there's also the chance thar we are the first to add this group, in which case we should add the group with the `gem` line at the end. When removing a group, we again consider the groups case. If there is no group specification, remove the first matching non-indented `gem "..."` declaration. If we have a group spec, find the group block in the Gemfile and remove it. If there is no such group block, do nothing. Closes #915.
positioning = final_group(existing_gemfile) | ||
|
||
if positioning | ||
insert_gemline(existing_gemfile, indentation: 2, positioning: positioning) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need to also generate the group block here and below. Whoops!
> No, the "Flying Saucer Men" are the Flying Saucer Men-- Narzac! Galaxy > 66, the Evil Empire! What's wrong with you! Clavius, AEon Flux, "Utopia or Deuteranopia?" --- In other news, we were generating stylesheet stuff when `--api` was passed and this lead to errors. Not sure how this caused us to catch it, but we can fix that now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I ran this version and generated a test project, looking much better! Just a little bit of a mix up with adding suspenders itself and the empty trailing development
group and rack-timeout
gem.
source "https://rubygems.org"
git_source(:github) do |repo_name|
repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/")
"https://github.com/#{repo_name}.git"
end
ruby "2.7.2"
gem "autoprefixer-rails"
gem "bootsnap", require: false
gem "bourbon", ">= 6.0.0"
gem "delayed_job_active_record"
gem "high_voltage"
gem "honeybadger"
gem "inline_svg"
gem "oj"
gem "pg"
gem "puma"
gem "rack-canonical-host"
gem "rack-mini-profiler", require: false
gem "rails", "~> 6.0.0"
gem "recipient_interceptor"
gem "sassc-rails"
gem "simple_form"
gem "skylight"
gem "spring"
gem "spring-watcher-listen", "~> 2.0.0"
gem "sprockets", "< 4"
gem "title"
gem "tzinfo-data", platforms: [:mingw, :x64_mingw, :mswin, :jruby]
gem "webpacker"
group :development do
gem "listen"
gem "rspec-rails", "~> 3.6"
gem "shoulda-matchers"
gem "spring-commands-rspec"
gem "standard"
gem "web-console"
end
group :development, :test do
gem "awesome_print"
gem "bullet"
gem "bundler-audit", ">= 0.7.0", require: false
gem "factory_bot_rails"
gem "pry-byebug"
gem "pry-rails"
end
group :test do
gem "formulaic"
gem "launchy"
gem "simplecov", require: false
gem "timecop"
gem "webdrivers"
gem "webmock"
end
gem "suspenders", group: [:development, :test]
group :development do
end
gem "rack-timeout"
@@ -143,11 +143,11 @@ def generate_default | |||
generate("suspenders:profiler") | |||
generate("suspenders:json") | |||
generate("suspenders:static") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice catch. Do we still want static site support when the api
option is passed? Not necessary to address in this PR just thought of it because of the stylesheet issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah probably not -- but I'm going to save that for another PR.
|
||
def gem_group(gemfile) | ||
groups_re = groups.map { |group| ":#{group}" }.join("[, ]+") | ||
data = /^group[ (]+#{groups_re}[ )]+do.+?^end/mo.match(gemfile) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Small thing: This works for the case when the groups are in the order specified (ie: :test, :development
vs. :development, :test
). Don't really think it's worth addressing since I don't know a simple way to do it with regex and it's simple enough to just make sure we are specifying the correct order in all of our calls to gem
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right ... we could explode all the permutations with an |
but it really doesn't seem worth it for just Suspenders.
end | ||
|
||
def gemline | ||
parts = [name, version].compact.map { |part| part.inspect } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
parts = [name, version].compact.map { |part| part.inspect } | |
parts = [name, version].compact.map(&:inspect) |
if groups.present? | ||
positioning = gem_group(existing_gemfile) | ||
|
||
if positioning | ||
insert_gemline(existing_gemfile, indentation: 2, positioning: positioning) | ||
else | ||
positioning = final_group(existing_gemfile) | ||
|
||
if positioning | ||
insert_gemline(existing_gemfile, indentation: 2, positioning: positioning) | ||
else | ||
insert_gemline(existing_gemfile, indentation: 2, positioning: [0, existing_gemfile.bytes.size]) | ||
end | ||
end | ||
else | ||
insert_gemline(existing_gemfile, indentation: 0, positioning: [0, existing_gemfile.bytes.size]) | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a deep enough nested conditional block it might benefit from some more method extractions for readability
end | ||
|
||
def invoke! | ||
existing_gemfile = IO.read(gemfile_path) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason we need to pass existing_gemfile
around to all the methods?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was trying to avoid doing IO in the initializer. But maybe it's fine so long as I'm not, like, writing to disc in the initializer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah it's a pretty good reason and it's already this way so your choice on the matter. It would certainly help the arity of the private methods stay to <=2 but at the end of the day it's minor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are all good reasons. One option is to pass the IO object to the initializer, but not very practical. Maybe we could do something like this:
def existing_gemfile
@existing_gemfile ||= IO.read(gemfile_path)
end
Which incurs the IO cost only once and avoids duplication (at the expense of "where does this come from?").
It is certainly a better |
Reliably remove comments from Rails config files when generating Suspenders apps. With the parser gem, we're now removing comments by processing their surrounding code using AST (abstract syntax tree) processors. We were using a regex to do that, which is text-based and thereby subject to edge cases that only a proper AST solution can handle. [This pull request](#1044) made changes to some config files to fix the Action Mailer asset host. While working on merging that PR, the tests were not passing because they looked for an output that was missing in one of the changed config files: ```ruby config.action_mailer.asset_host = %q{"https://#{ENV\.fetch\("ASSET_HOST", ENV\.fetch\("APPLICATION_HOST"\)\)}} ``` The PR code changes are kind of straightforward and that config option should have been present in the config file but it was not. The reason was that Suspenders was removing code comments with an overly permissive regex : (`/^.*#.*$/`), which removed every line containing a `#` character, no matter where they were in the line - so it was also removing the new Action Mailer config setting. That regex was also silently messing up with other config lines, for example: ```ruby config.public_file_server.headers = { 'Cache-Control' => "public, max-age=#{2.days.to_i}" } ``` As a quick fix to merge that PR, I've changed the regex to `/^\s*#.*$/` but it was not an ideal solution - which is what I'm striving for with this PR. With the old text-based regex solution, there were still nasty edge cases to deal with, and we may never know when they'd occur. Also, the previous regex did not work with inline comments. The final aesthetics of the config files could be improved in my opinion. This was how they looked like: ```ruby Rails.application.configure do config.cache_classes = false config.eager_load = false config.consider_all_requests_local = true if Rails.root.join('tmp', 'caching-dev.txt').exist? config.action_controller.perform_caching = true config.action_controller.enable_fragment_cache_logging = true config.cache_store = :memory_store config.public_file_server.headers = { 'Cache-Control' => "public, max-age=#{2.days.to_i}" } else config.action_controller.perform_caching = false config.cache_store = :null_store end config.active_storage.service = :local config.action_mailer.raise_delivery_errors = true config.after_initialize do Bullet.enable = true Bullet.bullet_logger = true Bullet.rails_logger = true end # ... end ``` And with the newest solution they look like this: ```ruby Rails.application.configure do config.cache_classes = false config.eager_load = false config.consider_all_requests_local = true if Rails.root.join('tmp', 'caching-dev.txt').exist? config.action_controller.perform_caching = true config.action_controller.enable_fragment_cache_logging = true config.cache_store = :memory_store config.public_file_server.headers = { 'Cache-Control' => "public, max-age=#{2.days.to_i}" } else config.action_controller.perform_caching = false config.cache_store = :null_store end config.action_mailer.raise_delivery_errors = true config.after_initialize do Bullet.enable = true Bullet.bullet_logger = true Bullet.rails_logger = true end # ... ``` Which preserves newlines where appropriate, so that's easier to read. This pull request uses the `parser` gem, and I feel like introducing that gem in the project may be a good move over the long term. For example, we need to finish up the [gem action](#1066) to sort `gem` declarations alphabetically when adding gems to the `Gemfile`, and the most reliable way to do that is with AST parsing. 1. Make the indentation of some templates match the Rails environment's config files'. This goes along with the aesthetics introduced in this PR. 2. Because of (1), I've also found a bug that was concatenaning two lines of codes in `config/environments/production.rb` with no blank line between them (in email_generator.rb), so I'm taking the opportunity to fix it 3. standardrb fixes after updating to the latest standardrb version
Reliably remove comments from Rails config files when generating Suspenders apps. With the parser gem, we're now removing comments by processing their surrounding code using AST (abstract syntax tree) processors. We were using a regex to do that, which is text-based and thereby subject to edge cases that only a proper AST solution can handle. [This pull request](#1044) made changes to some config files to fix the Action Mailer asset host. While working on merging that PR, the tests were not passing because they looked for an output that was missing in one of the changed config files: ```ruby config.action_mailer.asset_host = %q{"https://#{ENV\.fetch\("ASSET_HOST", ENV\.fetch\("APPLICATION_HOST"\)\)}} ``` The PR code changes are kind of straightforward and that config option should have been present in the config file but it was not. The reason was that Suspenders was removing code comments with an overly permissive regex : (`/^.*#.*$/`), which removed every line containing a `#` character, no matter where they were in the line - so it was also removing the new Action Mailer config setting. That regex was also silently messing up with other config lines, for example: ```ruby config.public_file_server.headers = { 'Cache-Control' => "public, max-age=#{2.days.to_i}" } ``` As a quick fix to merge that PR, I've changed the regex to `/^\s*#.*$/` but it was not an ideal solution - which is what I'm striving for with this PR. With the old text-based regex solution, there were still nasty edge cases to deal with, and we may never know when they'd occur. Also, the previous regex did not work with inline comments. The final aesthetics of the config files could be improved in my opinion. This was how they looked like: ```ruby Rails.application.configure do config.cache_classes = false config.eager_load = false config.consider_all_requests_local = true if Rails.root.join('tmp', 'caching-dev.txt').exist? config.action_controller.perform_caching = true config.action_controller.enable_fragment_cache_logging = true config.cache_store = :memory_store config.public_file_server.headers = { 'Cache-Control' => "public, max-age=#{2.days.to_i}" } else config.action_controller.perform_caching = false config.cache_store = :null_store end config.active_storage.service = :local config.action_mailer.raise_delivery_errors = true config.after_initialize do Bullet.enable = true Bullet.bullet_logger = true Bullet.rails_logger = true end # ... end ``` And with the newest solution they look like this: ```ruby Rails.application.configure do config.cache_classes = false config.eager_load = false config.consider_all_requests_local = true if Rails.root.join('tmp', 'caching-dev.txt').exist? config.action_controller.perform_caching = true config.action_controller.enable_fragment_cache_logging = true config.cache_store = :memory_store config.public_file_server.headers = { 'Cache-Control' => "public, max-age=#{2.days.to_i}" } else config.action_controller.perform_caching = false config.cache_store = :null_store end config.action_mailer.raise_delivery_errors = true config.after_initialize do Bullet.enable = true Bullet.bullet_logger = true Bullet.rails_logger = true end # ... ``` Which preserves newlines where appropriate, so that's easier to read. This pull request uses the `parser` gem, and I feel like introducing that gem in the project may be a good move over the long term. For example, we need to finish up the [gem action](#1066) to sort `gem` declarations alphabetically when adding gems to the `Gemfile`, and the most reliable way to do that is with AST parsing. 1. Make the indentation of some templates match the Rails environment's config files'. This goes along with the aesthetics introduced in this PR. 2. Because of (1), I've also found a bug that was concatenaning two lines of codes in `config/environments/production.rb` with no blank line between them (in email_generator.rb), so I'm taking the opportunity to fix it 3. standardrb fixes after updating to the latest standardrb version
Reliably remove comments from Rails config files when generating Suspenders apps. With the parser gem, we're now removing comments by processing their surrounding code using AST (abstract syntax tree) processors. We were using a regex to do that, which is text-based and thereby subject to edge cases that only a proper AST solution can handle. [This pull request](#1044) made changes to some config files to fix the Action Mailer asset host. While working on merging that PR, the tests were not passing because they looked for an output that was missing in one of the changed config files: ```ruby config.action_mailer.asset_host = %q{"https://#{ENV\.fetch\("ASSET_HOST", ENV\.fetch\("APPLICATION_HOST"\)\)}} ``` The PR code changes are kind of straightforward and that config option should have been present in the config file but it was not. The reason was that Suspenders was removing code comments with an overly permissive regex : (`/^.*#.*$/`), which removed every line containing a `#` character, no matter where they were in the line - so it was also removing the new Action Mailer config setting. That regex was also silently messing up with other config lines, for example: ```ruby config.public_file_server.headers = { 'Cache-Control' => "public, max-age=#{2.days.to_i}" } ``` As a quick fix to merge that PR, I've changed the regex to `/^\s*#.*$/` but it was not an ideal solution - which is what I'm striving for with this PR. With the old text-based regex solution, there were still nasty edge cases to deal with, and we may never know when they'd occur. Also, the previous regex did not work with inline comments. The final aesthetics of the config files could be improved in my opinion. This was how they looked like: ```ruby Rails.application.configure do config.cache_classes = false config.eager_load = false config.consider_all_requests_local = true if Rails.root.join('tmp', 'caching-dev.txt').exist? config.action_controller.perform_caching = true config.action_controller.enable_fragment_cache_logging = true config.cache_store = :memory_store config.public_file_server.headers = { 'Cache-Control' => "public, max-age=#{2.days.to_i}" } else config.action_controller.perform_caching = false config.cache_store = :null_store end config.active_storage.service = :local config.action_mailer.raise_delivery_errors = true config.after_initialize do Bullet.enable = true Bullet.bullet_logger = true Bullet.rails_logger = true end # ... end ``` And with the newest solution they look like this: ```ruby Rails.application.configure do config.cache_classes = false config.eager_load = false config.consider_all_requests_local = true if Rails.root.join('tmp', 'caching-dev.txt').exist? config.action_controller.perform_caching = true config.action_controller.enable_fragment_cache_logging = true config.cache_store = :memory_store config.public_file_server.headers = { 'Cache-Control' => "public, max-age=#{2.days.to_i}" } else config.action_controller.perform_caching = false config.cache_store = :null_store end config.action_mailer.raise_delivery_errors = true config.after_initialize do Bullet.enable = true Bullet.bullet_logger = true Bullet.rails_logger = true end # ... ``` Which preserves newlines where appropriate, so that's easier to read. This pull request uses the `parser` gem, and I feel like introducing that gem in the project may be a good move over the long term. For example, we need to finish up the [gem action](#1066) to sort `gem` declarations alphabetically when adding gems to the `Gemfile`, and the most reliable way to do that is with AST parsing. 1. Make the indentation of some templates match the Rails environment's config files'. This goes along with the aesthetics introduced in this PR. 2. Because of (1), I've also found a bug that was concatenaning two lines of codes in `config/environments/production.rb` with no blank line between them (in email_generator.rb), so I'm taking the opportunity to fix it 3. standardrb fixes after updating to the latest standardrb version
** First motivation Reliably remove comments from Rails config files when generating Suspenders apps. With the parser gem, we're now removing comments by processing their surrounding code using AST (abstract syntax tree) processors. We were using a regex to do that, which is text-based and thereby subject to edge cases that only a proper AST solution can handle. [This pull request](#1044) made changes to some config files to fix the Action Mailer asset host. While working on merging that PR, the tests were not passing because they looked for an output that was missing in one of the changed config files: config.action_mailer.asset_host = %q{"https://#{ENV\.fetch\("ASSET_HOST", ENV\.fetch\("APPLICATION_HOST"\)\)}} The PR code changes are kind of straightforward and that config option should have been present in the config file but it was not. The reason was that Suspenders was removing code comments with an overly permissive regex : (`/^.*#.*$/`), which removed every line containing a `#` character, no matter where they were in the line - so it was also removing the new Action Mailer config setting. That regex was also silently messing up with other config lines, for example: config.public_file_server.headers = { 'Cache-Control' => "public, max-age=#{2.days.to_i}" } As a quick fix to merge that PR, I've changed the regex to `/^\s*#.*$/` but it was not an ideal solution - which is what I'm striving for with this PR. With the old text-based regex solution, there were still nasty edge cases to deal with, and we may never know when they'd occur. Also, the previous regex did not work with inline comments. ** Second motivation The final aesthetics of the config files could be improved in my opinion. This was how they looked like: Rails.application.configure do config.cache_classes = false config.eager_load = false config.consider_all_requests_local = true if Rails.root.join('tmp', 'caching-dev.txt').exist? config.action_controller.perform_caching = true config.action_controller.enable_fragment_cache_logging = true config.cache_store = :memory_store config.public_file_server.headers = { 'Cache-Control' => "public, max-age=#{2.days.to_i}" } else config.action_controller.perform_caching = false config.cache_store = :null_store end config.active_storage.service = :local config.action_mailer.raise_delivery_errors = true config.after_initialize do Bullet.enable = true Bullet.bullet_logger = true Bullet.rails_logger = true end end And with the newest solution they look like this: Rails.application.configure do config.cache_classes = false config.eager_load = false config.consider_all_requests_local = true if Rails.root.join('tmp', 'caching-dev.txt').exist? config.action_controller.perform_caching = true config.action_controller.enable_fragment_cache_logging = true config.cache_store = :memory_store config.public_file_server.headers = { 'Cache-Control' => "public, max-age=#{2.days.to_i}" } else config.action_controller.perform_caching = false config.cache_store = :null_store end config.action_mailer.raise_delivery_errors = true config.after_initialize do Bullet.enable = true Bullet.bullet_logger = true Bullet.rails_logger = true end end Which preserves newlines where appropriate, so that's easier to read. ** Third motivation This pull request uses the `parser` gem, and I feel like introducing that gem in the project may be a good move over the long term. For example, we need to finish up the [gem action](#1066) to sort `gem` declarations alphabetically when adding gems to the `Gemfile`, and the most reliable way to do that is with AST parsing. ** Other related changes 1. Make the indentation of some templates match the Rails environment's config files'. This goes along with the aesthetics introduced in this PR. 2. Because of (1), I've also found a bug that was concatenaning two lines of codes in `config/environments/production.rb` with no blank line between them (in email_generator.rb), so I'm taking the opportunity to fix it 3. standardrb fixes after updating to the latest standardrb version
** First motivation Reliably remove comments from Rails config files when generating Suspenders apps. With the parser gem, we're now removing comments by processing their surrounding code using AST (abstract syntax tree) processors. We were using a regex to do that, which is text-based and thereby subject to edge cases that only a proper AST solution can handle. [This pull request](#1044) made changes to some config files to fix the Action Mailer asset host. While working on merging that PR, the tests were not passing because they looked for an output that was missing in one of the changed config files: config.action_mailer.asset_host = %q{"https://#{ENV\.fetch\("ASSET_HOST", ENV\.fetch\("APPLICATION_HOST"\)\)}} The PR code changes are kind of straightforward and that config option should have been present in the config file but it was not. The reason was that Suspenders was removing code comments with an overly permissive regex : (`/^.*#.*$/`), which removed every line containing a `#` character, no matter where they were in the line - so it was also removing the new Action Mailer config setting. That regex was also silently messing up with other config lines, for example: config.public_file_server.headers = { 'Cache-Control' => "public, max-age=#{2.days.to_i}" } As a quick fix to merge that PR, I've changed the regex to `/^\s*#.*$/` but it was not an ideal solution - which is what I'm striving for with this PR. With the old text-based regex solution, there were still nasty edge cases to deal with, and we may never know when they'd occur. Also, the previous regex did not work with inline comments. ** Second motivation The final aesthetics of the config files could be improved in my opinion. This was how they looked like: Rails.application.configure do config.cache_classes = false config.eager_load = false config.consider_all_requests_local = true if Rails.root.join('tmp', 'caching-dev.txt').exist? config.action_controller.perform_caching = true config.action_controller.enable_fragment_cache_logging = true config.cache_store = :memory_store config.public_file_server.headers = { 'Cache-Control' => "public, max-age=#{2.days.to_i}" } else config.action_controller.perform_caching = false config.cache_store = :null_store end config.active_storage.service = :local config.action_mailer.raise_delivery_errors = true config.after_initialize do Bullet.enable = true Bullet.bullet_logger = true Bullet.rails_logger = true end end And with the newest solution they look like this: Rails.application.configure do config.cache_classes = false config.eager_load = false config.consider_all_requests_local = true if Rails.root.join('tmp', 'caching-dev.txt').exist? config.action_controller.perform_caching = true config.action_controller.enable_fragment_cache_logging = true config.cache_store = :memory_store config.public_file_server.headers = { 'Cache-Control' => "public, max-age=#{2.days.to_i}" } else config.action_controller.perform_caching = false config.cache_store = :null_store end config.action_mailer.raise_delivery_errors = true config.after_initialize do Bullet.enable = true Bullet.bullet_logger = true Bullet.rails_logger = true end end Which preserves newlines where appropriate, so that's easier to read. ** Third motivation This pull request uses the `parser` gem, and I feel like introducing that gem in the project may be a good move over the long term. For example, we need to finish up the [gem action](#1066) to sort `gem` declarations alphabetically when adding gems to the `Gemfile`, and the most reliable way to do that is with AST parsing. ** Other related changes 1. Make the indentation of some templates match the Rails environment's config files'. This goes along with the aesthetics introduced in this PR. 2. Because of (1), I've also found a bug that was concatenating two lines of codes in `config/environments/production.rb` with no blank line between them (in email_generator.rb), so I'm taking the opportunity to fix it 3. standardrb fixes after updating to the latest standardrb version
This commit does the bare minimum to support Rails 6.1.6.1 Because the `gem` command is no longer reversible, we decided to override the method by borrowing as much from the [existing method](https://github.com/rails/rails/blob/04972d9b9ef60796dc8f0917817b5392d61fcf09/railties/lib/rails/generators/actions.rb#L22). The main difference being that we call `append_file` instead of `gsub_file`, so that we can preserve reversibility. However, #1066 provides a more elegant solution. Closes #1060
This commit does the bare minimum to support Rails 6.1.6.1 Because the `gem` command is no longer reversible, we decided to override the method by borrowing as much from the [existing method](https://github.com/rails/rails/blob/04972d9b9ef60796dc8f0917817b5392d61fcf09/railties/lib/rails/generators/actions.rb#L22). The main difference being that we call `append_file` instead of `gsub_file`, so that we can preserve reversibility. However, #1066 provides a more elegant solution. Closes #1060
We might want to consider closing this now that #1104 has been merged. |
@mike-burns do you think we still need this since merging #1104 and #1106? |
Not sure, I haven't kept up. Does the |
@mike-burns yes, the |
For too long we have suffered under the tyranny of Rails' mediocre
gem
action! But Rails 6 took it a step too far: it no longer supports a
destroy
generator.So it's high time we make our own. In the process, encode the rules we
like to see: keep gems alphabetical, and use the
group
block syntaxinstead of the
:group
argument.When inserting a gem, we have to consider two cases: do we have a group
specification? If we don't have a group name, insert it alphabetically
before the first non-indented
gem "..."
declaration. If we do have agroup name, find the block for that group and insert it alphabetically.
But there's also the chance thar we are the first to add this group, in
which case we should add the group with the
gem
line at the end.When removing a group, we again consider the groups case. If there is no
group specification, remove the first matching non-indented
gem "..."
declaration. If we have a group spec, find the group block in the
Gemfile and remove it. If there is no such group block, do nothing.
Closes #915.