Skip to content

Commit

Permalink
add snippet rails/convert_active_record_dirty_5_0_to_5_1
Browse files Browse the repository at this point in the history
  • Loading branch information
flyerhzm committed Mar 14, 2021
1 parent 327a157 commit e1a3b31
Show file tree
Hide file tree
Showing 5 changed files with 210 additions and 1 deletion.
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ gem 'coveralls', require: false
gem 'fakefs', require: 'fakefs/safe'
gem 'rake'
gem 'rspec'
gem 'synvert-core', '>= 0.21.2'
gem 'synvert-core', '>= 0.23.0'

gem 'guard'
gem 'guard-rspec'
144 changes: 144 additions & 0 deletions lib/rails/convert_active_record_dirty_5_0_to_5_1.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
# frozen_string_literal: true

Synvert::Rewriter.new 'rails', 'convert_active_record_dirty_5_0_to_5_1' do
description <<~EOS
It converts ActiveRecord::Dirty 5.0 to 5.1
```ruby
class Post < ActiveRecord::Base
before_create :call_before_create
before_update :call_before_update, if: :title_changed?
before_save :call_before_save, if: -> { status_changed? || summary_changed? }
after_create :call_after_create
after_update :call_after_update, if: :title_changed?
after_save :call_after_save, if: -> { status_changed? || summary_changed? }
def call_before_create
if title_changed?
changes
end
end
def call_after_create
if title_changed?
changes
end
end
end
```
=>
```ruby
class Post < ActiveRecord::Base
before_create :call_before_create
before_update :call_before_update, if: :will_save_change_to_title?
before_save :call_before_save, if: -> { will_save_change_to_status? || will_save_change_to_summary? }
after_create :call_after_create
after_update :call_after_update, if: :saved_change_to_title?
after_save :call_after_save, if: -> { saved_change_to_status? || saved_change_to_summary? }
def call_before_create
if will_save_change_to_title?
changes_to_save
end
end
def call_after_create
if saved_change_to_title?
saved_changes
end
end
end
```
EOS

if_gem 'activerecord', { gte: '5.1.0' }

BEFORE_CALLBACK_CHANGES = {
/(\w+)_changed\?$/ => 'will_save_change_to_{{attribute}}?',
/(\w+)_change$/ => '{{attribute}}_change_to_be_saved',
/(\w+)_was$/ => '{{attribute}}_in_database',
'changes' => 'changes_to_save',
'changed?' => 'has_changes_to_save?',
'changed' => 'changed_attribute_names_to_save',
'changed_attributes' => 'attributes_in_database'
}

AFTER_CALLBACK_CHANGES = {
/(\w+)_changed\?$/ => 'saved_change_to_{{attribute}}?',
/(\w+)_change$/ => 'saved_change_to_{{attribute}}',
/(\w+)_was$/ => '{{attribute}}_before_last_save',
'changes' => 'saved_changes',
'changed?' => 'saved_changes?',
'changed' => 'saved_changes.keys',
'changed_attributes' => 'saved_changes.transform_values(&:first)'
}

helper_method :convert_callback do |before_name, after_name|
with_node type: 'sym', to_value: before_name do
if before_name.is_a?(Regexp)
node.to_value =~ before_name
replace_with ":#{after_name.sub('{{attribute}}', $1)}"
else
replace_with after_name
end
end
with_node type: 'send', receiver: nil, message: before_name do
if before_name.is_a?(Regexp)
node.message.to_s =~ before_name
replace_with after_name.sub('{{attribute}}', $1)
else
replace_with after_name
end
end
end

within_files 'app/models/**/*.rb' do
before_callback_names = []

%i[before_create before_update before_save].each do |callback_name|
with_node type: 'send', receiver: nil, message: callback_name do
before_callback_names << node.arguments[0].to_value
if node.arguments[1] && node.arguments[1].type == :hash
goto_node node.arguments[1] do
BEFORE_CALLBACK_CHANGES.each do |before_name, after_name|
convert_callback(before_name, after_name)
end
end
end
end
end

with_node type: 'def' do
if before_callback_names.include?(node.name)
BEFORE_CALLBACK_CHANGES.each do |before_name, after_name|
convert_callback(before_name, after_name)
end
end
end

after_callback_names = []

%i[after_create after_update after_save after_commit after_create_commit after_update_commit after_save_commit].each do |callback_name|
with_node type: 'send', receiver: nil, message: callback_name do
after_callback_names << node.arguments[0].to_value
if node.arguments[1] && node.arguments[1].type == :hash
goto_node node.arguments[1] do
AFTER_CALLBACK_CHANGES.each do |before_name, after_name|
convert_callback(before_name, after_name)
end
end
end
end
end

with_node type: 'def' do
if after_callback_names.include?(node.name)
AFTER_CALLBACK_CHANGES.each do |before_name, after_name|
convert_callback(before_name, after_name)
end
end
end
end
end
2 changes: 2 additions & 0 deletions lib/rails/upgrade_5_0_to_5_1.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
`Rails.application.config.secrets[:smtp_settings][:address]`
EOS

add_snippet 'rails', 'convert_active_record_dirty_5_0_to_5_1'

if_gem 'rails', { gte: '5.1.0' }

within_files '**/*.rb' do
Expand Down
58 changes: 58 additions & 0 deletions spec/rails/convert_active_record_dirty_5_0_to_5_1_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe 'Convert ActiveRecord::Dirty 5.0 to 5.1' do
let(:rewriter_name) { 'rails/convert_active_record_dirty_5_0_to_5_1' }
let(:fake_file_path) { 'app/models/post.rb' }
let(:test_content) {
<<~EOS
class Post < ActiveRecord::Base
before_create :call_before_create
before_update :call_before_update, unless: :title_changed?
before_save :call_before_save, if: -> { status_changed? || summary_changed? }
after_create :call_after_create
after_update :call_after_update, unless: :title_changed?
after_save :call_after_save, if: -> { status_changed? || summary_changed? }
def call_before_create
if title_changed?
changes
end
end
def call_after_create
if title_changed?
changes
end
end
end
EOS
}
let(:test_rewritten_content) {
<<~EOS
class Post < ActiveRecord::Base
before_create :call_before_create
before_update :call_before_update, unless: :will_save_change_to_title?
before_save :call_before_save, if: -> { will_save_change_to_status? || will_save_change_to_summary? }
after_create :call_after_create
after_update :call_after_update, unless: :saved_change_to_title?
after_save :call_after_save, if: -> { saved_change_to_status? || saved_change_to_summary? }
def call_before_create
if will_save_change_to_title?
changes_to_save
end
end
def call_after_create
if saved_change_to_title?
saved_changes
end
end
end
EOS
}

include_examples 'convertable'
end
5 changes: 5 additions & 0 deletions spec/rails/upgrade_5_0_to_5_1_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,10 @@ def configs
let(:test_contents) { [post_model_content] }
let(:test_rewritten_contents) { [post_model_rewritten_content] }

before do
load_sub_snippets(%w[rails/convert_active_record_dirty_5_0_to_5_1])
end


include_examples 'convertable with multiple files'
end

0 comments on commit e1a3b31

Please sign in to comment.