Add scripts that automate the where(...).first to find_by(...)refactoring.
This commit is contained in:
parent
8cf937cdcb
commit
f1369e4503
1
Gemfile
1
Gemfile
|
@ -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.
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue