From 724cd72876e4e8a78aca0d1b02d59476afe77c05 Mon Sep 17 00:00:00 2001 From: munja Date: Wed, 15 Dec 2021 21:05:12 +0000 Subject: [PATCH] feat: adding mf_getfmtlist() and mf_getfmtname() macros and associated tests. Also added &sasjswork as a global macro variable in mp_init(). --- base/mf_getfmtlist.sas | 61 ++++++++++++++++++++++ base/mf_getfmtname.sas | 44 ++++++++++++++++ base/mp_init.sas | 12 +++-- tests/crossplatform/mf_getfmtlist.test.sas | 33 ++++++++++++ tests/crossplatform/mf_getfmtname.test.sas | 33 ++++++++++++ 5 files changed, 178 insertions(+), 5 deletions(-) create mode 100644 base/mf_getfmtlist.sas create mode 100644 base/mf_getfmtname.sas create mode 100644 tests/crossplatform/mf_getfmtlist.test.sas create mode 100644 tests/crossplatform/mf_getfmtname.test.sas diff --git a/base/mf_getfmtlist.sas b/base/mf_getfmtlist.sas new file mode 100644 index 0000000..1aac14b --- /dev/null +++ b/base/mf_getfmtlist.sas @@ -0,0 +1,61 @@ +/** + @file + @brief Returns a distinct list of formats from a table + @details Reads the dataset header and returns a distinct list of formats + applied. + + %put NOTE- %mf_getfmtlist(sashelp.prdsale); + %put NOTE- %mf_getfmtlist(sashelp.shoes); + %put NOTE- %mf_getfmtlist(sashelp.demographics); + + returns: + + > DOLLAR $CHAR W MONNAME + > $CHAR BEST DOLLAR + > BEST Z $CHAR COMMA PERCENTN + + + @param [in] libds Two part library.dataset reference. + +

SAS Macros

+ @li mf_getfmtname.sas + + @version 9.2 + @author Allan Bowe + +**/ + +%macro mf_getfmtlist(libds +)/*/STORE SOURCE*/; +/* declare local vars */ +%local out dsid nvars x rc fmt; + +/* open dataset in macro */ +%let dsid=%sysfunc(open(&libds)); + +/* continue if dataset exists */ +%if &dsid %then %do; + /* loop each variable in the dataset */ + %let nvars=%sysfunc(attrn(&dsid,NVARS)); + %do x=1 %to &nvars; + /* grab format and check it exists */ + %let fmt=%sysfunc(varfmt(&dsid,&x)); + %if %quote(&fmt) ne %quote() %then %let fmt=%mf_getfmtname(&fmt); + %else %do; + /* assign default format depending on variable type */ + %if %sysfunc(vartype(&dsid, &x))=C %then %let fmt=$CHAR; + %else %let fmt=BEST; + %end; + /* concatenate unique list of formats */ + %if %sysfunc(indexw(&out,&fmt,%str( )))=0 %then %let out=&out &fmt; + %end; + %let rc=%sysfunc(close(&dsid)); +%end; +%else %do; + %put &sysmacroname: Unable to open &libds (rc=&dsid); + %put &sysmacroname: SYSMSG= %sysfunc(sysmsg()); + %let rc=%sysfunc(close(&dsid)); +%end; +/* send them out without spaces or quote markers */ +%do;%unquote(&out)%end; +%mend mf_getfmtlist; \ No newline at end of file diff --git a/base/mf_getfmtname.sas b/base/mf_getfmtname.sas new file mode 100644 index 0000000..8ad3761 --- /dev/null +++ b/base/mf_getfmtname.sas @@ -0,0 +1,44 @@ +/** + @file + @brief Extracts a format name from a fully defined format + @details Converts formats in like $thi3. and th13.2 $THI and TH. + Usage: + + %put %mf_getfmtname(8.); + %put %mf_getfmtname($4.); + %put %mf_getfmtname(comma14.10); + + Returns: + + > W + > $CHAR + > COMMA + + Note that system defaults are inferred from the values provided. + + @param [in] fmt The fully defined format. If left blank, nothing is returned. + + @returns The name (without width or decimal) of the format. + + @version 9.2 + @author Allan Bowe + +**/ + +%macro mf_getfmtname(fmt +)/*/STORE SOURCE*/ /minoperator mindelimiter=' '; + +%local out dsid nvars x rc fmt; + +/* extract actual format name from the format definition */ +%let fmt=%scan(&fmt,1,.); +%do %while(%substr(&fmt,%length(&fmt),1) in 1 2 3 4 5 6 7 8 9 0); + %if %length(&fmt)=1 %then %let fmt=W; + %else %let fmt=%substr(&fmt,1,%length(&fmt)-1); +%end; + +%if &fmt=$ %then %let fmt=$CHAR; + +/* send them out without spaces or quote markers */ +%do;%unquote(%upcase(&fmt))%end; +%mend mf_getfmtname; \ No newline at end of file diff --git a/base/mp_init.sas b/base/mp_init.sas index 25471c3..ab51148 100644 --- a/base/mp_init.sas +++ b/base/mp_init.sas @@ -34,15 +34,17 @@ )/*/STORE SOURCE*/; %global - &prefix._INIT_NUM /* initialisation time as numeric */ - &prefix._INIT_DTTM /* initialisation time in E8601DT26.6 format */ + &prefix._INIT_NUM /* initialisation time as numeric */ + &prefix._INIT_DTTM /* initialisation time in E8601DT26.6 format */ + &prefix.WORK /* avoid typing %sysfunc(pathname(work)) every time */ ; %if %eval(&&&prefix._INIT_NUM>0) %then %return; /* only run once */ data _null_; dttm=datetime(); - call symputx("&prefix._init_num",dttm); - call symputx("&prefix._init_dttm",put(dttm,E8601DT26.6)); + call symputx("&prefix._init_num",dttm,'g'); + call symputx("&prefix._init_dttm",put(dttm,E8601DT26.6),'g'); + call symputx("&prefix.work",pathname('WORK'),'g'); run; options @@ -56,7 +58,7 @@ noquotelenmax /* avoid warnings for long strings */ noreplace /* avoid overwriting permanent datasets */ ps=max /* reduce log size slightly */ - ls=max /* reduce log a bit more, + avoid word truncation */ + ls=max /* reduce log even more and avoid word truncation */ validmemname=COMPATIBLE /* avoid special characters etc in table names */ validvarname=V7 /* avoid special characters etc in variable names */ varinitchk=%str(ERR)OR /* avoid data mistakes from variable name typos */ diff --git a/tests/crossplatform/mf_getfmtlist.test.sas b/tests/crossplatform/mf_getfmtlist.test.sas new file mode 100644 index 0000000..d0b19e8 --- /dev/null +++ b/tests/crossplatform/mf_getfmtlist.test.sas @@ -0,0 +1,33 @@ +/** + @file + @brief Testing mf_getfmtlist macro + +

SAS Macros

+ @li mf_getfmtlist.sas + @li mp_assert.sas + +**/ + +%mp_assert( + iftrue=( + "%mf_getfmtlist(sashelp.prdsale)"="DOLLAR $CHAR W MONNAME" + ), + desc=Checking basic numeric, + outds=work.test_results +) + +%mp_assert( + iftrue=( + "%mf_getfmtlist(sashelp.shoes)"="$CHAR BEST DOLLAR" + ), + desc=Checking basic char, + outds=work.test_results +) + +%mp_assert( + iftrue=( + "%mf_getfmtlist(sashelp.demographics)"="BEST Z $CHAR COMMA PERCENTN" + ), + desc=Checking longer numeric, + outds=work.test_results +) \ No newline at end of file diff --git a/tests/crossplatform/mf_getfmtname.test.sas b/tests/crossplatform/mf_getfmtname.test.sas new file mode 100644 index 0000000..da37b05 --- /dev/null +++ b/tests/crossplatform/mf_getfmtname.test.sas @@ -0,0 +1,33 @@ +/** + @file + @brief Testing mf_getfmtname macro + +

SAS Macros

+ @li mf_getfmtname.sas + @li mp_assert.sas + +**/ + +%mp_assert( + iftrue=( + "%mf_getfmtname(8.)"="W" + ), + desc=Checking basic numeric, + outds=work.test_results +) + +%mp_assert( + iftrue=( + "%mf_getfmtname($4.)"="$CHAR" + ), + desc=Checking basic char, + outds=work.test_results +) + +%mp_assert( + iftrue=( + "%mf_getfmtname(comma14.10)"="COMMA" + ), + desc=Checking longer numeric, + outds=work.test_results +) \ No newline at end of file