Add `config.generators.after_generate` for processing to generated files

Register a callback that will get called right after generators has
finished.

This is useful if users want to process generated files.
For example, can execute an autocorrect of RuboCop for generated files
as like following.

```ruby
config.generators.after_generate do |files|
  system("bundle exec rubocop --auto-correct " + files.join(" "), exception: true)
end
```
This commit is contained in:
yuuji.yaginuma 2019-06-19 17:22:46 +09:00
parent e61bdbf315
commit fde100d18e
8 changed files with 81 additions and 3 deletions

View File

@ -1,3 +1,9 @@
* Add `config.generators.after_generate` for processing to generated files.
Register a callback that will get called right after generators has finished.
*Yuji Yaginuma*
* Make test file patterns configurable via Environment variables
This makes test file patterns configurable via two environment variables:

View File

@ -108,7 +108,7 @@ module Rails
class Generators #:nodoc:
attr_accessor :aliases, :options, :templates, :fallbacks, :colorize_logging, :api_only
attr_reader :hidden_namespaces
attr_reader :hidden_namespaces, :after_generate_callbacks
def initialize
@aliases = Hash.new { |h, k| h[k] = {} }
@ -118,6 +118,7 @@ module Rails
@colorize_logging = true
@api_only = false
@hidden_namespaces = []
@after_generate_callbacks = []
end
def initialize_copy(source)
@ -131,6 +132,10 @@ module Rails
@hidden_namespaces << namespace
end
def after_generate(&block)
@after_generate_callbacks << block
end
def method_missing(method, *args)
method = method.to_s.sub(/=$/, "").to_sym

View File

@ -80,6 +80,7 @@ module Rails
templates_path.concat config.templates
templates_path.uniq!
hide_namespaces(*config.hidden_namespaces)
after_generate_callbacks.replace config.after_generate_callbacks
end
def templates_path #:nodoc:
@ -94,6 +95,10 @@ module Rails
@options ||= DEFAULT_OPTIONS.dup
end
def after_generate_callbacks # :nodoc:
@after_generate_callbacks ||= []
end
# Hold configured generators fallbacks. If a plugin developer wants a
# generator group to fallback to another group in case of missing generators,
# they can add a fallback.
@ -269,6 +274,7 @@ module Rails
if klass = find_by_namespace(names.pop, names.any? && names.join(":"))
args << "--help" if args.empty? && klass.arguments.any?(&:required?)
klass.start(args, config)
run_after_generate_callback if config[:behavior] == :invoke
else
options = sorted_groups.flat_map(&:last)
suggestion = Rails::Command::Spellchecker.suggest(namespace.to_s, from: options)
@ -281,6 +287,11 @@ module Rails
end
end
def add_generated_file(file) # :nodoc:
(@@generated_files ||= []) << file
file
end
private
def print_list(base, namespaces) # :doc:
namespaces = namespaces.reject { |n| hidden_namespaces.include?(n) }
@ -314,6 +325,15 @@ module Rails
def file_lookup_paths # :doc:
@file_lookup_paths ||= [ "{#{lookup_paths.join(',')}}", "**", "*_generator.rb" ]
end
def run_after_generate_callback
if defined?(@@generated_files) && !@@generated_files.empty?
@after_generate_callbacks.each do |callback|
callback.call(@@generated_files)
end
@@generated_files = []
end
end
end
end
end

View File

@ -19,6 +19,11 @@ module Rails
exists? && File.binread(existing_migration) == render
end
def invoke!
invoked_file = super
File.exist?(@destination) ? invoked_file : relative_existing_migration
end
def revoke!
say_destination = exists? ? relative_existing_migration : relative_destination
say_status :remove, :red, say_destination

View File

@ -62,13 +62,14 @@ module Rails
dir, base = File.split(destination)
numbered_destination = File.join(dir, ["%migration_number%", base].join("_"))
create_migration numbered_destination, nil, config do
file = create_migration numbered_destination, nil, config do
if ERB.instance_method(:initialize).parameters.assoc(:key) # Ruby 2.6+
ERB.new(::File.binread(source), trim_mode: "-", eoutvar: "@output_buffer").result(context)
else
ERB.new(::File.binread(source), nil, "-", "@output_buffer").result(context)
end
end
Rails::Generators.add_generated_file(file)
end
end
end

View File

@ -22,7 +22,7 @@ module Rails
no_tasks do
def template(source, *args, &block)
inside_template do
super
Rails::Generators.add_generated_file(super)
end
end

View File

@ -217,5 +217,37 @@ module ApplicationTests
output = rails("generate", "model", "post", "title:string", "body:string", "--force")
assert_no_match(/The name 'Post' is either already used in your application or reserved/, output)
end
test "generators with after_generate callback" do
model_file = File.join(app_path, "app/models/post.rb")
with_config do |c|
c.generators.after_generate do |files|
expected = %w(
db/migrate/20000101000000_create_posts.rb
app/models/post.rb
test/models/post_test.rb
test/fixtures/posts.yml
app/controllers/posts_controller.rb
app/views/posts/index.html.erb
app/views/posts/edit.html.erb
app/views/posts/show.html.erb
app/views/posts/new.html.erb
app/views/posts/_form.html.erb
test/controllers/posts_controller_test.rb
test/system/posts_test.rb
app/helpers/posts_helper.rb
)
assert_equal expected, files
File.open(model_file, "a") { |f| f.write("# Add comment to model") }
end
end
travel_to Time.utc(2000, 1, 1) do
rails("generate", "scaffold", "post", "title:string")
end
assert_match(/# Add comment to model/, File.read(model_file))
end
end
end

View File

@ -73,6 +73,15 @@ class CreateMigrationTest < Rails::Generators::TestCase
assert_predicate @migration, :identical?
end
def test_invoke_return_existing_file_when_exists_identical
migration_exists!
create_migration
invoked_file = nil
quietly { invoked_file = @migration.invoke! }
assert_equal @existing_migration.relative_existing_migration, invoked_file
end
def test_invoke_when_exists_not_identical
migration_exists!
create_migration { "different content" }