2009-06-30 8 views
17

Sono un po 'nuovo a Ruby e anche se trovo che sia un linguaggio molto intuitivo, sto avendo qualche difficoltà a capire come si comportano i valori di ritorno impliciti.Valori impliciti di ritorno in Ruby

Sto lavorando su un piccolo programma per eseguire il grep dei registri di Tomcat e generare file CSV delimitati da tubo dai dati pertinenti. Ecco un esempio semplificato che sto usando per generare le linee da una voce di log.

class LineMatcher 
    class << self 
    def match(line, regex) 
     output = "" 
     line.scan(regex).each do |matched| 
     output << matched.join("|") << "\n" 
     end 
     return output 
    end   
    end 
end 


puts LineMatcher.match("00:00:13,207 06/18 INFO stateLogger - TerminationRequest[[email protected][accountNumber=0951714636005,srNumber=20]", 
         /^(\d{2}:\d{2}:\d{2},\d{3}).*?(\d{2}\/\d{2}).*?\[accountNumber=(\d*?),srNumber=(\d*?)\]/) 

Quando eseguo questo codice torno quanto segue, che è quello che ci si aspetta quando esplicitamente la restituzione del valore della produzione.

00:00:13,207|06/18|0951714636005|20 

Tuttavia, se cambio LineMatcher al seguente e non esplicitamente ritorno di uscita:

class LineMatcher 
     class << self 
     def match(line, regex) 
      output = "" 
      line.scan(regex).each do |matched| 
      output << matched.join("|") << "\n" 
      end 
     end   
     end 
    end 

Poi ho ottenere il seguente risultato:

00:00:13,207 
06/18 
0951714636005 
20 

Ovviamente, questo non è il risultato desiderato. Sembra che dovrei essere in grado di eliminare la variabile di output, ma non è chiaro da dove provenga il valore di ritorno. Inoltre, eventuali altri suggerimenti/miglioramenti per la leggibilità sono i benvenuti.

+0

Formattazione corretta – csamuel

risposta

23

Qualsiasi dichiarazione in Ruby restituisce il valore dell'ultima espressione valutata . È necessario conoscere l'implementazione e il comportamento del metodo più utilizzato per sapere esattamente come agirà il programma.

#each restituisce la raccolta su cui è stata iterata. Detto questo, il codice seguente restituirà il valore di line.scan (regexp).

line.scan(regex).each do |matched| 
    output << matched.join("|") << "\n" 
end 

Se si desidera restituire il risultato della esecuzione, è possibile utilizzare map, che funziona come each ma restituisce la collezione modificato.

class LineMatcher 
    class << self 
    def match(line, regex) 
     line.scan(regex).map do |matched| 
     matched.join("|") 
     end.join("\n") # remember the final join 
    end   
    end 
end 

Esistono diversi metodi utili che è possibile utilizzare in base al caso specifico. In questo caso è possibile utilizzare inject a meno che il numero di risultati restituiti da scan sia elevato (lavorare sugli array quindi unirli è più efficiente rispetto a lavorare su una singola stringa).

class LineMatcher 
    class << self 
    def match(line, regex) 
     line.scan(regex).inject("") do |output, matched| 
     output << matched.join("|") << "\n" 
     end 
    end   
    end 
end 
+2

Grazie per il feedback ... Penso che la mia confusione sia dovuta al fatto che è difficile dire cosa viene interpretato come l'ultima affermazione. – csamuel

13

In ruby ​​il valore di ritorno di un metodo è il valore restituito dall'ultima istruzione. Puoi anche optare per un ritorno esplicito.

Nell'esempio, il primo snippet restituisce la stringa output. Il secondo snippet tuttavia restituisce il valore restituito dal metodo each (che ora è l'ultimo stmt), che si rivela essere una matrice di corrispondenze.

irb(main):014:0> "StackOverflow Meta".scan(/[aeiou]\w/).each do |match| 
irb(main):015:1* s << match 
irb(main):016:1> end 
=> ["ac", "er", "ow", "et"] 

Aggiornamento: Tuttavia, ciò non spiega ancora l'output su una singola riga. Penso che sia un errore di formattazione, dovrebbe stampare ognuna delle partite su una linea diversa perché è così che puts stampa una matrice. Un po 'di codice può spiegare meglio di me ..

irb(main):003:0> one_to_three = (1..3).to_a 
=> [1, 2, 3] 
irb(main):004:0> puts one_to_three 
1 
2 
3 
=> nil 

Personalmente trovo il metodo con il ritorno esplicito più leggibile (in questo caso)

+1

Spiacente, si, ho avuto un errore di formattazione. Corretto nella domanda – csamuel