Ruby:尝试使用参数对象发送模块函数

时间:2013-06-03 00:34:43

标签: ruby

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

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>

这是我第一次使用Ruby的动态调用方法的能力,当我没有使用范围解析运算符并且include Settings位于TestFileUtilities时,我能够使用它。但是我宁愿使用范围,以便用户定义的函数不会与我的类中的任何内容冲突(不仅与MiniTest冲突,而且与实际的FileUtilities类冲突)。任何想法/帮助都会非常高兴!对于那些在这里寻找信息的人来说,this是让我开始的原因。

3 个答案:

答案 0 :(得分:2)

您的示例有几个问题。

  1. 您没有做任何明显的事情find_by_name Blueprints的类方法,所以即使跳过send部分,如果你有NoMethodError试图致电Blueprints::find_by_name('name.txt', 'Users/MCP/Desktop/Projects/TestDir') 要解决这个问题,你必须说Blueprints.extend(Settings)将Settings模块与Blueprints类混合,其实例方法成为Blueprints的类方法。

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

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

    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
    

答案 1 :(得分:1)

从您的问题不清楚蓝图类与设置的关系。我假设蓝图是“设置”的子类,或者您打算使用“设置”。

  

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

您需要对要发送的对象(或类)调用send():( / p>

foreign_function = 'find_by_name'
Blueprints.send(foreign_function, 'name.txt', 'Users/MCP/Desktop/Projects/TestDir')

答案 2 :(得分: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 Something中的函数定义为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

这可能有助于澄清我的解决方案为何有效。当我发现更多时,我将添加到此。谢谢你们!