7

I'm trying to merge a hash with the key/values of string in ruby.

i.e.

h = {:day => 4, :month => 8, :year => 2010}
s = "/my/crazy/url/:day/:month/:year"
puts s.interpolate(h)

All I've found is to iterate the keys and replace the values. But I'm not sure if there's a better way doing this? :)

class String
  def interpolate(e)
    self if e.each{|k, v| self.gsub!(":#{k}", "#{v}")}
  end
end

Thanks

LazyJason
  • 71
  • 2

4 Answers4

7

No need to reinvent Ruby built-ins:

h = {:day => 4, :month => 8, :year => 2010}
s = "/my/crazy/url/%{day}/%{month}/%{year}"
puts s % h

(Note this requires Ruby 1.9+)

Mark Thomas
  • 37,131
  • 11
  • 74
  • 101
  • 1
    Still a lot of Ruby 1.8.x scripts out there, but it's nice that 1.9 finally implemented such a basic feature. – tokland Aug 14 '11 at 10:07
5

"Better" is probably subjective, but here's a method using only one call to gsub:

class String
  def interpolate!(h)
    self.gsub!(/:(\w+)/) { h[$1.to_sym] }
  end
end

Thus:

>> "/my/crazy/url/:day/:month/:year".interpolate!(h)
=> "/my/crazy/url/4/8/2010"
Michael Pilat
  • 6,480
  • 27
  • 30
1

That doesn't look bad to me, but another approach would be to use ERB:

require 'erb'

h = {:day => 4, :month => 8, :year => 2010}
template = ERB.new "/my/crazy/url/<%=h[:day]%>/<%=h[:month]%>/<%=h[:year]%>"
puts template.result(binding)
Jacob Mattison
  • 50,258
  • 9
  • 107
  • 126
1

Additional idea could be to extend String#% method so that it know how to handle Hash parameters, while keeping existing functionality:

class String
  alias_method :orig_percent, :%
  def %(e)
    if e.is_a?(Hash)
      # based on Michael's answer
      self.gsub(/:(\w+)/) {e[$1.to_sym]}
    else
      self.orig_percent e
    end
  end
end

s = "/my/%s/%d/:day/:month/:year"
puts s % {:day => 4, :month => 8, :year => 2010}
#=> /my/%s/%d/4/8/2010
puts s % ['test', 5]
#=> /my/test/5/:day/:month/:year
Mladen Jablanović
  • 43,461
  • 10
  • 90
  • 113