Application Development and Automation Blog Posts
Learn and share on deeper, cross technology development topics such as integration and connectivity, automation, cloud extensibility, developing at scale, and security.
cancel
Showing results for 
Search instead for 
Did you mean: 
antonsikidin
Participant
1,783
Macros is a powerful tool that increase boilerplate writing speed. Unfortunately, exploitation of  macros is forbidden in many projects because macros cannot be debugged.

Zmacros is my development to generate a boilerplate in few clicks.

Source: https://github.com/AntonSikidin/zmacros

Clone with abapGit

Transaction – Zmacros





  • F8 – rerun program

  • Refresh – reread template and create variables

  • List – load template from db

  • ListAll – show template with versions

  • Save – save template to db

  • Run – populate template with values

  • Range gen – generate number range


 

FIRST CASE – GENERATION OF SCREENS.


If you want to get something like that:
*----------------------------
*-- 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.

 

Use this template:
*----------------------------
*-- 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.

 

Copy, past and press “Refresh”.


Fill \screen_number/ and \struct_name/ and press “Run”.

Result:
*----------------------------
*-- 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 = 'pa0298'
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.

Replace 0100 with 0200 and you get boilerplate for screen 0200.


As you can see ‘\’ and ‘/’ start and stop symbol define variable in template.

You can save template for future use by press “Save”.

A dialog will appear:


This dialog shows templates to update.

If it’s a new template - just press “Escape” and enter new name.




  • List” - load a last version of template

  • List all” - show all versions of all templates


 

SECOND CASE - TYPE DEFINITION.


If you want to get something like that:
    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 .

 

Use this template:
    TYPES:
BEGIN OF t_\type/,
$1-1# TYPE $1-2#,
END OF t_\type/ .

Copy, past and press “Refresh”.


You can see table “Main” with variable \type/ and table1 with two fields.

Go to transaction se11 and copy field name and field type.

Next, copy desired fields.


Past in table1.


Press “Run” and you will get this:


As you can see there is a new kind of variable ‘$1-2#’.

  • $ - start symbol

  • # - end symbol

  • 1 – table 1

  • 2 – column 2


You can define any number of tables with any number of columns.

THIRD CASE - MOVING STRUCTURE FROM OLD TO NEW.


If you want to get something like that:
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 .

Template:
ls_new-$1-1# = ls_old-$1-2# .

Copy, past and press “Refresh”.

Result:


FOURTH CASE USING ANY TYPE OF “CASE-WHEN”.


If you want to get something like that:
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.

Template:
  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.

Copy, past and press “Refresh”.

As you can see there is new punctuation - ‘>1’ and ‘<1’.

  • >1 – start of template that will be copied n-times, where n is number of lines in table1

  • <1 - end of template that will be copied n-times, where n is number of lines in table1


As in HTML all start and stop tag must be nested.

This is good:
>1
>2
$1-1# $2-1#
<2
<1

This is bad:
>1
>2
$1-1# $2-1#
<1
<2

and you will get error:


Very often you need a sequence of increasing or decreasing numbers is required.
In this case, you haveRange gen”.

Generate range from 2 to 15 and copy to clipboard.


Generate range from 15 to 2 and copy to clipboard.


Generate range from 02 to 15 with leading zeros and copy to clipboard.


Generate range from 015 to 002 with leading zeros and copy to clipboard.


All you need is past values in table.

Press “Run” and you will get this:


Go to more complex example.

With template:
$1-1#  $2-1# $3-1#

We can get something like this:



FIFTH CASE – THIS TOOL IS BEST FOR GENERATING ALL POSSIBLE VARIANTS FOR UNIT TESTING.


With this template you can test logic function.
>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
❤️
<2


<1


Result:
 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 .

Conclusion:

All my code is about increase your speed writing boilerplate and save your time. Hope it will be helpful.
10 Comments
Labels in this area