Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Evaluating string templates

I have a string template as shown below

template = '<p class="foo">#{content}</p>'

I want to evaluate the template based on current value of the variable called content.

html = my_eval(template, "Hello World")

This is my current approach for this problem:

def my_eval template, content
  "\"#{template.gsub('"', '\"')}\""  # gsub to escape the quotes
end

Is there a better approach to solving this problem?

EDIT

I used HTML fragment in the sample code above to demonstrate my scenario. My real scenario has set of XPATH templates in a configuration file. The bind variables in the template are substituted to get a valid XPATH string.

I have thought about using ERB, but decided against as it might be a overkill.

like image 493
Harish Shetty Avatar asked Feb 23 '10 20:02

Harish Shetty


3 Answers

I can't say I really recommend either of these approaches. This is what libraries like erb are for, and they've been throughly tested for all the edge cases you haven't thought of yet. And everyone else who has to touch your code will thank you. However, if you really don't want to use an external library, I've included some recommendations.

The my_eval method you included didn't work for me. Try something like this instead:

template = '<p class="foo">#{content}</p>'

def my_eval( template, content )
  eval %Q{"#{template.gsub(/"/, '\"')}"}
end

If you want to generalize this this so you can use templates that have variables other than content, you could expand it to something like this:

def my_eval( template, locals )
  locals.each_pair{ |var, value| eval "#{var} = #{value.inspect}" }
  eval %Q{"#{template.gsub(/"/, '\"')}"}
end

That method would be called like this

my_eval( '<p class="foo">#{content}</p>', :content => 'value of content' )

But again, I'd advise against rolling your own in this instance.

like image 116
Emily Avatar answered Oct 09 '22 13:10

Emily


You can do what you want with String's native method '%':

> template = "<p class='foo'>%s</p>"
> content = 'value of content'
> output = template % content
> puts output
=> "<p class='foo'>value of content</p>"

See http://ruby-doc.org/core/classes/String.html#M000770

like image 32
seanreads Avatar answered Oct 09 '22 15:10

seanreads


You can render a string as if it were an erb template. Seeing that you're using this in a rake task you're better off using Erb.new.

template = '<p class="foo"><%=content%></p>'
html = Erb.new(template).result(binding)

Using the ActionController methods originally suggested, involves instantiating an ActionController::Base object and sending render or render_to_string.

like image 44
EmFi Avatar answered Oct 09 '22 14:10

EmFi