Thursday, April 5, 2012

Simple Utility Macros and SAS Server Pages

So much for plans . . .

Today's post was supposed to be a mail-merge example from Chapter 4 (included in the preview copy available at SAS Global Forum 2012) of SAS® Server Pages: Generating Dynamic Content.

In the book that example was not Web-based. I started with a simple example: generating a letter for a specified observation, and built on it. I had planned to something similar here but packaged for the Web - using it to illustrate some important features of PROC STREAM. My original plan was to just hard code the observation number - but I decided that was not a good idea and so I decided to:
  1. Allow the observation number from the SASHELP.CLASS data set for which the letter is to be generated to be passed in as a parameter.
  2. Have a default value used if no value is specified.
  3. That then led to needing to confirm that the value was an integer between 1 and the number of observations in the data set (19 in this case).
  4. Which then led to a simple utility macro that does that validation and assigns a default value.
Just as with any SAS application, I've discovered as I've used SAS Server Pages on numerous projects that its a good idea to create simple/short utility macros that perform a specific function. So here is the code for my macro that I can use in a SAS Server Page to validate the observation number.

%macro verifyInteger
  (value= /* the value to be verified as an integer */
  ,default=1 /* default if null */
  ,min= /* if specified, the minimum allowed value */
  ,max= /* if specified, the maximum allowed value */

%let value =
%if %sysfunc(notdigit(%superQ(value)))
    %then %let value=1;
%if %length(&min) gt 0 and &value lt &min
    %then %let value = &min;
%if %length(&max) gt 0 and &value gt &max
    %then %let value = &max;

&value /* return the value to the input stack */

%mend verifyInteger;
In my code, I can just add the following statement:
%let letterObs = %verifyInteger(value=&letterObs
And before ending this post, just a few comments about this macro and how I am using it:
  1. Note the use of the NOTDIGIT function to validate that the value contains only integers.
  2. I've hard-coded the value of the max parameter on the call because I know the data set only has 19 observations. I could have used the SCL data access functions to get the value if it was unknown.
  3. While it is true that I could define a parameter for a stored process that forces the value to be an integer, since I want these to work for the SAS/IntrNet Application Dispatcher as well, that is not an option. In addition, since I will typically want to use my generic sasServerPage and runMacro stored processes (also runnable as SAS/IntrNet Application Dispatcher programs), having the constraints on the parameter value is not really an option.
And I'll get back on track with my next blog posting - the SAS Server Page mail-merge example. The revised schedule can be seen using the links from my last blog post: