Skip to content

Instantly share code, notes, and snippets.

@stevereich
Created November 12, 2015 16:34
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 stevereich/46a869a267fcb9a03d2d to your computer and use it in GitHub Desktop.
Save stevereich/46a869a267fcb9a03d2d to your computer and use it in GitHub Desktop.
This is an example of using closures and callback functions with Coldfusion or Railo. This will probably bend your mind a little bit!
component output='false' {
// init component
public callback_component function init(){
return this;
};
// this function implicitly takes 2 named arguments. In this case, the arguments scope
// can be treated as an object with name value pairs or an array with the index being
// equal to the position they are expected. This was probably part of the thinking when
// Jeremy and JJ Allaire decided not to use a zero index way back when...
//
// arguments['fullname'] == arguments.fullname == arguments[1]
//
// (side note: though a similar circumstance, this is not the same case in javascript)
//
public string function getFirstName(required string fullName, callback){
try{
// we'll set our return variable and parse out the first name
var firstname = listgetat(arguments.fullName, 1, ' ');
// pass return variable to our callback function
// this is going to run with out return
callback(firstname);
}
catch(any e){
// if error, we will set the return variable to the error message
firstname = e.detail;
}
finally{
// Finally ALWAYS runs... like a promise!
return firstname;
}
};
// this is the same function as above, but with only one argument defined in the
// function definition. We can still pass a callback to it though... as long as
// the function know it could be a possibility.
public string function anotherWayToAcceptCallbackAndGetFirstName(required string fullName){
// we'll set our return variable and parse out the first name
var firstname = listgetat(arguments.fullName, 1, ' ');
// wait? what's this? it's a closure. this function has access to all the variables of it's
// parent function. However, the parent function does not have access any variables this
// closure function sets.
var throwItAroundOneMoreTime = function(thing){
// this return is only available to the parent function, which is then free to
// return it to 2 friends, and so on, and so on, and so on... :)
return reverse(thing);
};
// this is our calback! I romise that no illicit drugs were consumed in the assembly of
// this string. let's break it down....
//
// arguments is an object or an array. without a named index, we have to treat it as array
// arguments index is arraylen(arguments). this is assumming that no matter how many arguments
// were passed to this function, the callback was passed last. so we have:
//
// arguments[arraylen(arguments)] <<<<---- this is our function. if we just passed it the
// return of the called function, it would be arguments[arraylen(arguments)](firstname).
//
// but for the mere shock value, let's reverse the return, pass it to our closure,
// reverse it back, and the return it for our call back to return... haha!
//
// throwItAroundOneMoreTime(reverse(firstname)) <<<--- this is our argument we pass to our callback
//
//
//
// we run our callback function, not return it.
var callback = arguments[arraylen(arguments)];
callback(throwItAroundOneMoreTime(reverse(firstname)));
// we only return our return!
return firstname;
};
}
<html>
<head>
<title>Callbacks and Closures and Coldfusion... oh my!</title>
<style>
*{box-sizing:border-box}
html,body{background:#F5F5F5;width:100%;height:100%;margin:0;padding:0;font-family:sans-serif;overflow:hidden}
div#head{position:fixed;top:0;left:0;right:0;height:60px;line-height:60px;box-shadow:0 5px 20px 0 rgba(0,0,0,.2);
text-align:center;font-size:2em;font-weight:bold;color:#F5F5F5;background:#666;border-bottom:1px #333 solid}
ul{position:absolute;width:550px;left:50%;margin-left:-275px;top:30%;}
ul>li{font-size:1.2em;padding-left:0}
div#foot{position:fixed;bottom:0;left:0;right:0;text-align:center;height:40px}
a,a:link,a:visited,a:hover,a:acitve{text-decoration:none;font-size:.5em;color:#666}
</style>
</head>
<body>
<cfscript>
request.layout = false;
// just for the sake of showing how deep the rabbit hole is that Mike Arnold pulled me into,
// we'll wrap this up with a single function with nested closures...
// variables scope our component so it doesn't get reinit() each time the function is called
variables.comp = createobject('component','callback_component').init();
public string function wtf(){
// local scope the return variable
var theReturn = '';
// we'll switch on a single argument. in production we would want to do string validation
switch(arguments[1]){
// ok.. now the fun part. if 'steve' is passed as the arg
case 'steve':
// call our function. we pass fullname as argument[1] and a function as argument[2].
// the argument that I have in the callback function can be anything. When the function
// runs, it will assign it's return to that argument and run it through our callback,
// which in turn, we will assign it to this functions return var... stay with me!! :)
variables.comp.getFirstName('Jimmie Chapman',function(StevesArg){
theReturn = """" & repeatstring(StevesArg & '!',5) & """";
});
break;
// if 'mike' is passed as the arg
case 'mike':
// same as steve here...
variables.comp.getFirstName('Jimmie Chapman',function(mikesArg){
theReturn = reverse(mikesArg).toLowercase() & ".";
});
break;
// if 'jay' is passed as the arg
case 'jay':
// jay is special and he is going to call the second function in our component. if you
// remember, that function had a closure function that it tossed the return back and forth.
// well guess what? as payback, his callback function has a closure function too. Is your
// brain turned completely inside out yet? Mine is.. but we're almost there.
variables.comp.anotherWayToAcceptCallbackAndGetFirstName('Jimmie Chapman',function(jsyArg){
// this is a closure within the callback
var whosHouse = function(arg){
return arg & " Chapman loves OU football.";
};
// this is oru return var and we are setting the value to the return of our closure
// function, passing it the return of the callback's parent function.
theReturn = whosHouse(jsyArg);
});
break;
}
// in our swith, we were only assigning values to our return variable.
// we return it here....
return theReturn;
}
// now... we will set variables and test this mutha....
local.steve = wtf('steve');
local.mike = wtf('mike');
local.jay = wtf('jay');
/* ==================================================== */
// this is the output using the three variables above...
writeoutput("<div id='head'>Closure. Callbacks. Coldfusion. Oh my...</div>");
writeoutput("<ul>");
writeoutput("<li>Steve yelled, " & local.steve & "</li>");
writeoutput("<li>Mike thinks it's cool to say his name backwards... """ & local.mike & """</li>");
writeoutput("<li>Jay got closure in that " & local.jay & "</li>");
writeoutput("</ul>");
writeoutput("<div id='foot'>Steve Reich, Professional Application Developer<br>");
writeoutput("<a href='mailto:sr451g@att.com'>email me with any questions</a></div>");
</cfscript>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment