views:

215

answers:

2

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 it might be a overkill.

+3  A: 

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.

EmFi
I used HTML fragment in the template to demonstrate the scenario. I have bunch of XPATH strings that need substitution. I had thought about using ERB, but I wanted something lightweight.
KandadaBoggu
I must say this is an intriguing solution. I have to run my code in a rake task. So this solution might need some tweaking.
KandadaBoggu
If you're talking about a rake task, you're better off using Erb.new instead of ActionController#render. Solution updated to reflect that.
EmFi
You beat me to it. I was about to post that code fragment :-)
KandadaBoggu
+2  A: 

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.

Emily