Ruby- 跨模块的 NoMethodError

Ruby- NoMethodError across modules

提问人:Ben Garcia DB Solutions 提问时间:11/16/2023 最后编辑:Ben Garcia DB Solutions 更新时间:11/16/2023 访问量:32

问:

我在正确使用模块方面遇到了一些问题。

我有:

module Utilities
  def file_search()
    # some code
    return x
  end
end


module Remake_Components
  require 'csv'
  include Utilities

  f = Utilities.file_search()
end

这给了我一个错误:我本来希望是运行该函数的结果。#<NoMethodError: undefined method "file_search" for Utilities:Module>ffile_search

我的理解是我必须使用关键字才能使用其他方法中的函数,但似乎并非如此?include

Ruby 模块 包括

评论


答:

2赞 engineersmnky 11/16/2023 #1

我的理解是我必须使用 include 关键字才能使用其他方法中的函数,但似乎并非如此?

Module#include将 Module 注入到 include 对象的分层链中,并使 included Module 的实例方法可供 include Object 的实例访问。

在你的例子中,定义了一个实例方法,通过调用,你已经使这个方法可用于的实例(但是,s没有实例(本身))。file_searchUtilitiesinclude UtilitiesRemake_ComponentsModule

您尝试将 Module 作为接收方调用的方式不需要调用,而是需要将方法定义为“类实例方法”或“模块函数”。file_searchUtilitiesinclude

如果您希望它以这种方式工作,那么您有 2 个选择:

  • 通过将方法声明更改为Utilitiesdef self.file_search
  • 使用方法(通常不是推荐的方法),例如module_function
module Utilities
  def file_search 
    # some code
    return x
  end
  module_function :file_search
end

这两个选项都允许您致电;但是,后者还允许您在使用 时将此方法“包含”为私有实例方法。Utilities.file_searchModule#include

举例来说:

module A 
  def self.foo = 'Foo'
  def bar = 'Bar'
  module_function :bar
end 

class B 
  include A 
  def test_foo = A.foo
  def test_bar = bar
end 

A.foo
#=> "Foo"
A.bar 
#=> "Bar"
B.new.test_foo
#=> "Foo"
B.new.test_bar
#=> "Bar" 
B.new.foo
#=> undefined method `foo' for #<B:0x00007f0c7785e528> (NoMethodError)
B.new.bar
#=> private method `bar' called for #<B:0x00007ff5a5dbe5a0> (NoMethodError)

其他一些不太重要的说明:

  • def file_search()- 如果没有参数,可以省略括号,作为一般样式。
  • return x- Ruby 将始终返回最后一个表达式的值,因此除非您打算提前返回一个值,否则可以省略该值。return
  • module Remake_Components- 虽然方法名称(和局部/实例变量)以 lower_snake_case 表示,但类和模块常量以 UpperCamelCase 表示,因此该模块通常以 UpperCamelCase 命名RemakeComponents
  • require 'csv'- require 语句没有词法范围,因此它是否包含在模块声明中与它的可访问性无关。出于这个原因,require 调用(尤其是对核心库的调用)通常放在文件的顶部(在任何声明之外)。