Pergunta

Eu sou um pouco novo para Ruby e embora eu encontrá-lo para ser uma linguagem muito intuitivo eu estou tendo alguma dificuldade compreender como implícita valores de retorno comportar.

Eu estou trabalhando em um pequeno programa para grep registros do Tomcat e gerar arquivos CSV delimitado por tubos a partir dos dados pertinentes. Aqui está um exemplo simplificado que eu estou usando para gerar as linhas de uma entrada de registo.

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[accountId=AccountId@66679198[accountNumber=0951714636005,srNumber=20]",
                       /^(\d{2}:\d{2}:\d{2},\d{3}).*?(\d{2}\/\d{2}).*?\[accountNumber=(\d*?),srNumber=(\d*?)\]/)

Quando eu executar esse código eu voltar o seguinte, que é o que se espera quando retornar explicitamente o valor da produção.

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

No entanto, se eu mudar LineMatcher ao seguinte e não retornar explicitamente saída:

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

Então eu recebo o seguinte resultado:

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

Obviamente, este não é o resultado desejado. Parece que eu deveria ser capaz de se livrar da variável de saída, mas não está claro onde o valor de retorno está vindo. Além disso, quaisquer outras sugestões / melhorias para facilitar a leitura são bem-vindos.

Foi útil?

Solução

Qualquer declaração em Ruby retorna o valor da última expressão avaliada. Você precisa saber a implementação e o comportamento do método mais utilizado, a fim de saber exatamente como seu programa irá funcionar.

#each retorna a coleção que você iterated diante. Dito isto, o seguinte código irá retornar o valor de line.scan (regexp).

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

Se você quiser retornar o resultado da execução, você pode usar map, que funciona como each mas retorna a coleção modificado.

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

Existem vários métodos úteis que você pode usar dependendo do seu caso muito específico. Neste você pode querer usar inject a menos que o número de resultados retornados pelo scan é elevada (trabalhando em matrizes, em seguida, fundi-las é mais eficiente do que trabalhar em uma única string).

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

Outras dicas

Em rubi o valor de retorno de um método é o valor devolvido pela última declaração. Você pode optar por ter um retorno explícita também.

No seu exemplo, o primeiro trecho retorna o output string. O segundo trecho no entanto retorna o valor retornado pelo método each (que é agora o último stmt), que acaba por ser uma série de fósforos.

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"]

Update: No entanto, que ainda não explica sua saída em uma única linha. Eu acho que é um erro de formatação, deve imprimir cada uma das partidas em uma linha diferente porque é assim que puts imprime uma matriz. Um código de pouco pode explicar isso melhor do que eu ..

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

Pessoalmente acho o seu método com o retorno explícita mais legível (neste caso)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top