Skip to content

Instantly share code, notes, and snippets.

@ziaulrehman40
Last active June 24, 2024 06:39
Show Gist options
  • Save ziaulrehman40/6b61837627d97d3702e98209b7a214eb to your computer and use it in GitHub Desktop.
Save ziaulrehman40/6b61837627d97d3702e98209b7a214eb to your computer and use it in GitHub Desktop.
Ruby codemod: transformto rails 7.2 enum syntax with validate options to avoid argumentErrors on assignment
# Transforms
# From: enum name: values
# To: enum :name, values, validate: { allow_nil: true }
# Also removes _ from prefix and suffix for the new syntax to avoid un-intended bugs
# You can modify this tranformer in transform_enum method as per your needs
# USAGE:
# 1. gem install parser
# 2. run this file providing a single file or parent folder like: ruby tranform_enums.rb myApp/app/models OR ruby tranform_enums.rb myApp/app/models/user.rb
require 'parser/current'
require 'find'
class EnumTransformer < Parser::TreeRewriter
def on_send(node)
if node.children[1] == :enum && node.children[2].type == :hash
replace(node.loc.expression, transform_enum(node))
end
super(node)
end
private
def transform_enum(node)
# map name
name = node.children[2].children.first.children.first.children[0]
# map value hash/array
values = node.children[2].children.first.children.last.loc.expression.source
# map additional params
additionals = (node.children[2].children.slice(1..).map { _1.loc.expression.source }).join(', ')
# transform _prefix to prefix
additionals.gsub!('_prefix', 'prefix')
# transform _suffix to suffix
additionals.gsub!('_suffix', 'suffix')
additionals = additionals + ', ' if additionals != ''
"enum :#{name}, #{values}, #{additionals}validate: { allow_nil: true }"
end
end
def process_file(file_path)
puts "Checking #{file_path}"
buffer = Parser::Source::Buffer.new(file_path)
buffer.source = File.read(file_path)
parser = Parser::CurrentRuby.new
ast = parser.parse(buffer)
transformer = EnumTransformer.new
new_source = transformer.rewrite(buffer, ast)
File.write(file_path, new_source)
end
def process_directory(directory_path)
Find.find(directory_path) do |path|
if FileTest.directory?(path)
next
elsif path.end_with?('.rb')
process_file(path)
end
end
end
target_path = ARGV[0]
unless target_path && File.exist?(target_path)
puts 'Please provide a valid file or directory path.'
exit 1
end
if File.directory?(target_path)
process_directory(target_path)
else
process_file(target_path)
end
@Usama-devsinc
Copy link

👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment