mirror of
https://github.com/yabwon/SAS_PACKAGES.git
synced 2026-01-03 21:30:06 +00:00
SAS Packages Framework, version 20221212
SAS Packages Framework, version 20221212
- New type `CASLUDF` for CASL User Defined Functions added to the framework.
- If a package contains IML modules or CASL user defined functions additional utility macros for IML Modules and CASL UDFs are generated when package is loaded.
- Documentation updated.
- Minor bugfix.
This commit is contained in:
@@ -23,7 +23,7 @@
|
||||
default value 1 means "delete tests work" */
|
||||
)/ secure minoperator
|
||||
/*** HELP END ***/
|
||||
des = 'Macro to generate SAS packages, version 20221125. Run %generatePackage() for help info.'
|
||||
des = 'Macro to generate SAS packages, version 20221212. Run %generatePackage() for help info.'
|
||||
;
|
||||
%if (%superq(filesLocation) = ) OR (%qupcase(&filesLocation.) = HELP) %then
|
||||
%do;
|
||||
@@ -38,7 +38,7 @@ des = 'Macro to generate SAS packages, version 20221125. Run %generatePackage()
|
||||
%put ### This is short help information for the `generatePackage` macro #;
|
||||
%put #-------------------------------------------------------------------------------#;
|
||||
%put # #;
|
||||
%put # Macro to generate SAS packages, version `20221125` #;
|
||||
%put # Macro to generate SAS packages, version `20221212` #;
|
||||
%put # #;
|
||||
%put # A SAS package is a zip file containing a group #;
|
||||
%put # of SAS codes (macros, functions, data steps generating #;
|
||||
@@ -545,7 +545,10 @@ data &filesWithCodes.;
|
||||
|
||||
/* ignore unknown types for folders */
|
||||
if fileId AND not (upcase(type) in:
|
||||
('LIBNAME' 'MACRO' /*'MACROS'*/ 'DATA' 'FUNCTION' /*'FUNCTIONS'*/ 'FORMAT' /*'FORMATS'*/ 'IMLMODULE' 'PROTO' 'EXEC' 'CLEAN' 'LAZYDATA' 'TEST'))
|
||||
('LIBNAME' 'MACRO' /*'MACROS'*/ 'DATA'
|
||||
'FUNCTION' /*'FUNCTIONS'*/ 'FORMAT' /*'FORMATS'*/
|
||||
'IMLMODULE' 'PROTO' 'EXEC' 'CLEAN'
|
||||
'LAZYDATA' 'TEST' 'CASLUDF'))
|
||||
then
|
||||
do;
|
||||
put "WARNING: Type " type 'is not yet supported.' /
|
||||
@@ -911,8 +914,11 @@ data _null_;
|
||||
|
||||
put '%include ' " &_PackageFileref_.(packagemetadata.sas) / nosource2; " /; /* <- copied also to loadPackage macro */
|
||||
|
||||
isFunction = 0;
|
||||
isFormat = 0;
|
||||
isFunction = 0;
|
||||
isFormat = 0;
|
||||
isProto = 0;
|
||||
isIMLmodule = 0;
|
||||
isCASLudf = 0;
|
||||
|
||||
%if (%superq(packageRequired) ne )
|
||||
or (%superq(packageReqPackages) ne )
|
||||
@@ -1129,23 +1135,29 @@ data _null_;
|
||||
|
||||
set &filesWithCodes. end = EOF nobs=NOBS;
|
||||
by TYPE notsorted;
|
||||
if (upcase(type) in: ('CLEAN' 'LAZYDATA' 'TEST')) then continue; /* cleaning files are only included in unload.sas */
|
||||
/* lazy data are only loaded on demand
|
||||
%loadPackage(packagename, lazyData=set1 set2 set3)
|
||||
test files are used only during package generation
|
||||
*/
|
||||
if (upcase(type) in: ('CLEAN' 'LAZYDATA' 'TEST' 'CASLUDF'))
|
||||
then continue; /* CASLUDF type will go in the next loop */
|
||||
/* cleaning files are only included in unload.sas */
|
||||
/* lazy data are only loaded on demand
|
||||
%loadPackage(packagename, lazyData=set1 set2 set3)
|
||||
test files are used only during package generation
|
||||
*/
|
||||
/* test for supported types */
|
||||
if not (upcase(type) in:
|
||||
('LIBNAME' 'MACRO' /*'MACROS'*/ 'DATA' 'FUNCTION' /*'FUNCTIONS'*/ 'FORMAT' /*'FORMATS'*/ 'IMLMODULE' 'PROTO' 'EXEC' 'CLEAN' 'LAZYDATA' 'TEST'))
|
||||
('LIBNAME' 'MACRO' /*'MACROS'*/ 'DATA'
|
||||
'FUNCTION' /*'FUNCTIONS'*/ 'FORMAT' /*'FORMATS'*/
|
||||
'IMLMODULE' 'PROTO' 'EXEC' 'CLEAN'
|
||||
'LAZYDATA' 'TEST'))
|
||||
then
|
||||
do;
|
||||
putlog 'WARNING: Type ' type 'is not yet supported.';
|
||||
continue;
|
||||
end;
|
||||
|
||||
isFunction + (upcase(type)=:'FUNCTION');
|
||||
isFormat + (upcase(type)=:'FORMAT');
|
||||
isProto + (upcase(type)=:'PROTO');
|
||||
isFunction + (upcase(type)=:'FUNCTION');
|
||||
isFormat + (upcase(type)=:'FORMAT');
|
||||
isProto + (upcase(type)=:'PROTO');
|
||||
isIMLmodule + (upcase(type)=:'IMLMODULE');
|
||||
|
||||
/* HEADERS for IML, FCMP, and PROTO - start */
|
||||
if 1 = isFunction and upcase(type)=:'FUNCTION' then
|
||||
@@ -1173,7 +1185,8 @@ data _null_;
|
||||
do;
|
||||
/* macro variable for test if cherry picking used IML */
|
||||
put 'data _null_; ';
|
||||
put ' call symputX("cherryPick_IML", 0, "L"); ';
|
||||
put ' call symputX("cherryPick_IML", 0, "L"); ';
|
||||
put ' call symputX("cherryPick_IML_ALL", 0, "L"); ';
|
||||
put 'run; ';
|
||||
/* header, for IML modules */
|
||||
put "proc iml ; ";
|
||||
@@ -1240,7 +1253,8 @@ data _null_;
|
||||
end;
|
||||
if 1 = LAST.type and upcase(type)='IMLMODULE' then /* footer, for IML modules */
|
||||
do;
|
||||
put '%if 0 < &cherryPick_IML. %then %do; ' /
|
||||
put '%if 0 < &cherryPick_IML. %then %do; ' /
|
||||
'%let cherryPick_IML_ALL = %eval(&cherryPick_IML_ALL. + &cherryPick_IML.);' /
|
||||
"reset storage = WORK.&packageName.IML; " / /* set the storage location for modules */
|
||||
"store module = _ALL_; " / /* and store all created modules */
|
||||
'%end; ' /
|
||||
@@ -1268,6 +1282,125 @@ data _null_;
|
||||
|
||||
end; /* loopOverTypes - start */
|
||||
|
||||
/* this is a header for CASLudf macro */
|
||||
put 'data _null_; ';
|
||||
put ' call symputX("cherryPick_CASLUDF", 0, "L"); ';
|
||||
put 'run; ';
|
||||
put 'data _null_;';
|
||||
put 'length CASLUDF $ 32767;';
|
||||
put 'dtCASLudf = datetime();';
|
||||
put 'CASLUDF = ';
|
||||
put ' ''%macro ' "&packageName.CASLudf(' ";
|
||||
put ' !! "list=1,depList=" ';
|
||||
%if %superq(packageReqPackages) ne %then
|
||||
%do;
|
||||
length reqPackage $ 32;
|
||||
do i = 1 to countw(packageReqPackages, ",", "Q");
|
||||
reqPackage = compress(scan(scan(packageReqPackages, i, ",", "Q"), 1, "[{( )}]"),"_","KAD") ;
|
||||
put ' !! " ' reqPackage ' " ';
|
||||
end;
|
||||
%end;
|
||||
put " !! ')/ des = ''CASL User Defined Functions loader for &packageName. package'';'";
|
||||
|
||||
put ' !! '' %if HELP = %superq(list) %then ''' /
|
||||
' !! '' %do; ''' /
|
||||
' !! '' %put ****************************************************************************;''' /
|
||||
' !! '' %put This is help for the `' "&packageName.CASLudf" '` macro;''' /
|
||||
' !! '' %put Parameters (optional) are the following:;''' /
|
||||
|
||||
' !! '' %put - `list` indicates if the list of loaded CASL UDFs should be displayed,;''' /
|
||||
' !! '' %put %str( )when set to the value of `1` (the default) runs `FUNCTIONLIST USER%str(;)`,;''' /
|
||||
' !! '' %put %str( )when set to the value of `HELP` (upcase letters!) displays this help message.;''' /
|
||||
|
||||
' !! '' %put - `depList` [technical] contains the list of dependencies required by the package.;''' /
|
||||
' !! '' %put - %str( )for _this_ macro the default value is: `';
|
||||
%if %superq(packageReqPackages) ne %then
|
||||
%do;
|
||||
do i = 1 to countw(packageReqPackages, ",", "Q");
|
||||
reqPackage = compress(scan(scan(packageReqPackages, i, ",", "Q"), 1, "[{( )}]"),"_","KAD") ;
|
||||
put reqPackage @;
|
||||
end;
|
||||
%end;
|
||||
put '`.;''' /
|
||||
' !! '' %put The macro generated: '' !! put(dtCASLudf, datetime19.-L) !! ";"' /
|
||||
' !! '' %put with the SAS Packages Framework version 20221212.;''' /
|
||||
' !! '' %put ****************************************************************************;''' /
|
||||
' !! '' %GOTO theEndOfTheMacro;''' /
|
||||
' !! '' %end;''' ;
|
||||
|
||||
|
||||
put ' !! '' %if %superq(depList) ne %then ''' /
|
||||
' !! '' %do; ''' /
|
||||
' !! '' %do i = 1 %to %sysfunc(countw(&depList.,%str( ))); ''' /
|
||||
' !! '' %let depListNm = %scan(&depList.,&i.,%str( )); ''' /
|
||||
' !! '' %if %SYSMACEXIST(&depListNm.CASLudf) %then ''' /
|
||||
' !! '' %do; ''' /
|
||||
' !! '' %&depListNm.CASLudf(list=0) ''' /
|
||||
' !! '' %end; ''' /
|
||||
' !! '' %end; ''' /
|
||||
' !! '' %end; ''' ;
|
||||
|
||||
put ' !! '' %local tmp_NOTES;'' ';
|
||||
put ' !! '' %let tmp_NOTES = %sysfunc(getoption(NOTES));'' ';
|
||||
/* the PATH macrovariable will be resolved when the load.sas file is executed */
|
||||
put ' !! " filename ' "&_PackageFileref_." ' &ZIP. ''&path./' "%lowcase(&packageName.)" '.&zip.'';"';
|
||||
|
||||
/* this loop lists includes for CASLUDFs in the macro definition */
|
||||
do until(eof1); /* loopOverTypes1 - start */
|
||||
set &filesWithCodes. end = EOF1;
|
||||
by TYPE notsorted;
|
||||
if not (upcase(type) = 'CASLUDF') then continue; /* only CASLUDF type in this loop */
|
||||
isCASLudf + 1;
|
||||
|
||||
put ' ' /
|
||||
'%if (%str(*)=%superq(cherryPick)) or (' fileshort +(-1) ' in %superq(cherryPick)) %then %do; '; /* Cherry Pick test2 start */
|
||||
put ' %put NOTE- ;';
|
||||
put ' %put NOTE: >> Element of type ' type 'from the file "' file +(-1) '" will be included <<;';
|
||||
/* for CASLUDF we are building code of a macro to be run while loading */
|
||||
put ' !! '' %include' " &_PackageFileref_.(_" folder +(-1) "." file +(-1) ') / nosource2;''';
|
||||
put ' %let cherryPick_CASLUDF = %eval(&cherryPick_CASLUDF. + 1);';
|
||||
put '%end; ' /; /* Cherry Pick test2 end */
|
||||
|
||||
end; /* loopOverTypes1 - start */
|
||||
|
||||
/* this is a footer for CASLudf macro */
|
||||
put ' !! " options nonotes;" ' /
|
||||
" !! ' filename &_PackageFileref_. clear;' " /
|
||||
' !! '' options &tmp_NOTES.;'' ' /
|
||||
' !! '' %if 1 = %superq(list) %then '' ' /
|
||||
' !! '' %do; '' ' /
|
||||
' !! " FUNCTIONLIST USER;" ' /
|
||||
' !! " run;" ' /
|
||||
' !! '' %end; '' ' ;
|
||||
put ' !! ''%theEndOfTheMacro: %mend;''; ' ;
|
||||
|
||||
/* generate macro for CASL user defined functions */
|
||||
if 0 < isCASLudf then
|
||||
do;
|
||||
put '%if 0 < &cherryPick_CASLUDF. %then %do; ';
|
||||
/*put ' put / / CASLUDF / / ; ';*/
|
||||
put " rc = resolve(CASLUDF); ";
|
||||
put ' put "NOTE: Macro named:"; ';
|
||||
put " put @7 '%' '&packageName.CASLudf()'; ";
|
||||
put ' put "NOTE- will be generated. Its purpose";';
|
||||
put ' put "NOTE- is to allow fast load of CASL"; ';
|
||||
put ' put "NOTE- user defined functions into"; ';
|
||||
put ' put "NOTE- the Proc CAS session."; ';
|
||||
put ' put "NOTE-"; ';
|
||||
put ' put "NOTE- Use it the following way:"; ';
|
||||
put " put @7 'Proc CAS;'; ";
|
||||
put " put @7 ' %' '&packageName.CASLudf()'; ";
|
||||
put " put @7 ' <... your code ...>'; ";
|
||||
put " put @7 'quit;'; ";
|
||||
put ' put "NOTE-"; ';
|
||||
put ' put "NOTE-To get help run:"; ';
|
||||
put " put @7 ' %' '&packageName.CASLudf(list=HELP)';";
|
||||
put ' put "NOTE-"; ';
|
||||
put '%end; ';
|
||||
end;
|
||||
put 'run;'/;
|
||||
|
||||
|
||||
|
||||
/* cherry pick clean in cmplib for functions */
|
||||
if isFunction then
|
||||
@@ -1304,7 +1437,7 @@ data _null_;
|
||||
/* list fmtsearch for formats */
|
||||
if isFormat then
|
||||
do;
|
||||
put '%if 0 = &cherryPick_FCMP. %then %do;';
|
||||
put '%if 0 = &cherryPick_FORMAT. %then %do;';
|
||||
put 'options fmtsearch = (%unquote(%sysfunc(tranwrd(' /
|
||||
'%lowcase(%sysfunc(getoption(fmtsearch)))' /
|
||||
',%str(' "work.%lowcase(&packageName.)format" '), %str() ))));';
|
||||
@@ -1316,6 +1449,116 @@ data _null_;
|
||||
put '%put NOTE:[FMTSEARCH] %sysfunc(getoption(fmtsearch));'/;
|
||||
end;
|
||||
|
||||
/* create a macro loader for IML modules with dependencies */
|
||||
if isIMLmodule then
|
||||
do;
|
||||
put '%if (%str(*)=%superq(cherryPick)) or 0 < &cherryPick_IML_ALL. %then %do;';
|
||||
|
||||
/* this "text wrapper" was added to get datetime generated when macro is compiled */
|
||||
put "data _null_; dtIML=datetime(); IML='"; /* wrapper start */
|
||||
|
||||
put '%macro ' " &packageName.IML(list=1,err=ERROR,resetIMLstorage=1,depList=" ;
|
||||
%if %superq(packageReqPackages) ne %then
|
||||
%do;
|
||||
length reqPackage $ 32;
|
||||
do i = 1 to countw(packageReqPackages, ",", "Q");
|
||||
reqPackage = compress(scan(scan(packageReqPackages, i, ",", "Q"), 1, "[{( )}]"),"_","KAD") ;
|
||||
put " " reqPackage @;
|
||||
end;
|
||||
put ;
|
||||
%end;
|
||||
put ")/ des = ""IML Modules loader for &packageName. package""; " /
|
||||
' %if HELP = %superq(list) %then ' /
|
||||
' %do; ' /
|
||||
' %put ****************************************************************************; ' /
|
||||
' %put This is help for the `' "&packageName.IML" '` macro; ' /
|
||||
' %put Parameters (optional) are the following:; ' /
|
||||
|
||||
' %put - `list` indicates if the list of loaded moduls should be displayed,; ' /
|
||||
' %put %str( )when set to the value of `1` (the default) runs `SHOW MODULES%str(;)`,; ' /
|
||||
' %put %str( )when set to the value of `HELP` (upcase letters!) displays this help message.;' /
|
||||
|
||||
' %put - `resetIMLstorage` indicates if to reset default moduls storage,; ' /
|
||||
' %put %str( )when set to `1` (the default) runs `RESET STORAGE = WORK.IMLSTOR%str(;)`.; ' /
|
||||
|
||||
' %put - `err` [technical] indicates message type in case of missing modules catalog,; ' /
|
||||
' %put %str( )when set to the value of `ERROR` (the default) prints Error message.; ' /
|
||||
|
||||
' %put - `depList` [technical] contains the list of dependencies required by the package.; ' /
|
||||
' %put - %str( )for _this_ macro the default value is: `';
|
||||
%if %superq(packageReqPackages) ne %then
|
||||
%do;
|
||||
do i = 1 to countw(packageReqPackages, ",", "Q");
|
||||
reqPackage = compress(scan(scan(packageReqPackages, i, ",", "Q"), 1, "[{( )}]"),"_","KAD") ;
|
||||
put reqPackage @;
|
||||
end;
|
||||
%end;
|
||||
put '`.;' /
|
||||
' %put The macro generated: ''' " !! put(dtIML, datetime19.-L) !! " '''; ' /
|
||||
' %put with the SAS Packages Framework version 20221212.; ' /
|
||||
' %put ****************************************************************************; ' /
|
||||
' %GOTO theEndOfTheMacro; ' /
|
||||
' %end; ' /
|
||||
|
||||
' %local localSYSmacroName localPackageName i depListNm; ' /
|
||||
' %let localSYSmacroName = &sysmacroname.; ' /
|
||||
' %let localSYSmacroName = %LOWCASE(&localSYSmacroName.); ' /
|
||||
' %let localPackageName = %substr(&localSYSmacroName.,1,%eval(%length(&localSYSmacroName.)-3));' /
|
||||
' ' /
|
||||
' %if %superq(depList) ne %then ' /
|
||||
' %do; ' /
|
||||
' %do i = 1 %to %sysfunc(countw(&depList.,%str( ))); ' /
|
||||
' %let depListNm = %scan(&depList.,&i.,%str( )); ' /
|
||||
' %if %SYSMACEXIST(&depListNm.IML) %then ' /
|
||||
' %do; ' /
|
||||
' %&depListNm.IML(list=0,err=&err.,resetIMLstorage=0) ' /
|
||||
' %end; ' /
|
||||
' %end; ' /
|
||||
' %end; ' /
|
||||
' %if %sysfunc(CEXIST(WORK.&localSYSmacroName.)) %then ' /
|
||||
' %do; ' /
|
||||
' %put NOTE: Loading IML Modules from package &localPackageName.; ' /
|
||||
' RESET STORAGE = WORK.&localSYSmacroName.; ' /
|
||||
' LOAD MODULE = _all_; ' /
|
||||
' %end; ' /
|
||||
' %else ' /
|
||||
' %do; ' /
|
||||
' %put %superq(err): IML Modules not provided; ' /
|
||||
' %let list = 0; ' /
|
||||
' %end; ' /
|
||||
' %if 1 = %superq(list) %then ' /
|
||||
' %do; ' /
|
||||
' SHOW MODULES; ' /
|
||||
' %end; ' /
|
||||
' %if 1 = %superq(resetIMLstorage) %then ' /
|
||||
' %do; ' /
|
||||
' RESET STORAGE = WORK.IMLSTOR; ' /
|
||||
' %end; ' /
|
||||
'%theEndOfTheMacro: %mend; ' ;
|
||||
|
||||
put "'; rc = resolve(IML); run;"; /* wrapper end */
|
||||
|
||||
put '%put NOTE: Macro named:; ';
|
||||
put '%put %nrstr( %%)' "&packageName." 'IML(); ';
|
||||
put '%put NOTE- will be generated. Its purpose; ';
|
||||
put '%put NOTE- is to allow fast load of IML; ';
|
||||
put '%put NOTE- user defined modules into; ';
|
||||
put '%put NOTE- the Proc IML session.; ';
|
||||
put '%put NOTE-; ';
|
||||
put '%put NOTE- Use it the following way:; ';
|
||||
put '%put %nrstr( )Proc IML%str(;); ';
|
||||
put '%put %nrstr( %%)' "&packageName." 'IML(); ';
|
||||
put '%put %nrstr( )<... your code ...>; ';
|
||||
put '%put %nrstr( )quit%str(;); ';
|
||||
put '%put NOTE- ; ';
|
||||
put '%put NOTE- To get help info run:; ';
|
||||
put '%put %nrstr( %%)' "&packageName." 'IML(list=HELP);';
|
||||
put '%put NOTE-; ';
|
||||
|
||||
put '%end;';
|
||||
end;
|
||||
|
||||
|
||||
/* update SYSloadedPackages global macrovariable */
|
||||
put '%if (%str(*)=%superq(cherryPick)) %then %do; '; /* Cherry Pick test3 start */
|
||||
put ' data _null_ ; ';
|
||||
@@ -1463,15 +1706,17 @@ data _null_;
|
||||
put ' from dictionary.catalogs';
|
||||
put ' where ';
|
||||
put ' (';
|
||||
put ' objname in ("*"' /;
|
||||
put ' objname in ("*"' ;
|
||||
put " ,%UPCASE('&packageName.IML')" ;
|
||||
put " ,%UPCASE('&packageName.CASLUDF')" /;
|
||||
/* list of macros */
|
||||
EOF = 0;
|
||||
do until(EOF);
|
||||
set &filesWithCodes. end = EOF nobs = NOBS;
|
||||
if not (upcase(type)=:'MACRO') then continue;
|
||||
put '%put NOTE- Element of type ' type 'generated from the file "' file +(-1) '" will be deleted;';
|
||||
put '%put NOTE- ;';
|
||||
put ',"' fileshort upcase32. '"' /;
|
||||
put ' %put NOTE- Element of type ' type 'generated from the file "' file +(-1) '" will be deleted;';
|
||||
put ' %put NOTE- ;';
|
||||
put ' ,"' fileshort upcase32. '"' /;
|
||||
end;
|
||||
/**/
|
||||
put ' )';
|
||||
@@ -1487,9 +1732,9 @@ data _null_;
|
||||
do until(EOF);
|
||||
set &filesWithCodes. end = EOF;
|
||||
if not (upcase(type)=:'FORMAT') then continue;
|
||||
put '%put NOTE- Element of type ' type 'generated from the file "' file +(-1) '" will be deleted;';
|
||||
put '%put NOTE- ;';
|
||||
put ',"' fileshort upcase32. '"' /;
|
||||
put ' %put NOTE- Element of type ' type 'generated from the file "' file +(-1) '" will be deleted;';
|
||||
put ' %put NOTE- ;';
|
||||
put ' ,"' fileshort upcase32. '"' /;
|
||||
isFormat + 1;
|
||||
end;
|
||||
put ' )';
|
||||
@@ -1858,7 +2103,7 @@ data _null_;
|
||||
put ' end ; ';
|
||||
%end;
|
||||
|
||||
put 'put "***"; put "* SAS package generated by generatePackage, version 20221125 *"; put "***";';
|
||||
put 'put "***"; put "* SAS package generated by generatePackage, version 20221212 *"; put "***";';
|
||||
|
||||
put 'run; ' /;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user