2009-03-06 4 views
40

So che sto facendo qualcosa di stupido o non riesco a fare qualcosa di intelligente - Sono spesso colpevole di entrambi.Rails: non posso chiamare una funzione in un modulo in/lib - cosa sto facendo male?

Ecco un esempio di ciò che mi sta causando dolore:

ho un modulo salvato in/lib come test_functions.rb che assomiglia a questo

module TestFunctions 
    def abc 
    puts 123 
    end 
end 

Entrando in script Ruby/corridore, posso vedere che il modulo sta caricando automaticamente (good ol' convenzione sulla configurazione e tutto il resto ...)

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

in modo che il metodo è noto, proviamo definendolo

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

No. Cosa ne pensi di questo?

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

prova Nope di nuovo.

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

Come ho detto in cima, so che sono stupido, qualcuno può dumbder me?

risposta

24

ho intenzione di cercare di riassumere le varie risposte me stesso, dal momento che ognuno aveva qualcosa di valido da dire, ma nessuno ci ha veramente a quello che ora mi rendo conto è probabilmente la migliore risposta:

stavo chiedendo il torto domanda perché stavo sbagliando.

Per ragioni che non riesco più a spiegare, volevo un set di funzioni completamente autonome in una libreria, che rappresentava i metodi che stavo cercando di ASCIUGARE dalle mie lezioni.Ciò può essere realizzato, utilizzando le cose come

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 

ho potuto anche include mio modulo, sia all'interno di una classe, nel qual caso i metodi diventano parte della classe o fuori, nel qual caso esse sono definite su qualunque classe I sto correndo dentro (Object? Kernel? Irb, se sono interattivo? Probabilmente non è una grande idea, quindi)

Il fatto è che non c'era una buona ragione per non avere una classe in primo luogo - I ' In un modo o nell'altro, mi sono imbattuto in un treno di pensieri che mi ha portato a una linea di rami usata raramente e francamente un po 'strana. Probabilmente un flashback dei giorni prima che OO diventasse mainstream (sono abbastanza grande che fino ad oggi ho passato molti anni a scrivere codice procedurale).

Quindi le funzioni si sono spostate in una classe, dove sembrano piuttosto felici, ei metodi di classe così esposti vengono usati allegramente, laddove necessario.

4

è necessario includere il modulo

include Testfunctions

Poi 'abc' restituirà qualcosa.

4

Non è possibile chiamare direttamente un metodo in un modulo. Devi includerlo in una classe. Prova questo:

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

Hai guardato la risposta di Marcin? – m33lky

56

Se volete Module funzioni -Level, definirli in uno dei seguenti modi:

module Foo 
    def self.method_one 
    end 

    def Foo.method_two 
    end 

    class << self 
    def method_three 
    end 
    end 
end 

Tutti questi modi renderanno i metodi disponibili come Foo.method_one o Foo::method_one ecc

Come altri utenti hanno menzionato, i metodi di istanza in Module s sono i metodi disponibili in luoghi in cui è presente il numero include di Module

23

È inoltre possibile utilizzare module_function in questo modo:

module TestFunctions 
    def abc 
    puts 123 
    end 

    module_function :abc 
end 

TestFunctions.abc # => 123 

Ora è possibile includere TestFunctions in classe e chiamare "abc" dall'interno del modulo TestFunctions.

4

È necessario anteporre la funzione con il nome del modulo, perché i moduli non sono classi:

tuo /lib/test_functions.rb:

module TestFunctions 
    def TestFunctions.abc 
    puts 123 
    end 
end 

tuo codice utilizzando il metodo di modulo:

require 'test_functions' 
TestFunctions.abc 
6

Mi sono incasinato per un po 'e ho imparato diverse cose. Speriamo che questo possa aiutare qualcun altro. Sto usando Rails 3.2.8.

mio modulo (utilities.rb) assomiglia a questo e si trova nella/lib del mio rotaie app:

module Utilities 

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

end 

Il mio test (my_test.rb) assomiglia a questo ed è in/test/unità directory del mio rotaie app:

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 

qui ci sono alcune cose da notare: il mio test si estende ActiveSupport :: TestCase. Questo è importante perché ActiveSupport aggiunge/lib al $ LOAD_PATH. (seehttp: //stackoverflow.com/questions/1073076/rails-lib-modules-and)

In secondo luogo, avevo bisogno sia di "richiedere" il mio file di modulo, sia di "includere" il modulo. Infine, è importante notare che le cose che vengono incluse dal modulo vengono essenzialmente inserite nella classe di test. Quindi ... fai attenzione che il modulo che inserisci non inizi con "test_". In caso contrario, Rails tenterà di eseguire il metodo del modulo come test.