Showing posts with label CFlib. Show all posts
Showing posts with label CFlib. Show all posts

Sunday 12 October 2014

CFML: prime number generator UDF, and overhead of using inline function expressions

G'day:
I continued to play around with faux generators in CFML after I finished "CFML: emulating generators with closure" yesterday. Whilst I didn't think the world would benefit from there being a palindrome generator on CFLib.org, it might benefit slightly by having one that generated primes. CFLib.org already has a function which returns an array of primes up to a threshold (GetPrimes()), but that's a slightly different requirement than being able to generate them one at a time. And I wanted to fiddle about anyhow, so that became my mission.

The actual code is not mention-worthy in and of itself, but a coupla things I noticed along the way probably are.

Sunday 6 July 2014

Simplifying another CFLib function, and some more unit test examples

G'day:
Last week (I think) whilst I was messing around with some code, and TDDing it as I went, I posted on Twitter about my pleasure at testing with TestBox which yielded a request from Dan Fredericks:
The code I was working on will make it onto the blog at some point, but in the interim I was simplifying a CFLib UDF yesterday, and needed some regression tests for my fix, so took the TDD approach. And here's the business.

Friday 20 June 2014

Feedback on UDF submitted to CFLib

G'day:
This is just some feedback on one of the UDFs I just approved on CFLib (convertBBCodeToHtml()). I changed the function a fair bit, so figured it might be helpful to look at what I did.

Thursday 22 May 2014

CFML: Regex to the rescue again

G'day:
Once again (prev: "Regex for simplifying string manipulation logic") I found myself able to slough off a coupla dozen lines of code in a CFLib.org UDF, by using a regex (well: two) in place of a bunch of looping and branching logic.

There's nothing new in this article, but a good real-world demonstration of where regexes can replace logic.


This UDF (titleCaseList()) got on my radar because someone mentioned a bug it had today, and looking at the comments, there was an earlier bug still outstanding. So I decided to quickly fix it. Here's the code for the previous version:

Monday 21 April 2014

Regex for simplifying string manipulation logic

G'day:
An interesting blog article fell in front of me this morning: "Capitalization for us Mc’s and Mac’s!", by Brian McGarvie. It mentions a UDF on CFLib.org which handles... well as per his blog title: captialising his name as "McGarvie" rather than "Mcgarvie" like other capitalise() functions might do.

Saturday 12 April 2014

Well that's nice

G'day:
I had a nice comment posted against one of my UDFs @ cflib.org today:

Sting (Guest):
Well, This is He, even if his functions make no sense, he adds them here, because he is administrator of this site..
This is in regards to the savecontent() UDF I submitted a few weeks ago ("How about this for savecontent?").

TBH, the UDF is of minimal merit: it's definitely a proof of concept thing and simply replicates existing functionality. Although I happen to think it's a better approach to doing a <cfsavecontent> operation in CFScript, compared to the options Railo and ColdFusion have offered.

The reason why I posted is threefold:

  • it's a reasonable demonstration of doing less-obvious things with inline function expressions, so might prompt people to think about them more;
  • it demonstrates how "closing tag" operations can be done in CFScript without needing special "block" syntax (which I deeply dislike);
  • CFLib is a bit traffic-slow these days, so I thought it might remind people it's there.

Saturday 8 March 2014

Unit testing: the importance of testing over assumption

G'day:
Today some code! That's better than rhetoric innit? I'm sure it won't be as popular though.

OK, so I have been too busy recently with ColdFusion 11 and various other odds 'n' sods to either continue writing about unit testing, and also I have been neglecting the CFLib.org submission queue. So today I am remedying both of those in one fell swoop.

This article is not really "TDD" or "BDD" as the code I am testing is a fait accompli, so the tests are not driving the development. However this is perhaps a good lesson in how to retrofit tests into functionality, and what sort of things to test for. There's a bit of TDD I suppose, because I end up completely refactoring the function, but first create a test bed so that that is a safe thing to do without regressions.

On CFLib there is already a function firstDayOfWeek(), but someone has just submitted a tweak to it so that it defaults to using today's date if no date is passed into it. Fair enough. Here's the updated code:

function firstDayOfWeek() {
    var dow = "";
    var dowMod = "";
    var dowMult = "";
    var firstDayOfWeek = "";
    if(arrayLen(arguments) is 0) arguments.date = now();
    date = trim(arguments.date);
    dow = dayOfWeek(date);
    dowMod = decrementValue(dow);
    dowMult = dowMod * -1;
    firstDayOfWeek = dateAdd("d", dowMult, date);

    return firstDayOfWeek;
}

Nothing earthshattering there, and I basically scanned down it going, "yep... uh-huh... oh, OK, yeah... cool... yeah that seems OK". And I was about to just approve it. Then I felt guilty and thought "ah... I really should test this. And I'll use TestBox and its BDD-style syntax to do so, and I can get a blog article out of this too.

It's just as well I did test it, because it has a bug. Can you see it?

I sat down and looked at the code, and went "right... what do I need to test?". I came up with this lot:
  • if I don't pass in a date, it returns the first day of the current week;
  • if I do pass in a date, it returns the first day of that week;
  • if I pass in the date that is the first day of the week already, it passes back that same date;
  • if I pass it "not a date", it errors predictably.
I think that about covers the testing need here? OK, so I started writing the tests:

// TestFirstDayOfWeek.cfc
component extends="testbox.system.testing.BaseSpec" {

    function beforeAll(){
        include "udfs/firstDayOfWeek.cfm";

        variables.testDate = now();
        variables.testFirstDayOfWeek = dateAdd("d", -(dayOfWeek(variables.testDate)-1), variables.testDate);
    }

    function run(){
        describe("Tests for firstDayOfWeek()", function(){

            it("returns most recent sunday for default date", function(){
                expect(
                    dateCompare(variables.testFirstDayOfWeek, firstDayOfWeek(), "d")
                ).toBe(0);
            });

            it("returns most recent sunday for current date", function(){
                expect(
                    dateCompare(variables.testFirstDayOfWeek, firstDayOfWeek(variables.testDate), "d")
                ).toBe(0);
            });
        });
    }

}

Notes:
  • I've got the UDF saved in a separate file, so just include it at the beginning of the tests;
  • I set some helper variables for using in the tests;
  • I'll get to this.
I was running the tests as I went, and here's what I got on the test round with these first two tests:

Sunday 8 December 2013

CFML: For the sake of completeness: createLocalisedDayOfWeekAsInteger(): a closure approach

G'day:
A coupla days ago I continued my TDD / unit testing series with an article "Unit Testing / TDD - refactoring existing code". This engendered a few comments, none of which paid any attention to the intent article, instead focused on something pretty much irrelevant to what I was discussing. This engendered this reaction from me:


Oh how I love my readership sometimes. But, actually, the comments got me thinking...

That article covered the approval process for CFLib of a function dayOfWeekAsInteger(), which is the reverse of dayOfWeekAsString(): it takes a string (in English only), and returns which day of the week that corresponds to, starting with Sunday as the first day. Why does it start on Sunday instead of Monday (as per ISO 8601)? Because it's the inverse of dayOfWeekAsString(), and that's how that does it. Is that right? Well: no. Is that relevant to either this UDF or the blog article? Also: no.


However James's suggestion for how Simon could rewrite his function to suit James's requirements (James: write your own functions if you want them different from how others have implemented them!) did get me thinking about how to do it. A thought popped into my head that one could leverage closure to create a function which was specific to a given locale. This might not be exactly what James wants, but it was what I decided to look into, because it's slightly interesting, and covers a feature of closure I've not covered anywhere on this blog yet. So it interests me.

Friday 6 December 2013

Unit Testing / TDD - refactoring existing code

G'day:
I've just had a new submission in the CFLib queue, and as it's an easy one to test and release, I'm gonna jump on it and get it out there today. However I want to test it first, plus I want to refactor it slightly, so I'm gonna use TDD to do so. And document what I'm doing as I go.

This continues a series on unit testing and TDD that I'm doing, the rest of which are tagged with either "Unit Testing" or "TDD" or both, so you can look them up via those links (there's too many to list now, so I won't bother).

The code for this article will be here: https://github.com/daccfml/scratch/tree/master/cflib/dayOfWeekAsInt (only the baseline files are there at the moment, as I haven't written the code yet ;-).


Monday 21 October 2013

CFML: Community collaboration: fixing some bugs in my defer() function

G'day:
I released a UDF defer() to CFLib and Code Review yesterday. And Adam Tuttle quickly spotted a shortfall in my implementation. And whilst addressing that spotted two more bugs, which I have now fixed.

Adam's observation was thus:

you're not doing a thread join in this code anywhere, which means that if the deferred job takes longer than the rest of the request to run, it will not be able to affect the response.
[...]
For your function to be useful, either the result of the job function can't be something that's needed to create the response, or you'll need to add a way to expose a join reference for the created thread. 

All very true. So I mulled this over in my head this morning on the train, and came up with a fix. I also realised I had another significant bug in the original implementation at the same time. And when implementing the fix, spotted another bug. All now dealt with.

Here's the revised code:

public struct function defer(required function job, function onSuccess, function onFailure, function onError, function onTerminate){
    var threadId = "deferredThread_#createUuid()#";

    local[threadId] = "";

    try {
        cfthread.status = "Running";
        thread name=threadId action="run" attributecollection=arguments {
            try {
                successData.result = job();
                cfthread.status = "Completed";
                if (structKeyExists(attributes, "onSuccess")){
                    onSuccess(successData);
                }
            } catch (any e){
                cfthread.status = "Failed";
                if (structKeyExists(attributes, "onFailure")){
                    onFailure(e);
                }else{
                    rethrow;
                }
            }
        }
    } catch (any e){
        cfthread.status = "Errored";
        if (structKeyExists(arguments, "onError")){
            onError(e);
        }else{
            rethrow;
        }
    }
    return {
        getStatus = function(){
            return cfthread.status;
        },
        getThreadId = function(){
            return threadId;
        },
        terminate = function(){
            if (cfthread.status == "Running"){
                thread name=threadId action="terminate";
                cfthread.status = "Terminated";
                if (isDefined("onTerminate")){
                    onTerminate();
                }
            }
        }
    };
}

Sunday 20 October 2013

CFML: Threads, callbacks, closure and a pub

G'day:
I'm over in Ireland this weekend, and am doing my normal Sunday afternoon activity of sitting at Shannon Airport drinking Guinness, having finished my business early, so have a 4h wait in departures before my flight even considers boarding. Today's excitement here was the 500-odd US Army squaddies in transit to or from what I presume was Afghanistan. It makes a change from being the only person in the place, which was the case two weeks ago (other than shop staff, that is). Last night I killed some time in the pub too, during which I knocked out some quick code, to solve a problem I invented for myself to kill time. Here's the result.

A week or so ago Luis started an interesting thread on the Railo Google Group: "Add closure support to blocking operations to allow them to be non-blocking operations.". The summary of which is:

[...]I propose adding closure callback support to the following functions/operations so they can be processed natively in the background (non-blocking) and then call back when done.

FileRead
FileWrite
[...]
etc

Basically any operation that can block a network or local resource.  Imagine doing this:

fileRead( file, function(contents){
  process file here in the background once it is read.
});
[...]
The bits I omitted ([...]) are simply for abbreviation, and preserve the gist of his suggestion. This is a reasonable idea in general, but - as I go on to say in the thread - I don't think the suggested approach is very good for a coupla reasons. It's not bad, but it just seems a bit "embryonic" to me. But this is fine, this is what discussion forums are for.

My suggested approach would be more all-encompassing. Why limit this functionality to a subset of predetermined built-in functions? What about other built-in operations that might be slow, but otherwise doesn't need to interact with the rest of the code subsequent to it in the request? What about custom code that is similar? It makes little sense to me to "hard-code" this sort of behaviour to specific operations, to me.

A better solution would be to provide a general mechanism that can be used by any code to background-thread its execution, and fire callbacks on completion, failure etc, so as to kick off the next process, or flag-up that the process has completed.

Then it occurred to me that I thought I could knock a solution out to this using a single function. Not a very complete solution, but a solution nevertheless.

So sitting at the bar last night, over the course of four Guinnesseses, I came up with this lot:

Thursday 17 October 2013

CFML: listEach() on CFLib

G'day:
This one cropped up because of something Rob Glover mentioned in passing on Twitter, which I gave a fairly perfunctory response to.

Scott more helpfully pointed out that converting the list to an array and looping that is a good approach. I agree.

However this got me thinking: a list-iterating UDF would be handy, and CFLib doesn't seem to have one, so I knocked one together:

public array function listEach(required string list, required function callback, string delimiters=","){
    var arr = listToArray(list, delimiters);
    var arrLen = arrayLen(arr);
    var result = [];
    for (var index=1; index <= arrLen; index++){
        arrayAppend(result, callBack(argumentCollection=arguments, index=index, element=arr[index], length=arrLen));
    }
    return result;
}

There's nothing exciting here, it just takes a list, loops over it, and passes each element to a callback to process it. It'll return an updated array if that's helpful. I chose an array instead of a list because it's more useful, and allows non-simple values to be returned.

This follows the precedent set in my recent arraySetEach() UDF, passing all the passed-in args to the callback, plus the position the iterating index is at, and the value, and in this case the length of the list being processed.

It can be used both to create a new, transformed list:

numbers = "tahi|rua|toru|wha";

function _ucase(){
    return ucase(element);
}

upperCasedNumbers = listEach(numbers, _ucase, "|");
writeOutput(serializeJson(upperCasedNumbers));

Output:

["TAHI","RUA","TORU","WHA"]

Or just as a looping construct. Here we turn the list into an <ol>:

function toOL(){
    if (index == 1){
        writeOutput("<ol>");
    }
    writeOutput('<li id="index_#index#">#element#</li>');
    if (index == length){
        writeOutput("</ol>");
    }
}


listEach(numbers, toOL, "|");

Which outputs mark-up:

<ol>
    <li id="index_1">tahi</li>
    <li id="index_2">rua</li>
    <li id="index_3">toru</li>
    <li id="index_4">wha</li>
</ol>

So that was two examples: using it to create an updated data structure, or simply as a looping construct. Actually the toOL() UDF would probably be better done in tags, given we're outputting mark-up:

<cffunction name="toOL">
    <cfif index EQ 1>
        <ul>
    </cfif>
    <cfoutput><li id="index_#index#">#element#</li></cfoutput>
    <cfif index EQ length>
        </ul>
    </cfif>
</cffunction>

For the UDF I'll submit to CFLib (as above) the code is ColdFusion 10 / Railo 4.x only, but Rob was using CF8. However with a few cosmetic changes, this all works fine on CF8 too:
function listEach(list, callback, delimiters){
    var arr        = false;
    var arrLen    = false;
    var result    = [];
    var index    = 0; 

    if (!structKeyExists(arguments, "delimiters")){
        delimiters = ",";
    }

    arr = listToArray(list, delimiters);
    arrLen = arrayLen(arr);

    for (index=1; index <= arrLen; index++){
        arrayAppend(result, callBack(argumentCollection=arguments, index=index, element=arr[index], length=arrLen));
    }
    return result;
}

I just needed to change the function definition slightly, do my VARs at the top, and scope my arguments specifically in some places in the calling code:

function toOL(){
    if (arguments.index == 1){
        writeOutput("<ol>");
    }
    writeOutput('<li id="index_#arguments.index#">#arguments.element#</li>');
    if (arguments.index == arguments.length){
        writeOutput("</ol>");
    }
}

And that was it.

It's important to remember that people get confused when talking about closures and callbacks, and often use the word interchangably. And closure is only a facet of function expressions, and only available from CF10 / Railo 4.x. However being able to use callbacks has existed in CFML since CF5, and before Railo even existed.

None of this is terribly exciting, but maybe someone will find it helpful. Shrug.

Righto.

--
Adam

Sunday 13 October 2013

CFML: arraySetEach()

G'day:
I had a conversation on IRC the other day with Jason Dean about a shortcoming of arraySet().


The issue is that array set works like this:

arraySet(array, from, to, value)

So like this:

sameStructs = [];
arraySet(sameStructs, 1, 5, {});
sameStructs[3].foo = "bar";
writeDump(sameStructs);

Unfortunately - as you might guess from the variable name - ColdFusion only evaluates the value once - meaning each array element has the same structure. So this code outputs:

Thursday 25 July 2013

CFML implementation of Array.reduce()

G'day:
I've knocked out a quick arrayReduce() UDF, which I'll post on CFLib once I get some code review feedback (if any) on it. I'd appreciate sets of eyes on it, if you had time.

Update:
Adam Tuttle (only one mention today mate, sorry) offered some advice on Code Review, which I have taken onboard. This is the second iteration of the function. I have also updated the entry on Code Review too.

For the sake of completeness, here's the code, but pls feed-back on the Code Review page, as per link above:

/**
* @hint CFML implementation of Array.reduce(), similar to Javascript's one ref https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
* @array Array to reduce
* @callback Callback function to use to reduce. Will receive the following arguments: element (of current iteration of the all), index, array, (optional) result (of preceeding call to callback())
* @initialValue The initial value to use to start the reduction
*/
any function arrayReduce(required array array, required any callback, any initialValue){
    var startIdx = 1;
    if (!structKeyExists(arguments, "initialValue")){
        if (arrayLen(array) > 0){
            var result = callback(array[1], 1, array);
            startIdx = 2;
        }else{
            return;
        }
    }else{
        var result = initialValue;
    }
    for (var i=startIdx; i <= arrayLen(array); i++){
        result = callback(array[i], i, array, result);
    }
    return result;
}

If created a Gist with full(-ish) unit test coverage, too.

Ta.

--
Adam

Thursday 18 July 2013

replaceWithCallback() UDF for CFLib and suggested ER for ColdFusion

G'day:
I was looking up the docs for Javascript's String replace() function the other day (because, no, I could not remember the vagaries of its syntax!). And whilst being relieved I had remembered it correctly for my immediate requirements, I also noticed it can take a callback instead of a string for its replacement argument. How cool is that?

Wednesday 17 July 2013

CFML: My CFLib approval process

G'day:
A week or so ago there was some derision expressed that when approving UDFs submitted to CFLib we might change the code (for whatever reason). There was also derision expressed at how long it had thusfar taken to approve that person's UDF (it's still in the queue, and as far as I'm concerned: there it will stay for the foreseeable future... pretty much until everything else in the queue is cleared).

But due to this conversation I figured I might explain what it is I do when I approve a UDF. I cannot vouch for the process that Ray undertakes when he approves a UDF... this is simply the process I undertake. And I might perform some, all or none of these steps, as I see fit when doing the approving.

Monday 8 July 2013

Quick note: CFLib now accepting ColdFusion-10-specific UDFs

G'day:
This should possibly have happened a while back, but I suspect no-one's mentioned it until recently, so nothing was done about it.

When one submits a UDF to CFLib, one needs to specify which ColdFusion version it is for. It was possibly a bit of an oversight that until now "ColdFusion 10" was not on the selection list. It is now, and CFLib has had it's first submission (and approval) of a ColdFusion-10-specific UDF, from James Moberg: isImageCMYK().

There's a bunch of interesting stuff ColdFusion 10 can do with function-expressions, callbacks and closures, so perhaps you have a treasure trove of ColdFusion 10 stuff sitting on your hard drive that the community could benefit from? If so, please consider submitting it to CFLib. Cheers.

I'll have a poke around and see if I do. Although I've not done anything "production ready" on ColdFusion 10 yet.

--
Adam

Sunday 10 March 2013

Give me your tired, your poor your UDFs

G'day:
I've just had a "cflib afternoon", in which I remind myself I'm supposedly the moderator / approver on CFLib, which means I actually need to moderate / approve stuff every now and then.

Thursday 7 March 2013

Should a function handle its own threading?

G'day:
One of the UDFs I was triaging for CFLib was a function arrayDiff() which takes two arrays, and removes the elements from the second array from the first array.  For example if we called this code:

result = arrayDiff(["whero", "karaka", "kakariki"], ["karaka"]);

then result would be ["whero", "kakariki"].

This is a fairly useful sort of notion.

Wednesday 19 December 2012

When functions do too much, and how to get them to do more

G'day:
After soliciting more UDFs for CFLib a while ago, I've been dead slack at processing the inbound queue, and fixing some bugs people have found. Sorry about that. I started playing catch-up at lunchtime today: you might have noticed a coupla bugfixes bubbling through on Twitter if you follow the @cfbloggers feed.