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
Как я сказал наверху, я знаю, что я тупой, может ли кто-нибудь меня отключить?
Ответы
Ответ 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