TL; DR;
如何在Ruby核心类中调用一个方法(在不知名的地方编写)?
我正在编写管理文本文件的脚本。这是我的代码:
File.open("file.txt", "w").each do |f|
f.puts "Text to be inserted"
f.puts text_generated
f.puts "Some other text" if some_condition?
f.puts ""
end
我想通过引入一个方法来清理代码:
File.open("file.txt", "w").each do |f|
f.puts_content(text_generated, some_condition?
# -> Generates an error: private method called for <File> (NoMethodError)
end
def puts_content(text, cond)
puts "Text to be inserted"
puts text
puts "Some other text" if cond
puts ""
end
但事实上,由于私有方法访问,此方法无法在File
类中调用。
任何人都可以解释这个错误,以及我该怎么做?
我的解决方法是在继承自MyFile
的自定义File
类中编写这些方法:
MyFile.open("file.txt", "w").each do |f|
f.puts_content # Seems to work
end
class MyFile < File
def puts_content(cond)
puts "Text to be inserted"
puts text_generated_elsewhere
puts "Some other text" if cond
puts ""
end
end
我可以将这些内容直接放在File
中,但在触及语言核心库时我会胆怯。
我想知道这是否是一个很好的方法。
可以从其他核心模块/类调用Ruby核心方法。这是否意味着所有核心模块/类包含或需要彼此?它是如何在引擎盖下工作的?
答案 0 :(得分:1)
在顶层定义方法时,会在Object上添加一个实例方法,因此可供后代类(大多数其他核心类)访问
def foo
1
end
method(:foo)
# => #<Method: Object#foo>
然而,此方法的访问级别在IRB / pry中似乎与运行脚本时不同。
在IRB:
puts [].foo
# => 1
在剧本中:
puts [].foo
# => NoMethodError (private method called...)
当然,您始终只需使用send
调用私有方法:
[].send(:foo)
# or, in your case, f.send(:puts_content, text_generated, some_condition?)
此外,在任何情况下都不会覆盖后代类上的方法(如果已经定义了它):
def length
1
end
puts [].length
# => 0
你的第二种方法(直接修补核心类)将起作用,如果已经在文件中定义了puts_content(它不是),它将覆盖puts_content。但是,如果您想避免修补核心类,我建议采用两种方法:
使用静态(类)方法并将文件对象作为参数传递
class FileUtils
def self.puts_content(file, text, cond)
file.puts "Text to be inserted"
file.puts text
file.puts "Some other text" if cond
file.puts ""
end
end
File.open("file.txt", "w").each do |f|
FileUtils.puts_content(f, text_generated, some_condition?)
end
使用细化:
module FileUtils
refine File do
def puts_content(text, cond)
puts "Text to be inserted"
puts text
puts "Some other text" if cond
puts ""
end
end
end
# elsewhere ...
using FileUtils
File.open("file.txt", "w").each do |f|
f.puts_content(f, text_generated, some_condition?)
end
您可以阅读有关优化here的内容,但实质上,它们只是修补某个文件或类中的核心类的方法。这为您提供了良好,简洁的猴子修补语法的好处,同时降低了改变其他地方定义的行为的风险。
答案 1 :(得分:0)
关于你的第一个问题。您收到错误是因为该方法未在File
类中定义。所以你无法像f.puts_content
那样调用它。
您可以定义一个接收File
作为参数puts_content(file, ...)
的方法。
关于问题的第二部分,我这是一个很好的解决方案(思考面向对象)。