Rails: я не могу вызвать функцию в модуле в / lib - что я делаю не так? - PullRequest
41 голосов
/ 06 марта 2009

Я знаю, что я делаю что-то глупое или не могу сделать что-то умное - я часто виновен в обоих.

Вот пример того, что причиняет мне боль:

У меня есть модуль, сохраненный в / lib как test_functions.rb, который выглядит следующим образом

module TestFunctions
  def abc
    puts 123
  end
end

Зайдя в скрипт / бегунок ruby, я вижу, что модуль загружается автоматически (хорошее соглашение о конфигурации и все такое ...)

>> TestFunctions.instance_methods
=> ["abc"]

так что метод известен, давайте попробуем вызвать его

>> TestFunctions.abc
NoMethodError: undefined method `abc' for TestFunctions:Module from (irb):3

Неа. Как насчет этого?

>> TestFunctions::abc
NoMethodError: undefined method `abc' for TestFunctions:Module from (irb):4

Test Нет снова.

defined?(TestFunctions::abc) #=> nil, but
TestFunctions.method_defined? :abc #=> true

Как я уже говорил наверху, я знаю, что я тупой, может ли кто-нибудь меня отрешить?

Ответы [ 7 ]

58 голосов
/ 06 марта 2009

Если вам нужны функции Module -уровня, определите их одним из следующих способов:

module Foo
  def self.method_one
  end

  def Foo.method_two
  end

  class << self
    def method_three
    end
  end
end

Все эти способы сделают методы доступными как Foo.method_one или Foo::method_one и т. Д.

Как уже упоминали другие люди, методы экземпляра в Module s - это методы, которые доступны в местах, где вы include d Module

26 голосов
/ 12 марта 2009

Я собираюсь попытаться суммировать различные ответы самостоятельно, поскольку у каждого есть что-то ценное, чтобы сказать, но никто не дошел до того, что я теперь понимаю, вероятно, лучший ответ:

Я задавал неправильный вопрос, потому что я делал это неправильно.

По причинам, которые я больше не могу объяснить, я хотел, чтобы в библиотеке был набор полностью автономных функций, представляющих методы, которые я пытался СУХОЙ из своих классов. Этого можно достичь, используя такие вещи, как

module Foo
  def self.method_one
  end

  def Foo.method_two
  end

  class << self
    def method_three
    end
  end

  def method_four
  end

  module_function :method_four
end

Я мог бы также include мой модуль, либо внутри класса, в этом случае методы становятся частью класса, либо вне его, и в этом случае они определяются в любом классе, внутри которого я работаю (Object? Kernel? Irb , если я интерактивен? Наверное, не очень хорошая идея, тогда)

Дело в том, что не было никакой веской причины не начинать занятия - я как-то попал на ход мыслей, которые привели меня по редко используемой и откровенно немного странной ветке. Вероятно, воспоминание о днях до того, как ОО стало мейнстримом (я достаточно взрослый, чтобы до сегодняшнего дня я потратил гораздо больше лет на написание процедурного кода).

Таким образом, функции переместились в класс, где они кажутся довольно счастливыми, и представленные таким образом методы класса активно используются там, где это необходимо.

24 голосов
/ 06 марта 2009

Вы также можете использовать module_function следующим образом:

module TestFunctions
  def abc
    puts 123
  end

  module_function :abc
end

TestFunctions.abc  # => 123

Теперь вы можете включать TestFunctions в класс и вызывать abc из модуля TestFunctions.

6 голосов
/ 13 сентября 2012

Я какое-то время возился с этим и узнал несколько вещей. Надеюсь, это поможет кому-то еще. Я использую Rails 3.2.8.

Мой модуль (utilities.rb) выглядит следующим образом и находится в каталоге / lib моего приложения rails:

module Utilities

  def compute_hello(input_string)
     return "Hello #{input_string}"
  end

end

Мой тест (my_test.rb) выглядит следующим образом и находится в каталоге / test / unit моего приложения rails:

require "test_helper"
require "utilities"

class MyTest < ActiveSupport::TestCase
  include Utilities

  def test_compute_hello
    x = compute_hello(input_string="Miles")
    print x
    assert x=="Hello Miles", "Incorrect Response"
  end

end

Вот несколько вещей, на которые следует обратить внимание: Мой тест расширяет ActiveSupport :: TestCase. Это важно, потому что ActiveSupport добавляет / lib к $ LOAD_PATH. (См http://stackoverflow.com/questions/1073076/rails-lib-modules-and)

Во-вторых, мне нужно было «потребовать» файл моего модуля, а также «включить» модуль. Наконец, важно отметить, что материал, который включается из модуля, по существу помещается в тестовый класс. Так что ... будьте осторожны, чтобы модуль, который вы включили, не начинался с "test_". В противном случае Rails попытается запустить метод вашего модуля в качестве теста.

4 голосов
/ 01 сентября 2012

Вам необходимо добавить к имени функции префикс, потому что модули не являются классами:

Ваш /lib/test_functions.rb:

module TestFunctions
  def TestFunctions.abc
    puts 123
  end
end

Ваш код с использованием метода модуля:

require 'test_functions'
TestFunctions.abc
4 голосов
/ 06 марта 2009

Вы не можете вызвать метод в модуле напрямую. Вы должны включить его в класс. Попробуйте это:

>> class MyTest
>>   include TestFunctions
>> end
=> MyTest
>> MyTest.new.abc
123
=> nil
4 голосов
/ 06 марта 2009

Вам необходимо включить модуль

include Testfunctions

Тогда 'abc' вернет что-то.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...