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.

Tags
Tweets
Feeds
We Love
Powered by Squarespace

Entries in ruby (5)

Thursday
Feb232012

The CodeIgniter Handbook - Volume 1 - Available!

I am utterly thrilled to announce that my new book, The CodeIgniter Handbook Volume 1, is now available for order!

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.

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.

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

Purchase the CodeIgniter Handbook today!

Friday
Apr012011

A radical new shift in data storage; Rumblestorage

Last night I had an epiphany. I was working with one of those old, cruddy databases, and it got me thinking. Why isn't there a better solution? Why am I doomed to use legacy systems such as MySQL and MongoDB for the rest of eternity? So, I began researching alternatives. And when I couldn't find any, I chose to write my own.

I am proud to announce Rumblestorage. From now on, every project of mine will be using Rumblestorage as its data storage medium. I hope that you too can see the light and understand that, frankly, databases just don't cut it any more.

Rumblestorage utilises the native capabilities of your language and stores everything in a flat text file; a simple and elegant solution. It brings your data into memory at class instantiation and saves it on destruction. It has a beautifully usable API. It's clear that in this 21st century world, databases are just far too restrictive. Your storage engine should be built specifically for your programming language; it should be fast, easy to use and above all flexible.

Best of all, Rumblestorage is free and open source, available on GitHub. I'm already in talks with the CodeIgniter Reactor team as to integrate Rumblestorage as a replacement for the old and tired database class.

Access the source code at GitHub, and feel free to fork and make your contribution to the future of data storage!

Wednesday
Feb162011

Aliasing overridden methods in Ruby

So, one of the great things about Ruby is that you can open up a class and override methods. The problem is when you need to call the old method. The first thing you can do is use the alias method to alias the old method to a new name and call it from the new method.

class Post
  alias :old_save, :save

  def save
    puts "Saving post"
    old_save
  end
end

While this works, it can cause problems when working with larger codebases. Someone could define a method called old_save, or use it as their alias name, overwriting your work. A much better idea is to steal the method from the class, save it in a variable, bind it to the current instance then call it using Ruby's call method.

class Post
  old_save = self.instance_method(:save)

  define_method(:save) do
    puts "Saving post"
    old_save.bind(self).call
  end
end

The above version means that the old_save method won't be left around as a method, it's a private variable in the scope of that class. We have to use define_method to define the method as the old_save method is only available in the scope of the class. We could save it as an instance variable, but this would just cause the same issues.

Sunday
Jan022011

High-level testing PHP applications with Cucumber

One of the things that the PHP community have always been crap about is testing, and honestly, I've never really been much better at it either. This is partly due to the fact that there really aren't any good testing systems out there for PHP and partly due to the laziness of a lot of developers.

Ruby and Rails have been doing a great job of pushing test support in their communities. One of the best new solutions to have sprung up from the Ruby camp is Cucumber, a plain-text based tool that allows you to write user stories and test applications at a high-level. High-level testing is testing the application at the level that the user will see: ensuring that the appropriate text is displayed in appropriate places, ensuring that a certain change is made when the user visits a certain page, et cetera.

Cucumber can be used to test right down to a unit-test level, where individual blocks of code are tested, but this is somewhat limited to Ruby applications only.

Make sure you have the latest version of Ruby installed, jump into Terminal and install the Cucumber Rubygem. We'll also need the Webrat gem, which will give us browser simulation and a matchers API, the RSpec gem, which will give us our testing framework, and mechanize, which is an underlying framework that we'll use with Webrat.

sudo gem install cucumber
sudo gem install rspec
sudo gem install webrat
sudo gem install mechanize

Once you've installed all those gems, check they're installed and ready to use:

$ cucumber --version
0.10.0
$ spec --version
rspec 1.3.0
$ ruby -e 'require "rubygems"; print require("webrat")'
true
$ ruby -e 'require "rubygems"; print require("mechanize")'
true

Inside your project's directory, we're going to create a new directory called features. This is going to contain all of the code related to our testing. Create two new sub-directories too, features/support and features/step_definitions. The former will contain support files (principally our environment/setup file) and the latter will contain the Webrat code to do the actual testing.

Before we can start writing features, we need to set up our environment so that Webrat knows how to connect to our PHP application. Create a features/support/env.rb file.

require 'rspec/expectations'
require 'webrat'
require 'test/unit/assertions'

World(Test::Unit::Assertions)

Webrat.configure do |config|
  config.mode = :mechanize
end

World do
  session = Webrat::Session.new
  session.extend(Webrat::Methods)
  session.extend(Webrat::Matchers)
  session
end

We're loading RSpec, Webrat and Test::Unit (Ruby's built-in unit tester) and we're then adding the Test::Unit::Assertions module to our Cucumber World (scope). We're configuring Webrat to use Mechanize (which will allow Webrat to simulate a web browser), and then we're making a new Webrat session and exposing it to Cucumber.

For the purposes of demonstration, I've decided to test a remote site instead of a local one, and I thought it would be fun to test the CodeIgniter website. We'll write a very simple feature that tests whether we can login and logout successfully.

Create a new feature file inside features called authentication.feature. The name of this file can be anything, as long as it ends with .feature. A feature contains a bunch of scenarios that document a specific user feature in an application. It's then the job of the step definitions to make this code execute, but a helpful by-product of this is that you've got a bunch of feature definitions that can be easily written and read by non-programmers.

First, let's just describe our feature:

Feature: Authentication
  In order to use the CodeIgniter site
  As a user
  I want to be able to login and logout

This is a standard format for features. It doesn't really do anything, it just gives us a general overview of the specific feature we're writing. Let's add a scenario. Remember, indentation is important here.

  Scenario: Login
    Given I am on the home page
    And I am logged out
    When I click on Login
    Then I should see the login page

So, this scenario details when a user clicks the "Login" link on the http://codeigniter.com site. We're saying "Given I am on the home page", which we'll use to point Webrat to the homepage. We'll also check we're logged out (and click on the logout link to ensure this if we are). When the user clicks on the Login link, we want to see the login page.

Describing this in English might not make a lot of sense yet, but stay with me. It will all become a lot clearer when we write the step definitions. Create a new file in features/step_definitions called authentication_steps.rb. We'll start off by defining the "Given I am on the home page" step.

Given /I am on the home page/ do
  visit "http://codeigniter.com"
end

That was easy! We define the steps similar to the way we write them. We're visiting the homepage when that regex matches on the Given clause. Let's move on to "And I am logged out". This is a bit more tricky. "And", much like "But", is there just for readability. It takes the form of the previous clause, so we'll define it as Given.

Given /I am logged out/ do
  click_link 'Logout' if not contain('<a href="http://codeigniter.com/forums/member/login/">Login</a>')
end

We're clicking the 'Logout' link if the page doesn't contain the login link. This ensures we're logged out. Now it's time to implement the "When" step. We use this step to click on the login link. See where this is going?

When /I click on (.*)/ do |link|
  click_link link
end

I've used a regex here to make this a little more re-usable. Now, we can specify any link in our feature and Cucumber will know what to do with it. Finally, "Then".

Then /I should see the login page/ do
  response_body.should have_xpath(%\//input[@name='username']\)
  response_body.should have_xpath(%\//input[@name='password']\)
  response_body.should contain("Login Required")
end

We're using the response_body method to get the page, then using RSpec's should method to ensure that we've got the two input elements - have_xpath is a Webrat method that checks for the existence of matches on XPath queries - and the message "Login Required".

Now, in the Terminal, run cucumber features, where features is the features/ directory. You should see the feature and scenario outputted to the Terminal, with the Scenario steps in green. Congratulations, you just wrote your first Cucumber scenario!

Let's write another scenario. Replace login and password with your own CodeIgniter username and password.

  Scenario: Login processing
    Given I am on the login page
    When I fill in the username input with **login**
    And I fill in the password input with **password**
    And I click the button Submit
    Then I should see the logged in page

And the step definitions:

Given /I am on the login page/ do
  visit "http://codeigniter.com/forums/member/login/"
end

When /I fill in the (.*) input with (.*)/ do |input, value|
  fill_in input, :with => value
end

When /^I click the button (.*)$/ do |button|
  click_button button
end

Then /^I should see the logged in page$/ do
  response_body.should contain("You are now logged in")
end

I've reduced duplication again in a few places, and made some things regexes just in case we need to re-use them. We can use the fill_in method to fill in an input name with a value. Give that a run and you should get more passes.

Finally, let's write and implement the scenario for logging out.

  Scenario: Logout
    Given I am logged in
    And I am on the home page
    When I click on Logout
    Then I should see the logged out page

We only need to implement two steps here; "Given I am logged in" and "Then I should see the logged out page". The other two we've already written.

Given /I am logged in/ do
  visit "http://codeigniter.com"

  if contain('<a href="http://codeigniter.com/forums/member/login/">Login</a>')
    click_link "Login"
    fill_in 'username', :with => "**username**"
    fill_in 'password', :with => "**password**"
    click_button "Submit"
    response_body.should contain("You are now logged in")
  end
end

Then /I should see the logged out page/ do
  response_body.should contain("You are now logged out")
end

Given I am logged in visits the home page, checks if we're logged out, if we are, clicks on the link, submits the form and checks we're logged in successfully. Then I should see the logged out page goes checks that we see the logged out page. It's all pretty self-explanatory.

I hope I've managed to explain how to write Cucumber features. Cucumber really is a fantastic way to do this higher level testing, and you can use it with any platform and framework, including PHP. Check out the Cucumber site if you're interested in finding out more.

Friday
Nov122010

A quick MongoDB primer

The almost exponential growth of the web industry has brought a range of new and exciting technologies for developers to use. One of these is the simply fantastic NoSQL database, MongoDB. Here's a quick primer to those interested in using it in your projects.

Lay the foundations

Get to grips with NoSQL and the NoSQL movement; forget about relational databases like MySQL and start to think of your application in terms of documents instead. Start thinking about how Mongo could fit into your application. It's similar to designing a relational database schema, but instead of worrying about adding in new columns or making links in tables, you just decide what collections you'll be using and that's it.

Get in the trenches

Download MongoDB and get reading the Starter Tutorial. Then, the best thing to do is get started writing an application! Just start getting a flavour of what Mongo's about. One of the best and most useful things about working with your data directly in object-serialisation is that you can just add new columns/keys as you please. No more bloody schemas. 

If you're using PHP, there's already a great PECL extension available, and Alex Bilbie has written a wrapper around it for CodeIgniter. For Rubyers, Mongoid is gorgeous, incredibly easy to use, and even has a Railscast devoted to it. For those more inclined to whitespace significance, you'll almost certainly run into PyMongo, and would be very wise to study and learn this lower-level interface. When you want something higher-level, check out MongoEngine, which is a great ORM that fits in well with Django, but can be used elsewhere.

Going live

Installing and deploying MongoDB databases is very very very easy. If you'd rather not mess about with configuring Mongo - despite it being an incredibly simple task - you can use the frankly fantastic hosted solution, MongoHQ, who will host your databases in a scalable, quick and efficient cloud environment. If you'd rather host yourself, I'd recommend you check out a great post over at the Agile Testing blog that talks in detail about setting up a good Mongo environment.

There's no schema to copy over or run. All you have to do is create the database you'd like to use and you're done. No SQL files or messy schemas. Mongo creates the collections and documents on the fly. It's all dynamic.

A few gotchas

There are a couple of gotchas and things to watch out for. One of the biggest things that gets a lot of people is that there aren't any autoincrement IDs. Instead, MongoDB uses a random hash string, automatically created for every document.

If you want to retain using old autoincrement IDs, you have to go about it in a slightly different way. Check out this great tutorial from Chris Shiflett on autoincrement IDs in MongoDB. Otherwise, you'll have to use the MongoIDs. I'll also mention the fact that in the PHP extension you can't just look it up as a string - it's a serialised MongoID instance.

In fact, Mongo has a number of particular serialised classes for a number of different purposes, including MongoRegex, which can be used for querying the database and, more unusually, storing regular expression patterns, and MongoDate, for DateTimes.

Join the Mongo Revolution

MongoDB is bloody lovely. It's an exciting time to be getting into NoSQL web development, and you'll find that MongoDB is the absolute best NoSQL database that provides a great mix between familiar relational syntax and the power of map/reduce, document searching, indexing and sharding.