Подтвердить что ты не робот

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

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

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

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

module TestFunctions
  def abc
    puts 123
  end
end

Переходя в ruby ​​ script/runner, я вижу, что модуль загружается автоматически (хорошее соглашение о конфигурации и все это...)

>> 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

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

4b9b3361

Ответ 1

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

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

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

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, если я интерактивен? Возможно, это не отличная идея, тогда)

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

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

Ответ 2

Если вы хотите 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 - это методы, которые доступны в тех местах, где вы include d Module

Ответ 3

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

module TestFunctions
  def abc
    puts 123
  end

  module_function :abc
end

TestFunctions.abc  # => 123

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

Ответ 4

Я немного испортил это и узнал несколько вещей. Надеюсь, это поможет кому-то еще. Я запускаю 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. (Seehttp://stackoverflow.com/questions/1073076/rails-lib-modules-and)

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

Ответ 5

Вам нужно включить модуль

include Testfunctions

Затем 'abc' вернет что-то.

Ответ 6

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

>> class MyTest
>>   include TestFunctions
>> end
=> MyTest
>> MyTest.new.abc
123
=> nil

Ответ 7

Вам нужно префикс вашей функции с именем модуля, потому что модули не являются классами:

Ваш/lib/test_functions.rb:

module TestFunctions
  def TestFunctions.abc
    puts 123
  end
end

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

require 'test_functions'
TestFunctions.abc

Ответ 8

Сегодня вы можете сделать это с module_function нотации module_function.

module TestFunctions
  def abc
    puts 123
  end
end

Теперь TestFunctions.abc печатает "123"

Еще немного о module_function: https://apidock.com/ruby/Module/module_function