Blog ยป Powerful Rails 3 Templates
Posted on 30 Aug 2012 09:28
Rails 3 templates or Thor scripts can do any kind of modification on source code. As regular expressions can hunt for syntax patterns; you can replace existing methods with new definitions. For example:
def match_mtd(mtd) /^\s*def (#{mtd})\s+((?!end).)*\s+end\s*$/m end gsub_file 'app/models/post.rb', match_mtd('create_permitted\?'), <<-CODE def \\1 acting_user.signed_up? end CODE gsub_file 'app/models/post.rb', match_mtd('update_permitted\?'), <<-CODE def \\1 owner_is? acting_user end CODE
rake rails:template LOCATION=../my_template
Existing methods are found and replaced. Now you have your create_permitted? and update_permitted? methods.
This is extremely useful for automating the replacement of framework generated source code.
Notes:
- In create_permitted\?, ? is escaped because it is inserted in a regular expression. In a regular expression ? only means match any character.
- def \\1. Double escaped 1? If it's not escaped \1 means character with ascii code 1 and it gets replaced. \1 in a regex replacement means first match expression which is the method name here.
Ok. Ok. You cannot match any syntax with a regex. But it has untapped powers to handle most of the cases. ((?!end).)* means zero or more times something that's not 'end'. Let's analyize the expression.
/^\s*def (#{mtd})\s+((?!end).)*\s+end\s*$/m
\s* # 0 or more spaces
def (#{mtd}) # def <mtd>
\s+ # 1 or more spaces
((?!end).)* # 0 or more whatever that's not end
\s+ # 1 or more spaces
end # end
\s* # 0 or more spaces
$ # end of line
/m # match multiline
As you see this expression would not be good if there was an extra end used in the method definition.
Maybe the next idea should be to support Thor with Ruby parser?
If you like this page, please spread the word:
You can contact me if you have questions or corrections.