0b7b8a4ba91242f26238424ca491304a

A simple method that replaces multiple keywords in a string surrounded by curly braces.

This works, but surely there is a much easier way.

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 !

F9ac05fdd57915983ccea58699e1f942

mvanholstyn

November 16, 2007, November 16, 2007 02:50, permalink

2 ratings. Login to rate!
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'
0b7b8a4ba91242f26238424ca491304a

Bilson

November 16, 2007, November 16, 2007 03:14, permalink

No rating. Login to rate!

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.

D16d53391068ff0830269149b060789d

Jason Dew

November 16, 2007, November 16, 2007 03:18, permalink

1 rating. Login to rate!

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)
F9ac05fdd57915983ccea58699e1f942

mvanholstyn

November 16, 2007, November 16, 2007 04:30, permalink

No rating. Login to rate!

bilson -- that code is running for me -- you sure the replacements are not taking place?

5392d0a82eb7a8d8c6246f9dbbc2244a

Scott Patten

November 16, 2007, November 16, 2007 05:41, permalink

1 rating. Login to rate!

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'
0b7b8a4ba91242f26238424ca491304a

Bilson

November 16, 2007, November 16, 2007 06:00, permalink

No rating. Login to rate!

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

D16d53391068ff0830269149b060789d

Jason Dew

November 16, 2007, November 16, 2007 13:16, permalink

4 ratings. Login to rate!

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)
0b7b8a4ba91242f26238424ca491304a

Bilson

November 17, 2007, November 17, 2007 00:00, permalink

No rating. Login to rate!

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"

5392d0a82eb7a8d8c6246f9dbbc2244a

Scott Patten

November 17, 2007, November 17, 2007 06:56, permalink

3 ratings. Login to rate!

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

Your refactoring





Format Copy from initial code

or Cancel