在Ruby中合并哈希和字符串的键/值。

7

我想在Ruby中将哈希与字符串的键/值合并。

例如:

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

我找到的方法是迭代键并替换值。但我不确定是否有更好的方法来做这件事? :)

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

谢谢

4个回答

7

无需重新发明 Ruby 内置函数:

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

(请注意,这需要Ruby 1.9+版本)

1
仍然有很多基于Ruby 1.8.x的脚本存在,但是很高兴1.9终于实现了这样一个基本功能。 - tokland

5
“更好”可能是主观的,但这里有一种方法只使用一次 gsub 调用:
class String
  def interpolate!(h)
    self.gsub!(/:(\w+)/) { h[$1.to_sym] }
  end
end

因此:
>> "/my/crazy/url/:day/:month/:year".interpolate!(h)
=> "/my/crazy/url/4/8/2010"

但是如果你有s="/my/crazy/url/:somethingelse/:month/:year"会发生什么? - John La Rooy
好的,h[:nothashed] 返回 nil,所以它会被替换为空字符串。你可以使用类似于 h[$1.to_sym]||"default" 的东西来修复它。 - Michael Pilat

1

我觉得那看起来还不错,但另一种方法是使用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)

1
另一个想法是扩展String#%方法,使其知道如何处理Hash参数,同时保持现有功能:
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

1
谢谢Mladen。这看起来真的很有前途。 - LazyJason

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接