假设我想puts
用大写字母{em> 编写大量字符串,但是为了简洁起见,我想每次写puts(string)
而不是puts(string.upcase)
我有办法像这样重新定义puts
仅在一个区块内吗?
# This will puts as normal
puts "abc"
# => abc
# This will puts an upcased string, but it's too verbose
puts "abc".upcase
# => ABC
# I want to do something like this, which will override the puts method for code run within the block
def always_upcase_strings(&block)
def puts(string)
super(string.upcase)
end
end
always_upcase_strings do
puts "abc"
puts "def"
puts "ghi"
end
puts "xyz"
# => ABC
# => DEF
# => GHI
# => xyz
我上面的示例得到了简化-我不是用puts
而是我自己编写的方法。
答案 0 :(得分:3)
在second thoughts上,这是一个更好的答案:
@CsvRecord(separator = ",",skipFirstLine = true)
public class Sample
{
//some fields
}
此creates临时类(匿名,因为它不需要名称),具有所需的方法覆盖。
然后在该类实例的上下文中调用产生的块。
与我的“重新定义-未定义-重新定义方法”解决方案相比,该方法不但令人困惑,而且还具有线程安全的优点。因此,例如,在调用方法的同时运行并行测试,您将不会得到怪异的行为。
...但是我仍然坚持最初的说法,即在一个块内重新定义方法是非常令人惊讶的行为。同事可能不喜欢您选择那种设计模式(除非以有限的方式进行,并且有充分的理由!)
答案 1 :(得分:1)
这有点疯狂;我不建议在生产环境中运行类似的东西...但是我很好奇,并找到了一种使用ruby的元编程来做到这一点的方法:
def always_upcase_strings(&block)
original_puts = method(:puts)
define_method(:puts) do |string|
original_puts.call(string.upcase)
end
yield
undef :puts
define_method(:puts, original_puts.unbind)
end
always_upcase_strings do
puts "abc" #=> "ABC"
puts "def" #=> "DEF"
puts "ghi" #=> "GHI"
end
puts "xyz" #=> "xyz"
这是怎么回事?
puts
Method
object,并将其存储在变量中。puts
重新定义为invoke it。 (我也可以使用super(string.upcase)
来做到这一点,但是我认为上面的内容更好地说明了发生了什么。)yield
到一个块,以便您可以调用该方法的新版本。undef
方法(!!!)完全摆脱了覆盖。 (但是不幸的是,这也删除了原始方法。所以...)puts
method by re-binding the orignal回到self
。这是绝对的黑魔法。使用后果自负。
相反,我的“现实世界”建议是:
def puts_upcase(str)
puts str.upcase
end
puts_upcase "abc" #=> "ABC"
puts "xyz" #=> "xyz"
或者在您的情况下,如果您实际上想调整类方法的行为,也许Module#prepend
是工作的更好工具。
简单的解决方案通常是更好的解决方案。