Add scripts that automate the where(...).first to find_by(...)refactoring.

This commit is contained in:
Louis Rose 2014-05-06 14:38:29 +01:00
parent 8cf937cdcb
commit f1369e4503
6 changed files with 137 additions and 0 deletions

View File

@ -188,6 +188,7 @@ group :development do
gem 'librarian', '>= 0.0.25', require: false
gem 'annotate'
gem 'foreman', require: false
gem 'metamorpher', '~> 0.1.0'
end
# Gem that enables support for plugins. It is required.

View File

@ -0,0 +1,50 @@
require "optparse"
require_relative "refactorers/refactor_where_first_to_find_by.rb"
require_relative "refactorers/refactor_where_first_not_called_expectations.rb"
require_relative "refactorers/refactor_where_first_mocks.rb"
require_relative "refactorers/refactor_where_first_strict_mocks.rb"
options = { overwrite: true }
OptionParser.new do |opts|
opts.banner = "Usage: refactorer.rb [options]"
opts.on("-d", "--dry-run", "Write changes to console, rather than to source files.") do |v|
options[:overwrite] = false
end
end.parse!
source_dir = ARGV.first || "."
base = File.expand_path(File.join("**", "*.rb"), source_dir)
puts "Refactoring in source directory: #{base}"
[
# Refactor "where(...).first -> find_by(...)"
RefactorWhereFirstToFindBy,
# Refactor ".expect(:where).never" to ".expect(:find_by).never"
RefactorWhereFirstNotCalledExpectations,
# Refactor ".expect(:where).return([X])" to ".expect(:find_by).return(X)"
# and ".stubs(:where).return([X])" to ".stubs(:find_by).return(X)"
RefactorWhereFirstMocks,
# Refactor ".expect(:where).with(...).return([X])" to ".expect(:find_by).with(...).return(X)"
RefactorWhereFirstStrictMocks
].each do |refactorer|
refactorer.new.refactor_files(Dir.glob(base)) do |path, refactored, changes|
if changes.empty?
puts "No changes in #{path}"
else
puts "In #{path}:"
changes.each do |change|
puts "\tAt #{change.original_position}, inserting:\n\t\t#{change.refactored_code}"
puts ""
end
File.open(path, "w") { |f| f.write(refactored) } if options[:overwrite]
end
end
end

View File

@ -0,0 +1,31 @@
require "metamorpher"
class RefactorWhereFirstMocks
include Metamorpher::Refactorer
include Metamorpher::Builders::Ruby
def pattern
builder
.build("TYPE.DOUBLE_METHOD(:where).returns(ARRAY_VALUE)")
.ensuring("DOUBLE_METHOD") { |m| m.name == :expects || m.name == :stubs }
.ensuring("ARRAY_VALUE") { |v| v.name == :array }
# Doesn't match non-array return types, such as Topic.stubs(:where).returns(Topic)
end
def replacement
builder
.build("TYPE.DOUBLE_METHOD(:find_by).returns(SINGLE_VALUE)")
.deriving("SINGLE_VALUE", "ARRAY_VALUE") { |array_value| take_first(array_value) }
end
private
# Refactor the argument from [] to nil, or from [X] to X
def take_first(array_value)
if array_value.children.empty?
builder.build("nil")
else
array_value.children.first
end
end
end

View File

@ -0,0 +1,14 @@
require "metamorpher"
class RefactorWhereFirstNotCalledExpectations
include Metamorpher::Refactorer
include Metamorpher::Builders::Ruby
def pattern
builder.build("TYPE.expects(:where).never")
end
def replacement
builder.build("TYPE.expects(:find_by).never")
end
end

View File

@ -0,0 +1,27 @@
require "metamorpher"
class RefactorWhereFirstStrictMocks
include Metamorpher::Refactorer
include Metamorpher::Builders::Ruby
def pattern
builder.build("TYPE.expects(:where).with(PARAMS_).returns(ARRAY_VALUE)")
end
def replacement
builder
.build("TYPE.expects(:find_by).with(PARAMS_).returns(SINGLE_VALUE)")
.deriving("SINGLE_VALUE", "ARRAY_VALUE") { |array_value| take_first(array_value) }
end
private
# Refactor the argument from [] to nil, or from [X] to X
def take_first(array_value)
if array_value.children.empty?
builder.build("nil")
else
array_value.children.first
end
end
end

View File

@ -0,0 +1,14 @@
require "metamorpher"
class RefactorWhereFirstToFindBy
include Metamorpher::Refactorer
include Metamorpher::Builders::Ruby
def pattern
builder.build("TYPE.where(PARAMS_).first")
end
def replacement
builder.build("TYPE.find_by(PARAMS_)")
end
end