从Ruby核心类中调用自定义方法

问题描述 投票:1回答:2

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核心方法。这是否意味着所有核心模块/类包含或需要彼此?它是如何在引擎盖下工作的?

ruby oop
2个回答
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。但是,如果您想避免修补核心类,我建议使用两种方法:

  1. 使用静态(类)方法并将文件对象作为参数传递 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
  2. 使用细化: 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的内容,但实际上,它们只是在某个文件或类中修补核心类的方法。这为您提供了良好,简洁的猴子修补语法的好处,同时降低了改变其他地方定义的行为的风险。

0
投票

关于你的第一个问题。您收到错误是因为该方法未在File类中定义。所以你无法像这个f.puts_content那样称呼它。

您可以定义一个接收File作为参数puts_content(file, ...)的方法。

关于你问题的第二部分,我这是一个很好的解决方案(思考面向对象)。

© www.soinside.com 2019 - 2024. All rights reserved.