About Jamie on Software

Jamie on Software is the online journal of web developer and writer Jamie Rumbelow.

Jamie likes books, guitars, programming, open source and food. He writes about these things too. This is where he puts the things he writes.

My Books

Tags
Tweets
Feeds
We Love
Powered by Squarespace
Friday
May182012

Peru - May 12

Background: This month I'm in Cusco, seeing the city and volunteering at a school project for underprivileged, impoverished kids. This is an almost verbatim entry from the diary I'm keeping while I'm out here.

The past few days have been regular. I say regular, but this is Peru, so there isn’t anything regular about it. I suppose I mean predictable, but even then...

I spend my days learning Spanish and working with the kids and my nights out. K and I are  getting along even better and spend three consecutive nights together; good food, good drinks and great company. She’s complex and mature, and I sincerely like that. I wonder how much of my attraction to her is intellectual and how much of it is physical. I’m not a physical being (as anyone who has witnessed me trying to play football will know), but she is conventionally beautiful, at the same time as being intriguingly intricate.

Things are going really well at the project. I really enjoy working with the kids, the other volunteers are supportive and it’s been really rewarding so far.

I decide to try and engage the kids in programming. A seemingly impossible task, considering I don’t speak technical Spanish, they don’t have computers and none of the other profesores have any programming experience. I set about trying to teach the concept of input through to output, which lies at the core of programming a computer.

As far as I’m aware, the only real way to engage young kids in fundamentally dull concepts is to simplify them and make them exciting. Input through to output, in this context, equates to code through to result. Commands through to actions. The most accessible computer with the most immediately ‘viewable’ results, conceptually, is a robot. Everyone knows what a robot is, so I began trying to design a game to allow the kids to control a robot.

To give the activity a sense of community, I make los profesores the robots, and the kids divide into teams to control them.

The idea is, they write a series of commands on a piece of paper, which is then given to the robot, who then executes the commands. The program must guide the robot through an obstacle course, pick up a bag of sweets and drop the sweets off in a box at the other end of the course.

Within moments the kids grasp the concept and start writing programs. The first round goes terribly, but once they’ve had a chance to see their programs in action, they’re much more confident with the idea and they really start to have fun. This is problem solving at its core, and they take to it incredibly well. They’re pacing across the room, shouting numbers out to team members, 

Everybody’s laughing, everybody’s working and everybody’s thinking. It’s moments like this that make me really excited about the future. Understanding these basic concepts are, and will be, fundamental to the future of businesses and the fact that I get to play a tiny role in this is so fulfilling.

Moved my Lake Titicaca trip forward so K isn’t alone (and I won’t be alone either). Looking forward to seeing nature. Looking forward to seeing the stars. Looking forward to eating the food and doing some hiking in the mountains of the islands.

Fingers crossed it won’t disappoint.

Saturday
May122012

Peru - May 8th

Background: This month I'm in Cusco, seeing the city and volunteering at a school project for underprivileged, impoverished kids. This is an almost verbatim entry from the diary I'm keeping while I'm out here.

I begin my project today. After breakfast, Spanish lessons, a walk around Cusco and more leisurely loitering, I get to the Spanish school and meet Niko, who is taking me to the project. We go via another project - Caitlin, one of the Americans, works at United Planet, the volunteering network, and is looking around the various projects - an orphanage. So, the six of us cram into a taxi and make our way.

Seeing such poverty is totally sobering.

There are six houses and each house contains twelve kids. There’s mold on the ceiling, the walls are damp and the bedsheets and mattresses are old and dirty. 

Our visit is well received by the kids. They swarm to us, tug our clothes and hug us. We take lots of photos, they dance around, play with each other and ask to use my camera (what’s Spanish for “For the love of God please be careful!”?).

The kids know Niko; he volunteered there when he first arrived in Peru. Shouts of “¡Hola Niko!” echo around the block.

Outside there’s a walkway, if you could call it that. It’s more like a construction site. There are open drains, nails and big, wide cracks in the concrete.

The path leads to a modest play area. There are some swings, a slide and a makeshift castle made from wooden crates, old bins and plastic piping. I spot a plank of wood with a nail sticking out of it, lying, exposed in the grass. I bend the nail into the wood and throw the plank far away from the play area.

Like I said. Sobering.

What fascinates me, and I don’t wish to sound trite here, is how happy the kids are in the midst of all this poverty. Their smiles, laughter and innocence really does put your problems into perspective. My redhead dilemma is now totally insiginificant.

According to Niko, when the kids reach the age of eighteen they have to leave. They most likely go into a life of crime; unemployment is rife in Peru and stealing or drug trafficking is a lot of people’s only possible financial recourse. 

I hope things will change in the next ten years so that these kids have a better future. Until then they’re left in a poor, difficult, but thankfully loving, home.

They’re also fanatical about Justin Beiber. Bizarrely.

We pile back into a taxi and head for my project. Source travel is initially difficult; apparently my project is in a really dangerous area, or at least dangerous enough to deter taxi drivers. This bodes well.

The journey is quick. Up an extraordinarily steep hill - think San Francisco - and through a rainbow-painted door lies the Asociacion Civil Giordana Liva de Cusco, or ‘my project’ as it will be henceforth known.

The project was started by an Italian guy called Perci in 2002. Since then it’s blossomed into a humble but pleasant programme for homework help and after school activities. The district, Santiago, is poor, and many of the kids come from families of unemployment and alcoholism.

The kids are a fantastic bunch and they work hard at their homework. The project runs activities too: music time with recorders and basic reading from staffs, creative drawing, arts and crafts and reading. Los niños seem to enjoy doing it all, even if they are a bit restless sometimes.

There are roughly ten volunteers (the kids call us los profesores, I’m ‘Profesor Jamie’, so use that if you’re writing any fan mail to me). Most of them are Italian, but they all speak a little bit of English and my Spanish is starting to get a lot better.

I dive straight in and start helping the kids with their maths homework. They’re very bright; long division seems to be easy for them. I don’t know why, it’s bloody hard.

They’re re-doing the garden area outside, and need help, so, after a cement mixing crash course in Spanish, I spend the rest of the afternoon doing manly building stuff.

We’d planned to meet back at the school and go out for a few drinks. I get to the school, but it’s locked and closed, so I walk down to the bar we’d been discussing.

Lo and behold, I bump into Katrina, one of the Americans. She’s quite short, totally antagonistic and really, really good looking. Painfully good looking. We end up spending the entire evening together, arguing with each other, and although we don’t see eye to eye on pretty much anything we get along very well. Opposites attract, I suppose.

We pop to the aforementioned Irish pub. We sit opposite an Irish couple (whose names we’ve both forgotten, sorry!). They were going to get a mortgage, get married and have a family, but in their words: “Feck that, getting pissed and seeing the world is much more fun”.

We have a blast. I introduce Katrina to proper British ale, I eat a fantastic steak sandwich and we thoroughly make the most of happy hour. The Irish couple are bollixed, but they carry on regardless and we make our merry way over to Frogs at about 10:30PM. I bump into Marko, one of the Italians at my project, and we drink muchas bebidas. I walk Katrina home.

All in all a very interesting day.

Wednesday
May092012

Peru - 7th May

Background: This month I'm in Cusco, seeing the city and volunteering at a school project for underprivileged, impoverished kids. This is an almost verbatim entry from the diary I'm keeping while I'm out here.

It’s 5:30AM and this is the earliest I’ve been up in a very long time. The difference of -6 hours is just enough to cause considerable jet lag, but I should be okay in a couple of days.

Last night was lovely. Doris walked me to the Spanish school (not to be confused with the after school programme I’m volunteering with, the San Blas Spanish School is a basecamp for a whole host of volunteering projects). I met Niko, a funny, charming and charismatic Austrian who works at the school. He told me we were going for dinner soon but needed to wait for a few others. The others turned out to be six Americans; five girls and a guy. They were all absolutely delightful and I very much look forward to getting to know them better. They all seem to be in their mid-Twenties.

We ate at a funky little cocktail bistro called ‘The Frogs’. The food was superb and the Pisco sours plentiful; to top it off, my newly acquired volunteer card gives me 15% off food and happy hour all night long. It’s also pretty cheap, at s/.15 per drink, which is about $4, or £2.50 for the sterling-inclined.

Niko distributed a bunch of welcome packs. My pack contains a map of Cusco, the discount card, a few coupons, a bunch of useful numbers and addresses and most importantly, the schedule. I’ve got a busy few weeks ahead of me but it seems to be rather flexible too. I think it’s the Peruvian attitude: a pervasive culture of ‘why do it now when you can do it later?’ The Spanish translation of this is mañana, I believe.

I’ve got Spanish lessons Mon-Thu 11-1 this week. I’m on an after school programme so my volunteering doesn’t begin until 3, which means I’m busy this week but I will have plenty of exploring time next week when the Spanish classes aren’t so intensive.

Wednesday and Thursday nights host some great activities at San Blas: this week it’s Salsa lessons, the following week cooking. Niko tells us on Thursday night we can go to The Frogs for a cocktail class.

I’m very much looking forward to my Spanish lessons: my patchy Spanish is already improving but a one-to-one class is going to be extremely valuable. I feel very limited at the moment. Those of you who know me know how much I like to express myself and not being able to articulate myself properly is proving to be a major barrier to, say, winning arguments.

I eat some potato skins with sour cream and salsa, followed by a Peruvian dish with big chunks of beef cooked up with a load of veg in soy sauce. They’re big on their carbohydrates here; most meals are served with rice AND potatoes or chips.

For breakfast today it’s fresh bread with butter and jam, as well as freshly squeezed and pulped pineapple juice. Pineapple is quite clearly the king of the juices.

I chat to a fellow lodger over breakfast; Gabrielle is a 50-year-old Swiss woman who speaks fluent Spanish and has just quit her job as the HR director of a large Swiss firm in order to travel full time with her husband. Stories like hers are utterly inspiring and it’d be amazing to have the courage and audacity to do that. Her kids have grown up so she has no attachments, which is hugely freeing, but I wonder if in a few years she’ll yearn for a home, for a base, for stability.

I walk up to the Spanish school and take a wander around town. I buy an SD card reader, but it doesn’t work in my laptop or the school’s computer, so I’ll return it tomorrow.

I’ve taken some great photos today and can’t wait to share them. There are so many interesting scenes and people here in Cusco and they make for some excellent photography.

On a walk through an old Incan sidestreet I come across this small sign with a guitar and an arrow pointing to an open doorway. Walking through the doorway brings you into a yard; a chicken pecks at some corn and a dog chills in the shade. Another sign points to the direction of a arrow store corridor. I walk through, turn the corner and cross the threshold into a small, but bright workshop.

Wooden chippings make up a carpet, and a man stands with a chisel, hunched over a small wooden instrument. It’s got the build of a ukelele but the bridge and head of a guitar, so it must be a Peruvian instrument I’m not aware of. I make the worker aware of my presence with a simple “¡Hola!” and instantly he switches from focused craftsmen to scatty amigo. I ask him about his instruments and he begins animately describing the process, the tools and the business he runs.

Of course, it’s all in speedy technical Spanish and I understand close to none of it. I take a few photos, nod along, smile, say “gracias señor” a lot and leave. I’d like to revisit him in a couple of weeks to see the instrument when it’s complete. I think he also appreciated the visit. I don’t think he gets a lot of company normalmente.

It’s time for my first Spanish lesson. I arrive back at the school to find a bunch of confused foreigners sitting in chairs and eating avocado. I get chatting with a dutch girl called Anuk. She’s an art historian and yoga instructor. People are interesting.

Franklin, my soon-to-be Spanish teacher, pops his head round the door and yells my name. He says “¡Arriba!” and marches up the stairs. Thankfully, I knew arriba means upstairs rather than the “let’s get drunk, take our clothes off and party all night” that it’s synonymous with in British culture. That could have been embarrassing.

The lesson is entertaining and rewarding, and I already feel a lot more confident with my Spanish. Give it a few more weeks and I’ll be talking no ends of bullshit. It’ll be fantastic. The equilibrium will be restored. I don’t like not being able to express myself.

I have another look round the city, sit in a café and type up yesterday’s entry. Just as I’m about to leave, the Dutch girl from earlier sidles up to me and says hello. I initially don’t recognise her - she’s not wearing her glasses - but after a couple of seconds it comes to me and we start chatting.

She mentions getting a coffee. I come clean and sheepishly admit to having no more money on me (lunch was more pricey than I was expecting), but she says it’s okay and offers to buy me a latte. We grab our coffees and sit by the fountain in Plaza de Ramas, chatting about everything and anything and watching the tourists pass by. We walk back to the school and go our separate ways.

This is what I love most about traveling. Because I’m on my own I have to make an effort to chat and make friends, and I’m meeting so many interesting people.

I spend the rest of the evening tucked up in bed reading, writing and sleeping. The combination of jet lag and altitude has left me thoroughly exhausted. Just remembered I have Office Space on my laptop so I might watch that. I’m tempted to go out and abuse my discount at Frogs but I decide against it in favour of an early night and the thrilling final chapters of Boris.

I begin at the after school programme tomorrow, as well as the two hour Spanish class, so I ought to be rested up. I’m also starting to run out of my initial $100. I’ve spent about $50 so far and I want this to last me until Thursday or so. 

An early night it is.

Monday
May072012

Peru - 5/6th May

Background: This month I'm in Cusco, seeing the city and volunteering at a school project for underprivileged, impoverished kids. This is an almost verbatim entry from the diary I'm keeping while I'm out here.

Spent the plane flight absent minded. Bought a beer in the hope of enticing sleep but to little avail; three hours of shuteye achieved and the rest of the trip spent engrossed in Boris: The Rise of Boris Johnson. I suppose I’ve had worse flights.

Arrived in Lima with a few hours to kill before connection and walked into airport food court. Ahh, globalisation, you really want me to have an Egg McMuffin, don’t you? I resist my Western urges and approach the most Peruvian counter I can find. I ask for ‘un desayuno tradicional’ - a traditional breakfast - and get given a sandwich containing onions, an unidentifiable root vegetable and some very questionable beef. And a beer. For 5:30AM I’m doing rather well. I think I’m going to like this country.

From glimpses through plane windows and the vast, low panorama of the departure lounge, Lima seems to be a very industrial city. I can see towering mechanical structures off in the distance, reminiscent of Rockerfeller’s Standard Oil nodding donkeys. I don’t think it’s oil here in Peru but the structures are certainly significant; they’re essentially the only thing visible in the otherwise flat Lima skyline.

The airport itself offers no intrigue or cultural significance; it’s very much a normal airport, which I suppose is exactly what you want from an institution created to shuttle you across continents at 500mph and 30,000ft up. Still, it’d be nice to see some llamas or something.

It’s a balmy 19°C, which is keeping me happy. I won’t dwell on Lima or its airports any more. After all, it’s Cusco I’ve come here to see and Cusco I shall write more about. Back to Boris I go while I await the 09:20 to CUZ.

My flight to Lima lands in the early hours, while it’s still dark, so my first real glimpse of Peru while airborne is from the LIM -> CUZ flight. As the plan ascends into the clouds I see glimpses of an unimpressive city. It feels totally European, which is really not what I came here hoping to see. An hour later the plane descends, breaking through the thick cloud, and suddenly all my previous skepticism is put to rest.

We glide over mountains. It’s a totally unpredictable landscape: soaring rockfaces jutting out of the Earth, deep, dark canyons and dense forest covering a plateau, stretching out into the distance. The variety of terrain really is a remarkable sight. I can see a hundreds of tiny little pueblos dotted across the countryside.

It’s an experience like this that makes me think Peru was meant to be viewed by air. It is akin to the Grand Canyon with its heterogeneous landscape; while it looks amazing now, I’m sure from a helicopter it’d look fucking phenomenal.

As the plane draws closer to my destination the little pueblos out in the country begin to grow in number and increase in density until they morph into the unbroken urban sprawl of Cusco. It’s much bigger than Google Maps has lea me to believe. The airport is old, dusty and archaic (yes!). There is something disingenuous about overly modern and Westernised facilities in poor cities. I suppose it’s to attract tourism, but still, it saddens me to think of where that money could be put to much better use.

I’m picked up by the Mother of my host family, Doris, a delightful 57-year-old that speaks absolutely no English (or refuses to... I’ve not sussed her out properly yet). I rely on my poor Spanish to make it through several conversations, including one about how “las chicas de Cusco” are lovely and bountiful, but they may just want me for my money. Fantastic Doris, thanks.

After lunch - a potato soup followed by pollo with rice and marinaded-in-something veg - I decide to take a stroll around the town.

As far as I’m aware, Peru is a country in (what is known by pretentious middle-class white boys like me) the ‘developing world’. Whatever the ethics of the terminology, Peru definitely deserves to have its present tense nomenclature. 

The entire city of Cusco feels like one giant work in progress. Street after street of empty concrete buildings, dozens of abandoned roadworks and unclosed sewers. The whole place screams unfinished. The road on which I’m staying, Avenue de la Cultura, is partitioned on the left (facing downhill) by tens of pieces of corrugated aluminium, bolted onto planks of wood to form a fence. A cycle bridge crosses over the busy road to a new roundabout, circling a fountain, while straight opposite is a new block of offices. It’s a fascinating juxtaposition, from the makeshift, shantytown fencing on my left to the modern, clean, contemporary design of the workspace to my right.

Poverty is not overtly apparent, but neither is wealth. Cultura is joined with its parallel road through a series of mini-markets. These bazaars are deceptively extensive, forming a labarinthine maze full of independent retailers trying to sell rip-off bags, boots and clothing, pirated CDs and DVDs, cheap plastic toys and local foods and drinks. I’ve been warned by various people, including my Mother, not to get food from street stalls lest I suffer from diarrhea. It’s very good advice, but the adventurer and rebel in me is tempted to try some of it out. I think I’ll play that one by ear.

I walk up to the more touristy area - a typical tourism scene, and fundamentally nothing too interesting to report - and sit myself in a posh bar overlooking a little piazza. I order a pisco sour (what else?!) and enjoy the last of the sub before the clouds consume it again. I pay the s/.25 (approximately $9, which isn’t that bad but still seems overpriced) and walk back down the hill to the house.

One thing I notice very quickly is the altitude and what effect it’s having on my body. I’m not exceptionally fit, but I’m not in terrible shape either, and after five minutes of walking up a slight fradient I am quite severly out of breath. It feels like adifferent out of breath, not the panting, sweaty faced out-of-breathness, such as one Eric Pickles might get after walking up the stairs, no, it’s an altogether different sensation, one of clawing at the oxygen in front of you, begging for it to enter your lungs. I’ve never experienced this kind of altitude before so I had no idea what it would be like. I assume my body will adjust to it.

I’m back at the house now. After a 23 hour trip, plus walking around, I really want a shower, but alas, the hot water is off until tomorrow morning. I’ll have to wait ‘till then. I’ve more or less unpacked, set up a desk with my laptop, notepad and camera, as well as the pile of books I hope to get through. There’s one power socket in my room and in order for any of my appliances to work I have to prop the plug up with my camera’s tripod. It’s hilarious.

Slightly annoyed I’ve forgotten my camera cable, but it’s not a huge worry as it’s a standard microUSB and I’m bound to find one in one of the phone shops I saw on my walk. Other than that, the room is homely and the family are hospitable. It’ll be dinner soon and I’m going to try to catch some sleep before I head off to the volunteering project welcome thing this evening. It would be nice if there are some younger people working with me. It’ll be even nicer if they speak English.

I suppose the perfect candidate would be a 5’5 redhead girl who’s into books, has strong political opinions and loves Pink Floyd. A guy can dream, right? Knowing me I’ll get a smelly, angry, perspiring, bulimic Czech with a bronchial infection and a habit of breaking down in tears of hysteria at the word “and”. I’ll report back as to the team members as the situation develops.

Now, it’s time for a 30 minute kip under the watchful eye of a Jesus Christ clock suspended over my bed. At least Jesus loves me, even if fate and cute redheads don’t.


Dinner was lovely. It’s 4AM English time so will write more in next entry.

No redhead.

P.S. I've not been able to get any photos onto my laptop yet, but I'll update this post with the pics when I can.

Wednesday
May022012

How I Test

It's been over a year since I've wrote the libellous words "One of the things the PHP community has always been crap about is testing"; an annum on and change is really starting to gain momentum. Personally, I'm now programatically testing pretty much every line of code I ship, in some way or another, and I've learnt a lot over the past year about the best ways to test. Others are starting to really see the value of unit testing.

One of the things I've discovered by talking to other developers is that a lot of people lack direction in what to test and how to make it a part of their process. They get the basics, but they struggle to get into the mindset of someone who writes tests. If you don't get it chances are you're doing it wrong.

Learning the tools is easy. Grabbing PHPUnit off PEAR is a piece of cake, as is setting up a couple of files and running phpunit at your command line. Nowadays, the basic steps of setting up an environment for testing are so few and so effortless, it's child's play. For that reason I don't believe there's much more value in writing another introductory article.

This piece is about the process of testing. It's about test-driven development, how I work when I'm writing code and how writing unit tests gives me smarter, more stable and more refactorable code.


Get PHPUnit installed. We're going to write a small PHP class that takes an email request body and parses a bunch of info about it.

Create two new files, email_parser_test.php and email_parser.php. I like to work with these files side by side, so in Sublime Text 2 - a great text editor which you should all be using, incidentally - I'll hit Command + Alt + 2 to open my editor up into two columns. This means I can have my tests on the left and my implementation on the right.

Inside our test file, create a new class and a basic test method:

class Email_parser_test extends PHPUnit_Framework_TestCase
{
    public function test_something()
    {
        $this->assertTrue(true);
    }
}

Jump into Terminal and give it a run:

$ phpunit --colors email_parser_test.php
PHPUnit 3.6.10 by Sebastian Bergmann.

.

Time: 0 seconds, Memory: 2.25Mb

OK (1 test, 1 assertion)

That --colors flag is going to get annoying, so we'll dump this in a phpunit.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<phpunit colors="true"></phpunit>

There's one tiny little bit more of setup we need to do before we can begin writing proper code. We'll need some test data to work with; an email we know the format of and can reproduce every time. Tests are only valuable if they're consistent. We want two emails to work with; and you'll see why in a moment. I'll use an email I got from good friend Alex Bilbie about his excellent CodeIgniter MongoDB Library. Save this in a file email.eml:

Delivered-To: jamie@jamierumbelow.net
Return-Path: <alex.bilbie@gmail.com>
Date: Wed, 2 May 2012 01:06:01 +0100
From: Alex Bilbie <alex.bilbie@gmail.com>
To: jamie@jamierumbelow.net
Message-ID: <586B7E1735704A1CB388F4434B4EAA9B@gmail.com>
Subject: =?utf8?Q?Update_to_my_Mongo_library?=
X-Mailer: sparrow 1.5 (build 1043.1)
Content-Type: text/html
MIME-Version: 1.0

I've updated my CodeIgniter MongoDB library to version 0.5.1. It mostly contains bug fixes and optimisations.

Version 2.0 of the library is almost finished – check it out at <a href="https://github.com/alexbilbie/codeigniter-mongodb-library/tree/v2">https://github.com/alexbilbie/codeigniter-mongodb-library/tree/v2</a>. I'm currently working out how PHP Unit works so that the library can be tested on Travis CI each time a new commit is made.

And another one (email2.eml):

Delivered-To: jamie@jamierumbelow.net
Return-Path: <me@jeremygimbel.net>
Date: Wed, 3 May 2012 09:25:55 +0100
From: Jeremy Gimbel <me@jeremygimbel.net>
To: praise@jamierumbelow.net
Message-ID: <109A8F7538567P7VD675E7990N8NDS7T@gmail.com>
Subject: =?utf8?Q?A_quick_note!?=
Content-Type: text/html
MIME-Version: 1.0

Jamie, I love what you're doing with <a href="https://github.com/jamierumbelow/codeigniter-base-model">MY_Model</a> and <a href="https://github.com/jamierumbelow/codeigniter-base-controller">MY_Controller</a>!

Now we know everything's working a okay and we've got our test data, we'll waste no more time and get straight on with writing our first test.

Actually, that was a lie. I just want to make three points before we begin:

  1. Remember that we should always write the smallest amount of code possible to get the test to pass. That'll become clearer shortly.
  2. We're writing unit tests, so we're testing the input -> output flow of a unit of code (and any side effects)
  3. Your tests should never negatively affect the API. If a parameter is only necessary for the tests, you're doing it wrong.

We'll start off by simply parsing the headers out and grabbing them. This is good place to start because we'll need to parse the headers anyway; it's therefore worth our while to test that core functionality first.

public function test_parses_headers()
{
    $parsed = $this->parser->parse($this->email);
    $this->assertEquals(10, count($parsed['headers']));
}

The test might be simple, and it certainly doesn't test all the functionality we need to, but that is exactly what we want.

When I test, I find it valuable to write the smallest amount of code to test and the smallest possible amount to get the test past. It doesn't matter what the system needs to do in the future, it's just about getting the test to past.

You'll spot that we're accessing $this->parser and $this->email. Let's define them:

public function setUp()
{
    $this->parser = new Email_parser();
    $this->email = file_get_contents('email.eml');
}

Run our tests:

$ phpunit email_parser_test.php
PHPUnit 3.6.10 by Sebastian Bergmann.

Configuration read from /Users/jamierumbelow/Sites/email_parser/phpunit.xml

PHP Fatal error:  Class 'Email_parser' not found in /Users/jamierumbelow/Sites/email_parser/Email_parser_test.php on line 7

Fatal error: Class 'Email_parser' not found in /Users/jamierumbelow/Sites/email_parser/Email_parser_test.php on line 7

What's the smallest amount of code that can fix this error? In our Emailparser.php_ file:

class Email_parser { }

...and require it at the top of our test file:

require_once 'email_parser.php';

Run again and we get an error about missing parse() method. Define it:

public function parse($email) { }

Run again and we get an assertion error:

$ phpunit email_parser_test.php
PHPUnit 3.6.10 by Sebastian Bergmann.

Configuration read from /Users/jamierumbelow/Sites/email_parser/phpunit.xml

F

Time: 0 seconds, Memory: 2.75Mb

There was 1 failure:

1) Email_parser_test::test_parses_headers
Failed asserting that 0 matches expected 10.

/Users/jamierumbelow/Sites/email_parser/email_parser_test.php:17

FAILURES!
Tests: 1, Assertions: 1, Failures: 1.

What's the smallest amount of code that we can write to make this test pass?

return array( 'headers' => array( 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ) );

You're probably shouting at the screen and telling me I'm an idiot right now, and honestly, I wouldn't blame you. This might seem like a total waste of time. You'll have to bare with me here; you'll soon see why this can become valuable.

Now we've got our test passing, let's add another assertion to it:

public function test_parses_headers()
{
    $parsed = $this->parser->parse($this->email);

    $this->assertEquals(10, count($parsed['headers']));
    $this->assertEquals('jamie@jamierumbelow.net', $parsed['headers']['To']);
}

Got it yet? Nope? Okay, I'll carry on.

$ phpunit email_parser_test.php
PHPUnit 3.6.10 by Sebastian Bergmann.

Configuration read from /Users/jamierumbelow/Sites/email_parser/phpunit.xml

E

Time: 0 seconds, Memory: 2.50Mb

There was 1 error:

1) Email_parser_test::test_parses_headers
Undefined index: To

/Users/jamierumbelow/Sites/email_parser/email_parser_test.php:18

FAILURES!
Tests: 1, Assertions: 1, Errors: 1.

What's the smallest possible amount of code to fix it? We'll actually cheat a little bit here since we KNOW that once the To index is in the array, it'll ask for the value of jamie@jamierumbelow.net, so we might as well kill two birds with one stone.

return array( 'headers' => array( 'To' => 'jamie@jamierumbelow.net', 2, 3, 4, 5, 6, 7, 8, 9, 10 ) );

Good good. Let's add one more just to ensure we're being thorough:

$this->assertEquals('<586B7E1735704A1CB388F4434B4EAA9B@gmail.com>', $parsed['headers']['Message-ID']);

The failure:

1) Email_parser_test::test_parses_headers
Undefined index: Message-ID

Again, killing two birds with one stone:

return array( 
        'headers' => array( 'To' => 'jamie@jamierumbelow.net', 
                            'Message-ID' => '<586B7E1735704A1CB388F4434B4EAA9B@gmail.com>',
                            3, 4, 5, 6, 7, 8, 9, 10 ) );

So WHAT IS THE POINT OF ALL THIS?

What happens when we copy + paste our assertions and run the same test on email2.eml as well?

Update the assertions so that we're checking for the appropriate number of headers and the appropriate values:

public function test_parses_headers()
{
    $parsed = $this->parser->parse($this->email);

    $this->assertEquals(10, count($parsed['headers']));
    $this->assertEquals('jamie@jamierumbelow.net', $parsed['headers']['To']);
    $this->assertEquals('<586B7E1735704A1CB388F4434B4EAA9B@gmail.com>', $parsed['headers']['Message-ID']);

    $parsed = $this->parser->parse($this->email2);

    $this->assertEquals(9, count($parsed['headers']));
    $this->assertEquals('praise@jamierumbelow.net', $parsed['headers']['To']);
    $this->assertEquals('<109A8F7538567P7VD675E7990N8NDS7T@gmail.com>', $parsed['headers']['Message-ID']);
}

And load our email in our tests' setUp():

$this->email2 = file_get_contents('email2.eml');

Run it:

$ phpunit email_parser_test.php
PHPUnit 3.6.10 by Sebastian Bergmann.

Configuration read from /Users/jamierumbelow/Sites/email_parser/phpunit.xml

F

Time: 0 seconds, Memory: 2.75Mb

There was 1 failure:

1) Email_parser_test::test_parses_headers
Failed asserting that 10 matches expected 9.

/Users/jamierumbelow/Sites/email_parser/email_parser_test.php:24

FAILURES!
Tests: 1, Assertions: 4, Failures: 1.

Understand the logic yet?

Ahhhhhh. There we go.

Suddenly, we're now in the position where in order to get this test to pass, we're forced to parse the email. In order to get the test passing, we need to implement our test appropriately. Adding in some weird switch as a parameter, although would require less code, detracts from our API (that is to say, it would be pointless in production/implementation code). So the only thing we can really do is actually parse the email.

public function parse($email)
{
    list($headers_list, $body) = explode(PHP_EOL . PHP_EOL, $email, 2);
    $headers_list = explode(PHP_EOL, $headers_list);

    $headers = array();
    foreach ($headers_list as $h)
    {
        list($key, $value) = explode(':', $h, 2);
        $headers[$key] = trim($value);
    }

    return array( 'headers' => $headers );
}

This does two great things. It makes our tests pass:

$ phpunit email_parser_test.php
PHPUnit 3.6.10 by Sebastian Bergmann.

Configuration read from /Users/jamierumbelow/Sites/email_parser/phpunit.xml

.

Time: 0 seconds, Memory: 2.50Mb

OK (1 test, 6 assertions)

...and it has the fortunate side effect of providing us with the body, parsed and separated out nice and easily!

While it's good that that's already done for us, it's currently untested, so let's fix that posthaste:

public function test_parses_body()
{
    $expected_body_email = "I've updated my CodeIgniter MongoDB library to version 0.5.1. It mostly contains bug fixes and optimisations.\n\nVersion 2.0 of the library is almost finished – check it out at <a href=\"https://github.com/alexbilbie/codeigniter-mongodb-library/tree/v2\">https://github.com/alexbilbie/codeigniter-mongodb-library/tree/v2</a>. I'm currently working out how PHP Unit works so that the library can be tested on Travis CI each time a new commit is made.";
    $expected_body_email2 = 'Jamie, I love what you\'re doing with <a href="https://github.com/jamierumbelow/codeigniter-base-model">MY_Model</a> and <a href="https://github.com/jamierumbelow/codeigniter-base-controller">MY_Controller</a>!';

    $parsed = $this->parser->parse($this->email);
    $this->assertEquals($expected_body_email, $parsed['body']);

    $parsed = $this->parser->parse($this->email2);
    $this->assertEquals($expected_body_email2, $parsed['body']);
}

And making this pass is now just a matter of adding the $body variable to the return line:

return array( 'headers' => $headers, 'body' => $body );

So. We have our headers and we have our body. While cool, it's not very useful. Let's try to extract the subject.

For those of you who know the MIME protocol, you'll know that the subject field is usually encoded in some way. This is conventionally Q-encoding or Base64. PHP's iconv extension provides a great little function for decoding MIME headers: iconv_mime_decode.

Let's write a test:

public function test_subject()
{
    $parsed = $this->parser->parse($this->email);
    $this->assertEquals('Update to my Mongo library', $parsed['subject']);
}

To get it passing:

return array( 'headers' => $headers, 'body' => $body, 'subject' => 'Update to my Mongo library' );

Expand the tests:

$parsed = $this->parser->parse($this->email2);
$this->assertEquals('A quick note!', $parsed['subject']);

And we can implement the function to get the tests to pass:

$subject = iconv_mime_decode($headers['Subject']);

return array( 'headers' => $headers, 'body' => $body, 'subject' => $subject );

And there we have it!

$ phpunit email_parser_test.php
PHPUnit 3.6.10 by Sebastian Bergmann.

Configuration read from /Users/jamierumbelow/Sites/email_parser/phpunit.xml

...

Time: 0 seconds, Memory: 2.50Mb

OK (3 tests, 10 assertions)

It's a simple piece of code and a simple test suite, but hopefully this article has clarified how I test and why I believe this process to be truly valuable.

Page 1 ... 2 3 4 5 6 ... 12 Next 5 Entries »