Thursday 31 July 2014

CFML switches: how they're implemented in the underlying Java

G'day:
This is just a quick follow-up tot he earlier article "Cool (I think?) Railo can have dynamic case values". Michael was wondering out loud what the CFML gets compiled down to in Java (well: he was talking bytecode, but samesame).

Cool (I think?) Railo can have dynamic case values

G'day:
Thanks to NicholasC from IRC for putting me onto this. Apparently in Railo, one can have dynamic values for case values in a switch/case!

Tuesday 29 July 2014

Embryonic ideas

G'day:
This is gonna have to be quick, as I've spent my "before work" blogging window chatting on Twitter / Skype with various people. So I need to get this out the door in the next 30min.

Over the last week, a coupla interesting (well...) ideas have been presented to me by way of community projects. Which I might undertake.

Monday 28 July 2014

CFML survey results: scoping of variables-scope variables

G'day:
So I'll close off the survey "Survey: to scope or not to scope" now. I got a good level of response: 79 responses. Here's the aggregation of said responses. Including some charts just for you, Phil Duba.

Sunday 27 July 2014

7Li7W: Ruby Day 1

G'day:
That's short of "Seven Languages in Seven Weeks", btw: some ppl get arsey when I write about non-CFML stuff on a blog claiming to be about CFML, so it's an enabler for them to know to piss off and do something else instead of read this.

Friday 25 July 2014

<?cf ?>

G'day:
I was thinking about this independently the other day, but then the same question came up on Stack Overflow today: "Is there a shorthand for <cfoutput>", in which the punter asks if this sort of thing is possible in CFML:

<input name="LastName" <?> value="#FORM.LastName#" </?> />

Where <?> / </?> is shorthand for <cfoutput>.

Thursday 24 July 2014

Survey: to scope or not to scope

G'day:
And, indeed as the old trope goes: "that's the question". I have been looking at some code that follows one coding standard, which says "thou shalt scope all variables". And I look at my code, in which I only scope when needed, and I really feel the former is a pile of... clutter compared to my own code.

However the scope of my own code is much narrower and much less mission critical. And only I work on it. So just because I prefer to do something a given way which specifically suits me doesn't mean that's the best way to do it.

So I want to know how you do it. And with that in mind, here's a survey for you to fill out, if you so choose: "Scoping of variables scope variables".

Wednesday 23 July 2014

CFML: Finally had a chance to look at Sean's version of case()

G'day:
This took way longer to revisit than I intended. Apologies to Sean, as it might have seemed like I solicited some code from him and then ignored it. And, indeed, that was mostly the case other than an initial peek and a "hang on... what? How the? But... oh, I think I see..." and a conclusion my assessment of it needed more than 2min.

Right, so a coupla weeks back I wrote and article "Some more TestBox testing, case/when for CFML and some dodgy code". This demonstrated some code (and its tests) that I was messing around with that implemented a case/when/then/else function in CFML. That'll make more sense if you read the article.

Sean had a look at it and could see some simplifications which could be made, and popped a revised version through to me via Github ("adamcase / case.cfm"). As I alluded to above, my initial parsing of the solution just made my eyebrow raise - Spock-like - and other than that I saw what he was doing, but not how it worked (and it did work; the relevant tests still passed). Today I sat down and had a look at the code, and made myself understand it. And I like it.

Here it is:

Tuesday 22 July 2014

I'm sick of vendors screwing up CFML

G'day:
AAARRRGGGGHHHH!!!

How hard does any of this need to be? I'm posting this here and against the Railo bug report I started typing it into "CFHTTP accept callback UDF to report progress" (RAILO-3131). As it's stroppy, Micha should feel welcome to delete it from Jira. However it's staying here.

Saturday 19 July 2014

Different bugs in each() function in each of Railo and ColdFusion

G'day:
A quick one. I was investigating a bug in Railo, detailed in "Arguments - Struct or Array", and as well as verifying the bug in Railo, I found a different one in ColdFusion.

Oh dear: tags vs script in CFML

G'day:
I'm surprised this one didn't come up earlier (like back when I did this one: "/>"). But Marcus Fernstrom and I started talking about this last night on Twitter, and - despite "best" efforts - I've concluded 140-char-limits are just stupid for such things.

My personal opinion regarding CFML code is that tags are very clunky, and in modern code seldom have an appropriate place in one's code, compared to the clarity and comparative elegance of CFscript-based code.

Some people will already feel their undies bunching up at this point... get over yourselves. This is just my opinion. You're entitled to yours, I'm entitled to mine. This is my blog, so we're getting mine.

Thursday 17 July 2014

Warning: don't de-install patches from ColdFusion 10

G'day:
Here's a warning... it's a bit of an edge-case, but worth knowing. I just tried to de-install some patches from two of my ColdFusion 10 servers, and in both cases it has rendered CF Administrator inaccessible due to a ColdFusion error.

My position on running ColdFusion 11.0.0 in production

G'day:
I've seen a few people claim they're about to go into production with ColdFusion 11. My reaction to that is "are you a lunatic" (note lack of question mark).

Where are the ColdFusion 10 & 11 updates, Adobe?

G'day:
Here's a quick thought that's been bugging me for a month or two now. What's happened with the ColdFusion updater?

Checking Wikipedia, the update history for ColdFusion 10 is as follows:
2012-May-15: Adobe ColdFusion 10 (build 10,0,0,282462)
2012-August-31: Adobe ColdFusion 10 Update 1 (build 10,0,0,282462)
2012-September-11: Adobe ColdFusion 10 Update 2 (build 10,0,0,283111)
2012-October-16: Adobe ColdFusion 10 Update 3 (build 10,0,3,283145)
2012-November-02: Adobe ColdFusion 10 Update 4 (build 10,0,4,283281)
2012-November-19: Adobe ColdFusion 10 Update 5 (build 10,0,5,283319)
2012-December-11: Adobe ColdFusion 10 Update 6 (build 10,0,6,283435)
2013-January-15: Adobe ColdFusion 10 Update 7 (build 10,0,7,283649)
2013-February-27: Adobe ColdFusion 10 Update 8 (build 10,0,8,284032)
2013-Apr-10: Adobe ColdFusion 10 Update 9 (build 10,0,9,284568)
2013-May-14: Adobe ColdFusion 10 Update 10 (build 10,0,10,284825)
2013-July-09: Adobe ColdFusion 10 Update 11 (build 10,0,11,285437)
2013-November-12: Adobe ColdFusion 10 Update 12 (build 10,0,12,286680)
2014-January-10: Adobe ColdFusion 10 Update 13 (build 10,0,13,287689)

So there's a steady stream of updates and hotfixes there, up until Jan this year. Then nothing for over six months now. And it's not as if there's no bugs to fix in ColdFusion 10. I posted some analysis of "significant" ColdFusion 10 bugs a while back: "What should Adobe be retro-fitting into ColdFusion 10? Here's a potential list", and there's a reasonable case that Adobe should be dripping out fixes from that list (or similar) pretty much constantly. But nothing.

Some will leap to Adobe's defence saying "but they were busy working on ColdFusion 11", sorry but we oughtn't give a shit. Life goes on, and we've already paid for ColdFusion 10, so they should be making good on the bill of goods they're already sold us before prioritising the next thing they expect us to buy.

I also think by now there ought to have been a few hotfixes for ColdFusion 11... it's not short in the bug / half-finished department either.

So what's going on, Adobe?

--
Adam

Tuesday 15 July 2014

2

G'day:
I'm frickin' lousy with dates (as in "calendar", not as in "romance". Although the same applies, from memory ;-). Well: remembering dates is never a problem, but remembering what the current date is is something I'm not so good at. I forgot to touch base with my big sister on her birthday over the weekend... and there's another anniversary on the same day.

I've been doing this bloody blog for two years now. Which is approximately 23 months longer than I expected it to last.


Last year I gave you some stats ("1"). I'll try to do the same now.

  • I've now published 750 (this'll be the 751st) articles. I still have about a dozen in progress. The same ones as last year, funnily enough. The topics just don't have legs, I think.
  • And the word tally is now up around 600000 words. So in the second year I didn't write quite as much as the first year (350000), but spread over more articles (428 in the last 12 months vs 322 in the first year).
  • I've had another 3000 comments since the previous year's 2000. That's pretty cool. Thanks for the contributions everyone. Often the comments are more interesting than the articles, I find.
  • Google Analytics claims I've had 86000 visitors over the last year (up from 25k in the first year). So this thing is getting more popular. The average per day is 230-odd. It was around 120/day in year one. It's still not a huge amount of traffic, but I guess my potential audience is pretty small too.
  • The busiest day in the last 12 months was 5 March 2014, with 593 visitors. That was towards the end of the isValid() saga, with this article: "ColdFusion 11: Thank-you Carl, Mary-Jo, many other community members and indeed Rupesh", and a click-chasing one entitled "CFML is dying. Let's drop it off at Dignitas". Looking at the analytics, that was the bulk of it, plus I was writing a lot about new features in ColdFusion 11 around about then, which boosted things. That was also my biggest week ever, by quite a margin.
  • The most popular article last year was the one about me migrating from "ColdFusion Builder to Sublime Text 2". That's had 2200 visitors. The next most popular were as follows:
  • The most +1'ed article was "I am one step closer to being unshackled from ColdFusion". It's interesting that that was the one that people liked the most. It had 13 +1s. Most articles get none or maybe one, so that's quite a lot.
  • Last year I worked out which article had the most comments. I have no idea how I did that, and I can't be bothered working it out again. So erm... that'll remain a mystery.
I've blogged a lot about ColdFusion 11 during the year... what with it being in public beta and then being released. I've also compared its functionality to Railo's equivalents. I've shifted my primary dev platform at home to Railo now. I've done a lot of JavaScript over the last 12 months (I've spared you most of the detail), but haven't progressed in other languages as much as I'd like to. That's my mission for the next year.

I battered Adobe a lot about how they (don't) handle their bugs. I will continue to do this. They're long overdue for an updater to ColdFusion 10, for one thing; plus we should have had at least a coupla small updates to ColdFusion 11 by now.

The biggest shift in my coding practices in the last year has been down to reading Clean Code, and adopting a lot of its suggestions. My code is better for it. I've got my colleagues Chris and Brian to thank for this... both the encouragement to read the book, but also keeping at me about it. Sometimes to great irritation on my part. If you have not read that book: do so. Especially if you're either of the two members of our team who still haven't read it. Ahem.

Another thing I've been fascinated with this year gone is TestBox. I love it. I am looking forward to shifting off ColdFusion 9 at work so we can start converting our MXUnit styled tests to BDD ones. Brad and Luis are dudes.

I've bitched a lot about Stack Overflow, but contrary to what I threatened ("Not that it will really matter in the bigger scheme of things..."), I still answer questions there every day (if I can find questions I can answer, that is).

Railo continues to rock. As do Gert, Micha, Igal from Railo. They really have done brilliant work keeping CFML alive and interesting.

A bunch of people have motivated me to write this year... it's too difficult to pull out a list of the main miscreants, but Sean would be the top. And the list of my various muses (or adversaries!) is - as always - on the right hand side of the screen, over there.

Gavin deserves special mention, as he very kindly tried to raise money to get me across to CF.Objective() ("Shamelessful plug"), but we had to kill that plan just as it was getting started ("Do not sponsor me to go to CF.Objective()"). But happily Gert stumped up with a ticket at the last minute ("Well that was unexpected"), so I made it anyhow. I really am taken aback by you guys. Seriously.

And of course Mike from CFCamp paid for my entire conference last year too ("CFCamp 2013"). That was amazing. And I mean both Mike's generousity, and the conference itself. Go to it this year if you can: CFCamp.

Ray's done most of the work for ColdFusion UI the Right Way, but I've helped out a bit. I'm glad we got going with that project.

Thanks for your participation in this blog, everyone. If you weren't reading it or commenting on it, I'd've chucked it in. But you keep coming back. Cheers.

Oh and let's not forget: <cfclient> sucks arse. And I can tell that without using it, Dave Ferguson ;-)

--
Adam

Survey Results: A REST API

G'day:
A few days back I ran a survey on Survey Monkey asking:

A client has a rusty-old SOAP API written in CFML which needs overhauling. We possibly have the opportunity to rewrite it. The rest of the codebase is CFML, and the team's strengths lie in CFML and C#, with passable clientside JS. This survey is soliciting community advice as to which language we should considerfor this implementation.

Note: for the purposes of this survey, the existing skill set is a reasonable consideration, but not necessarily the only one.

I've had 54 responses for it, so I'll call time on the responses and summarise them here.

The bottom line is:

Option%ageVotes
CFML53.70%29
Node.js22.22%12
Groovy1.85%1
Clojure0.00%0
Scala0.00%0
Ruby1.85%1
Python1.85%1
C#9.26%5
Other (please specify)9.26%5

Query.cfc et al functions have file-reads and server-wide exclusive locks buried in their code

G'day:
Today's muse is Henry, with this Twitter status message:


Monday 14 July 2014

parameterExists() and stuff like that

G'day:
This is a fairly old school topic. TBH, the mention of parameterExists() was mostly to get your click through, but I do mention it along the way.

Yesterday (note: it's taken me a few days to finish this article... I mean "on July 10") Justin Hall put this out on Twitter:


Reminder: REST API survey

G'day:
I'm still a few submissions shy of enough to warrant aggregating 'em, so if you haven't done my REST API survey ("A new survey: which language would you use to develop a new REST API?"), it'd be cool if you did. The survey URL is https://www.surveymonkey.com/s/96XVQGR.

I'll report back on the results tomorrow, either way.

Thanks to the people who already have completed it, I've got some really thoughtful responses in there.

Cheers.

--
Adam

Odd: one cannot have a <cfbreak> within a <cfcase>

G'day:
This is an odd one. This morning I was looking at a StackOverflow question ("ColdFusion cfcase statements and referencing their variables?") which had me writing a <cfswitch> statement which had some compound logic in it which was best served by having an explicit <cfbreak> statement:

Sunday 13 July 2014

Seven Languages [etc], and how guilt tripping me tends to work

G'day:
A few weeks ago Sean piped-up about the sequel to "Seven Languages in Seven Weeks":

Seven more languages? I hadn't even looked at the first seven yet :-|

I do actually have the first book at home (Marcos, I must give it back to you), but haven't really opened it.

However then this happened:

I claim I don't "do" peer-pressure, but it seems to have worked this time. I'm over in Ireland @ the mo', so don't have the book with me, but bought my own soft-copy of "Seven Languages in Seven Weeks" y/day, and have commenced working through it. And once I've done that, I will consider moving on to the sequel.

The first language is Ruby which I've done a bit of already, and at the end of Day 1 I have not covered anything I didn't already know or haven't already actually covered on this blog:


However the writing style is accessible, and I've now paid to learn this stuff, so I had better work through it.

I'll keep you up to date as I go (and guilt trip me if I do not!). In the mean time, Ben Nadel did all this stuff years ago, so maybe go read what he had to say on the topic: "Seven Languages In Seven Weeks: A Pragmatic Guide To Learning Programming Languages By Bruce Tate". There are links to each day's progress at the bottom. I think perhaps I'll go read them myself.

This seems a bit of a pointless article, outwardly. The general gist is that once I have said I am going to do this stuff, I want you to give me a hard time if I go not. I'm crowd-sourcing motivation, it seems.

But short-term... I'm done with programming for the weekend. I shall now resume drinking Guinness and waiting for my flight. And probably pass the time with a DVD rather than with code.

Righto.

--
Adam

ColdFusion: some built-in functions aren't actually functions. It seems.

G'day:
This caught me out the other day, but I've just now had a change to have a look at it some more. In ColdFusion (as distinct from Railo) some built-in CFML functions such as writeLog(), throw() and writeDump() aren't actually functions. Or aren't implemented properly if they are.

Saturday 12 July 2014

Oh dear. I am a big meany again

G'day:
This greeted me in my in box just now:

Adam,
We can do without some of the petty comments and downvotes and suggested closures from people such as yourself on Stackoverflow.
Thanks,
[person's name provided]

Friday 11 July 2014

A new survey: which language would you use to develop a new REST API?

G'day:
SSIA, really. As per the survey intro text:

A client has a rusty-old SOAP API written in CFML which needs overhauling. We possibly have the opportunity to rewrite it. The rest of the codebase is CFML, and the team's strengths lie in CFML and C#, with passable clientside JS. This survey is soliciting community advice as to which language we should considerfor this implementation.

Note: for the purposes of this survey, the existing skill set is a reasonable consideration, but not necessarily the only one.
The survey is here: "A REST API". It's only two questions - one multi-choice to pick a language, and one to explain why.

Once I get a reasonable amount or replies, I'll aggregate them in a follow-up article.

Do not, however, just comment against this article. Fill-in the survey. I will not be paying attention to the comments against this article when it comes to aggregating the results.

Oh, and hey... if your reach is outside of the CFML community, it'd be cool if you could forward this on to your colleagues who focus on other languages too. It is a major consideration that the codebase & personnel are heavily CFML and C# influenced, but it's only one consideration. I like the idea of trying to diversity from those languages, if possible.

Cheers!

--
Adam

Quickly: read Sean's comments and code

G'day:
I said this on Twitter last night, but in case you're wise enough not to busy yourself with that sort of nonsense, I'll repeat it here.

A few days ago I posted some woolly code which implemented a case / when in CFML ("Some more TestBox testing, case/when for CFML and some dodgy code"), and solicited help in improving it.

Sean's leapt to the fore and reworked it in a much more clean fashion. His comments start here, and there's links to his code. He's put a lot of effort into it, and I'm quite chuffed he's taken the time that he has.

So thanks, Sean. And everyone else: you could learn a thing or two by comparing my effort and his approach to tidying it up.

I haven't analysed his code thoroughly myself yet - I've just had no time - but will be doing so over the weekend, and will write up my conclusions.

Again: thanks Sean.

--
Adam

Thursday 10 July 2014

CFML: This always trips people up: the difference between listContains() and listFind()

G'day:
This question came in via email. Fortunately (given my reaction the other day "I'm not Ben Nadel (or Ray Camden)") this one was suggesting a blog article, and a blog article it shall receive. The email was about listContains(), as is as follows:

I just wanted to throw this out there for you as a possible blog post if you’re interested. I was working on some code which I was running through an array of structures. Anyhow, as I loop the structure, I have an if condition ListContainsNoCase(“label,fieldtype”,KEY). One of the keys is “type” which was causing the dynamic form not to display correctly. When I remove the “fieldtype” from the list, the form works. I was removing “fieldtype” so that it’s not an attribute of the field. I thought it was interesting that it’s looking at the word “type” within “fieldtype” vs. looking at the comma delimited list instead and looking at the word as a whole.
Unfortunately the person here is falling foul of something I think everyone falls foul of... when they're seeing is exactly what's expected, and exactly how listContains() (and listContainsNoCase() works).

Here's what it says in the docs ("listContains()"):

Regex help please

G'day:
I'm hoping Peter Boughton or Ben Nadel might see this. Or someone else who is good @ regular expression patterns that I'm unaware of.

Here's the challenge...



Given this string:

Lorem ipsum dolor sit

I want to extract the leading sub-string which is:
  • no more than n characters long;
  • breaks at the previous whole word, rather than in the middle of a word;
  • if no complete single word matches, them matches at least the first word, even if the length of the sub-string is greater than n.

I've come up with this:

// trimToWord.cfm
string function trimToWord(required string string, required numeric index){
    return reReplace(string, "^((?:.{1,#index#}(?=\s|$)\b)|(?:.+?\b)).*", "\1", "ONE");
}

It works, but that regex is a bit hoary.

Here's a visual representation of it (courtesy of regexper.com), by way of explanation:



Anyone fancy improving it for me?

Here's some unit tests to run your suggestions through:

Wednesday 9 July 2014

Some more TestBox testing, case/when for CFML and some dodgy code

G'day:
This is an odd one. I was looking at some Ruby code the other day... well it was CoffeeScript but one of the bits influenced by Ruby, and I was reminded that languages like Ruby and various SQL flavours have - in addition to switch/case constructs - have a case/when construct too. And in Ruby's case it's in the form of an expression. This is pretty cool as one can do this:

myVar = case
    when colour == "blue" then
        "it's blue"
    when number == 1 then
        "it's one"
    else
        "shrug"
end

And depending on the values of colour or number, myVar will be assigned accordingly. I like this. And think it would be good for CFML. So was gonna raise an E/R for it.

But then I wondered... "Cameron, you could probably implement this using 'clever' (for me) use of function expressions, and somehow recursive calls to themselves to... um... well I dunno, but there's a challenge. Do it".

So I set out to write a case/when/then/else/end implementation... as a single UDF. The syntax would be thus:

// example.cfm
param name="URL.number" default="";
param name="URL.colour" default="";

include "case.cfm"

result =
    case()
        .when(URL.number=="tahi")
            .then(function(){return "one"})
        .when(function(){return URL.colour=="whero"})
            .then(function(){return "red"})
        .else(function(){return "I dunno what to say"})
    .end()

echo(result)

This is obviously not as elegant as the Ruby code, but I can only play the hand I am dealt, so it needs to be in familiar CFML syntax.

Basically the construct is this:

case().when(cond).then(value).when(cond).then(value).else(value).end()

Where the condition can be either a boolean value or a function which returns one, and the value is represented as a function (so it's only actually called if it needs to be). And then when()/then() calls can be chained as much as one likes, with only the then() value for the first preceding when() condition that is true being processed. Clear? You probably already understood how the construct worked before I tried to explain it. Sorry.

Anyway, doing the design for this was greatly helped by using the BDD-flavoured unit tests that TestBox provides. I could just write out my rules, then then infill them with tests after that.

So I started with this lot (below). Just a note: this code is specifically aimed at Railo, because a few things I needed to do simply weren't possible with ColdFusion.

// TestCase.cfc
component extends="testbox.system.BaseSpec" {

    function run(){
        describe("Tests for case()", function(){
            describe("Tests for case() function", function(){
                it("compiles when called", function(){})
                it("returns when() function", function(){})
            });
            describe("Tests for when() function", function(){
                it("is a function", function(){})
                it("requires a condition argument", function(){})
                it("accepts a condition argument which is a function", function(){})
                it("accepts a condition argument which is a boolean", function(){})
                it("rejects a condition argument is neither a function nor a boolean", function(){})
                it("returns a struct containing a then() function", function(){})
                it("can be chained", function(){
                })
                it("correctly handles a function returning true as a condition", function(){})
                it("correctly handles a function returning false as a condition", function(){})
                it("correctly handles a boolean true as a condition", function(){})
                it("correctly handles a boolean false as a condition", function(){})
            })
            describe("Tests for then() function", function(){
                it("is a function", function(){})
                it("requires a value argument", function(){})
                it("requires a value argument which is a function", function(){})
                it("returns a struct containing when(), else() and end() functions", function(){})
                it("can be chained", function(){})
                it("executes the value", function(){})
                it("doesn't execute a subsequent value when the condition is already true", function(){})
                it("doesn't execute a false condition", function(){})
            })
            describe("Tests for else() function", function(){
                it("is a function", function(){})
                it("requires a value argument", function(){})
                it("requires a value argument which is a function", function(){})
                it("returns a struct containing an end() function", function(){})
                it("cannot be chained", function(){})
                it("executes when the condition is not already true", function(){})
                it("doesn't execute when the condition is already true", function(){})
            })
            describe("Tests for end() function", function(){
                it("is a function", function(){})
                it("returns the result", function(){})
                it("returns the result of an earlier true condition followed by false conditions", function(){})
                it("returns the result of the first true condition", function(){})
            })
        })
    }
}

TestBox is cool in that I can group the sets of tests with nested describe() calls. This doesn't impact how the tests are run - well as far as it impacts my intent, anyhow - it just makes for clearer visual output, and also helps me scan down to make sure I've covered all the necessary bases for the intended functionality.

I then chipped away at the functionality of each individual sub function, making sure they all worked as I went. I ended up with this test code:

Tuesday 8 July 2014

Couldn't have said it better: Brad explains objects in CFML

G'day:
I'm being a bit lazy here... I'm just pointing you towards some reading. Brad does a great job of answering a question on StackOverflow: "Behavior of creating objects in ColdFusion".

Go have a read.

--
Adam


Monday 7 July 2014

Doh!

G'day:
Actually it was pretty easy to reinstate the comments (the process has improved and is more reliable since the last time I had to do it), and rejig the template. I think everything is OK now?

Lemme know if not.

Righto.

--
Adam

Doh!

G'day:
So... yesterday I was monkeying with my blog templates, and I inadvertently wiped all my customisations. And did I do a back-up? Of course I didn't.

So, yeah, it's not working or looking quite right @ the moment. I have also switch off commenting as I don't want them to go to the default Blogspot commenting system.

Normal service will be returned... at some point before too long, but I am not working on it immediately as there are bigger fish to fry just now.

Sorry 'bout that.

--
Adam

Sunday 6 July 2014

Both ColdFusion and Railo make an incomplete job of validating email addresses

G'day:
A question came up on StackOverflow just now "new to coldfusion. is there any function that defines Email is typed correctly" (how hard, btw, is it to give a coherent title to one's question? [furrow]).

My initial reaction was along the lines of "RTFM, and if you had, you'd see isValid() validates email addresses". However I also know that isValid() is very poorly implemented (see a google of "site:blog.adamcameron.me isvalid" by way of my findings/rantings on the matter).

So I decided to check how reliable it actually is.

The rules for what constitutes a valid email address a quite simply, and a laid out very clearly in various RFCs. Or if one can't be bothered doing that (although the engineers & Adobe and Railo should be bothered), then they're fairly comprehensively defined even on Wikipedia: "Email_address (Syntax)". I found that page by googling for it.

Anyway, I won't bore you by replicating the rules here, but I wrote some TestBox tests to test all the rules, and how isValid() supports them. The answer to this on both ColdFusion (11) and Railo (4.2) is "only to a moderate level". This is kinda what I expect of the Adobe ColdFusion Team (this is the level of quality they seem to aim for, generally, it seems), but am pretty let down by the Railo guys here.

I won't reproduce all the code here as it's long and boring, but it's on GitHub: "TestIsValidEmail.cfc".

Anyhow, the bottom lines are as follows:

ColdFusion:


Railo:


Railo did slightly better, but ran substantially slower (running on same machine, same spec JVM).

I hasten to add that 50 of those tests were testing the validity of individual invalid characters, so that blows the failures out a bit (given they pretty much all failed). But both also failed on some fairly bog-standard stuff.

It's seriously as if it didn't occur to the engineers involved to actually implement the functionality as per the published specification; instead they simply made some shit up, based on what their own personal knowledge of what email addresses kinda look like. This is a bit slack, I'm afraid, chaps. And would just be so easy to do properly / thoroughly.

NB: there are rules around comments in email addresses that I only gave superficial coverage of, but I covered all the other rules at least superficially in these tests.



One new TestBox thing which I learned / noticed / twigged-to today... one can write test cases within loops. One cannot do that with MXUnit! eg:

describe("Tests for invalid ASCII characters", function(){
    for (var char in [" ", "(", ")", ",", ":", ";", "<", ">", "@", "[", "]"]){
        var testAddress = "example#char#example@example.com";
        it("rejects [#char#]: [#testAddress#]", function(){
            expect(
                isValid("email", testAddress)
            ).toBeFalse();
        });
        testAddress = '"example#char#example"@example.com';
        it("accepts [#char#] when quoted: [#testAddress#]", function(){ 
            expect(
                isValid("email", testAddress)
            ).toBeTrue();
        });
    }
});

Here I loop through a bunch of characters, and Here for each character perform two tests. This is possible because testBox uses function expressions for its tests, whereas MXUnit uses declared functions (which cannot be put in loops). This is not a slight on MXUnit at all, because it predates CFML's support for function expressions; it's more just that I'm so used to having to write individual test functions it did not occur to me that I could do this in TestBox until today. I guess there's nothing stopping one from writing one's test functions as function expressions in MXUnit either, that said. But this is the encouraged approach with TestBox.

Nice one, TestBox.

Anyway, this is not helping me prep for my presentation tomorrow. Give me a ballocking if you hear from me again today, OK?

--
Adam

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.

Saturday 5 July 2014

Code for annotation highlighter

G'day:
As mentioned a coupla days ago ("Attempting a new approach to annotating code"), I've decided my approach to annotating my code examples - by colour-highlighting the lines of code I want to discuss, and then cross-referencing that back into the notes - doesn't work so well when there's lots of stuff to discuss. So I decided to come up with a different approach.

Thursday 3 July 2014

Sneaky...

G'day:
A few days ago I mentioned that "Adobe apparently cease development and/or support of UI tags in ColdFusion". This was because one of their dudes said as much (this was on 3043516):



Ray sniffed into this - as it didn't sound right to him, and confirmed it was not actually the case. I've been holding off on adjusting my initial comment until I got clarification from the ColdFusion Team themselves.

I had followed up Uday's comment with the observation that it's all well and good to deprecate the UI stuff, but some customers have already in good faith paid for these features, so there really is a professional burden on Adobe to fix the bugs that people have raised, rather than basically just go "[nothing to see here, move along]".

Attempting a new approach to annotating code

G'day:
My code examples recently have been getting very bloody cluttered with highlighting, so I'm just using this article to experiment with a new approach. I need to test the CSS and JS in a live article, so need to publish something to test it. There is nothing interesting in this article. Don't read it. It's just a scratch pad for me to test my new solution.