How to match and replace tag templates in Ruby / Rails?

Trying to add a very rudimentary description template to one of my Rails models. I want to make a template string as follows:

template = "{{ name }} is the best {{ occupation }} in {{ city }}." 

and the hash like this:

 vals = {:name => "Joe Smith", :occupation => "birthday clown", :city => "Las Vegas"} 

and get the generated description. I thought I could do this with a simple gsub, but Ruby 1.8.7 does not accept hashes as the second argument. When I make gsub as a block like this:

 > template.gsub(/\{\{\s*(\w+)\s*\}\}/) {|m| vals[m]} => " is the best in ." 

You can see that it replaces it with the whole string (with curly braces), and not a match.

How can I replace it with "{{something}}" vals ["something"] (or vals ["something" .to_sym])?

TIA

+7
source share
2 answers

Using Ruby 1.9.2

The string format operator % will format the string with a hash as the arg argument

 >> template = "%{name} is the best %{occupation} in %{city}." >> vals = {:name => "Joe Smith", :occupation => "birthday clown", :city => "Las Vegas"} >> template % vals => "Joe Smith is the best birthday clown in Las Vegas." 

Using Ruby 1.8.7

The string formatting operator in Ruby 1.8.7 does not support hashing . Instead, you can use the same arguments as the Ruby 1.9.2 solution and fix the String object, so you won’t have to edit the lines when updating Ruby.

 if RUBY_VERSION < '1.9.2' class String old_format = instance_method(:%) define_method(:%) do |arg| if arg.is_a?(Hash) self.gsub(/%\{(.*?)\}/) { arg[$1.to_sym] } else old_format.bind(self).call(arg) end end end end >> "%05d" % 123 => "00123" >> "%-5s: %08x" % [ "ID", 123 ] => "ID : 0000007b" >> template = "%{name} is the best %{occupation} in %{city}." >> vals = {:name => "Joe Smith", :occupation => "birthday clown", :city => "Las Vegas"} >> template % vals => "Joe Smith is the best birthday clown in Las Vegas." 

sample code showing default behavior and advanced behavior

+24
source

The easiest way is probably to use $1.to_sym in your block:

 >> template.gsub(/\{\{\s*(\w+)\s*\}\}/) { vals[$1.to_sym] } => "Joe Smith is the best birthday clown in Las Vegas." 

From the exact guide :

In the block form, the current matching string is passed as a parameter, and variables such as $ 1, $ 2, $ `, $ &, and $ will be set accordingly. The value returned by the block will be replaced with a match on every call.

+2
source

All Articles