bbdaniels
11/8/2018 - 9:54 PM

How to have to commands in seperate ado-files sharing the same sub-commands in a separate file.

How to have to commands in seperate ado-files sharing the same sub-commands in a separate file.

Two commands sharing the same sub-functions

It is common that two ado-files in the same package share a lot of sub-commands (also called utility commands, functions etc.). It is bad practice to write the commands in one file first and copy and paste the sub-commands to the other ado-file. This is ad practice as updating these commands is very likely to lead to errors. This is a part of the DRY coding principle that is one of the few coding paradigms that all computer scientists agree on.

This Gist explains how you can set this up in a Stata environment.

The mySubCommandsXYZ.do file

You should give this file a unique name if you are planning on publishing commands using this method as there will be a name conflict if someone else also have a file called mySubCommandsXYZ.do or whatever you end up calling your file.

This file includes all sub-commands that should be included in the ado-files for the commands. The commands in this file may not have the same name as any sub-command written directly in the ado-files.

The ado-files

In the ado-files the following line of code is used capture findfile mySubCommandsXYZ.do. findfile is a command that looks in the adopath folders - these are the folders where user-written commands may be installed - for a file called mySubCommandsXYZ.do.

If the file is found, then the local path to that file is saved in the return local r(fn). That local is used in run "'r(fn)'". That line runs the file with all the functions and saves them into temporary memory so that the command can use them.

If the file is not found, an error is thrown.

How to publish

If you are planning on publishing commands using this set-up, for example at SSC, all you need to do is to include the mySubCommandsXYZ.do (or whatever you called your file) with the ado-files and help-files.

/********************************************************************************
	These functions are loaded into the command in 
	the prefix_bar.ado and the prefix_foo.ado file
********************************************************************************/

cap program drop 	suff_foo
    program define 	suff_foo

    syntax , string(string) 
    di "`string'_foo"
end

cap program drop 	suff_bar
    program define 	suff_bar

    syntax , string(string)
    di "`string'_bar"
end
	
  cap program drop 	prefix_bar
      program define 	prefix_bar
  
    syntax , string(string) suffix_foo suffix_bar

    *This segment of code imports the utility functions for this command
    capture findfile mySubCommandsXYZ.do //Search for file in adopath
    if (_rc == 0) {
      run "`r(fn)'" //Running the file loads all functions in the mySubCommandsXYZ.do file
    }
    else {
      error 601 //the mySubCommandsXYZ.do file not found in the adopaths
    }
    
    local string "bar_`string'"
    
    di "`string'"
    if "`suffix_foo'" != "" suffix_foo , string("`string'")
    if "`suffix_foo'" != "" suffix_foo , string("`string'")
    
 end
	
  cap program drop 	prefix_foo
      program define 	prefix_foo
  
    syntax , string(string) suffix_foo suffix_bar

    *This segment of code imports the utility functions for these commands
    capture findfile mySubCommandsXYZ.do //Search for file in adopath
    if (_rc == 0) {
      run "`r(fn)'" //Running the file loads all functions in the mySubCommandsXYZ.do file
    }
    else {
      error 601 //the mySubCommandsXYZ.do file not found in the adopaths
    }
    
    local string "foo_`string'"
    
    di "`string'"
    if "`suffix_foo'" != "" suffix_foo , string("`string'")
    if "`suffix_foo'" != "" suffix_foo , string("`string'")
    
 end