1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Merge pull request #43984 from jonathanhefner/fix-route-action-revocation

Fix generated route revocation
This commit is contained in:
Rafael Mendonça França 2022-01-05 15:47:20 -05:00 committed by GitHub
commit f9761739a3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 76 additions and 15 deletions

View file

@ -279,26 +279,32 @@ module Rails
# route "root 'welcome#index'" # route "root 'welcome#index'"
# route "root 'admin#index'", namespace: :admin # route "root 'admin#index'", namespace: :admin
def route(routing_code, namespace: nil) def route(routing_code, namespace: nil)
routing_code = Array(namespace).reverse.reduce(routing_code) do |code, ns| namespace = Array(namespace)
"namespace :#{ns} do\n#{optimize_indentation(code, 2)}end" namespace_pattern = route_namespace_pattern(namespace)
routing_code = namespace.reverse.reduce(routing_code) do |code, name|
"namespace :#{name} do\n#{rebase_indentation(code, 2)}end"
end end
log :route, routing_code log :route, routing_code
after_pattern = Array(namespace).each_with_index.reverse_each.reduce(nil) do |pattern, (ns, i)|
margin = "\\#{i + 1}[ ]{2}"
"(?:(?:^[ ]*\n|^#{margin}.*\n)*?^(#{margin})namespace :#{ns} do\n#{pattern})?"
end.then do |pattern|
/^([ ]*).+\.routes\.draw do[ ]*\n#{pattern}/
end
in_root do in_root do
if existing = match_file("config/routes.rb", after_pattern) if namespace_match = match_file("config/routes.rb", namespace_pattern)
base_indent, *, prev_indent = existing.captures.compact.map(&:length) base_indent, *, existing_block_indent = namespace_match.captures.compact.map(&:length)
routing_code = optimize_indentation(routing_code, base_indent + 2).lines.grep_v(/^[ ]{,#{prev_indent}}\S/).join existing_line_pattern = /^[ ]{,#{existing_block_indent}}\S.+\n?/
routing_code = rebase_indentation(routing_code, base_indent + 2).gsub(existing_line_pattern, "")
namespace_pattern = /#{Regexp.escape namespace_match.to_s}/
end end
inject_into_file "config/routes.rb", routing_code, after: after_pattern, verbose: false, force: false inject_into_file "config/routes.rb", routing_code, after: namespace_pattern, verbose: false, force: false
if behavior == :revoke && namespace.any? && namespace_match
empty_block_pattern = /(#{namespace_pattern})((?:\s*end\n){1,#{namespace.size}})/
gsub_file "config/routes.rb", empty_block_pattern, verbose: false, force: true do |matched|
beginning, ending = empty_block_pattern.match(matched).captures
ending.sub!(/\A\s*end\n/, "") while !ending.empty? && beginning.sub!(/^[ ]*namespace .+ do\n\s*\z/, "")
beginning + ending
end
end
end end
end end
@ -363,6 +369,7 @@ module Rails
return "#{value}\n" unless value.is_a?(String) return "#{value}\n" unless value.is_a?(String)
"#{value.strip_heredoc.indent(amount).chomp}\n" "#{value.strip_heredoc.indent(amount).chomp}\n"
end end
alias rebase_indentation optimize_indentation
# Indent the +Gemfile+ to the depth of @indentation # Indent the +Gemfile+ to the depth of @indentation
def indentation # :doc: def indentation # :doc:
@ -387,6 +394,16 @@ module Rails
def match_file(path, pattern) def match_file(path, pattern)
File.read(path).match(pattern) if File.exist?(path) File.read(path).match(pattern) if File.exist?(path)
end end
def route_namespace_pattern(namespace)
namespace.each_with_index.reverse_each.reduce(nil) do |pattern, (name, i)|
cummulative_margin = "\\#{i + 1}[ ]{2}"
blank_or_indented_line = "^[ ]*\n|^#{cummulative_margin}.*\n"
"(?:(?:#{blank_or_indented_line})*?^(#{cummulative_margin})namespace :#{name} do\n#{pattern})?"
end.then do |pattern|
/^([ ]*).+\.routes\.draw do[ ]*\n#{pattern}/
end
end
end end
end end
end end

View file

@ -648,6 +648,43 @@ class ActionsTest < Rails::Generators::TestCase
ROUTING_CODE ROUTING_CODE
end end
test "route with namespace option revokes route without breaking existing namespace blocks" do
run_generator
action :route, <<~ROUTING_CODE.chomp
namespace :baz do
get 'foo1'
namespace :qux do
get 'foo2'
namespace :hoge do
get 'foo3'
end
end
get 'bar1'
end
ROUTING_CODE
revoke :route, "get 'foo2'", namespace: %w[baz qux]
assert_routes <<~ROUTING_CODE.chomp
namespace :baz do
get 'foo1'
namespace :qux do
namespace :hoge do
get 'foo3'
end
end
get 'bar1'
end
ROUTING_CODE
revoke :route, "get 'foo3'", namespace: %w[baz qux hoge]
assert_routes <<~ROUTING_CODE.chomp
namespace :baz do
get 'foo1'
get 'bar1'
end
ROUTING_CODE
end
def test_readme def test_readme
run_generator run_generator
assert_called(Rails::Generators::AppGenerator, :source_root, times: 2, returns: destination_root) do assert_called(Rails::Generators::AppGenerator, :source_root, times: 2, returns: destination_root) do
@ -682,8 +719,15 @@ class ActionsTest < Rails::Generators::TestCase
end end
private private
def action(*args, **kwargs, &block) def action(...)
capture(:stdout) { generator.send(*args, **kwargs, &block) } capture(:stdout) { generator.send(...) }
end
def revoke(...)
original_behavior, generator.behavior = generator.behavior, :revoke
action(...)
ensure
generator.behavior = original_behavior
end end
def assert_runs(commands, config = {}, &block) def assert_runs(commands, config = {}, &block)