1 2 3 4 5 6 7 8 9 10 11 12 13 14
def replace_keywords(keyword_hash, text_to_parse) keyword_hash.each do |key, value| new_key = key.dup # escape the closing brace for insertion into regexp new_key.sub!(/\}/, "\}") eval("text_to_parse.gsub!(/\\" + new_key + "/, '" + value + "')") end end my_hash = { '{city}' => 'Chicago', '{state}' => 'Illinois' } my_text = "Welcome to {city}, {state}" replace_keywords( my_hash, my_text ) # returns 'Welcome to Chicago, Illinois'
Refactorings
No refactoring yet !
mvanholstyn
November 16, 2007, November 16, 2007 02:50, permalink
1 2 3 4 5 6 7 8 9 10
def replace_keywords(keyword_hash, text_to_parse) text_to_parse.gsub(/\{(.*?)\}/) do |match| keyword_hash[$1] || match end end my_hash = { 'city' => 'Chicago', 'state' => 'Illinois' } my_text = "Welcome to {city}, {state}" puts replace_keywords( my_hash, my_text ) # =>'Welcome to Chicago, Illinois'
Bilson
November 16, 2007, November 16, 2007 03:14, permalink
Wow. I won't pretend that I understand exactly what's going on here, but it looks much slicker than my solution.
However, it is just printing "Welcome to {city}, {state} when I run it.
Jason Dew
November 16, 2007, November 16, 2007 03:18, permalink
How about this?
1 2 3 4 5 6 7 8 9 10 11 12
def replace_keywords(keywords, text) keywords.each do |keyword, replacement| text.send( 'gsub!', "\{#{keyword}\}", "#{replacement}" ) end text end keywords = { 'city' => 'Chicago', 'state' => 'Illinois' } text = "Welcome to {city}, {state}" puts replace_keywords(keywords, text)
mvanholstyn
November 16, 2007, November 16, 2007 04:30, permalink
bilson -- that code is running for me -- you sure the replacements are not taking place?
Scott Patten
November 16, 2007, November 16, 2007 05:41, permalink
If you make the first argument to gsub a string rather than a reg-exp, it gets much easier.
1 2 3 4 5 6 7 8 9 10 11 12
def replace_keywords(keyword_hash, text_to_parse) keyword_hash.each do |key, value| text_to_parse.gsub!(key, value) end text_to_parse end my_hash = { '{city}' => 'Chicago', '{state}' => 'Illinois' } my_text = "Welcome to {city}, {state}" puts replace_keywords( my_hash, my_text ) # returns 'Welcome to Chicago, Illinois'
Bilson
November 16, 2007, November 16, 2007 06:00, permalink
Ha. Agreed.
Thanks to all refactorers. All great stuff.
Are there any common courtesies I should be following here? Am I supposed to rate every refactoring post in this thread?
Best Regards,
Bilson
Jason Dew
November 16, 2007, November 16, 2007 13:16, permalink
I agree with Scott about making the first argument to gsub! a string rather than a hash and I also agree with not using send (or eval). However, I also think that you should DRY up the hash by removing the curly braces. So, to add onto Scott's code:
About the common courtesies, I would say rate them and leave comments for the refactorers.
1 2 3 4 5 6 7 8 9 10 11 12
def replace_keywords(keywords, text) keywords.each do |keyword, replacement| text.gsub! "\{#{keyword}\}", replacement end text end keywords = { 'city' => 'Chicago', 'state' => 'Illinois' } text = "Welcome to {city}, {state}" puts replace_keywords(keywords, text)
Bilson
November 17, 2007, November 17, 2007 00:00, permalink
This is really getting whipped into shape now. I have incorporated the code above and also converted it to an instance method.
I would actually like to be able to use this functionality on any object. Would this be better as an application_helper or module?
Thanks to everyone. Also, I removed the escape characters from the #{keyword} portion. They don't seem to be necessary since it is just a string value.
Best Regards,
Bilson
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
class Thing < ActiveRecord::Base def replace_placeholders(placeholders) placeholders.each do |placeholder, replacement| self.text.gsub! "{#{placeholder}}", replacement end self end end # call in controller with... placeholders = { 'city' => 'Chicago', 'state' => 'Illinois' } text = "Welcome to {city}, {state}" puts text.replace_placeholders(placeholders) #=> "Welcome to Chicago, Illinois"
Scott Patten
November 17, 2007, November 17, 2007 06:56, permalink
Jason, good call on getting rid of the curly brackets. I slapped myself on the forehead when I saw that :).
Bilson, I'm not sure exactly what you mean by "I'd like to be able to use this on any object". I'm going to interpret it as meaning that you want to use this in any Active Record Model, or in any view, but only want to use it on Strings. If this is the case, then I'd just add a replace_placeholders method to String. You could then place this in a file in /lib (or in a plugin, in a file in /vendor/plugins/text_replacer/lib). You'd call it like your last refactoring:
placeholders = { 'city' => 'Chicago', 'state' => 'Illinois' }
text = "Welcome to {city}, {state}"
puts text.replace_placeholders(placeholders) #=> "Welcome to Chicago, Illinois"
1 2 3 4 5 6 7 8 9 10 11
class String def replace_placeholders(placeholders) text = self.dup placeholders.each do |placeholder, replacement| text.gsub!("{#{placeholder}}", replacement) end text end end
A simple method that replaces multiple keywords in a string surrounded by curly braces.
This works, but surely there is a much easier way.