2012-06-28 11 views
9

Ho una classe che contiene questo metodo di una classe:Ruby: Posso utilizzare i metodi di istanza all'interno di un metodo di classe?

def self.get_event_record(row, participant) 
    event = Event.where(
     :participant_id => participant.id, 
     :event_type_code => row[:event_type], 
     :event_start_date => self.format_date(row[:event_start_date]) 
).first 

    event = Event.new(
     :participant_id => participant.id, 
     :event_type_code => row[:event_type], 
     :event_start_date => self.format_date(row[:event_start_date]) 
) if event.blank? 

    event 
end 

e ho anche, nella stessa classe, un metodo di istanza:

def format_date(date) 
    parsed_date = date.split('/') 

    # if month or day are single digit, make them double digit with a leading zero 
    if parsed_date[0].split("").size == 1 
    parsed_date[0].insert(0, '0') 
    end 
    if parsed_date[1].split("").size == 1 
    parsed_date[1].insert(0, '0') 
    end 

    parsed_date[2].insert(0, '20') 

    formatted_date = parsed_date.rotate(-1).join("-") 
    formatted_date 
end 

Ricevo un 'metodo non definito' errore per #format_date. (L'ho provato senza lo self davanti, all'inizio). Non puoi usare i metodi di istanza nei metodi di classe della stessa classe?

+2

Perché 'format_date' è un metodo di istanza? Non sta usando nulla dall'istanza. – tdgs

+0

Certo, non puoi. Per chiamare un metodo di istanza hai bisogno di un'istanza della tua classe. –

+0

@tdgs Buon punto. L'ho reso un metodo di istanza perché pensavo che renderlo un metodo di classe implicherebbe che fosse per uso pubblico, quando il caso è solo per uso interno –

risposta

22

risposta è no, non è possibile utilizzare i metodi istanza di una classe all'interno di un metodo di classe unles s avete qualcosa di simile:

class A 
    def instance_method 
    # do stuff 
    end 

    def self.class_method 
    a = A.new 
    a.instance_method 
    end 
end 

Ma, per quanto posso vedere, format_date non deve essere un metodo di istanza. Quindi scrivere format_date come

def self.format_date(date) 
    # do stuff 
end 
+0

Ho un metodo di istanza perché è chiamato da una convalida, e un metodo di classe che andava bene per poter chiamare il metodo di istanza, per essere DRY –

+0

Quindi fare qualcosa come questo 'classe A; def instance_method; self.class.class_method; fine; def self.class_method; -- fare cose -- ; fine; FINE' – tdgs

3

Si potrebbe fare YourClassName.new.format_date(your_date), anche se penso che sia abbastanza chiaro si dovrebbe essere ristrutturazione del codice - questo metodo probabilmente non appartiene a un'istanza. Perché non estendi la classe Date o fai il format_date un metodo di classe sulla classe che stai utilizzando?

EDIT: Qui ci sono alcune altre cose a cui pensare con il tuo codice:

  • Tutto il tuo metodo format_date va a un sacco di lunghezze per manipolare le date come stringhe. Perché non usare Ruby's Date Class? Utilizzando Date.parse o Date.strptime o addirittura "01/01/2001".to_date potrebbe essere utile a seconda del proprio locale
  • considerare di estendere la classe String per il metodo, se si ha realmente bisogno per rendere il proprio metodo:

    class String 
        def to_friendly_formatted_date 
        Date.strptime(self, "%d/%m/%y") 
        end 
    end 
    "01/08/09".to_friendly_formated_date 
    
  • Il vostro metodo di classe sta piangendo la nostra per i metodi helper find_or_initialize_by:

    self.get_event_record(row, participant) 
        find_or_initialize_by_participant_id_and_event_type_code_and_event_start_date(:participant_id => participant.id, :event_type_code => row[:event_type_code], :event_start_date => row[:event_start_date].to_friendly_formatted_date) 
    end 
    

da Dio è lungo, ma realizza quello che stai cercando di fare più elegante (anche se io sono aperto a tesi!)

+0

Inizialmente avevo un metodo di classe, ma stavo pensando (possibilmente erroneamente) che i metodi di classe siano pensati per essere usati al di fuori della classe, mentre questo metodo è strettamente un metodo interno. –

+0

Penso che il pensiero * fosse * errato! I metodi di istanza dovrebbero riguardare gli attributi specifici di un'istanza di quella classe. Il tuo metodo non ha davvero nulla a che fare con un'istanza. Lo trasformerei in un metodo di classe. Hai anche alcune opportunità per ridimensionare il tuo codice - modifico la mia risposta. –

+0

@steve_gallagher: puoi rendere privati ​​i metodi di classe. Dai uno sguardo a [questo] (https://gist.github.com/3011405) gist. – Linuxios

4

Basta creare metodo di classe

def self.format_date (..) 
    ... 
end 

E se u bisogno metodo di istanza, delegato al metodo di classe

def format_date *args 
    self.class.format_date *args 
end 

E io non credo che sia una buona idea quella di chiamare i metodi di istanza dal campo di applicazione della classe

+1

'class.format_args'? Perché stai chiamando un metodo di classe sulla 'classe' jeyword? – Linuxios

+0

perché format_date è il metodo di classe –

+2

Ciò non significa che il suo richiamo sulla parola chiave 'class' farà qualsiasi cosa ma ha un errore di sintassi. Hai bisogno di "te stesso". – Linuxios

Problemi correlati