tl; dr;
如何从红宝石核心类中调用方法(写在茫茫荒野中)?
我正在编写一个管理文本文件的脚本。这是我的代码:
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
类中不可coll。
任何人都可以解释这个错误,以及我该怎么做?
我的解决方法是在从File
继承的自定义MyFile
类中写下这些方法:
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 Core方法。这是否意味着所有核心模块/类都包括或需要彼此?它如何在引擎盖下工作?
当您在顶级定义方法时,它将在对象上添加一个实例方法,因此可以访问下降类(大多数其他核心类)
def foo
1
end
method(:foo)
# => #<Method: Object#foo>
但是,此方法的访问级别在IRB/pry中似乎与运行脚本时不同。
in 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
您可以在此处阅读有关改进的信息,但是从本质上讲,它们仅在某个文件或类中修补核心类。这为您带来了那种精美的,简短的猴子捕捉语法的好处,而更改其他地方定义的行为的风险较小。
关于您的第一个问题。您遇到了错误,因为该方法未在File
类中定义。因此,您无法像此f.puts_content
一样称呼它。
您可以定义接收File
为参数puts_content(file, ...)
的方法。
关于您问题的第二部分,我是一个很好的解决方案(以对象为导向)。