Skip to content

Instantly share code, notes, and snippets.

@bennadel
Created August 17, 2019 14:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bennadel/e5052a2b72be9fd0ac9e2c1454482487 to your computer and use it in GitHub Desktop.
Save bennadel/e5052a2b72be9fd0ac9e2c1454482487 to your computer and use it in GitHub Desktop.
Upgrading A Built-In Function To A First-Class Citizen In Lucee 5.3.2.77
<cfscript>
values = values.map( trim );
</cfscript>
<cfscript>
operator = ( doUppercase )
? ucase
: lcase
;
echo( operator( "I said Good-Day, sir." ) );
</cfscript>
<cfscript>
values = [ "oLLeH", "Ym", "dOOg", "DnEiRf" ];
// NOTE: The .map() operations in the following calls will pass-in several arguments
// to the provided operator ("reverse", "ucase", "lcase"); however, these Functions
// can only accept one argument. As such, our proxy function will pare down the
// arguments based on built-in function's native arity.
values = values.map( upgradeBIF( "reverse" ) );
// Randomly choose an operator for our next .map() call.
operator = randRange( 0, 1 )
? upgradeBIF( "ucase" )
: upgradeBIF( "lcase" )
;
dump( values.map( operator ) );
// ------------------------------------------------------------------------------- //
// ------------------------------------------------------------------------------- //
/**
* I attempt to upgrade the given built-in function (BIF) such that it can be passed-
* around like a first-class Function reference.
*
* @name I am the name of the BIF to upgrade.
*/
public Function function upgradeBIF( required string name )
cachedWithin = "request"
{
var bifMetadata = getFunctionData( name );
// The getFunctionData() function returns meta-data about the built-in function
// with the given name. This includes the array of arguments that it expects,
// which can use to determine the arity of the function (ie, how many arguments
// it expects).
var bifArity = bifMetadata.arguments.len();
return(
() => {
// If there are no arguments - the Built-In Function (BIF) doesn't expect
// arguments - pass-through an empty set of arguments.
if ( ! bifArity || ! arguments.len() ) {
var argumentList = "";
// If the arguments passed to the proxy function are provided as an
// ordered list of values, then we have to pare down the collection to
// just those expected by the Built-In Function's (BIF) native arity (or
// ColdFuison will throw an error).
// --
// NOTE: We are loosely determining argument-type by seeing if an index-
// oriented argument key exists.
} else if ( arguments.keyExists( "1" ) ) {
var argumentList = arguments
.keyArray()
.slice( 1, min( bifArity, arguments.len() ) )
.map( ( index ) => "arguments[ #index# ]" )
.toList( "," )
;
// If the arguments passed to the proxy function are provided as a set of
// key-value pairs, then we need to pass them through to the Built-In
// Function (BIF) in the same manner.
// --
// CAUTION: While some BIFs support argumentCollection (those that are
// implemented in CFML), the vast majority of BIFs do not support this
// type of invocation. As such, we have to explicitly create a listed of
// named arguments.
} else {
var argumentList = arguments
.keyArray()
.map( ( key ) => "#key# = arguments.#key#" )
.toList( "," )
;
}
return( evaluate( "#name#( #argumentList# )" ) );
}
);
}
</cfscript>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment