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:
commit
f9761739a3
2 changed files with 76 additions and 15 deletions
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in a new issue