Como adicionar “wrappers” em torno de métodos no código fonte baseado em um padrão, usando sed, awk, grep e amigos

2

Como posso adicionar wrappers a um arquivo com base em um padrão?

Por exemplo, tenho o seguinte:

  ...
  find(css_policy_form_stage3).click
  with_ajax_wait
    expect(css_coverage_type_everquote).to be_visible
  end
  with_ajax_wait
    expect(css_coverage_type_everquote).to be_visible
  end
end
it "Stage 3" do
  select(coverage_type, from: css_coverage_type_everquote)
  find(css_has_auto_insurance).click
  ...

E eu quero "embrulhar" esses "with_ajax_wait" blocos com it "waits" do ... end ao redor deles.

i.e. Eu quero pegar:

  ...
  find(css_policy_form_stage3).click
  it "waits" do
    with_ajax_wait
      expect(css_coverage_type_everquote).to be_visible
    end
  end
  it "waits" do
    with_ajax_wait
      expect(css_coverage_type_everquote).to be_visible
    end
  do
end
it "Stage 3" do
  select(coverage_type, from: css_coverage_type_everquote)
  find(css_has_auto_insurance).click
  ...

Notas e suposições :

    O bloco
  • para o código de recuo é sempre de 3 linhas (com ... espera ... e fim). Seria bom permitir mais do que a linha de código interna, mas não é necessário para o caso mais simples.
  • o próprio bloco deve ter um recuo adicional de 2 espaços.
  • existem outras finalidades que não estão relacionadas (exemplo mostrado antes da "Etapa 3"
  • seria bom poder especificar um padrão interno também, por ex. somente esses blocos que possuem expect iniciando a linha de código sendo recuados. Eu acho que o awk é provavelmente a ferramenta devido à capacidade de ler linhas consecutivas, mas eu estou lutando para saber como escrever isso.

Eu estou imaginando que este é um q & geralmente útil como adicionar wrapper dentro de arquivos não é incomum.

Algo semelhante à minha pergunta anterior: Como usar o awk para recuar um arquivo de origem baseado em regras simples?
No entanto, neste caso, estou adicionando o wrapper mais o recuo.

    
por Michael Durrant 04.09.2015 / 14:08

3 respostas

1

Aqui está uma maneira com sed :

sed -E '/with_ajax_wait/,/end/{       # if line is in this range
H                                     # append to hold space
/end/!d                               # if it doesn't match end, delete it
//{                                   # if it matches
s/.*//                                # empty the pattern space
x                                     # exchange pattern space w. hold space
s/^(\n)( *)/it "waits" do/      # add first line + initial spacing
s/\n/&  /g                            # re-indent all other lines
G                                     # append hold space to pattern space
s/^(( *).*)/do/                   # add the closing 'do' + initial spacing
}
}
' infile

então com uma entrada como:

with_ajax_wait
  expect(css_coverage_type_everquote).to be_visible
end
  find(css_policy_form_stage3).click
  with_ajax_wait
    expect(css_coverage_type_everquote).to be_visible
  end
  something here
    with_ajax_wait
      expect(css_coverage_type_everquote).to be_visible
        got some more stuff here to do
          process it
        done
    end
  end

a saída é:

it "waits" do
  with_ajax_wait
    expect(css_coverage_type_everquote).to be_visible
  end
do
  find(css_policy_form_stage3).click
  it "waits" do
    with_ajax_wait
      expect(css_coverage_type_everquote).to be_visible
    end
  do
  something here
    it "waits" do
      with_ajax_wait
        expect(css_coverage_type_everquote).to be_visible
          got some more stuff here to do
            process it
          done
      end
    do
  end

Ele deve funcionar com blocos de mais de três linhas, desde que seus blocos with_ajax_wait sempre terminem com end .
Substitua o do de fechamento por end , se necessário, pois seu exemplo é confuso ... (você usou end para o primeiro bloco e do para o segundo). desta vez usando BRE e [[:blank:]] em vez de (espaço):

sed '/with_ajax_wait/,/end/{
/with_ajax_wait/{
G
s/\([[:blank:]]*\)\(with_ajax_wait\)\(\n\)/it "waits" do  /
p
d
}
//!{
/end/!{
s/^/  /
}
/end/{
G
s/\([[:blank:]]*\)\(end\)\(\n\)/  end/
}
}
}
' infile

Este está processando cada linha nesse intervalo separadamente, o primeiro e o último no intervalo são re-indentados e wrappers são adicionados, o resto das linhas são apenas re-indentados.

    
por 04.09.2015 / 20:04
1

Isso funcionou para mim, com awk :

awk '/with_ajax_wait/,/end/{          # match the lines between the blocks
  i=substr($0,0,match($0, "[^ ]")-1); # i contains the indented spaces
  if($0~/with_ajax_wait/){            # if it is the starting block
    $0=i"it \"waits\" do\n  "$0       # ... add the starting block before the line
  }else if($0~/end/){                 # if it is the ending block
    $0="  "$0"\n"i"end"               # ... add the end block after the line
  }else{                              # else
    $0="  "$0                         # just indent the line with 2 spaces
  }
}1' file

A explicação está nos comentários. O 1 no final de toda a instrução é apenas uma condição verdadeira, de forma que awk imprime todas as linhas.

    
por 04.09.2015 / 14:54
1

Experimente o seguinte SED:

sed '/with_ajax_wait/{/end/!N;N;s/^/  it \"waits\" do\n/;s/$/\nend/;s/\n/\n  /g}'

Isso funciona para o exemplo que você deu.

versão do Mac OS

(Testado no OS X 10.8.5) O Mac OS não gosta de certas novas linhas ou comandos de encadeamento junto com ponto e vírgula. Use o seguinte em vez disso:

sed -E -e '/with_ajax_wait/{' -e '/end/!N' -e 'N' -e 's/^/  it \"waits\" do\
/' -e 's/$/\
end/' -e 's/\n/\
  /g' -e '}'

Essas são novas linhas literais que você pode digitar no terminal ou copiar.

Como funciona

A chave é o comando N . Queremos preencher a memória do SED (o espaço padrão ) com um grupo do formulário

  with_ajax_wait
    // commands
  end

O programa percorre o arquivo uma linha por vez, até atingir uma linha correspondente a with_ajax_wait ; Em seguida, ele executa o comando N , que acrescenta mais linhas ao espaço padrão, até alcançar uma linha correspondente a end . O resto do programa é uma seqüência de substituições que realizam o acondicionamento: anexamos a linha it "waits" do ao início do bloco, a linha do até o final e depois recortamos tudo.

Limitações

  • Isso não funcionará se a palavra end ocorrer em qualquer lugar dentro do bloco with_ajax_wait ... end . Fazer esse trabalho exigirá uma análise mais séria do próprio código. Se pudermos garantir que o end de fechamento será sempre indentado por dois espaços, então poderemos melhorar este SED substituindo {/end/!N por {/\n end/!N ou algo assim.
  • Os comandos it "waits" do e do são sempre recuados por dois espaços, mesmo se o texto dentro dele for indentado por mais ou menos. Isso é provavelmente mais fácil de consertar, ao custo de um comando mais complicado.
por 04.09.2015 / 18:17