Patrocinado por
Patrocinado por Inetum

Usa Python para reescrever código ABAP

images/thumbnail.jpg - Thumbnail

Quando é preciso fazer alterações de fundo ao código o IDE do SAPGui não ajuda. O Eclipse ADT já é bem melhor mas mesmo assim há muitas alterações que essas ferramentas não conseguem automatizar. Nomeadamente alterações que têm de ser feitas centenas de vezes e que não se conseguem fazer com um simples find and replace. Nesses casos o mais normal é acabar por fazer tudo à mão.

Automatiza

Mas não tem de ser assim. No outro dia aconteceu-me uma dessas: precisei de modernizar algum código num programa muito antigo. Decidi criar um pequeno programa em Python para fazer as alterações por mim.

Não só é mais rápido como é mais seguro e também mais divertido.

Aqui está um fluxograma a descrever o que fiz:

Exemplo

Temos um report antigo que usa WRITE para escrever os resultados e queremos que passe a escrevê-los para o Application Log.

AS-IS

REPORT z_very_old.

START-OF-SELECTION.
  WRITE / 'Starting...'.
  LOOP AT itbl INTO wa.
    WRITE: / 'Processing', wa-id, wa-description.
    (...)
  ENDLOOP.
  WRITE 'Finised.'.

TO-BE

REPORT z_very_old.

START-OF-SELECTION.
  logger->add_text( 'Starting...' ).
  LOOP AT itbl INTO wa.
    logger->add_text( 'Processing' && wa-id && wa-description ).
    (...)
  ENDLOOP.
  logger->add_text( 'Finised.' ).

Python

Como podes ver, find and replace não chegaria. E por isso desenvolvi um programinha Python para o fazer por mim. Não sou muito experiente em Python mas não é preciso. É simples e divertido. Fui iterando e verificando o ABAP resultante até obter o que queria. No fim ficou isto:

#!/usr/bin/python

import re
import os
import sys

REGEX_WRITE = [
  r'WRITE: / (.*?)\.',
  r'WRITE / (.*?)\.',
  r'WRITE: (.*?)\.',
  r'WRITE (.*?)\.'
]

def load_file(filename: str) -> str:
    with open(os.path.join(sys.path[0], filename), "r") as f:
        return(f.read())

def remove_points_inside_strings(str: str) -> str:
    """ To avoid making the regex expression unnecessarily complex """
    str = str.replace("'Req.", "'Req")
    str = str.replace(" repl.", " repl")
    str = str.replace("Screen Rel.", "Screen Rel")
    str = str.replace("WRITE: /.", "logger->add_text( ' ' ).")
    str = str.replace("WRITE /.", "logger->add_text( ' ' ).")
    return str

def convert_write_to_logger(str: str) -> str:
    for r in REGEX_WRITE:
      p = re.compile(r, re.S)
      str = p.sub(r'logger->add_text( \1 ).', str)
    return str

def concatenate_parts(str: str) -> str:
    p = re.compile(r'logger->add_text\( ((?:.){0,300}?),((?:.){0,300}?) \)\.', re.S)
    str2 = p.sub(
      r'logger->add_text( \1 && \2 ).', str
    )
    if str2 != str:
      str2 = concatenate_parts(str2)
    return str2

if __name__ == "__main__":
    str = load_file(sys.argv[1])
    str = remove_points_inside_strings(str)
    str = convert_write_to_logger(str)
    str = concatenate_parts(str)
    print(str)

Não é nada do outro mundo mas faz em segundos aquilo que me teria demorado horas e com uma enorme probabilidade de me enganar.

Se o código a alterar estiver espalhado por vários programas, includes, métodos, etc, podes usar o abapGit para exportar o código todo para um XML e aplicar o programa a esse XML ao invés. Deverá funcionar à mesma, mais coisas menos coisa.

O Abapinho saúda-vos.