<?xml version="1.0" encoding="UTF-8"?>
<!--Generated by Squarespace Site Server v5.11.81 (http://www.squarespace.com/) on Fri, 24 Feb 2012 13:56:41 GMT--><rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rss="http://purl.org/rss/1.0/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:admin="http://webns.net/mvcb/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:cc="http://web.resource.org/cc/"><rss:channel rdf:about="http://jamieonsoftware.com/journal/"><rss:title>Journal</rss:title><rss:link>http://jamieonsoftware.com/journal/</rss:link><rss:description></rss:description><dc:language>en-US</dc:language><dc:date>2012-02-24T13:56:41Z</dc:date><admin:generatorAgent rdf:resource="http://www.squarespace.com/">Squarespace Site Server v5.11.81 (http://www.squarespace.com/)</admin:generatorAgent><rss:items><rdf:Seq><rdf:li rdf:resource="http://jamieonsoftware.com/journal/2012/2/23/the-codeigniter-handbook-volume-1-available.html"/><rdf:li rdf:resource="http://jamieonsoftware.com/journal/2012/2/6/happier-shelling.html"/><rdf:li rdf:resource="http://jamieonsoftware.com/journal/2012/1/7/syntax-sugar-5-a-quick-codeigniter-caching-helper-function.html"/><rdf:li rdf:resource="http://jamieonsoftware.com/journal/2011/12/26/codeigniter-view-presenters.html"/><rdf:li rdf:resource="http://jamieonsoftware.com/journal/2011/11/17/on-smoking.html"/><rdf:li rdf:resource="http://jamieonsoftware.com/journal/2011/11/7/on-commercialising-a-community-at-net-magazine.html"/><rdf:li rdf:resource="http://jamieonsoftware.com/journal/2011/11/5/getting-to-know-expressionengine-2s-config-file-part-3.html"/><rdf:li rdf:resource="http://jamieonsoftware.com/journal/2011/10/31/jamie-rumbelow-freelancer-extraordinaire.html"/><rdf:li rdf:resource="http://jamieonsoftware.com/journal/2011/9/12/syntax-sugar-4-coffeescript-one-liners.html"/><rdf:li rdf:resource="http://jamieonsoftware.com/journal/2011/8/12/add-on-updates.html"/></rdf:Seq></rss:items></rss:channel><rss:item rdf:about="http://jamieonsoftware.com/journal/2012/2/23/the-codeigniter-handbook-volume-1-available.html"><rss:title>The CodeIgniter Handbook - Volume 1 - Available!</rss:title><rss:link>http://jamieonsoftware.com/journal/2012/2/23/the-codeigniter-handbook-volume-1-available.html</rss:link><dc:creator>Jamie Rumbelow</dc:creator><dc:date>2012-02-23T02:48:18Z</dc:date><dc:subject>books codeigniter php ruby</dc:subject><content:encoded><![CDATA[<p><a href="http://codeigniterhandbook.com">I am utterly thrilled to announce that my new book, The CodeIgniter Handbook Volume 1, is now available for order!</a></p>

<p>Volume 1, Who Needs Ruby? is a pragmatic, succinct guide to improving your efficiency and the cleanness of your code. Attractive to amateurs and professionals alike, The CodeIgniter Handbook isn't your usual programming book. It's short, useful and easy to read, and covers how to improve the quality of your code and the speed of your development time.</p>

<p>It's available to buy as a print book or an eBook. It's also much cheaper than most programming books, at only £12 (roughly $18) for the print book and £6 ($10) for the eBook.</p>

<p>I've had some great feedback already -- everyone appears to be enjoying it! Thanks for your support.</p>

<p><a href="http://codeigniterhandbook.com">Purchase the CodeIgniter Handbook today!</a></p>
]]></content:encoded></rss:item><rss:item rdf:about="http://jamieonsoftware.com/journal/2012/2/6/happier-shelling.html"><rss:title>Happier Shelling</rss:title><rss:link>http://jamieonsoftware.com/journal/2012/2/6/happier-shelling.html</rss:link><dc:creator>Jamie Rumbelow</dc:creator><dc:date>2012-02-06T15:26:52Z</dc:date><dc:subject>unix</dc:subject><content:encoded><![CDATA[<p>I've just added something to my <strong>~/.profile</strong> file that has made me much happier when moving around in Terminal / the UNIX shell. If you're anything like me, you forget where you put things and what directories look like.</p>

<p>In order to cure this ailment, I re-defined the <code>cd</code> command and got it to list the contents of a directory every time I change directories. It's nice to have a constant reminder of how unorganised I am.</p>

<p>If you'd like to have this sweetness, add this to your <strong>~/.profile</strong>:</p>

<pre><code>cd () {
  builtin cd "$*"
  ls -al
}
</code></pre>

<p>Then, either re-open your Terminal window or run <code>$ source ~/.profile</code> to load it into the shell. Happy cding!</p>
]]></content:encoded></rss:item><rss:item rdf:about="http://jamieonsoftware.com/journal/2012/1/7/syntax-sugar-5-a-quick-codeigniter-caching-helper-function.html"><rss:title>Syntax Sugar #5 - A Quick CodeIgniter Caching Helper Function</rss:title><rss:link>http://jamieonsoftware.com/journal/2012/1/7/syntax-sugar-5-a-quick-codeigniter-caching-helper-function.html</rss:link><dc:creator>Jamie Rumbelow</dc:creator><dc:date>2012-01-07T17:45:31Z</dc:date><dc:subject>codeigniter memcached syntax sugar</dc:subject><content:encoded><![CDATA[<p>Caching your data in CodeIgniter? Good. You should be.</p>

<p>I use <a href="http://memcached.org/">memcached</a> lots. CI has <a href="http://codeigniter.com/user_guide/libraries/caching.html">a fantastic caching driver</a> built in (as of 2.0). Normally, the code you'll write looks like this:</p>

<pre><code>$accounts = $this-&gt;cache-&gt;memcached-&gt;get('user.' . $user_id . '.accounts');

if (!$accounts)
{
    $accounts = $this-&gt;db-&gt;where('user_id', $user_id)-&gt;get('accounts')-&gt;results();
    $this-&gt;cache-&gt;memcached-&gt;save('user.' . $user_id . '.accounts', $accounts);
}

$this-&gt;load-&gt;view('accounts/index', array( 'accounts' =&gt; $accounts ));
</code></pre>

<p>However this quickly becomes repetitive, boring and cluttering. With a bit of PHP5.3 magic, we can create a really nice little caching helper function that cleans this code up in no time:</p>

<pre><code>function cache($key, $data) {
    $CI =&amp; get_instance();
    $cache = $CI-&gt;cache-&gt;memcached-&gt;get($key);

    if (!$cache) {
        // There's been a miss, so run our data function and store it
        $cache = $data($CI);
        $CI-&gt;cache-&gt;memcached-&gt;save($key, $cache);
    }

    return $cache;
}
</code></pre>

<p>Now, our cluttered caching code becomes a commendable concoction of coding culinary craft:</p>

<pre><code>$accounts = cache('user.' . $user_id . '.accounts', function(&amp;$ci){
    return $ci-&gt;db-&gt;where('user_id', $user_id)-&gt;get('accounts')-&gt;results();
});
</code></pre>

<p>The anonymous method you pass through will only be executed if the cache misses (i.e. there's no data under that key, or it has expired). It will be saved into the cache and return. Delicious.</p>
]]></content:encoded></rss:item><rss:item rdf:about="http://jamieonsoftware.com/journal/2011/12/26/codeigniter-view-presenters.html"><rss:title>CodeIgniter View Presenters</rss:title><rss:link>http://jamieonsoftware.com/journal/2011/12/26/codeigniter-view-presenters.html</rss:link><dc:creator>Jamie Rumbelow</dc:creator><dc:date>2011-12-26T17:54:51Z</dc:date><dc:subject>codeigniter php presenters</dc:subject><content:encoded><![CDATA[<p>Whenever building applications with CodeIgniter, I always try my best to follow the Model-View-Controller design pattern as much as possible. MVC tells us that views are the presentational filter of the model's data. Over the course of an application's development, it can be very common for views to grow and accumulate cruft. I find that <strong>presenters</strong> can be a really sleek way of hiding presentational logic away in a class.</p>

<p>Let's look at a simple view that displays some information about a user's bank account:</p>

<pre><code>&lt;div id="account"&gt;
    &lt;h1&gt;&lt;?= $this-&gt;bank-&gt;get($account-&gt;bank_id)-&gt;name ?&gt; - &lt;?= $account-&gt;title ?&gt;&lt;/h1&gt;

    &lt;p class="information"&gt;
        &lt;strong&gt;Name:&lt;/strong&gt; &lt;?php if ($account-&gt;name): ?&gt;&lt;?= $account-&gt;name ?&gt;&lt;?php else: ?&gt;N/A&lt;?php endif; ?&gt;&lt;br /&gt;
        &lt;strong&gt;Number:&lt;/strong&gt; &lt;?php if ($account-&gt;number): ?&gt;&lt;?= $account-&gt;number ?&gt;&lt;?php else: ?&gt;N/A&lt;?php endif; ?&gt;&lt;br /&gt;
        &lt;strong&gt;Sort Code:&lt;/strong&gt; &lt;?php if ($account-&gt;sort_code): ?&gt;&lt;?= substr($account-&gt;sort_code, 0, 2) . "-" . substr($account-&gt;sort_code, 2, 2) . "-" . substr($account-&gt;sort_code, 4, 2) ?&gt;&lt;?php else: ?&gt;N/A&lt;?php endif; ?&gt;
    &lt;/p&gt;

    &lt;p class="balances"&gt;
        &lt;strong&gt;Total Balance:&lt;/strong&gt; &lt;?php if ($account-&gt;total_balance): ?&gt;&lt;?= "&amp;pound;" . number_format($account-&gt;total_balance) ?&gt;&lt;?php else: ?&gt;N/A&lt;?php endif; ?&gt;
        &lt;strong&gt;Available Balance:&lt;/strong&gt; &lt;?php if ($account-&gt;available_balance): ?&gt;&lt;?= "&amp;pound;" . number_format($account-&gt;available_balance) ?&gt;&lt;?php else: ?&gt;N/A&lt;?php endif; ?&gt;
    &lt;/p&gt;

    &lt;p class="statements"&gt;
        &lt;?php if ($this-&gt;statements-&gt;get_by('account_id', $account-&gt;id)): ?&gt;
            &lt;?= anchor('/statements/' . $account-&gt;id, 'View Statements') ?&gt;
        &lt;?php else: ?&gt;
            Statements Not Currently Available
        &lt;?php endif; ?&gt;
    &lt;/p&gt;
&lt;/div&gt;
</code></pre>

<p>This is a rather typical view; it's displaying bits of content from an object, checking for a value's existence and pulling in bits from other database tables. It's fine, but it's all a bit messy, and we're duplicating a fair bit of code. Ideally, we want our view to look something like this:</p>

<pre><code>&lt;div id="account"&gt;
    &lt;h1&gt;&lt;?= $account-&gt;title() ?&gt;&lt;/h1&gt;

    &lt;p class="information"&gt;
        &lt;strong&gt;Name:&lt;/strong&gt; &lt;?= $account-&gt;name() ?&gt;&lt;br /&gt;
        &lt;strong&gt;Number:&lt;/strong&gt; &lt;?= $account-&gt;number() ?&gt;&lt;br /&gt;
        &lt;strong&gt;Sort Code:&lt;/strong&gt; &lt;?= $account-&gt;sort_code() ?&gt;
    &lt;/p&gt;

    &lt;p class="balances"&gt;
        &lt;strong&gt;Total Balance:&lt;/strong&gt; &lt;?= $account-&gt;total_balance() ?&gt;
        &lt;strong&gt;Available Balance:&lt;/strong&gt; &lt;?= $account-&gt;available_balance() ?&gt;
    &lt;/p&gt;

    &lt;p class="statements"&gt;&lt;?= $account-&gt;statements_link() ?&gt;&lt;/p&gt;
&lt;/div&gt;
</code></pre>

<p>This clears up our view considerably and removes a bunch of the duplication. It also strips out as much logic as possible from the views, and can make for some very succinct code.</p>

<p>We're going to create an <strong>application/presenters</strong> directory, and inside there an <strong>account_presenter.php</strong> file. This file will contain the presenter class for our account object. Let's start by extracting the title:</p>

<pre><code>&lt;?php

class Account_Presenter {

    public function __construct($account) {
        $this-&gt;account = $account;
        $this-&gt;ci =&amp; get_instance();
    }

    public function title() {
        return $this-&gt;ci-&gt;bank-&gt;get($this-&gt;account-&gt;bank_id)-&gt;name . "-" . $account-&gt;title;
    }
}
</code></pre>

<p>We make sure that we can access the CodeIgniter superobject in <code>$this-&gt;ci</code> and the account object that we're presenting in <code>$this-&gt;account</code>. We can then port the logic that was previously in the view into a <code>title()</code> method.</p>

<p>We can now go ahead and tidy up the information section:</p>

<pre><code>public function name() {
    return $this-&gt;account-&gt;name ?: "N/A";
}

public function number() {
    return $this-&gt;account-&gt;number ?: "N/A";
}

public function sort_code() {
    if ($sc = $this-&gt;account-&gt;sort_code) {
        return substr($sc, 0, 2) . "-" . substr($sc, 2, 2) . "-" . substr($sc, 4, 2);
    } else {
        return "N/A";
    }
}
</code></pre>

<p>Similarly, we can tidy up the balances section:</p>

<pre><code>public function total_balance() {
    return ($this-&gt;account-&gt;total_balance) ? "&amp;pound;" . number_format($this-&gt;account-&gt;total_balance) : "N/A";
}

public function available_balance() {
    return ($this-&gt;account-&gt;available_balance) ? "&amp;pound;" . number_format($this-&gt;account-&gt;available_balance) : "N/A";
}
</code></pre>

<p>And finally, the statements link:</p>

<pre><code>public function statements_link() {
    if ($this-&gt;ci-&gt;statements-&gt;get_by('account_id', $this-&gt;account-&gt;id)) {
        return anchor('/statements/' . $this-&gt;account-&gt;id, 'View Statements');
    } else {
        return "Statements Not Currently Available";
    }
}
</code></pre>

<p>Fantastic. Finally, in our controller, we need to pass through an instance of the presenter <em>rather than the account object itself</em>.</p>

<pre><code>public function show($account_id) {
    $account = $this-&gt;account-&gt;get($account_id);
    $this-&gt;data['account'] = new Account_Presenter($account);

    $this-&gt;load-&gt;view('account/show', $this-&gt;data);
}
</code></pre>

<p>...and don't forget to load the presenter at the top of your controller:</p>

<pre><code>require_once APPPATH . 'presenters/account_presenter.php';
</code></pre>

<p>...and we are done!</p>

<p>As I'm sure you can see, using presenters allows you to tidy up your views in a really object-oriented way. It'd be great to hear your thoughts about presenters and whether or not you plan on using them.</p>
]]></content:encoded></rss:item><rss:item rdf:about="http://jamieonsoftware.com/journal/2011/11/17/on-smoking.html"><rss:title>On Smoking</rss:title><rss:link>http://jamieonsoftware.com/journal/2011/11/17/on-smoking.html</rss:link><dc:creator>Jamie Rumbelow</dc:creator><dc:date>2011-11-17T14:43:33Z</dc:date><dc:subject>life postdesk writing</dc:subject><content:encoded><![CDATA[<p>I've just published the first of a new weekly column I'll be writing for PostDesk. This week I talk about smoking. I think it's really interesting.</p>
<p>And lots of people think I'm an idiot.</p>
<p><a href="http://postdesk.com/blog/whats-wrong-with-smoking">http://postdesk.com/blog/whats-wrong-with-smoking</a></p>]]></content:encoded></rss:item><rss:item rdf:about="http://jamieonsoftware.com/journal/2011/11/7/on-commercialising-a-community-at-net-magazine.html"><rss:title>On Commercialising a Community at .net magazine</rss:title><rss:link>http://jamieonsoftware.com/journal/2011/11/7/on-commercialising-a-community-at-net-magazine.html</rss:link><dc:creator>Jamie Rumbelow</dc:creator><dc:date>2011-11-07T15:45:33Z</dc:date><dc:subject>business elsewhere writing</dc:subject><content:encoded><![CDATA[<p>I've just had an article published in .net magazine, and I'd absolutely love it if you could read it. It's an opinion piece on why you should take advantage of communities and make a shedload of cash.</p>

<blockquote>
  <p>Teenage developer Jamie Rumbelow is all for open source but argues that creating a side business surrounding a community can actually help it grow and flourish.</p>
</blockquote>

<p><a href="http://www.netmagazine.com/opinions/commercialising-community">Read it over on .net.</a></p>
]]></content:encoded></rss:item><rss:item rdf:about="http://jamieonsoftware.com/journal/2011/11/5/getting-to-know-expressionengine-2s-config-file-part-3.html"><rss:title>Getting to know ExpressionEngine 2's config file - Part 3</rss:title><rss:link>http://jamieonsoftware.com/journal/2011/11/5/getting-to-know-expressionengine-2s-config-file-part-3.html</rss:link><dc:creator>Jamie Rumbelow</dc:creator><dc:date>2011-11-05T13:09:15Z</dc:date><dc:subject>expressionengine</dc:subject><content:encoded><![CDATA[<p>This is the belated finale in the trilogy of articles I'm writing about how to customise your ExpressionEngine <em>config.php</em> file to allow for a much more dynamic and customisable ExpressionEngine install.</p>

<p>In <a href="http://jamieonsoftware.com/journal/2011/4/6/getting-to-know-expressionengine-2s-config-file.html">Part 1</a>, we looked at the basics, why and how to use the config file most effectively and we built a simple example. In <a href="http://jamieonsoftware.com/journal/2011/4/11/getting-to-know-expressionengine-2s-config-file-part-2.html">Part 2</a>, we extended our config file to allow for multiple servers without changing any values. Today, in Part 3, we'll look at tidying up our config file and we'll take a look at some of the extensive hidden configuration variables.</p>

<p>Let's take a look at our config file so far:</p>

<pre><code>&lt;?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

/* Dynamic Configuration
-------------------------------------------------------------------*/
$ext        = ($_SERVER['SERVER_ADDR'] == '127.0.0.1') ? ‘.local’ : ‘.com’;
$base_url   = $base_url = ((isset($_SERVER['HTTPS']) &amp;&amp; $_SERVER['HTTPS'] == "on") ? "https" : "http");
$base_url .= "://".$_SERVER['HTTP_HOST'].$ext;
$admin_url  = $base_url . '/admin.php';

/* ExpressionEngine Configuration
-------------------------------------------------------------------*/
$config['app_version'] = "213";
$config['license_number'] = "0000-0000-0000-0000";
$config['debug'] = "1";
$config['install_lock'] = "";
$config['system_folder'] = "system";
$config['is_system_on'] = "y";
$config['allow_extensions'] = "y";
$config['site_url'] = $base_url;
$config['server_path'] = FCPATH;
$config['cp_url'] = $admin_url;
$config['theme_folder_url'] = $config['site_url']."/themes/";
$config['theme_folder_path'] = $config['server_path']."/themes/";
$config['save_tmpl_files'] = "y";
$config['tmpl_file_basepath'] = $config['server_path']."/templates/";
$config['avatar_url'] = $base_url."/uploads/system/avatars/";
$config['avatar_path'] = $config['server_path']."/uploads/system/avatars/";
$config['photo_url'] = $base_url."/uploads/system/member_photos/";
$config['photo_path'] = $config['server_path']."/uploads/system/member_photos/";
$config['sig_img_url'] = $base_url."/uploads/system/signature_attachments/";
$config['sig_img_path'] = $config['server_path']."/uploads/system/signature_attachments/";
$config['prv_msg_upload_path'] = $config['server_path']."/uploads/system/pm_attachments/";

/* CodeIgniter Configuration
-------------------------------------------------------------------*/
$config['base_url'] = $config['site_url'];
$config['uri_protocol'] = 'AUTO';
$config['language'] = 'english';
$config['charset'] = 'UTF-8';
$config['subclass_prefix'] = 'EE_';
$config['permitted_uri_chars'] = 'a-z 0-9~%.:_\\-';
$config['enable_query_strings'] = FALSE;
$config['directory_trigger'] = 'D';
$config['controller_trigger'] = 'C';
$config['function_trigger'] = 'M';
$config['log_threshold'] = 0;
$config['log_path'] = '';
$config['log_date_format'] = 'Y-m-d H:i:s';
$config['time_reference'] = 'local';

/* End of file config.php */
/* Location: ./system/expressionengine/config/config.php */
</code></pre>

<p>This is already nice and tidy. But it'd be great to consolidate our database information in here too, wouldn't it? That way, we can change all our system configuration in one file. This is how we do it:</p>

<pre><code>/* Universal database connection settings
-------------------------------------------------------------------*/
$active_group = $ext;
$active_record = TRUE;

$db['.local']['hostname'] = 'localhost';
$db['.local']['username'] = 'root';
$db['.local']['password'] = 'root';
$db['.local']['database'] = 'some_database';
$db['.local']['dbprefix'] = "exp_";
$db['.com']['hostname'] = 'localhost';
$db['.com']['username'] = 'user';
$db['.com']['password'] = 'password';
$db['.com']['database'] = 'database';
$db['.com']['dbprefix'] = "exp_";

$db[$active_group]['dbdriver'] = "mysql";
$db[$active_group]['pconnect'] = FALSE;
$db[$active_group]['swap_pre'] = "exp_";
$db[$active_group]['db_debug'] = FALSE;
$db[$active_group]['cache_on'] = FALSE;
$db[$active_group]['autoinit'] = FALSE;
$db[$active_group]['char_set'] = "utf8";
$db[$active_group]['dbcollat'] = "utf8_general_ci";
$db[$active_group]['cachedir'] = $config['server_path'].$config['system_folder']."/expressionengine/cache/db_cache/";
</code></pre>

<p>By extracting out the majority of the variables (the ones that probably won't change depending on environment), and then using the <code>$ext</code> variable to switch the <code>$active_group</code>, we can adjust the database connection settings automatically depending on environment. There's one more thing we need to do. Open up your <em>config/database.php</em> file, empty it, and give it a solitary line:</p>

<pre><code>&lt;?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');

require 'config.php';

/* End of file database.php */
/* Location: ./system/expressionengine/config/database.php */
</code></pre>

<p>Now, all references to the database configuration will be brought through the DB config file from the <em>config.php</em> file.</p>

<p>Alongside the standard configuration - paths, debug settings, URLs etc - we can customise a lot of ExpressionEngine's behaviour through a little-known technique called hidden configuration variables. A quick TextMate project search for 'Hidden Configuration Variable' bears 33 different variables with which to customise behaviour. Let's look at a couple of them:</p>

<pre><code>$config['allow_textarea_tabs'] = 'y';
</code></pre>

<p>If you wish to preserve tabs in textareas, or let the user add a tab character, rather than shift focus to the next input, you can set this config item and all textareas in MarkItUp mode will preserve their tabs. Turning it off is as simple as setting it to 'n'.</p>

<p>Is the automatic JavaScript login reminder in the CP annoying you? Turn it off:</p>

<pre><code>$config['login_reminder'] = 'n';
</code></pre>

<p>Do you want your formatted text links to automatically open in a new window?</p>

<pre><code>$config['popup_link'] = 'y';
</code></pre>

<p>I'm sure you get the idea. There's a <a href="http://expressionengine.com/user_guide/general/hidden_configuration_variables.html">comprehensive list of the hidden configuration variables</a> in the user guide.</p>

<p>I hope that this series has taught you one or two things about customising and using your <em>config.php</em> file to best effect. It's a fantastically powerful weapon to have in your arsenal, and it should make creating dynamic websites with ExpressionEngine much simpler.</p>
]]></content:encoded></rss:item><rss:item rdf:about="http://jamieonsoftware.com/journal/2011/10/31/jamie-rumbelow-freelancer-extraordinaire.html"><rss:title>Jamie Rumbelow: Freelancer Extraordinaire</rss:title><rss:link>http://jamieonsoftware.com/journal/2011/10/31/jamie-rumbelow-freelancer-extraordinaire.html</rss:link><dc:creator>Jamie Rumbelow</dc:creator><dc:date>2011-10-31T11:36:22Z</dc:date><dc:subject>freelancing life</dc:subject><content:encoded><![CDATA[<p>For the past few months I've been working full-time for a fantastic company with some fantastic people. VIA has empowered me and brought me satisfaction and happiness. But it's time to spread my wings and move on.</p>

<p>I've decided to go back to college and finish my education. I want to go to University, study and grow as a person. I realise that moving out so early on was a wrong choice. It wasn't a mistake; I'm very happy in Bath and I'm really enjoying my life. I just feel like I can do so much more, get so much further and grow so much more.</p>

<p>The problem is, I'm too late into the term to start back at college. The solution, thankfully, is simple. Take my gap year :)</p>

<p>So, I'm now looking for freelance/contract work, in any language - preferably PHP, Ruby or CoffeeScript - in any country. I'm a fast, able and independent developer. I love working with other people and can manage myself independently. I'm charismatic, friendly and energetic. Historically, I've specialised in CodeIgniter and ExpressionEngine development, but I'm happy to work with any other platforms. I'm willing to relocate anywhere in the world too for a few months - hell, I'd love it. I speak decent Spanish and am willing to invest time in learning any other languages.</p>

<p>I'm also looking for writing and speaking gigs. I want to use the next year to diversify and work on a range of different things, and I really enjoy engaging with the community and allowing my creative side to flourish.</p>

<p>Email me on jamie@jamierumbelow.net or telephone me on +44 (0)7956 363875. I can't wait to hear from you.</p>
]]></content:encoded></rss:item><rss:item rdf:about="http://jamieonsoftware.com/journal/2011/9/12/syntax-sugar-4-coffeescript-one-liners.html"><rss:title>Syntax Sugar #4 - CoffeeScript one-liners</rss:title><rss:link>http://jamieonsoftware.com/journal/2011/9/12/syntax-sugar-4-coffeescript-one-liners.html</rss:link><dc:creator>Jamie Rumbelow</dc:creator><dc:date>2011-09-12T15:02:40Z</dc:date><dc:subject>coffeescript syntax sugar</dc:subject><content:encoded><![CDATA[<p>I'm a sucker for short, concise syntax. One of the beautiful features about <a href="http://coffeescript.org">CoffeeScript</a> - the JavaScript/Ruby lovechild that I'm slowly learning to adore - is its single line function declaration. Using this powerful syntax one can write really expressive functions with terse code.</p>

<p>Let's demonstrate this with a quick function. Let's say we want to remove a specific element from an array. My first guess would be to write:</p>

<pre><code>var arr = [ 1, 2, 3, 4 ];
delete arr[0]; // [ nil, 2, 3, 4 ]
</code></pre>

<p>The issue with this, of course, is that we are left with a stray <code>nil</code>. That's not particularly convenient if we're using the array a lot. Instead, let's write a function and patch it onto the <code>Array</code> class.</p>

<pre><code>Array::remove = ( element ) -&gt; 
    if (@indexOf(element)) &gt; -1
        @splice @indexOf(element), 1
</code></pre>

<p>We're using the built-in <code>splice()</code> method to remove the element at the index of our element. That isn't such a bad first attempt, but it's not particularly terse or pleasant. Let's remove the repetition and move <code>index</code>'s assignment into the conditional:</p>

<pre><code>Array::remove = ( element ) -&gt;
    if (index = @indexOf(element)) &gt; -1
        @splice index, 1
</code></pre>

<p>We can use CoffeeScript's keyword syntax and bracketless method calling to clean it up a bit further:</p>

<pre><code>Array::remove = ( element ) -&gt;
    if (index = @indexOf element) isnt -1
        @splice index, 1
</code></pre>

<p>And finally we can push it all into one line:</p>

<pre><code>Array::remove = ( e ) -&gt; @splice i, 1 if (i = @indexOf e) isnt -1
</code></pre>

<p>If we compare this to the JavaScript it generates:</p>

<pre><code>Array.prototype.remove = function(e) {
    var i;
    if ((i = this.indexOf(e)) !== -1) {
        return this.splice(i, 1);
    }
};
</code></pre>

<p>…it's a no-brainer. CoffeeScript is a wonderful way of making JavaScript cleaner, more concise and altogether much more pleasant to work with. I'd highly recommend <a href="http://coffeescript.org">downloading a copy and trying it out</a>.</p>
]]></content:encoded></rss:item><rss:item rdf:about="http://jamieonsoftware.com/journal/2011/8/12/add-on-updates.html"><rss:title>Add-on updates</rss:title><rss:link>http://jamieonsoftware.com/journal/2011/8/12/add-on-updates.html</rss:link><dc:creator>Jamie Rumbelow</dc:creator><dc:date>2011-08-12T18:08:21Z</dc:date><dc:subject>addons expressionengine</dc:subject><content:encoded><![CDATA[<p>Over the past few days I've released a couple of updates to some of my <a href="http://getsparkplugs.com">ExpressionEngine add-ons</a>.&nbsp;</p>
<p><a href="http://getsparkplugs.com/taggable">Taggable</a> is now at version 1.4.6, which fixes some pretty major bugs and improves the intutitiveness of the tag searching. It's highly recommended you update your Taggable install to this version.</p>
<p>I've also updated one of my free add-ons, <a href="http://devot-ee.com/add-ons/sp-table-select">SP Table Select</a>, which allows you to create dropdowns filled with arbitrary data from arbitrary database tables. Version 1.2.0 adds support for the excellent Matrix add-on. Check it out!</p>
<p><a href="http://getsparkplugs.com/taggable">http://getsparkplugs.com/taggable</a><br /><a href="http://devot-ee.com/add-ons/sp-table-select">http://devot-ee.com/add-ons/sp-table-select</a></p>]]></content:encoded></rss:item></rdf:RDF>
