ruby - 有没有办法重新定义块内的方法?
问题描述
假设我想要puts
大量的大写字符串,但为简洁起见,我想写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
在我的例子中使用,而是我自己写的一个方法。
解决方案
再想一想,这里有一个更好的答案:
def always_upcase_strings(&block)
anon_class = Class.new do
def puts(str)
super(str.upcase)
end
end
anon_class.new.instance_eval(&block)
end
always_upcase_strings do
puts "abc" #=> "ABC"
puts "def" #=> "DEF"
puts "ghi" #=> "GHI"
end
puts "xyz" #=> "xyz"
这将创建一个具有所需方法覆盖的临时类(匿名,因为它不需要名称)。
然后在此类实例的上下文中调用产生的块。
除了比我的“redefine-undefine-redefine the method”解决方案更容易混淆之外,这种方法还具有线程安全的额外优势。因此,例如,如果在调用方法时运行并行测试,您将不会出现奇怪的行为。
...但我仍然坚持我最初的说法,即在一个块中重新定义方法是非常令人惊讶的行为。同事可能不喜欢您选择该设计模式(除非它以有限的方式完成,并且有充分的理由!)
推荐阅读
- javascript - jQuery DataTables:如果字符串存在于?
- android - Android Management API 中的自定义 SignUpURL
- javascript - 从上到下自动滚动元素内的图像
- hyperledger-fabric - 添加新同行 | 作曲家网络开始上的'名称为'cc'的链码已经存在'
- unity3d - 如何在 Unity3D 上安装 Azure IoT Hub SDK (C#)?
- node.js - 如何修复未插入本地 dynamodb(NodeJS)的数据
- hive - 在 Avro 中声明简单时间戳的正确方法是什么
- sql-server - 为什么 SSIS OData 连接器突然开始引发 VS_ISBROKEN 异常?
- ssl - Boringssl 可以在裸机 ARM 系统中工作吗?
- php - 序列号在我的分页中的每一页中从 1 开始