I’ve been working with a user-written module in Stata where the program’s code isn’t separate from its data; that is, the program relies on a big macro containing operational details it needs to perform. The program iterates a selected do-file over a set of data files that can be selected on the basis of a battery of characteristics, and the roster of data files and their characteristics is a big local macro inside the program.
That’s not a bad way to go, but I want that data to be accessible outside the program so that I can use it for other things, have someone who doesn’t understand code maintain it, etc. Separating code from data also satisfies a programming principle that was drilled into me from an early age (but, see this exchange on SE).
Because the program needs to be portable, I can’t hard-code the data file’s location into the program. Because the program needs to be backward-compatible with the user code that calls it, I can’t require that the program take a new argument indicating where the data live.
What to do?
The -adopath- command lets the user specify a location to look for ado files. It stores those values in the global macro $S_ADO, along with Stata’s native paths (like /ado/base/, /ado/plus/, et al).
If a user specifies adopath + /somepathname/
, it’ll put /somepathname/ at the end of the list. If a user specifies adopath ++ /somepathname/
, /somepathname/ is inserted at the front.
If I know how the user specified adopath, I can put this in my program’s ado-file:
adopath + "/mypathname/"
local adop = `"$S_ADO"' // Unnecessary -- I do this for comfort.
local adop = subinstr(`"`adop'"',";"," ",.) // Stata likes spaces
local len_adop: word count `adop' // macro length (numeric)
tokenize `"`adop'"' // splits into `1',`2',...,`len_adop'
di "``len_adop''" // value of the last (`len_adop'th) element
Then I can do two more things:
- Put my data file in the same folder as my ado file, and
- Reference `mypath’/mydatafile in my code.
I don’t have to pass an argument to my program telling it where its operational data lives, and I don’t have to open the program’s source and change a hard-coded path every time the program moves.