2012-07-18 17 views
39

In ruby, capisco che le funzioni del modulo possono essere rese disponibili senza la miscelazione nel modulo utilizzando module_function come mostrato qui. Riesco a vedere come questo è utile in modo da poter utilizzare la funzione senza mescolare nel modulo.ruby ​​module_function vs includendo il modulo

module MyModule 
    def do_something 
    puts "hello world" 
    end 
    module_function :do_something 
end 

La mia domanda è però perché si potrebbe desiderare di avere la funzione definita in entrambi i modi.

Perché non hanno

def MyModule.do_something 

O

def do_something 

In quale tipo di casi sarebbe utile avere la funzione disponibile per essere miscelati, o da utilizzare come un metodo statico ?

risposta

35

Pensa a Enumerable.

Questo è l'esempio perfetto di quando è necessario includerlo in un modulo. Se la classe definisce #each, si ottiene un sacco di bontà solo includendo un modulo (#map, #select, ecc.). Questo è l'unico caso in cui utilizzo i moduli come mixin - quando il modulo fornisce funzionalità in termini di alcuni metodi, definiti nella classe in cui è incluso il modulo. Posso sostenere che questo dovrebbe essere l'unico caso in generale.

Per quanto riguarda la definizione di metodi "statici", un approccio migliore sarebbe:

module MyModule 
    def self.do_something 
    end 
end 

non si ha realmente bisogno di chiamare #module_function. Penso che sia solo una questione strana.

Si può anche fare questo:

module MyModule 
    extend self 

    def do_something 
    end 
end 

... ma non funziona bene se si vuole includere anche il modulo da qualche parte. Suggerisco di evitarlo fino a quando non imparerai le sottigliezze della metaprogrammazione di Ruby.

Infine, se lo farete:

def do_something 
end 

... esso non finire come una funzione globale, ma come un metodo privato su Object (non ci sono funzioni in Ruby, a soli metodi). Ci sono due aspetti negativi. Innanzitutto, non disponi di namespace: se definisci un'altra funzione con lo stesso nome, è quella che verrà valutata in seguito. In secondo luogo, se la funzionalità è implementata in termini di #method_missing, l'utilizzo di un metodo privato in Object lo ombreggia. E, infine, la scimmia patch Object sono affari solo male :)

EDIT:

module_function può essere utilizzato in modo simile a private:

module Something 
    def foo 
    puts 'foo' 
    end 

    module_function 

    def bar 
    puts 'bar' 
    end 
end 

In questo modo, è possibile chiamare Something.bar, ma non non Something.foo. Se si definiscono altri metodi dopo questa chiamata a module_function, sarebbero anche disponibili senza mescolare.

Non mi piace per due motivi, però.Innanzitutto, i moduli che sono entrambi mixati e con metodi "statici" sembrano un po 'ambigui. Potrebbero esserci casi validi, ma non sarà così spesso. Come ho detto, preferisco usare un modulo come spazio dei nomi o mescolarlo, ma non entrambi.

In secondo luogo, in questo esempio, bar sarebbe anche disponibile per classi/moduli che si mescolano in Something. Non sono sicuro quando questo sia desiderabile, dal momento che il metodo usa o self e deve essere mischiato o no e quindi non è necessario che venga mescolato.

Penso di usare module_function senza passare il nome del metodo è usato molto più spesso rispetto a. Lo stesso vale per private e protected.

+0

grazie per la spiegazione. Capisco perché vorresti mescolare un modulo, la mia domanda riguardava di più quando potresti effettivamente usare la funzione module_function. C'è qualche volta che potresti effettivamente usarlo? –

+2

C'è un altro problema in questo ultimo esempio con 'module_function': La funzione" privata "' foo' non è accessibile da 'bar', perché' pippo' è quindi un metodo di istanza (non ha 'self') e può essere chiamato solo quando questo modulo è mescolato in qualche classe. Impossibile quando è un modulo standalone solo per scopi di namespace. Quindi come averlo entrambi? Come usare il modulo solo per namespacing e nascondere alcune funzioni di helper di implementazione dal mondo esterno, ma consentire loro di essere chiamati con i suoi metodi di interfaccia? – SasQ

12

È un buon modo per una libreria Ruby di offrire funzionalità che non utilizzano (molto) stato interno. Pertanto, se tu (ad es.) Vuoi offrire una funzione sin e non vuoi inquinare lo spazio dei nomi "globale" (Object), puoi definirlo come metodo di classe sotto una costante (Math).

Tuttavia, uno sviluppatore di app, che desidera scrivere un'applicazione matematica, potrebbe richiedere sin ogni due righe. Se il metodo è anche un metodo di istanza, può semplicemente includere il modulo Math (o My::Awesome::Nested::Library) e ora può chiamare direttamente sin (esempio stdlib).

Si tratta davvero di rendere una libreria più confortevole per i suoi utenti. Possono scegliere da soli, se vogliono la funzionalità della tua libreria al massimo livello.

A proposito, è possibile ottenere una funzionalità simile a module_function utilizzando: extend self (nella prima riga del modulo). A mio parere, sembra migliore e rende le cose un po 'più chiare da capire.

Aggiornamento: Altre informazioni in background this blog article.

+3

Il [ruby styleguide] (https://github.com/bbatsov/ruby-style-guide#classes--modules) preferisce '' module_function'' su '' extend self'' – zhon

+3

Grazie per il puntatore. Non sono d'accordo, però. 'module_function' potrebbe essere più amichevole per i principianti, ma chiunque stia facendo Ruby seria dovrebbe essere in grado di leggere e capire la versione' extend self'. 'estendere se stessi' è meno astrazione.Usa il set di strumenti di base di Ruby, mentre 'module_function' può essere rimosso da Ruby, senza perdere funzionalità importanti. –

+0

Grazie per aver fornito le tue ragioni. Prima di leggere questo Q/A, usavo '' self.method'' e '' class << self''. – zhon