Hi,
I am trying to create a utility macro (check_params as shown below) which is when invoked from a macro - it should check all the parameters defined in that macro's definition.
%macro abc(aa=, bb=, cc=);
/* Utility macro invoked here */
%check_params;
/* Actual code starts from here */
%mend abc;
%abc(aa=mm,bb=nn);
When I explore, I see PARMBUFF option with SYSPBUFF system automatic macro variable as a way out. But, this will only give me the parameters which are passed during macro invocation. E.g. In the above call SYSPBUFF = (aa=mm,bb=nn). This is not the full list of parameters defined in the macro definition, I would need all params i.e. (aa=mm, bb=nn, cc=)
Is there any way I get this (aa=mm, bb=nn, cc=)into a macro variable then I can play around and have checks?
Thanks in advance,
Satya
Thanks Tom. Agree, that suggestion only works for the limited use case from the OP (get a list of the parameters), and could check they are non-null. Your suggestions would allow for a more complete parameter validation framework.
I understand you're playing around a little, but I am not sure, if this would be a proper approach. If your macro list is a tupel, this is, if you always have aa, bb, and cc combined, you could simply check, for example, if cc has a value at all with "%If (&cc^=) %Then ..", etc.
%macro abc(aa=, bb=, cc=);
%If (&aa.^=) & (&bb.^=) & (&cc.^=) %Then %Do;
*execute something;
%End;
%Else %Do;
%Put **something is missing**;
%End;
%mend abc;
%abc(aa=mm,bb=nn)
However, if your macro parameter list is dynamic, you might want to do the checking before you split your list up into individual elements.
You could. There are plently of posts on parameter lists. In most of them you will find me advising against it. The code gets large and unreadble very quickly having to maks/unmask, reference other references etc.
IMO if you are writing macros/system for other people you will first want to read up on Software Development Life Cycle. Sit down and plan what it is you want to achieve, how things fit together, what the standards will be, how things will be tested. Once you have all the documentation - Functional Design Specifications, Testing Document etc. then start looking at coding. In the companies I have worked for the first thing I notice when I get there is at least one folder full up with undocumented, untested, vague bits of code put into macros over 10 years or more.
In response to your point, there are various methods, yes parambuff is one of them. However me personally, I would put paramters into a dataset. The reason is that datasets are very easy to work with, do checking on etc. Its also easy to pass parameter tables through:
%macro Do_Something (Parameter_Table=work.abc);
%Check_Parameter_Table (Parameter_Table=&Parameter_Table.);
...
You can set up your dataset any way you like with as much information as you need, and example:
PARAMETER VALUE CHECK
FILE c:\temp\temp.xlsx EXISTENCE
OUT_LOCATION c:\temp EXISTENCE
...
Then your check is simply:
data _null_;
set parameter_table;
call execute('%'||strip(check)||'("'||strip(value)||'");');
run;
And this will generate the following two macro calls:
%EXISTENCE("c:\temp\temp.xlsx");
%EXISTENCE("c:\temp");
That said, that is just an example and heavily depends on what you want to do and where. For simple macros, its quite simple to have your checks up front and then then jump to the end if fails:
%macro Test (file=);
%if %sysfunc(fileexist(&file.))=0 %then %do;
%put Macro Test failed to find &file. and has stopped operation;
%goto exit;
%end;
/* Process file */
...
%put Macro Test passed execution;
%exit:
%mend Test;
This looks like a repeat of your earlier post:
https://communities.sas.com/thread/75519
I posted one approach there. I think what you're looking for is reasonable. In my check macro I usually pass the list of required parameters explicitly, because I sometimes have optional parameters with default null value. So my macros end up looking like:
%macro abc(p1=, p2=, p3=);
%if %MissingRequiredParameter(p1 p2) %then %goto mexit;
%mexit:
%mend abc;
And %MissingRequiredParameter is the helper macro that checks them all for null, and %PUTs and ERROR: message to the log etc.
You cannot query anything at runtime to find the list of parameters defined for the macro you are currently running.
I would suggest one of two approaches.
1) Have a general utility for checking parameters and enforce coding standards that macros call this utility. If you modify the macro to have more parameters you modify the code of the macro to test them.
%macro mymac(parm1,parm2);
%checkparm(parm1,....)
%checparm(parm2,.....)
....
%mend mymac;
2) Maintain a database of parameter checks using the macro name as a key. Again you will need to enforce by your coding standards that the data in the database matches the macro definition.
%macro mymac(parm1,parm2);
%let _macro = &sysmacroname ;
%checkparms(&_macro);
...
%mend ;
data parameters ;
length macroname $32 parameter $32 test $2000 ;
infile cards dsd truncover ;
input macroname parameter test ;
cards;
mymac parm1 REQUIRED
mymac parm2 OPTIONAL
;;;;
did you see my suggestion in the other thread? Would be interested in your thoughts.
While you can't query at run time to get the parameters in the current macro, you could query to get the list of local macro variables in the current macro. And if you do that early enough (before creating any local macro variables other than the parameters), in effect you get the parameters.
Pasting that response below, since this thread is now more-alive:
****
That helps a little, but to properly check you would still need to have other metadata. Is the parameter required? What are the valid list of values?
Plus many macros will also need to validate options that are passed in via macro variables instead of parameters.
Thanks Tom. Agree, that suggestion only works for the limited use case from the OP (get a list of the parameters), and could check they are non-null. Your suggestions would allow for a more complete parameter validation framework.
Dear All,
Thank you very much.. I am overwhelmed with the responses.. this is the first time I posted something on board here.. Great to have such supportive programmers around. Thanks a lot!
Yes, with %sysmexecname and %sysmexecdepth we can only get the list of parameters and check for non-null. However, to have further checks like if it is required/ optional and is restricted to values. So, I would have an excel sheet located centrally which has all these details for each of the macros and macro parameters and I use this as a kind of metadata. Thanks a lot.. I appreciate everyones participation in the discussion and look forward to contribute more to the forum.
Nice day all,
Satya
Seriously, for yours and everyones sanity, don't use Excel! Worse case scenario, save as CSV. You can still use Excel as input, but the output is plain text file you can write a datastep read. Even then, get a database, or metadata management software.
I am reminded of the famous quote from an engineer.
"Sure I can idiot-proof this design.
How big of an idiot do you want me to proof it against?"
My first response is to suggest that all your macro parameters have default values.
%macro Demo(data=sashelp.class,var=age);
The macro runs with no parameters
and the user is already aware of the expected values,
e.g. that data is a two-level name.
My next suggestion is to examine the assumption(s) that an unassigned mvar is indeed worthy of concern.
Here is a sas community org wiki page on assertions.
This page has a number of reality checks for existence of various objects, data, var, catalog, etc..
http://www.sascommunity.org/wiki/Conditionally_Executing_Global_Statements
My solution is to write my macros to do nothing gracefully.
Ron Fehd testing-aware programs maven
Writing Testing Aware Programs - sasCommunity
... and, of course, being an introvert, I thought of a couple more comments to add * Here is a macro with the code for checking existence of various objects. http://www.sascommunity.org/wiki/Macro_Exist * from a design perspective, what you are doing by adding the parm-check macro to any other macro is changing from a subroutine which calls no other macros to complete its task to a routine which raises the level of complexity of your test suites. Message was edited by: Ronald Fehd, Friday morning May 1.
Registration is now open for SAS Innovate 2025 , our biggest and most exciting global event of the year! Join us in Orlando, FL, May 6-9.
Sign up by Dec. 31 to get the 2024 rate of just $495.
Register now!
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.
Ready to level-up your skills? Choose your own adventure.