Macros to Manage your Macros? - Lex JansenMacros to Manage Your Macros?, continued 3 To better...

12
Macros to Manage your Macros? Garrett Weaver, University of Southern California, Los Angeles, CA ABSTRACT SAS ® currently offers several methods for users to store and retrieve user-generated macros. The stored macro compiled facility is one such method that allows users to store a macro, along with the source code, to a location of their choice. To more effectively utilize the stored compiled macro facility, we developed a solution that enables a user to upload, delete, and search for macros generated by multiple users in a common directory. Along with presentation of this solution, we intend to highlight a number of coding techniques with uses beyond this particular example. Techniques include user management, automatic creation and deletion of files, regular expressions, use of PROC REPORT, and a number macro development techniques. Through the implementation of these macros, an organization can increase collaboration and code reuse without ever having to leave the SAS environment. INTRODUCTION For the individual user, SAS® provides three primary methods to permanently store user created macros. The first and easiest method is to save your macro in its own program file and then to use the %INCLUDE statement in any other program that requires use of the macro. The %INCLUDE statement only requires that you provide the physical location of the program file that contains the macro as follows: %INCLUDE 'C:/...../MyMacro.sas'; The macro stored in the program will then be stored in an external .txt file that is then incorporated into your program at the position of the %INCLUDE statement. Another method is the Autocall Library, which stores the source code for a macro to a specific directory or SAS catalog for access at a later time. The Autocall method requires that the user specify a file where the macros will be stored using the SASAUTOS system option, and to set the system option MAUTOSOURCE to ON when they want SAS to search the assigned Autocall Library for saved macros. The last method, the Stored Compiled Macro Facility, will be the focus of our discussion for the remainder of the paper and is the technique that allows for the development of our macros. Similar to the Autocall Library, the Stored Compiled Macro Facility will compile and the store the source code for user compiled macros to a chosen SASMACR Catalog. A user simply needs to enable this macro facility, provide the location where the macros will be stored, and include a couple of additional options in their macro definition as shown below: *enable stored compiled macro facility, set location of stored macros to the location of the macro variable &libn; %LET libn = C:/……………/macro_folder_location/; OPTIONS MSTORED SASMSTORE=&libn; *store the macro, %test, to &libn, store the macro and the source code; %MACRO test() / STORE SOURCE DES="Testing"; %put Testing; %MEND test; The option STORE tells SAS to permanently store the macro %test() to the SASMACR catalog location specified by &libn. SOURCE specifies that the source code for the macro should also be saved permanently as well. To utilize the stored macros at a later time, a user simply needs to reference the location of the SASMACR catalog by using the system option, MSTORED SASMSTORE=, again. Regardless of choice, one of the three methods will most likely meet the needs of an individual SAS user for storing their macros. However, in an environment that requires storage of macros from multiple users across a group or organization, the methods available may not be sufficient. A number of issues may be encountered that include overwriting macros of the same name across users, organization of macros in the shared catalog, and the ability to efficiently share macros between users. Thus, we have developed the following four macros that utilize the Stored Compiled Macro Facility to enable effortless storage of macros across multiple users to a common and searchable directory. The following paper will provide an in depth discussion how each macro works and how they can be utilized by a user after being implemented.

Transcript of Macros to Manage your Macros? - Lex JansenMacros to Manage Your Macros?, continued 3 To better...

Page 1: Macros to Manage your Macros? - Lex JansenMacros to Manage Your Macros?, continued 3 To better understand, let’s assume that there are no users in the directory. When the macro executes,

Macros to Manage your Macros? Garrett Weaver, University of Southern California, Los Angeles, CA

ABSTRACT

SAS® currently offers several methods for users to store and retrieve user-generated macros. The stored macro

compiled facility is one such method that allows users to store a macro, along with the source code, to a location of their choice. To more effectively utilize the stored compiled macro facility, we developed a solution that enables a user to upload, delete, and search for macros generated by multiple users in a common directory. Along with presentation of this solution, we intend to highlight a number of coding techniques with uses beyond this particular example. Techniques include user management, automatic creation and deletion of files, regular expressions, use of PROC REPORT, and a number macro development techniques. Through the implementation of these macros, an organization can increase collaboration and code reuse without ever having to leave the SAS environment.

INTRODUCTION

For the individual user, SAS® provides three primary methods to permanently store user created macros. The first

and easiest method is to save your macro in its own program file and then to use the %INCLUDE statement in any

other program that requires use of the macro. The %INCLUDE statement only requires that you provide the physical

location of the program file that contains the macro as follows:

%INCLUDE 'C:/...../MyMacro.sas';

The macro stored in the program will then be stored in an external .txt file that is then incorporated into your program

at the position of the %INCLUDE statement.

Another method is the Autocall Library, which stores the source code for a macro to a specific directory or SAS catalog for access at a later time. The Autocall method requires that the user specify a file where the macros will be

stored using the SASAUTOS system option, and to set the system option MAUTOSOURCE to ON when they want

SAS to search the assigned Autocall Library for saved macros.

The last method, the Stored Compiled Macro Facility, will be the focus of our discussion for the remainder of the paper and is the technique that allows for the development of our macros. Similar to the Autocall Library, the Stored Compiled Macro Facility will compile and the store the source code for user compiled macros to a chosen SASMACR Catalog. A user simply needs to enable this macro facility, provide the location where the macros will be stored, and include a couple of additional options in their macro definition as shown below:

*enable stored compiled macro facility, set location of stored macros to the

location of the macro variable &libn;

%LET libn = C:/……………/macro_folder_location/;

OPTIONS MSTORED SASMSTORE=&libn;

*store the macro, %test, to &libn, store the macro and the source code;

%MACRO test() / STORE SOURCE DES="Testing";

%put Testing;

%MEND test;

The option STORE tells SAS to permanently store the macro %test() to the SASMACR catalog location specified

by &libn. SOURCE specifies that the source code for the macro should also be saved permanently as well. To utilize

the stored macros at a later time, a user simply needs to reference the location of the SASMACR catalog by using the

system option, MSTORED SASMSTORE=, again.

Regardless of choice, one of the three methods will most likely meet the needs of an individual SAS user for storing their macros. However, in an environment that requires storage of macros from multiple users across a group or organization, the methods available may not be sufficient. A number of issues may be encountered that include overwriting macros of the same name across users, organization of macros in the shared catalog, and the ability to efficiently share macros between users. Thus, we have developed the following four macros that utilize the Stored Compiled Macro Facility to enable effortless storage of macros across multiple users to a common and searchable directory. The following paper will provide an in depth discussion how each macro works and how they can be utilized by a user after being implemented.

Page 2: Macros to Manage your Macros? - Lex JansenMacros to Manage Your Macros?, continued 3 To better understand, let’s assume that there are no users in the directory. When the macro executes,

Macros to Manage Your Macros?, continued

2

Figure 1. User Directory Structure

MACRO #1: USER LOGIN AND MACRO DIRECTORY CREATION - checkUser()

In order for users to start sharing their macros with one another, we designed a simple user directory (Figure 1). Within a parent folder, called ‘Macros’, are two permanent SAS datasets that contain data on users (users.profiles), metadata for generated macros across all users (meta.metadata), and a subfolder called ‘Users’. Within the ‘Users’ folder are additional folders, one for each user, that hold their SAS macro catalog and the corresponding source code, saved as .txt files, for each of their saved macros. To start uploading and searching for macros, both new and current users simply need to use the %INCLUDE statement to call the SAS program user_macros.sas, which holds all

four macros reviewed in this paper. The expectation is that the common directory and the SAS program, user_macros.sas, will be placed on a server that is accessible to the entire user community.

Macros

User 1

User.Profiles . Meta.metadata

User 2 User 3

Users Metadata

To determine whether the user is in the directory already we always run the %checkUser() macro first (this macro

automatically runs when the %INCLUDE for user_macros.sas is executed). Within this macro, we take advantage of

the system macro variable &SYSUSERID, which returns the user ID associated with the SAS installation. As an example, if I were to write and execute the following on my PC, the SAS log will show GarrettWeaver:

%PUT &SYSUSERID; *GarrettWeaver;

We use &SYSUSERID as both the user name in the user profile dataset (users.profile) and to identify the existence of a user in the directory. After assigning the location of the ‘Users’ folder and &SYSUSERID to the local macro variables &loc and &uname using the %LOCAL command, we check for the existence of the user by using the FILEEXIST() function. FILEEXIST() accepts a file name as a string and will return one if the file exists and zero if it does not. If the user folder is found, we assign the library reference name associated with that user from the (users.profiles) dataset to a macro variable called &libn. The macro variable &libn is then used to assign the location of their folder in the directory through a LIBNAME statement. Lastly, we activate the stored compiled macro facility and assign to the same folder location by using the &libn macro variable as shown below:

OPTIONS MSTORED SASMSTORE=&libn;

Page 3: Macros to Manage your Macros? - Lex JansenMacros to Manage Your Macros?, continued 3 To better understand, let’s assume that there are no users in the directory. When the macro executes,

Macros to Manage Your Macros?, continued

3

To better understand, let’s assume that there are no users in the directory. When the macro executes, FILEEXIST() will first check to see if a file exist in the ‘Users’ folder that has a user name that matches the current &SYSUSERID. Since the directory is empty, FILEEXIST() returns a zero and the macro proceeds on to the else statement to create a new user. When creating a new user, we must ensure that the (users.profiles) dataset exists prior to adding a new record. This is accomplished with the function EXIST(dataset_name), which again returns a one if the dataset exists and a zero if it does not exist. If the dataset exists, we determine the number of observations in the (users.profiles) dataset, which is equivalent to the number of unique users in the directory. Each user is assigned both a user name and a user ID that increments by one for every new user added (i.e. first user has userID = 1, second has userID = 2,….etc). By taking one plus the number of observations in (users.profiles) we can now assign the user name by using the &SYSUSERID, a unique user ID, and a permanent library reference name where all the user’s macros will be stored for the new user. The library reference name takes on the form User(userID) (i.e. userID = 1 will have the associated library reference User1). All of this data is saved in the (users.profiles dataset). In the case that the users.profiles dataset does not exist yet, we generate the initial observation:

username = &SYSUSERID, userid = 1, library = User1

After saving the new user to the (users.profiles) dataset, the library reference name is assigned to the file location where we will store the new user’s macros. The stored compiled macro facility is activated and assigned to the same file location.

Note in the code below where we use the SAS system option DLCREATEDIR. Invoking this system option forces the creation of a new folder when a library references a file location that does not actually exist. Use of this option turns out to be a simple way to automate the generation of each user’s folder and removes the need for an administrator to manually create and assign folders in the directory.

%MACRO checkUser();

%LOCAL uname numusers loc; *assign macro vars as local;

*assign directory;

%LET loc = C:/Users/GarrettWeaver/desktop/macros/users/;

LIBNAME users "&loc.";

%LET uname = &SYSUSERID;

*determine if user exists in directory, if not, then create new folder for

user;

%IF %SYSFUNC(FILEEXIST("&loc&sysuserid./")) %THEN %DO;

DATA _NULL_;

SET users.profiles;

IF SYMGET('uname') = username THEN CALL SYMPUT('libn',library);

STOP;

RUN;

LIBNAME &libn "&loc&sysuserid./";

OPTIONS MSTORED SASMSTORE=&libn;

%END;

%*executed if user does not exist, adds user, folder and information to user

profiles dataset;

%ELSE %DO;

%IF %SYSFUNC(EXIST(users.profiles)) %THEN %DO;

DATA _NULL_;

IF 0 THEN SET users.profiles nobs=n;

CALL SYMPUT('numusers',TRIM(LEFT(PUT(n,8.))));

STOP;

run;

%LET libn = user%EVAL(&numusers+1);

PROC SQL;

INSERT INTO users.profiles

SET userid = "%EVAL(&numusers+1)",

username = "&SYSUSERID.",

LIBRARY = SYMGET('libn');

QUIT;

OPTIONS DLCREATEDIR;

Page 4: Macros to Manage your Macros? - Lex JansenMacros to Manage Your Macros?, continued 3 To better understand, let’s assume that there are no users in the directory. When the macro executes,

Macros to Manage Your Macros?, continued

4

LIBNAME &libn "&loc.&sysuserid./";

OPTIONS MSTORED SASMSTORE=&libn;

OPTIONS NODLCREATEDIR;

%END;

%*condition executed only for creation of first user record and folder;

%ELSE %DO;

%LET libn = user1;

DATA users.profiles;

LENGTH userid $5;

userid = "1";

username = SYMGET('sysuserid');

library = "user1";

RUN;

OPTIONS DLCREATEDIR;

LIBNAME &libn "&loc&sysuserid./";

OPTIONS MSTORED SASMSTORE=&libn;

%END;

%END;

%MEND checkUser;

%checkUser()

MACRO #2: UPLOADING MACROS TO THE DIRECTORY – macroUpload()

With the appropriate location assigned for where our macros will be compiled to, we are now ready to upload our first macro. Prior to using %macroUpload(), a user needs to compile the macro with the options STORE, SOURCE, and

DES= ‘ ‘ (des is optional). STORE tells SAS that we want to save the macro to the library specified when we

activated the stored compiled macro facility.

SOURCE specifies that we would like to also store the source code for the macro, and DES=” ” allows for us to include a short description for the macro. The general format is as follows:

%MACRO test() / STORE SOURCE DES="Testing";

%PUT Testing;

%MEND test;

After compiling the macro, we run %macroUpload(macro_name, author_name, category) with parameters for macro name, author name, and category. To upload the test macro above, we would run the following:

%macroUpload (test, Garrett Weaver, Test)

If completed correctly, the log will print out the statement, “The macro was successfully uploaded!” Note that when you initially compiled the macro, the macro and source code were already stored to the catalog in the user folder. By running %macroUpload(), we complete three additional steps.

1. Check to see if the macro name is a duplicate of one already in the user catalog 2. Create a .txt file of the source code in the user folder 3. Generate metadata for the macro saved into a separate dataset (meta.metadata) to be used in the search

function.

There are a couple pieces of code we would like to highlight in %macroUpload(). First, just as there was a function to check for the existence of a file and dataset, we also have the function LIBREF() to check for the existence of a library reference. In all four macros, we always check that the (user.profiles) and (meta.metadata) datasets have valid library references. You will also notice the use of the TRIM() and LOWCASE() functions when checking for duplicates. These are important to have when matching character variables to ensure trailing blanks or capitalization do not affect string matching. Lastly, after assigning the location where the .txt file will be stored (&dest), we make use of the %COPY macro function to copy the source code to that location, the default output of %COPY is a .txt file:

Page 5: Macros to Manage your Macros? - Lex JansenMacros to Manage Your Macros?, continued 3 To better understand, let’s assume that there are no users in the directory. When the macro executes,

Macros to Manage Your Macros?, continued

5

%COPY &macroname / SOURCE OUT=&dest;

In the event that a macro already exists in the catalog with the same name, the user will receive a warning message in the log. By checking for duplicates, we preserve the source code in the .txt file, which allows the user to recompile the original macro from the .txt file and then select a unique name for the new macro.

%MACRO macroUpload(macroname,authorname,category)/store source;

%*assign local macro variables;

%LOCAL dest dup mname;

%LET dest =

"C:/Users/GarrettWeaver/desktop/macros/users/&sysuserid./%lowcase(&macroname).t

xt";

%LET uname = &sysuserid;

%*Assign library where user macros stored if not assigned already;

%IF (%SYSFUNC(LIBREF(users))) NE 0 %THEN %DO;

LIBNAME users C:/Users/GarrettWeaver/desktop/macros/users/;

%END;

DATA _NULL_;

SET users.profiles;

IF SYMGET('uname') = username THEN DO;

CALL SYMPUT('libn',library);

CALL SYMPUT('uid',userid);

STOP;

END;

RUN;

%*check if meta library assigned, if not, then assign to appropriate libary;

%IF (%SYSFUNC(LIBREF(meta))) NE 0 %THEN %DO;

LIBNAME meta 'C:/Users/GarrettWeaver/desktop/macros/metadata/';

%END;

%*check to see if metadata dataset exists, if it does, then add a new record to

it with the new macro;

%IF %SYSFUNC(EXIST(meta.metadata)) &

%SYSFUNC(CEXIST(&libn..sasmacr.&macroname..macro)) %THEN %DO;

%*assign local macro var for macro name;

%LET mname = %SYSFUNC(TRIM(%LOWCASE(&macroname)));

%*check to ensure macro name has not already been used;

DATA _Null_;

SET meta.metadata;

IF SYMGET('mname') = LOWCASE(name) THEN DO;

CALL SYMPUT('dup',1);

STOP;

END;

RUN;

%*upload macro if name is not a duplicate;

%IF &dup NE 1 %THEN %DO;

PROC SQL;

INSERT INTO meta.metadata

SET userid="&uid.",

author="&authorname.",

category="&category.",

name="&macroname.";

QUIT;

%*copy actual macro code to .txt file on server;

%COPY &macroname / SOURCE OUT=&dest;

%PUT The Macro was successfully uploaded!;

Page 6: Macros to Manage your Macros? - Lex JansenMacros to Manage Your Macros?, continued 3 To better understand, let’s assume that there are no users in the directory. When the macro executes,

Macros to Manage Your Macros?, continued

6

%END;

%*if name is a duplicate, warn user in log;

%IF &dup = 1 %THEN %DO;

%PUT This Macro Variable Name Already Exists!;

%PUT Please change name of macro and rerun. Also, rerun source

code of original macro;

%END;

%END;

%ELSE %IF %SYSFUNC(CEXIST(&libn..sasmacr.&macroname..macro))%THEN %DO;

DATA meta.metadata;

length name $32 userid $5 author $50 category $50;

userid = "&uid.";

name = "&macroname.";

author = "&authorname.";

category = "&category.";

RUN;

%COPY &macroname / SOURCE OUT=&dest;

%PUT The Macro was successfully uploaded!;

%END;

%ELSE %DO;

%PUT Macro upload failed.;

%PUT Please ensure you have specified 'store' and 'source' in macro

definition.;

%END;

%MEND macroUpload;

MACRO #3: SEARCHING MACROS BY NAME AND KEYWORD – macroSearch()

Once you have a significant number of macros uploaded by a user group, you may be interested in viewing your colleagues’ macros for a number of reasons. Perhaps they have developed a new annual report, or you want to see how they developed a particular graphic using proc template, or maybe you want to identify different techniques to solve a particular problem. Regardless of the reason, you want to be able to view and potentially utilize macros within your user community without disturbing the original source code. The following macro allows you to search for macros by both macro name and keywords that are matched to text placed in the DES = “ “ option for any macro in the directory, without ever opening the source code. The search can be done by macro name or keywords as follows:

%macroSearch(macro_name, keywords)

The first challenge we encountered is to reference all the macro catalogs in a single library. To solve this problem, we reference multiple file locations with a single LIBNAME reference by separating the individual LIBNAME references with a comma:

LIBNAME combined (library1,library2,…..,etc);

After compiling all user macros under one library reference, we format the keywords into a regular expression to search text in the des = “ “ option. The regular expression generated in this macro is simple and can be expanded upon by those with more experience in free text search techniques. In its simplest form, we want to find any macro that has one or more of the keywords that we input. The form of the regular expression is as follows,

/word1|word2|word3|…|word(n)/i

where “i” signifies that we will ignore the case of the words in the search. Thus, we need to collect the keywords entered into macroSearch() and place them into the correct form. To complete this task, we first determine the number of keywords entered and then use a do loop to concatenate the words together with a “|” in between each word. To create the final search string, we must use the %STR() function to add the forward slashes into the string. %STR() is used to identify special characters as being part of the string and prevents misinterpretation of the characters when the code is executed. With a completed search string, we now use the PRXPARSE() and PRXMATCH() functions to complete a search the macro descriptions. PRXPARSE() creates a Perl regular expression from the search string we generated.

myRegEx = PRXPARSE(&searchstr);

Page 7: Macros to Manage your Macros? - Lex JansenMacros to Manage Your Macros?, continued 3 To better understand, let’s assume that there are no users in the directory. When the macro executes,

Macros to Manage Your Macros?, continued

7

PRXMATCH() takes our search string and source text (the macro description) as parameters.

PRXMATCH(myRegEx,desc);

If one of the keywords is located in the macro description, PRXMATCH() returns the starting position where the match was found. Zero is returned if no matches are found. Now all that must be done is to output a dataset that contains the name and descriptions of all macros in the combined library:

PROC CATALOG CATALOG=combined.sasmacr;

CONTENTS out=myMacros;

QUIT;

We then subset the output dataset (myMacros) to those records that match either by macro name or description. With the final set of matching macros, we add additional information from (meta.metadata) and output a report that displays the macro name, author, category, and a link to view the macro code directly in SAS. The link is accomplished through the use of proc report. In order to generate the URL link in the report, we use CALL DEFINE() to modify the format of the column containing the link:

COMPUTE view;

href="C:/Users/GarrettWeaver/desktop/macros/users/"||STRIP(username)||"/"

||STRIP(LOWCASE(name))||".txt";

CALL DEFINE(_col_,"URL",href);

ENDCOMP;

We now have a report that allows us to directly view any matching macro without worrying about changing someone else’s source code.

*Macro to help combine all user libraries into one library to search all available

macros;

%MACRO libassign();

%IF (%SYSFUNC(LIBREF(&ulib.))) NE 0 %THEN %DO;

LIBNAME &ulib. "C:/Users/GarrettWeaver/desktop/macros/users/&uloc.";

%END;

%IF &libcomb= %THEN %LET libcomb=&ulib.;

%ELSE %LET libcomb=%SYSFUNC(CATX(&comma,&libcomb.,&ulib.));

%MEND libassign;

*Main search macro;

%MACRO macroSearch(name,terms) / STORE SOURCE;

*Initialize macro variables;

%LET libcomb=;

%LET comma=%STR(,);

%*Assign library where users stored if not assigned already;

%IF (%SYSFUNC(LIBREF(users))) NE 0 %THEN %DO;

LIBNAME users C:/Users/GarrettWeaver/desktop/macros/users/;

%END;

%*Create library of macros compiled from all user folders;

DATA _NULL_;

SET users.profiles;

CALL SYMPUT('uloc',name);

CALL SYMPUT('ulib',library);

CALL EXECUTE('%libassign');

RUN;

LIBNAME combined (&libcomb.);

%*Determine if meta library assigned, if not, assign library;

%IF (%SYSFUNC(LIBREF(meta))) NE 0 %THEN %DO;

libname meta "C:/Users/GarrettWeaver/desktop/macros/metadata/";

%END;

Page 8: Macros to Manage your Macros? - Lex JansenMacros to Manage Your Macros?, continued 3 To better understand, let’s assume that there are no users in the directory. When the macro executes,

Macros to Manage Your Macros?, continued

8

%*Create search string from search terms entered;

%LOCAL n count sep wordcnt searchstr word;

%IF &name NE %THEN %LET n=%SYSFUNC(TRIM(%LOWCASE(&name)));

%LET count=1;

%LET sep=%STR(|);

%IF &terms NE %THEN %DO;

%LET wordcnt = %SYSFUNC(COUNTW(&terms));

%DO i=1 %TO &wordcnt;

%LET word = %SCAN(&terms,&count);

%IF &count = 1 %then %LET searchstr = &word;

%ELSE %LET searchstr = %SYSFUNC(CATX(&sep,&searchstr,&word));

%LET count = %EVAL(&count+1);

%END;

%LET searchstr = "%STR(/)&searchstr.%STR(/)i";

%END;

%*output dataset with all user compiled macros;

PROC CATALOG CATALOG=combined.sasmacr;

CONTENTS out=myMacros;

QUIT;

%*Subset to macros that match by name or keyword search;

DATA matches;

SET myMacros;

RETAIN myRegEx;

%IF &searchstr NE %THEN %DO;

IF _N_ = 1 THEN myRegEx = PRXPARSE(&searchstr);

match = PRXMATCH(myRegEx,desc);

%END;

mname = SYMGET('n');

IF match > 0 | mname = LOWCASE(name);

name = LOWCASE(name);

LABEL name="Macro Name" desc="Description" crdate="Date Created"

moddate="Date Modified" view="View"

href="Location" libname="Library";

RUN;

%*merge matching macros with metadata and user profiles

(author,category,username,userid);

PROC SORT DATA=matches; BY name; RUN;

%IF %SYSFUNC(EXIST(meta.metadata)) %THEN %DO;

PROC SORT DATA=meta.metadata; BY name; RUN;

DATA macro_author;

MERGE matches (IN=a) meta.metadata;

BY name;

IF a;

RUN;

%END;

%ELSE %DO;

DATA macro_author;

SET matches;

RUN;

%END;

%IF %SYSFUNC(EXIST(users.profiles)) %THEN %DO;

PROC SORT DATA=users.profiles; BY userid; RUN;

PROC SORT DATA=macro_author; BY userid; RUN;

DATA macro_detailed;

MERGE macro_author (IN=a) users.profiles;

BY userid;

href="C:/Users/GarrettWeaver/desktop/macros/users/"||STRIP(username)||"/"

||STRIP(LOWCASE(name))||".txt";

Page 9: Macros to Manage your Macros? - Lex JansenMacros to Manage Your Macros?, continued 3 To better understand, let’s assume that there are no users in the directory. When the macro executes,

Macros to Manage Your Macros?, continued

9

Output 1. Results of %macroSearch(test,regression)

Output 2. View generated when ‘View Code’ selected for regress() macro

view = "View Code";

IF a;

LABEL author="Author" category="Category" view="View";

RUN;

%END;

%*Print macros for viewing;

TITLE1 "Search Results: Available User-Compiled Macros";

FOOTNOTE1 "Server Location: C:/Users/GarrettWeaver/desktop/macros/users/";

PROC REPORT DATA=macro_detailed NOWD;

COLUMN name author category desc crdate username view;

DEFINE desc / FLOW STYLE(COLUMN)=[CELLWIDTH=4in];

DEFINE username / DISPLAY NOPRINT;

COMPUTE view;

href="C:/Users/GarrettWeaver/desktop/macros/users/"||STRIP(usernam

e)||"/"||STRIP(LOWCASE(name))||".txt";

CALL DEFINE(_col_,"URL",href);

ENDCOMP;

RUN;

%MEND macroSearch;

Example: macroSearch() Let’s take a look at simple example in which the directory contains two macros from a single user. The first macro, called %test(), contains a single %PUT statement with some text. The second macro, %regress(), provides simple linear regression and is saved with the description, “Simple linear regression using proc glm”. We run %macroSearch() to look for any macro with name ‘test’ or a description that contains the word ‘regression’:

The resulting output is shown below:

From the generated report, a user can then review a macro by selecting the corresponding ‘View Code’ in the last column of the report. As an example, if we select the %regress() macro, we are redirected to the following code:

From this example, we see that users now have a simple method to access macros across their entire SAS user group by both a specific name and general keyword searches without accessing the source code.

Page 10: Macros to Manage your Macros? - Lex JansenMacros to Manage Your Macros?, continued 3 To better understand, let’s assume that there are no users in the directory. When the macro executes,

Macros to Manage Your Macros?, continued

10

MACRO #4: DELETING MACROS – macroDelete()

Within a short time span, a user is likely to generate a large number of macros and to continually improve upon their design and efficiency. As their macro library grows, there will of course be a need to remove obsolete code from the directory. Introduce %macroDelete(), which shares a number of techniques in common with those utilized in %macroUpload(). To delete a macro from one’s directory, simple type the name of the macro:

%macroDelete(macroname);

%macroDelete() will proceed to remove the macro from the user catalog, the .txt source file, and the associated metadata from (meta.metadata). Within this macro, we would like to bring attention to the technique used to delete the .txt file.

DATA _NULL_;

fname = "tempfile";

rc = FILENAME(fname,"&sastxt.");

rc = FDELETE(fname);

RUN;

We associate the location of the .txt file that needs to be deleted (&sastxt) with the file reference fname by using the FILENAME() function. After creating the reference, we use the FDELETE() function to remove the .txt file from the folder. FDELETE() is a simple function to use that accepts a string containing the file location and will proceed to delete the file if found. The user is provided with feedback as to whether the file was found and deleted in the log after execution of the code. With all four macros, user can now upload, delete, and search for macros across the directory.

%MACRO macroDelete(macroname);

%LOCAL uid userid mname sastxt;

*Assign library where users stored if not assigned already;

%IF (%SYSFUNC(LIBREF(users))) NE 0 %THEN %DO;

LIBNAME users "C:/Users/GarrettWeaver/desktop/macros/users/";

%END;

%LET uname = &SYSUSERID;

DATA _NULL_;

SET users.profiles;

IF SYMGET('uname') = username THEN DO;

CALL SYMPUT('libn',library);

CALL SYMPUT('uid',userid);

END;

STOP;

RUN;

%IF %SYSFUNC(CEXIST(&libn..sasmacr.&macroname..macro)) %THEN %DO;

%LET mname = %SYSFUNC(LOWCASE(%SYSFUNC(STRIP(&macroname))));

%LET userid = %SYSFUNC(STRIP(&uid));

%LET sastxt =

C:/Users/GarrettWeaver/desktop/macros/users/&sysuserid./&mname..txt;

proc CATALOG CATALOG=&libn..sasmacr FORCE;

DELETE &mname / ET=MACRO;

RUN;

DATA _NULL_;

fname = "tempfile";

rc = FILENAME(fname,"&sastxt.");

rc = FDELETE(fname);

RUN;

Page 11: Macros to Manage your Macros? - Lex JansenMacros to Manage Your Macros?, continued 3 To better understand, let’s assume that there are no users in the directory. When the macro executes,

Macros to Manage Your Macros?, continued

11

%*Determine if meta library assigned, if not, assign library;

%IF (%SYSFUNC(LIBREF(meta))) NE 0 %THEN %DO;

LIBNAME meta "C:/Users/GarrettWeaver/desktop/macros/metadata/";

%END;

%*remove metadata for macro from dataset;

DATA meta.metadata;

SET meta.metadata;

IF name = "&mname." AND userid = "&userid." THEN delete;

RUN;

%PUT Macro Successfully Deleted!;

%END;

%ELSE %DO;

%PUT Macro name not found! Please check spelling and try again.;

%END;

%MEND macroDelete;

CONCLUSION

By implementing the above macros, a user will be able to maintain a personal directory of SAS macros and exchange macros across a local group. Given that the macros presented above are a first attempt at implementing a macro code collaboration solution, a number of improvements and modifications can be made in order to fit within a particular environment. This is just one technique from which I hope the SAS user community can expand upon to create more integrated coding environments within both academic and industry settings.

REFERENCES Hemedinger, Chris. “SAS trick: get the LIBNAME statement to create folders for you”. The SAS Dummy. July 2,

2013. Available at http://blogs.sas.com/content/sasdummy/2013/07/02/use-dlcreatedir-to-create-folders/.

McMahill, Allison. 2007. “Beyond the Basics: Advanced PROC REPORT Tips and Tricks”. Proceedings of the

SAS® Global Forum 2007 Conference. Cary, NC: SAS Institute Inc.

Pless, Richard. 2004. “An Introduction to Regular Expressions with examples from Clinical Data”. Proceedings of

the Twenty-Ninth Annual SAS® Users Group International Conference, Cary, NC: SAS Institute Inc.

SAS Institute Inc., Base SAS® Procedures Guide, Second Edition, Cary, NC: SAS institute Inc.. 2012

SAS Institute Inc., SAS® 9.2 Language Reference: Dictionary, Fourth Edition, Cary, NC: SAS Institute Inc. 2010

Stojanovic, Mirjana & Hollis, Donna. 2005. “Ways to Store Source Codes and How to Retrieve Them”.

Proceedings of the SouthEast SAS® Users Group, Portsmouth, VA: SouthEast SAS Users Group

Page 12: Macros to Manage your Macros? - Lex JansenMacros to Manage Your Macros?, continued 3 To better understand, let’s assume that there are no users in the directory. When the macro executes,

Macros to Manage Your Macros?, continued

12

ABOUT THE AUTHOR Garrett Weaver is a PhD student in Biostatistics at the University of Southern California. With only a little over a year of experience with SAS, he is interested in the continued expansion of his SAS skillset as one of his primary analysis and data management tools.

AUTHOR CONTACT Your comments and questions are valued and encouraged. Contact the author at: Name: Garrett Weaver Enterprise: University of Southern California, Department of Preventive Medicine, Division of Biostatistics Address: 2001 N. Soto Street, SSB201A City, State, ZIP: Los Angeles, CA 90089 Email: [email protected]

SAS and all other SAS Institute Inc. product or service names are registered trademarks or trademarks of SAS Institute Inc. in the USA and other countries. ® indicates USA registration.

Other brand and product names are trademarks of their respective companies.