4

我有一个模块,其中定义了一个函数:

module Settings
def find_by_name(name, start)
  puts "find_by_name: Found me!"
end

在 miniTest 中,我试图以一种模拟它在运行时动态定义/调用的方式测试“发送”到这个函数。这就是我在 MiniTest 中尝试做的事情。

require 'settings'

class TestFileUtilities < MiniTest::Unit::TestCase

  def test_dynamic_call_to_Settings
    foreign_function = 'Settings::find_by_name'
    send(foreign_function, 'name.txt', 'Users/MCP/Desktop/Projects/TestDir')
  end

我期待的是 send() 将调用“foreign_function”方法,将字符串转换为符号,然后将两个参数添加到调用中。我想要的只是没有错误,并在我的控制台上放一个,以便我知道它正在工作......然后我将开始定义“断言”。现在虽然我得到:

NoMethodError: undefined method `Settings::find_by_name' for #<TestFileUtilities:0x007fdf59840310>

include Settings这是我第一次尝试使用 Ruby 动态调用方法的能力,当我不使用范围解析运算符并且在其中时,我能够让它工作,TestFileUtilities但我宁愿使用范围以便用户定义的函数不会与我的类中的任何东西冲突(不仅与 MiniTest 冲突,而且与实际的 FileUtilities 类冲突)。任何想法/帮助将不胜感激!对于在这里偶然发现信息的任何人来说,就是让我开始的原因。

4

3 回答 3

3

你的例子有几个问题。

  1. 你没有做任何明显的事情来创建find_by_name一个类方法Blueprints,所以即使跳过send你应该得到的部分,NoMethodError如果你试图调用Blueprints::find_by_name('name.txt', 'Users/MCP/Desktop/Projects/TestDir') 要解决这个问题,你必须说Blueprints.extend(Settings)哪个会将 Settings 模块混合到 Blueprints 类中,其实例方法变为蓝图的类方法。

  2. 方法名称是一个符号,Object#send需要一个符号作为它的第一个参数,如果它是一个字符串,它会将它转换为一个符号。您传递的字符串'Blueprints::find_by_name'是一个非常奇怪的方法名称,而不是您定义的方法。我认为您打算find_by_name在 class 或 module 上调用该方法Blueprints。为此,您可以说foreign_function = 'find_by_name'; Blueprints.send(foreign_function, 'name.txt', 'Users/MCP/Desktop/Projects/TestDir')如果您也需要动态解析类/模块名称,则需要Module#const_get.

所以这就是我认为你的意思:

module Settings
  def find_by_name(name, start)
    puts "find_by_name: Found me!"
  end
end

class Blueprints
  extend Settings
end

require 'settings'

class TestFileUtilities < MiniTest::Unit::TestCase

  def test_dynamic_call_to_actual_Blueprints
    klass = 'Blueprints'
    func = 'find_by_name'
    Object.const_get(klass).send(func, 'name.txt', 'Users/MCP/Desktop/Projects/TestDir')
  end

end
于 2013-06-03T00:57:36.067 回答
1

从您的问题中不清楚蓝图类与设置的关系。我将假设 Blueprints 是 Settings 的子类,或者您打算改用 Settings。

我期待的是 send() 将调用“foreign_function”方法,将字符串转换为符号,然后将两个参数添加到调用中。

您需要在要发送()到的对象(或类)上调用 send():

foreign_function = 'find_by_name'
Blueprints.send(foreign_function, 'name.txt', 'Users/MCP/Desktop/Projects/TestDir')
于 2013-06-03T00:51:19.943 回答
1

在这个特定的实例中,我在尝试包含另一个模块中的函数时遇到了麻烦,而不是在任何类中。我require正在尝试发送到的模块,但是当我这样做时,ModuleName::send(:function_name)我收到一条错误消息,指出“该名称不存在任何方法”(或接近该错误的内容)。解决这个问题的方法是将模块中我试图“发送”到的函数定义为“self.function_name”。

module Something
  def self.my_function
    puts "Silliness"
  end
end

然后在发送文件/模块/类中:

require '../lib/something.rb'

    class MyClass
      def this_crazy_thing
        funct = 'my_function'
        Something::send(funct)
      end
    end

所以现在上面的工作......通过简单地将函数定义为module Somethingas self。根据我的理解,这与对象在 Ruby 中的实例化方式有关。让我来到这里的是,不使用动态send功能......如果我知道我想调用的模块中的函数的名称,我可以调用它:

ModuleName::function_name(params)

所以我希望有类似的东西可以使用send。我的猜测是,由于我试图发送到一个对象,所以该函数需要绑定到我发送到的对象,即模块,以便它可以作为该对象的实例调用。显然,我仍然在思考在 Ruby 中一切都是对象的事实。希望这至少能让某人走上正确的道路。如果有人可以解释为什么这确实有效:

module ModuleSomething
  def a_function
   puts "hi"
  end
end

require '../lib/modulesomething'
class MyClass
  def this_thing
    ModuleSomething::a_function
  end
end

但不是:

require 'ModuleSomething'
class MyClass
  def this_string
    funct = 'a_function'
    ModuleSomething::send(funct)
  end
end

这可能有助于更清楚地了解我的解决方案为何有效。当我发现更多时,我会添加到这个。多谢你们!

于 2013-06-05T14:53:52.290 回答