05.31.07

Parenting Lessons from Animal Husbandry

Posted in General at 5:16 pm by BestFriendChris

This is pretty funny. This guy used to teach animal husbandry to teen volunteers at a wildlife rehabilitation center. Later he had a kid. He assumed that his experience teaching the teens would help him understand raising his kid. Turns out, his experience working with animals was better training.

Favorite quote? “Besides, the coolest things in life are gross.” :-) Too true…

The take away for me? Babies are animals.

05.11.07

Apache vs. Yaws

Posted in Erlang at 12:04 pm by BestFriendChris

Ok. I know I already posted today, but this was just cool. A performance diagram comparing Apache to Yaws (An Erlang webserver). Apache dies at around 4,000 parallel sessions, while yaws still works at 80,000. Amazing.

EUnit vs ErUnit

Posted in ErUnit at 8:15 am by BestFriendChris

I recently was pointed to this article by pragdave about test-first development in Erlang with EUnit. I’m going to use his examples to show you how it would be done in ErUnit instead. First, some history…

The reason I wrote ErUnit instead of just using EUnit is for a couple of reasons

  1. The best way to learn a language is to reimplement xUnit. There’s so much meta stuff going on that it really requires you to dig in the language. And when I say reimplement, I don’t mean, “Follow the xUnit spec exactly.” What I mean is leverage the things that make the language good to create a good fit.
  2. I didn’t see it on the web. Mostly because I assumed EUnit was for the E programming language. So, I searched for ErUnit and found nothing…
  3. Even after I found out about EUnit, it didn’t gel with me. Now, that might be due to there not being any good tutorials that I could find, but I just wasn’t seeing it. I don’t like using macros specifically for assertions as it makes the failures hard to debug.
  4. I really don’t like having your tests live in the same file as your production code… It makes your code much harder to understand if you have to double the size of the file just to test it…
  5. I’m not a big fan of the standard that I saw of using pattern matching for the tests. I personally think there should be a difference between a failed assertion and a failed pattern match within your code, and I don’t know how to make that distinction.

A huge benefit of going with EUnit is that it is MUCH more mature than ErUnit. I’m still tweaking it as need arises. One thing that I’m not sure if it really matters yet is all tests are run in their own thread, concurrently. I did that because it seemed super easy and fun to do, but I don’t know if you really get any benefit with that yet…

Well, on to creating a word wrap utility, test first, with ErUnit.

ErUnit in >60 Seconds

When creating a ErUnit test, you first name the file starting with “test_”. In our example below, when testing “text.erl”, we create the test file “test_text.erl”. ErUnit, with erunit_suite, has the convention of either:

  • If your code and tests are in the same folder, add that folder to the path
  • If your code is in the “ebin” folder and the tests are in the “ebin_tests” folder, adding both folders to the path

This allows you to break up the tests from the code it’s testing pretty easily. Within the test class, you have to add the erunit_test behaviour. Behaviours in Erlang (well, technically the OTP library in Erlang) are used to define what callback functions are required. In this case, the erunit_test callback requires a function call “tests” with no arguments to be exported.

I personally also add a no argument “run” function that just delegates to erunit:run() with the tests passed in. I also like to import all of the erunit functions I’m going to be using (test/2, assertEquals/2, run/1) and the functions I’m going to be testing. This makes the code later on easier to read.

The file so far is:

-module(test_text).

-behaviour(erunit_test).
-export([tests/0, run/0]).

-import(erunit, [test/2, assertEquals/2, run/1]).
-import(text, [wrap/1]).

run() ->
	run(tests()).

As mentioned earlier, you must declare a no argument function called “tests”. All this returns is an array of tests. So, for the first example we want to test that the “wrap” function works with no words.

tests() ->
		[
			test("Should wrap no words", fun() ->
				assertEquals([""], wrap([]))
			end)
		].

When you use the erunit:test/2 function, you pass in the description of what you’re testing and a fun/0 of the actual test. assert(Description, true-false-test), assertEquals(First, Second), assertEquals(Description, First, Second), and fail(Description) are all currently implemented. Behind the scenes, the “test” function spawns a new thread that will run the fun/0 and send the answer back to the current test runner thread.

The code for the “text” module is the same as in pragdave’s example, so I won’t repeat it here. In fact, I’m just going to show you the entire test file:

-module(test_text).

-behaviour(erunit_test).
-export([tests/0, run/0]).

-import(erunit, [test/2, assertEquals/2, run/1]).
-import(text, [wrap/1]).

run() ->
	run(tests()).

tests() ->
		[
			test("Should wrap no words", fun() ->
				assertEquals([""], wrap([]))
			end),

			test("Should wrap one word", fun() ->
				assertEquals(["cat"], wrap(["cat"]))
			end),

			test("Should wrap two words", fun() ->
				assertEquals(["cat dog"], wrap(["cat", "dog"]))
			end),

			test("Should wrap when more than 10 chars long", fun() ->
				Expected = ["cat dog", "elk"],
				assertEquals(Expected, wrap(["cat", "dog", "elk"]))
			end),

			test("Should allow word larger than 10 on its own line", fun() ->
				Expected = ["cat dog", "hummingbird", "ibix"],
				Actual = wrap(["cat", "dog", "hummingbird", "ibix"]),
				assertEquals(Expected, Actual)
			end)
		].

The output when running from erl is:

1> test_text:run().
.....
ok
2>

When a test fails with this extra test added:

			test("This will fail", fun() ->
				erunit:fail("Called erunit:fail/1")
			end),

…you get…

1> test_text:run().
....F.
-"This will fail" failed:
        Called erunit:fail/1
fail
2>

To show an error, this is the test:

			test("This will have an error", fun() ->
				erunit:assert("This method does not work with a integer", wrap(1))
			end),

…which produces…

1> test_text:run().
....E.
-"This will have an error" had error:
        error:function_clause
                {erunit,'-test_process/3-fun-0-',3}
fail
2>

…Not the best error message, but I’m working on it. :-)

05.03.07

m15m

Posted in General at 10:33 pm by BestFriendChris

I recently rediscovered the wonderful Movies in 15 Minutes. If you’ve never heard of this, you really need to check it out. Cleolinda Jones is a genius. *joygasm*

She also has a book out. The odd thing is that while she’s born and raised here in the united states, you can’t actually buy her book here. I bought my copy from amazon.co.uk.

Here are a couple of excerpts from a couple of the online movies:

Harry Potter and the Goblet of Fire in Fifteen Minutes

The Champion Is Selected

DUMBLEDORE: We are gathered here now to choose one person (who is not Harry Potter) to represent each school, but only one (who is not Harry Potter) will achieve eternal fame and glory in the Triwizard Tournament, in which Harry Potter is not old enough to compete!

[Only characters we’ve already seen in closeup are chosen: Krum, the famous one! Cedric, the pretty one! Fleur, the uppity one!]

SNAPE: Professor…? About that…

THE GOBLET OF FIRE: *coughHARRYPOTTERcough*

The Trophy Room

[All the professors race downstairs so everyone can shriek at Harry in privacy, while the newly-chosen champions watch uncomfortably.]

MOODY: Oh, come on, Potter didn’t do it! Look at the kid, he can’t even comb his hair!

DUMBLEDORE [throttling]: DID YOU DO IT, HARRY? DID YOU PUT YOUR NAME IN THE GOBLET? ANSWER ME, YOU LITTLE SHIT! JUST GO AHEAD AND DIE IF YOU’RE THAT STUPID, SEE IF I CARE!

HARRY [choking]: This—this is not mellow!

FLEUR: L’awkward.


The Prestige in Fifteen Minutes

Julia’s Funeral


ANGIER: WOLVERINE COULD TOTALLY KICK BATMAN’S ASS.

BORDEN: YOU TAKE THAT BACK!

[And thus, a rivalry is born.]

Angier’s Cunning Plan

OLIVIA: So what you’re saying is, you want me to go to Borden, offer to work for him, tell him you sent me to find out his secrets, and then somehow actually get him to tell me his secrets?

ANGIER: Basically, yeah.

OLIVIA: You realize that this is probably going to involve me sleeping with him?

ANGIER: Ride ‘em, cowgirl.

Angier’s Plan: Not So Cunning As Previously Thought

BORDEN: So what you’re saying is, Angier sent you here to work for me and fake me out by telling me you really came to find out my secrets, but you really really came here to sell him out? And I’m supposed to believe that?

OLIVIA: You’re forgetting that I also kind of hate him now.

BORDEN: Hey, we have something in common, then.

OLIVIA: So, sex?

BORDEN: Sure thing.

05.02.07

Chris-mas comes early?

Posted in General at 2:33 pm by BestFriendChris

I just received an email from Hammacher Schlemmer announcing their brand new sale:

Words fail me1. I’m just wondering who decided that May 2nd was the best time to sell/buy pre-lit chris-mas trees… I suppose the bigger question is, “Will they stay lit all the way into December, or should I just open my presents now?”

1. Which, of course, won’t keep me from commenting