diff --git a/src/#mbtools#cl_string_map.clas.abap b/src/#mbtools#cl_string_map.clas.abap index fe66eb7..0231eb7 100644 --- a/src/#mbtools#cl_string_map.clas.abap +++ b/src/#mbtools#cl_string_map.clas.abap @@ -5,7 +5,7 @@ CLASS /mbtools/cl_string_map DEFINITION PUBLIC SECTION. - CONSTANTS version TYPE string VALUE 'v1.0.3'. + CONSTANTS version TYPE string VALUE 'v1.0.5'. CONSTANTS origin TYPE string VALUE 'https://github.com/sbcgua/abap-string-map'. CONSTANTS license TYPE string VALUE 'MIT'. @@ -17,13 +17,15 @@ CLASS /mbtools/cl_string_map DEFINITION TYPES: tty_entries TYPE STANDARD TABLE OF ty_entry WITH KEY k. TYPES: - tts_entries TYPE SORTED TABLE OF ty_entry WITH UNIQUE KEY k. + tts_entries TYPE SORTED TABLE OF ty_entry WITH NON-UNIQUE KEY k. DATA mt_entries TYPE tts_entries READ-ONLY. CLASS-METHODS create IMPORTING !iv_case_insensitive TYPE abap_bool DEFAULT abap_false + !iv_list_mode TYPE abap_bool DEFAULT abap_false " removes uniqueness requirement, + " use with care: it is not the primary scenario !iv_from TYPE any OPTIONAL PREFERRED PARAMETER iv_from RETURNING @@ -31,6 +33,8 @@ CLASS /mbtools/cl_string_map DEFINITION METHODS constructor IMPORTING !iv_case_insensitive TYPE abap_bool DEFAULT abap_false + !iv_list_mode TYPE abap_bool DEFAULT abap_false " removes uniqueness requirement, + " use with care: it is not the primary scenario !iv_from TYPE any OPTIONAL. METHODS get @@ -49,6 +53,11 @@ CLASS /mbtools/cl_string_map DEFINITION !iv_val TYPE clike RETURNING VALUE(ro_map) TYPE REF TO /mbtools/cl_string_map. + METHODS setx + IMPORTING + !iv_str TYPE csequence + RETURNING + VALUE(ro_map) TYPE REF TO /mbtools/cl_string_map. METHODS size RETURNING VALUE(rv_size) TYPE i. @@ -98,6 +107,9 @@ CLASS /mbtools/cl_string_map DEFINITION METHODS to_string RETURNING VALUE(rv_string) TYPE string. + METHODS to_entries + CHANGING + !ct_entries TYPE STANDARD TABLE. METHODS strict IMPORTING @@ -111,6 +123,7 @@ CLASS /mbtools/cl_string_map DEFINITION DATA mv_is_strict TYPE abap_bool. DATA mv_read_only TYPE abap_bool. DATA mv_case_insensitive TYPE abap_bool. + DATA mv_list_mode TYPE abap_bool. ENDCLASS. @@ -133,6 +146,7 @@ CLASS /mbtools/cl_string_map IMPLEMENTATION. DATA lo_from TYPE REF TO /mbtools/cl_string_map. mv_is_strict = abap_true. mv_case_insensitive = iv_case_insensitive. + mv_list_mode = iv_list_mode. IF iv_from IS NOT INITIAL. @@ -173,6 +187,7 @@ CLASS /mbtools/cl_string_map IMPLEMENTATION. METHOD create. CREATE OBJECT ro_instance EXPORTING + iv_list_mode = iv_list_mode iv_case_insensitive = iv_case_insensitive iv_from = iv_from. ENDMETHOD. @@ -368,13 +383,19 @@ CLASS /mbtools/cl_string_map IMPLEMENTATION. lv_key = iv_key. ENDIF. - READ TABLE mt_entries ASSIGNING WITH KEY k = lv_key. - IF sy-subrc = 0. - -v = iv_val. - ELSE. + IF mv_list_mode = abap_true. ls_entry-k = lv_key. ls_entry-v = iv_val. INSERT ls_entry INTO TABLE mt_entries. + ELSE. + READ TABLE mt_entries ASSIGNING WITH KEY k = lv_key. + IF sy-subrc = 0. + -v = iv_val. + ELSE. + ls_entry-k = lv_key. + ls_entry-v = iv_val. + INSERT ls_entry INTO TABLE mt_entries. + ENDIF. ENDIF. ro_map = me. @@ -382,6 +403,32 @@ CLASS /mbtools/cl_string_map IMPLEMENTATION. ENDMETHOD. + METHOD setx. + + DATA lv_key TYPE string. + DATA lv_val TYPE string. + + ro_map = me. + + IF iv_str IS INITIAL. + RETURN. + ENDIF. + + SPLIT iv_str AT ':' INTO lv_key lv_val. + CONDENSE lv_key. + CONDENSE lv_val. + + IF lv_key IS INITIAL. + RETURN. + ENDIF. + + set( + iv_key = lv_key + iv_val = lv_val ). + + ENDMETHOD. + + METHOD size. rv_size = lines( mt_entries ). @@ -395,6 +442,52 @@ CLASS /mbtools/cl_string_map IMPLEMENTATION. ENDMETHOD. + METHOD to_entries. + + DATA lo_ttype TYPE REF TO cl_abap_tabledescr. + DATA lo_dtype TYPE REF TO cl_abap_datadescr. + DATA lo_stype TYPE REF TO cl_abap_structdescr. + FIELD-SYMBOLS LIKE LINE OF lo_stype->components. + FIELD-SYMBOLS LIKE LINE OF mt_entries. + FIELD-SYMBOLS TYPE any. + FIELD-SYMBOLS TYPE any. + FIELD-SYMBOLS TYPE any. + + lo_ttype ?= cl_abap_typedescr=>describe_by_data( ct_entries ). + lo_dtype = lo_ttype->get_table_line_type( ). + + IF lo_dtype->kind <> cl_abap_typedescr=>kind_struct. + lcx_error=>raise( 'Unsupported table line type' ). + ENDIF. + + lo_stype ?= lo_dtype. + + IF lines( lo_stype->components ) <> 2. + lcx_error=>raise( 'Wrong number of fields in target table (must be 2)' ). + ENDIF. + + + LOOP AT lo_stype->components ASSIGNING . + IF NOT ( -type_kind = cl_abap_typedescr=>typekind_char OR -type_kind = cl_abap_typedescr=>typekind_string ). + lcx_error=>raise( 'Wrong type of fields in target table (must be char or string)' ). + ENDIF. + ENDLOOP. + + + LOOP AT mt_entries ASSIGNING . + APPEND INITIAL LINE TO ct_entries ASSIGNING . + ASSERT sy-subrc = 0. + ASSIGN COMPONENT 1 OF STRUCTURE TO . + ASSERT sy-subrc = 0. + ASSIGN COMPONENT 2 OF STRUCTURE TO . + ASSERT sy-subrc = 0. + = -k. + = -v. + ENDLOOP. + + ENDMETHOD. + + METHOD to_string. DATA lv_size TYPE i. diff --git a/src/#mbtools#cl_string_map.clas.testclasses.abap b/src/#mbtools#cl_string_map.clas.testclasses.abap index 027c27f..85e0817 100644 --- a/src/#mbtools#cl_string_map.clas.testclasses.abap +++ b/src/#mbtools#cl_string_map.clas.testclasses.abap @@ -19,6 +19,7 @@ CLASS ltcl_string_map DEFINITION METHODS keys_values FOR TESTING. METHODS case_insensitive FOR TESTING. METHODS set_clike FOR TESTING. + METHODS setx FOR TESTING. METHODS strict FOR TESTING. METHODS freeze FOR TESTING. @@ -32,9 +33,11 @@ CLASS ltcl_string_map DEFINITION METHODS to_struc FOR TESTING. METHODS to_string FOR TESTING. + METHODS to_entries FOR TESTING. METHODS create_from FOR TESTING. METHODS case_insensitive_create FOR TESTING. + METHODS list_mode FOR TESTING. ENDCLASS. @@ -838,4 +841,166 @@ CLASS ltcl_string_map IMPLEMENTATION. ENDMETHOD. + + METHOD to_entries. + + TYPES: + BEGIN OF lty_str, + a TYPE string, + b TYPE string, + END OF lty_str, + lty_str_t TYPE STANDARD TABLE OF lty_str, + BEGIN OF lty_char, + a TYPE c LENGTH 10, + b TYPE c LENGTH 10, + END OF lty_char, + lty_char_t TYPE STANDARD TABLE OF lty_char, + BEGIN OF lty_bad1, + a TYPE c LENGTH 10, + END OF lty_bad1, + lty_bad1_t TYPE STANDARD TABLE OF lty_bad1, + BEGIN OF lty_bad2, + a TYPE i, + b TYPE i, + END OF lty_bad2, + lty_bad2_t TYPE STANDARD TABLE OF lty_bad2. + + DATA lo_cut TYPE REF TO /mbtools/cl_string_map. + DATA lt_str_act TYPE lty_str_t. + DATA lt_str_exp TYPE lty_str_t. + DATA ls_str LIKE LINE OF lt_str_act. + DATA lt_char_act TYPE lty_char_t. + DATA lt_char_exp TYPE lty_char_t. + DATA ls_char LIKE LINE OF lt_char_act. + DATA lx TYPE REF TO lcx_error. + DATA lt_bad1 TYPE lty_bad1_t. + DATA lt_bad2 TYPE lty_bad2_t. + DATA lt_bad3 TYPE string_table. + lo_cut = /mbtools/cl_string_map=>create( `x=1,y=2` ). + + + ls_str-a = 'x'. + ls_str-b = '1'. + APPEND ls_str TO lt_str_exp. + ls_str-a = 'y'. + ls_str-b = '2'. + APPEND ls_str TO lt_str_exp. + lo_cut->to_entries( CHANGING ct_entries = lt_str_act ). + cl_abap_unit_assert=>assert_equals( + act = lt_str_act + exp = lt_str_exp ). + + ls_char-a = 'x'. + ls_char-b = '1'. + APPEND ls_char TO lt_char_exp. + ls_char-a = 'y'. + ls_char-b = '2'. + APPEND ls_char TO lt_char_exp. + lo_cut->to_entries( CHANGING ct_entries = lt_char_act ). + cl_abap_unit_assert=>assert_equals( + act = lt_char_act + exp = lt_char_exp ). + + + TRY. + lo_cut->to_entries( CHANGING ct_entries = lt_bad1 ). + cl_abap_unit_assert=>fail( ). + CATCH lcx_error INTO lx. + cl_abap_unit_assert=>assert_char_cp( + act = lx->get_text( ) + exp = '*number*' ). + ENDTRY. + + + TRY. + lo_cut->to_entries( CHANGING ct_entries = lt_bad2 ). + cl_abap_unit_assert=>fail( ). + CATCH lcx_error INTO lx. + cl_abap_unit_assert=>assert_char_cp( + act = lx->get_text( ) + exp = '*type*' ). + ENDTRY. + + + TRY. + lo_cut->to_entries( CHANGING ct_entries = lt_bad3 ). + cl_abap_unit_assert=>fail( ). + CATCH lcx_error INTO lx. + cl_abap_unit_assert=>assert_char_cp( + act = lx->get_text( ) + exp = '*table line*' ). + ENDTRY. + + ENDMETHOD. + + METHOD setx. + + DATA lo_cut TYPE REF TO /mbtools/cl_string_map. + + lo_cut = /mbtools/cl_string_map=>create( ). + + lo_cut->setx( 'a:1' ). + lo_cut->setx( |b : 2| ). + lo_cut->setx( ':c' ). + lo_cut->setx( '' ). + + cl_abap_unit_assert=>assert_equals( + exp = 2 + act = lo_cut->size( ) ). + cl_abap_unit_assert=>assert_equals( + exp = lo_cut->get( 'a' ) + act = '1' ). + cl_abap_unit_assert=>assert_equals( + exp = lo_cut->get( 'b' ) + act = '2' ). + + ENDMETHOD. + + METHOD list_mode. + + DATA lo_cut TYPE REF TO /mbtools/cl_string_map. + DATA lt_entries TYPE /mbtools/cl_string_map=>tty_entries. + DATA ls_item LIKE LINE OF lt_entries. + + lo_cut = /mbtools/cl_string_map=>create( ). + lo_cut->setx( 'a:1' ). + lo_cut->setx( 'a:2' ). + + cl_abap_unit_assert=>assert_equals( + exp = 1 + act = lo_cut->size( ) ). + cl_abap_unit_assert=>assert_equals( + exp = lo_cut->get( 'a' ) + act = '2' ). + + lo_cut = /mbtools/cl_string_map=>create( iv_list_mode = abap_true ). + lo_cut->setx( 'a:1' ). + lo_cut->setx( 'a:2' ). + + cl_abap_unit_assert=>assert_equals( + exp = 2 + act = lo_cut->size( ) ). + + + lt_entries = lo_cut->mt_entries. + SORT lt_entries BY k v. + + READ TABLE lt_entries INDEX 1 INTO ls_item. + cl_abap_unit_assert=>assert_equals( + exp = '1' + act = ls_item-v ). + + READ TABLE lt_entries INDEX 2 INTO ls_item. + cl_abap_unit_assert=>assert_equals( + exp = '2' + act = ls_item-v ). + + lo_cut->delete( 'a' ). + cl_abap_unit_assert=>assert_equals( + exp = 0 + act = lo_cut->size( ) ). + + ENDMETHOD. + + ENDCLASS.