简体   繁体   中英

How to match and replace templating tags in Ruby / Rails?

Trying to add a very rudimentary description template to one of my Rails models. What I want to do is take a template string like this:

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

and a hash like this:

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

and get a description generated. I thought I could do this with a simple gsub but Ruby 1.8.7 doesn't accept hashes as the second argument. When I do a gsub as a block like this:

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

You can see it replaces it with the entire string (with curly braces), not the match captures.

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

TIA

Using Ruby 1.9.2

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

>> 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 doesn't support hashes . Instead, you can use the same arguments as the Ruby 1.9.2 solution and patch the String object so when you upgrade Ruby you won't have to edit your strings.

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."

codepad example showing the default and extended behavior

The easiest thing 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 fine manual :

In the block form, the current match string is passed in as a parameter, and variables such as $1, $2, $`, $&, and $' will be set appropriately. The value returned by the block will be substituted for the match on each call.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM