SAP R/3 форум ABAP консультантов
Russian ABAP Developer's Club

Home - FAQ - Search - Memberlist - Usergroups - Profile - Log in to check your private messages - Register - Log in - English
Blogs - Weblogs News

Zmacros - генератор программ



 
Post new topic   Reply to topic    Russian ABAP Developer's Club Forum Index -> Submit a new program | Новые материалы, программы для сайта
View previous topic :: View next topic  
Author Message
Anton Sikidin
Участник
Участник



Joined: 11 Mar 2009
Posts: 18
Location: Украина

PostPosted: Fri May 12, 2017 4:58 pm    Post subject: Zmacros - генератор программ Reply with quote

Добрый день.

Время затраченное програмистом над решением поставленной задачи, когда он не занят всем другим, делется на 2 типа:

1) творчество
2) рутина

C творчеством все просто – каджый творит как может. Для автоматизайии рутины я написал программу которая генерирует тексты по шаблону, заменяя переменные нужными значениями.

Эту задачу можно решить макросами, но макросы просты в написании и тяжелы в редактировании особенно в отладке, они не поддаются отладке. Для того чтоб писать также легко как с макросами и в тоже время без них была написана эта программа. Потому как макросы в общем случае не приветствуются.

исходник

Я поквжу примеры кода котрые иногда необходимо написать и как это генерировать быстрее и проще.

F8 - перезапускает программу
Refresh - перечитывает шаблон создает переменные для шаблона
List сохраненные шаблоны в базе
Save - сохранить в базу
Run - подставить переменные в шаблон



Первый пример создание экрана для alv .

Нужно объявмить переменные, инициализировать экран, обработать события. Все экраны алв однотипны. Мняется в них кроме имена структуры и имена таблицы только суффиксы переменных обозначающие пренадлежность к конкретному экрану. Делать это можно разными способами:
1) каждый раз писать с нуля
2) копипастить из другой программы и подпровлять индексы

и наиболее оптимальный способ
3) воспользоваться шаблоном

что нужно сгенерировать

Code:



*----------------------------
*-- top screen 0100
      , ok_code      TYPE sy-ucomm
      , gr_alv_0100            TYPE REF TO cl_gui_alv_grid
      , gr_cont_0100           TYPE REF TO cl_gui_custom_container
      , gt_fieldcat_0100       TYPE lvc_t_fcat
      , gt_sort_0100           TYPE lvc_t_sort
      , gs_layout_0100         TYPE lvc_s_layo
      , gs_vari_0100           TYPE disvariant



*----------------------------
*screen logic

PROCESS BEFORE OUTPUT.
 MODULE STATUS_0100.
*
PROCESS AFTER INPUT.
 MODULE USER_COMMAND_0100.


*----------------------------
*modules
MODULE status_0100 OUTPUT.
  SET PF-STATUS 'STATUS0100'.
  SET TITLEBAR 'TITLEBAR0100'.


  IF gr_alv_0100 IS NOT BOUND.
    CREATE OBJECT gr_cont_0100
      EXPORTING
        container_name = 'CONT_0100'.

    CREATE OBJECT gr_alv_0100
      EXPORTING
        i_parent = gr_cont_0100.

    gs_layout_0100-no_rowmove = 'X'.
    gs_layout_0100-cwidth_opt = 'X'.

    gs_layout_0100-zebra = 'X'.
    gs_layout_0100-no_rowmark = ''.
    gs_layout_0100-sel_mode = 'A'.

    gs_vari_0100-report = sy-repid.
    gs_vari_0100-handle = '0100'.


    CALL FUNCTION 'LVC_FIELDCATALOG_MERGE'
      EXPORTING
        I_STRUCTURE_NAME = 'but100'
      CHANGING
        ct_fieldcat      = gt_fieldcat_0100.


    CALL METHOD gr_alv_0100->set_table_for_first_display
      EXPORTING
        i_save          = 'A'
        is_layout       = gs_layout_0100
        is_variant      = gs_vari_0100
      CHANGING
        it_sort         = gt_sort_0100
        it_outtab       = gt_0100
        it_fieldcatalog = gt_fieldcat_0100.

  ELSE.

    CALL METHOD gr_alv_0100->get_frontend_layout
      IMPORTING
        es_layout = gs_layout_0100.

    gs_layout_0100-cwidth_opt = 'X'.

    CALL METHOD gr_alv_0100->set_frontend_layout
      EXPORTING
        is_layout = gs_layout_0100.


    gr_alv_0100->refresh_table_display( ).
  ENDIF.

ENDMODULE.




MODULE user_command_0100 INPUT.

  CASE  ok_code .
    WHEN 'BACK'.
      SET SCREEN 0.
*   when 'XXXXXXX'.

  ENDCASE.
  clear ok_code.

ENDMODULE.


вот шаблон
Code:
 


*----------------------------
*-- top screen {screen_number}
      , ok_code      TYPE sy-ucomm
      , gr_alv_{screen_number}            TYPE REF TO cl_gui_alv_grid
      , gr_cont_{screen_number}           TYPE REF TO cl_gui_custom_container
      , gt_fieldcat_{screen_number}       TYPE lvc_t_fcat
      , gt_sort_{screen_number}           TYPE lvc_t_sort
      , gs_layout_{screen_number}         TYPE lvc_s_layo
      , gs_vari_{screen_number}           TYPE disvariant



*----------------------------
*screen logic

PROCESS BEFORE OUTPUT.
 MODULE STATUS_{screen_number}.
*
PROCESS AFTER INPUT.
 MODULE USER_COMMAND_{screen_number}.


*----------------------------
*modules
MODULE status_{screen_number} OUTPUT.
  SET PF-STATUS 'STATUS{screen_number}'.
  SET TITLEBAR 'TITLEBAR{screen_number}'.


  IF gr_alv_{screen_number} IS NOT BOUND.
    CREATE OBJECT gr_cont_{screen_number}
      EXPORTING
        container_name = 'CONT_{screen_number}'.

    CREATE OBJECT gr_alv_{screen_number}
      EXPORTING
        i_parent = gr_cont_{screen_number}.

    gs_layout_{screen_number}-no_rowmove = 'X'.
    gs_layout_{screen_number}-cwidth_opt = 'X'.

    gs_layout_{screen_number}-zebra = 'X'.
    gs_layout_{screen_number}-no_rowmark = ''.
    gs_layout_{screen_number}-sel_mode = 'A'.

    gs_vari_{screen_number}-report = sy-repid.
    gs_vari_{screen_number}-handle = '{screen_number}'.


    CALL FUNCTION 'LVC_FIELDCATALOG_MERGE'
      EXPORTING
        I_STRUCTURE_NAME = '{struct_name}'
      CHANGING
        ct_fieldcat      = gt_fieldcat_{screen_number}.


    CALL METHOD gr_alv_{screen_number}->set_table_for_first_display
      EXPORTING
        i_save          = 'A'
        is_layout       = gs_layout_{screen_number}
        is_variant      = gs_vari_{screen_number}
      CHANGING
        it_sort         = gt_sort_{screen_number}
        it_outtab       = gt_{screen_number}
        it_fieldcatalog = gt_fieldcat_{screen_number}.

  ELSE.

    CALL METHOD gr_alv_{screen_number}->get_frontend_layout
      IMPORTING
        es_layout = gs_layout_{screen_number}.

    gs_layout_{screen_number}-cwidth_opt = 'X'.

    CALL METHOD gr_alv_{screen_number}->set_frontend_layout
      EXPORTING
        is_layout = gs_layout_{screen_number}.


    gr_alv_{screen_number}->refresh_table_display( ).
  ENDIF.

ENDMODULE.




MODULE user_command_{screen_number} INPUT.

  CASE  ok_code .
    WHEN 'BACK'.
      SET SCREEN 0.
*   when 'XXXXXXX'.

  ENDCASE.
  clear ok_code.

ENDMODULE.






По нажатию кнопки обновить програма выбирает из шаблона все переменные автоматически. Количество переменных в шаблоне ограничено только здравым смыслом. Простые пременные в шаблоне берутся в фигурные скобки{} например {screen_number}

второй пример – объявление типов внутри программы

что желаем получить
Code:

    TYPES:
      BEGIN OF  t_data_row,
        LINE  TYPE CIFCOUNT,
        T_TYPE  TYPE CLASSTTYPE,
        TABNAME  TYPE TABNAME,
        JJOIN  TYPE TABNAME,
        LEFT1  TYPE TABNAME,
        RIGHT1  TYPE TABNAME,
        LV_KEY_SELECT  TYPE TABNAME,
        LEFT_61  TYPE ECP_FIELDNAME,
        RIGHT_61  TYPE ECP_FIELDNAME,
        LV_KEY_JOIN  TYPE ECP_FIELDNAME,
        SORTORDER  TYPE ANZST,
        CRITERIAFOR  TYPE ADDIFCTCOD,
        DISABLE  TYPE CLASSTTYPE,
        OR1  TYPE AKB_NOTE,
        OR2  TYPE AKB_NOTE,
        OR3  TYPE AKB_NOTE,
        OR4  TYPE AKB_NOTE,
      END OF t_data_row .


шаблон
Code:

    TYPES:
      BEGIN OF  t_{type},
        $1-1  TYPE $1-2,
      END OF t_{type} .





Можно скопировать из словаря имена полей и типов, потом руками расставлять запятые, ключевое слово type или воспользоваться шаблоном.



Переменные которые имеют по несколько значений в строке и имеют несколько строк в шаблоне обозначаются $3-2 .

$ говорит программе что здесь будет переменная, следующая цифра говорит номер переменной, следующая цифра говорит номер столбца.

Количество столбцов ограничено здравым смыслом. Количество сложных переменным ограничено только максимальным количеством генерацций для программы, в моем случае это было 18. Шаблон с 18-ю табличными переменными использующийся в реальной программе я придумать не смог, так что тут все ок.

Если увидите сообщение "Generation Limi Reached", нужно сохранить шаблон если не сохранен и перезапустить программу.

Шаблоны можно хранить в файлах и копипастить, можно загружать и выгружать в файлы,
правильный вариант хранить в базе. Если нужные таблицы не созданы то появится подсказка какие таблицы с какими полями типами и ключами нужно создать.






подобные по уровню сложности примеры
перенос значения из старой в новую структуру

что ожидаем получить
Code:

ls_new-TABNAME = ls_old-TAB .
ls_new-JJOIN = ls_old-JJOIN_old .
ls_new-LEFT1 = ls_old-LEF .
ls_new-RIGHT1 = ls_old-RIG .
ls_new-LV_KEY_SELECT = ls_old-LV_KEY_old .


шаблон
Code:

ls_new-$1-1 = ls_old-$1-2 .





различной сложности case .. when

что желаем получить
Code:

  LOOP AT mt_alv_fieldcat INTO ls_alv_fieldcat WHERE tech EQ space
 AND no_out EQ space.
    CASE ls_alv_fieldcat-fieldname.
      WHEN 'A38'.
        lv_string = ls_totals-a38.
         set_shift.
      WHEN 'A39'.
        lv_string = ls_totals-a39.
         set_shift.
      WHEN 'A40'.
        lv_string = ls_totals-a40.
         set_shift.
      WHEN 'A41'.
        lv_string = ls_totals-a41.
         set_shift.
      WHEN 'A42'.
        lv_string = ls_totals-a42.
         set_shift.
      WHEN 'A43'.
        lv_string = ls_totals-a43.
         set_shift.
      WHEN 'A44'.
        lv_string = ls_totals-a44.
         set_shift.
      WHEN 'A45'.
        lv_string = ls_totals-a45.
         set_shift.
    ENDCASE.
    ADD ls_alv_fieldcat-outputlen TO lv_len.
    ADD 1 TO lv_len.
  ENDLOOP.


шаблон
Code:

  LOOP AT mt_alv_fieldcat INTO ls_alv_fieldcat WHERE tech EQ space
 AND no_out EQ space.
    CASE ls_alv_fieldcat-fieldname.
>1
      WHEN 'A$1-1'.
        lv_string = ls_totals-a$1-1.
         set_shift.
<1
    ENDCASE.
    ADD ls_alv_fieldcat-outputlen TO lv_len.
    ADD 1 TO lv_len.
  ENDLOOP.





До этого мы рассмотрели шаблоны нулевой и первой размерности. Перейдем к второй и высшей, все остальные примерно как второй.

Вот таким шаблоном можно посторить набор всех возможных комбинаций значений.


что желаем получить
Code:

0  X A
0  X B
0  X C
0  _ A
0  _ B
0  _ C
1  X A
1  X B
1  X C
1  _ A
1  _ B
1  _ C



шаблон
Code:

$1-1  $2-1 $3-1





Допустим вы пишете тесты для своего кода. Генерация тестов утомительная процедура, с шаблонами все просто.

Вот таким шаблоном можно сгенерировать тесты для проверки нескольких логических функций на всех возможных наборах значений.

что желаем получить
Code:


 
 perform logic_or using 'X' 'X'  'X' changing lv_result.
 write :/  ' or on  v1=X v2=X  v3=X ' , lv_result .

 perform logic_or using 'X' 'X'  '' changing lv_result.
 write :/  ' or on  v1=X v2=X  v3= ' , lv_result .

 perform logic_or using 'X' ''  'X' changing lv_result.
 write :/  ' or on  v1=X v2=  v3=X ' , lv_result .

 perform logic_or using 'X' ''  '' changing lv_result.
 write :/  ' or on  v1=X v2=  v3= ' , lv_result .

 perform logic_or using '' 'X'  'X' changing lv_result.
 write :/  ' or on  v1= v2=X  v3=X ' , lv_result .

 perform logic_or using '' 'X'  '' changing lv_result.
 write :/  ' or on  v1= v2=X  v3= ' , lv_result .

 perform logic_or using '' ''  'X' changing lv_result.
 write :/  ' or on  v1= v2=  v3=X ' , lv_result .

 perform logic_or using '' ''  '' changing lv_result.
 write :/  ' or on  v1= v2=  v3= ' , lv_result .



 perform logic_and using 'X' 'X'  'X' changing lv_result.
 write :/  ' and on  v1=X v2=X  v3=X ' , lv_result .

 perform logic_and using 'X' 'X'  '' changing lv_result.
 write :/  ' and on  v1=X v2=X  v3= ' , lv_result .

 perform logic_and using 'X' ''  'X' changing lv_result.
 write :/  ' and on  v1=X v2=  v3=X ' , lv_result .

 perform logic_and using 'X' ''  '' changing lv_result.
 write :/  ' and on  v1=X v2=  v3= ' , lv_result .

 perform logic_and using '' 'X'  'X' changing lv_result.
 write :/  ' and on  v1= v2=X  v3=X ' , lv_result .

 perform logic_and using '' 'X'  '' changing lv_result.
 write :/  ' and on  v1= v2=X  v3= ' , lv_result .

 perform logic_and using '' ''  'X' changing lv_result.
 write :/  ' and on  v1= v2=  v3=X ' , lv_result .

 perform logic_and using '' ''  '' changing lv_result.
 write :/  ' and on  v1= v2=  v3= ' , lv_result .



 perform logic_xor using 'X' 'X'  'X' changing lv_result.
 write :/  ' xor on  v1=X v2=X  v3=X ' , lv_result .

 perform logic_xor using 'X' 'X'  '' changing lv_result.
 write :/  ' xor on  v1=X v2=X  v3= ' , lv_result .

 perform logic_xor using 'X' ''  'X' changing lv_result.
 write :/  ' xor on  v1=X v2=  v3=X ' , lv_result .

 perform logic_xor using 'X' ''  '' changing lv_result.
 write :/  ' xor on  v1=X v2=  v3= ' , lv_result .

 perform logic_xor using '' 'X'  'X' changing lv_result.
 write :/  ' xor on  v1= v2=X  v3=X ' , lv_result .

 perform logic_xor using '' 'X'  '' changing lv_result.
 write :/  ' xor on  v1= v2=X  v3= ' , lv_result .

 perform logic_xor using '' ''  'X' changing lv_result.
 write :/  ' xor on  v1= v2=  v3=X ' , lv_result .

 perform logic_xor using '' ''  '' changing lv_result.
 write :/  ' xor on  v1= v2=  v3= ' , lv_result .



 perform logic_magic using 'X' 'X'  'X' changing lv_result.
 write :/  ' magic on  v1=X v2=X  v3=X ' , lv_result .

 perform logic_magic using 'X' 'X'  '' changing lv_result.
 write :/  ' magic on  v1=X v2=X  v3= ' , lv_result .

 perform logic_magic using 'X' ''  'X' changing lv_result.
 write :/  ' magic on  v1=X v2=  v3=X ' , lv_result .

 perform logic_magic using 'X' ''  '' changing lv_result.
 write :/  ' magic on  v1=X v2=  v3= ' , lv_result .

 perform logic_magic using '' 'X'  'X' changing lv_result.
 write :/  ' magic on  v1= v2=X  v3=X ' , lv_result .

 perform logic_magic using '' 'X'  '' changing lv_result.
 write :/  ' magic on  v1= v2=X  v3= ' , lv_result .

 perform logic_magic using '' ''  'X' changing lv_result.
 write :/  ' magic on  v1= v2=  v3=X ' , lv_result .

 perform logic_magic using '' ''  '' changing lv_result.
 write :/  ' magic on  v1= v2=  v3= ' , lv_result .




шаблон
Code:

>1
  >2
     >3
       >4

 perform logic_$1-1 using '$2-1' '$3-1'  '$4-1' changing lv_result.
 write :/  ' $1-1 on  v1=$2-1 v2=$3-1  v3=$4-1 ' , lv_result .
     <4
  <3
 <2


<1





Строки размножаются согласно порядка встречаемости переменных в коде. Если нужно изменить порядок обхода переменных или включить несколько строк в шаблон то нужно использовать открывающие и закрывающие теги.
>1 - открывающий тег для первой переменной

<1 – закрывающий тег для первой переменной

программа автоматически проверяет что все открытые теги закрыты, и то что теги закрыты в правильном порядке. Поддерживается прицип LIFO Last In First Out. Если вы знакомы с тегами HTML, то все как у них.

Для автоматической генерации целочисленных переменных можно исрользовать следующий шаблон $1-5 сгенерирует 5 строк с цифрами от 1 до 5.






Шаблон $01-15 сгенерирует строки с цифрами от 01 до 15 с ведущими нулями.






_15-3 сгенерирует 3 строки с цифрами от 15 до 17





Собственно все.

P.S.
В качестве бонуса спомощью этой программы можно выстрелить себе в ногу, достаточно указать в качестве значения переменных значения которые можно интерпритировать как переменные.

Code:

$$1-1-1





Вобщем если в программе появляется количество однотипных строчек кода больше чем время затраченное на написание шаблона, то это повод задуматься над использованием программы. Шаблон написаный однажды можно использовать всегда. Лучше день потерять потом за 5 минут долететь ©.
Have fun!
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    Russian ABAP Developer's Club Forum Index -> Submit a new program | Новые материалы, программы для сайта All times are GMT + 4 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


All product names are trademarks of their respective companies. SAPNET.RU websites are in no way affiliated with SAP AG.
SAP, SAP R/3, R/3 software, mySAP, ABAP, BAPI, xApps, SAP NetWeaver and any other are registered trademarks of SAP AG.
Every effort is made to ensure content integrity. Use information on this site at your own risk.