*! version 1.1.6 25mar2023 Gorkem Aksaray *! *! Changelog *! --------- *! [1.1.6] *! - frapply now returns r-class results, in addition to e-class results if *! any, stored by the last command in commandlist. *! [1.1.5] *! - Using ||-operator of twoway syntax in command list was causing an error. *! This is now fixed. *! [1.1.4] *! - More robust prefix parsing. *! [1.1.3] *! - More efficient frame copying to achieve slightly faster frapply. *! [1.1.2] *! - Revised parsing of command list again to allow for "empty pipes". *! The command list can now start with |>, end with |>, and have *! consecutive |>'s with nothing in between. frapply is now robust to *! those "errors". *! [1.1.1] *! - Rewrote parsing of command list to allow for protected locals *! while also allowing for | and > characters within the individual *! commands. *! [1.1.0] *! - Changed the 'pipe' operator from "||" to "|>" as in R language. *! [1.01] *! - Using an if expression on a non-current frame was causing an error. *! This is now fixed. *! [1.0] *! - Initial SSC release. capture program drop frapply program define frapply, rclass version 16.0 // parse prefix and command(s) gettoken prefix command : 0, parse(":") if "`prefix'" == ":" { local prefix "" } else { gettoken colon command : command , parse(":") } parse_prefix `prefix' local retlist "from if in intoname intoreplace intochange quietly" foreach ret of local retlist { capture local `ret' "`r(`ret')'" } // from frame check if "`from'" != "" { confirm frame `from' local cframe "`from'" } else { local cframe = c(frame) } // into frame check if "`intoname'" == "" { tempname tempframe local intoname "`tempframe'" } if "`intoname'" == "`cframe'" { display as error "into() option may not specify the applied frame" exit 198 } if "`intoreplace'" == "" { confirm new frame `intoname' } // run command(s) tempname tempframe frame copy `cframe' `tempframe' frame `tempframe' { qui capture keep `in' `if' while `"`command'"' != "" { gettoken part command : command, parse("|") if `"`part'"' == "|" & substr(`"`command'"', 1, 1) == ">" { gettoken part command : command, parse(">") local part "" } if substr(`"`command'"', 1, 2) == "|>" | `"`command'"' == "" { gettoken sep command : command, parse("|") gettoken sep command : command, parse(">") `quietly' `cmd'`part' local cmd "" if `"`command'"' == "" { return add } } else { local cmd `"`cmd'`part'"' } } } frame copy `tempframe' `intoname', `intoreplace' capture frame `intochange' `intoname' end capture program drop parse_prefix program define parse_prefix, rclass version 16.0 gettoken from 0 : 0, parse(" ,") capture confirm frame `from' if !_rc frame `from' { syntax [if] [in] [, into(string asis) QUIetly] } else if !inlist("`from'", "", ",", "if", "in") { confirm frame `from' } else { local 0 "`from' `0'" syntax [name(name=from)] [if] [in] [, into(string asis) QUIetly] } return local from "`from'" return local if "`if'" return local in "`in'" capture parse_into `into' if _rc { display as error `"Illegal into option: `into'"' exit 198 } return local intoname "`r(name)'" return local intoreplace "`r(replace)'" return local intochange "`r(change)'" return local quietly "`quietly'" end capture program drop parse_into program define parse_into, rclass version 16.0 syntax [name(name=name)] [, replace CHange] return local name "`name'" return local change "`change'" return local replace "`replace'" end