James Wilding's Weblog

Tag: ruby

Ruby’s OpenStruct: An Introduction

OpenStructs are magic — they’re like hashes, but far less fussy about what methods you throw at them. The key feature of OpenStructs is this: they allow you to arbitrarily set and access attributes for your models, on the fly.

Here’s an example:

require 'ostruct'

s = OpenStruct.new
s.name # => nil
s.name = 'James'
s.name # => 'James'

Note that we don’t need to initialise the ‘name’ attribute: we just set the value and Ruby takes care of the rest. Want to add a new attribute? Easy.

s.age # => nil
s.age = 29
s.age # => 29

We can add any attribute we want to our objects, on the fly, and different instances of the OpenStruct class can have different attributes. Importantly, we don’t have to worry about what methods we send to our OpenStructs, because anything that doesn’t have a value just returns nil 1:

s.location # => nil
s.hobbies # => nil

Clearing Values

To unset a value, we can do one of two things: in most cases, it’s the obvious…

2.age # => 29
s.age = nil
s.age # => nil

…but to grab the value before setting the attribute back to nil, we can use delete_field 2:

# Returns 29, and sets 'age' to nil
age = s.delete_field('age')
age # => 29
s.age # => nil

Initialising With Values

We can create new OpenStruct objects with attribute/value pairs by providing a hash:

s = OpenStruct.new(:name => 'James', :occupation => 'Rubyist')
s.name # => 'James'
s.occupation # => 'Rubyist'

How It Works

Behind the scenes, Ruby uses a hash to implement OpenStruct’s easy access so we get all the flexibility of a hash with a nice, clean, method-style access laid on top. Don’t worry about the details: just throw whatever you want into your OpenStructs, and let Ruby take care of your data.

Advanced Initialization

If you want object with the flexibility of OpenStructs but with default values for some attributes then something like the following would work:

require 'ostruct'

class MyStruct < OpenStruct
  # Hard-code age and status
  def initialize(hash = {})
    super hash.merge(:age => 29, :role => 'Manager')
  end
end

s = MyStruct.new(:name => 'Bob')
s.name # => 'Bob'
s.age # => 29
s.role # => 'Manager'

# We can override the default values
s = MyStruct.new(:age => 45)
s.age # => 45

OpenStruct vs Struct

Ruby’s Struct is subtly, but importantly, different to OpenStruct. How to use Struct is another blog post, but put simply Structs are less flexible. Check the Struct docs for more info :)

Notes:

  1. This can be a curse as well as a blessing, because you’ll often get nil when you’d expect Ruby to raise a NoMethodError. Checkout OpenStruct’s method_missing to see what’s going on behind the scenes.
  2. This is one of OpenStruct’s few built-in instance methods which don’t act as attribute accessors. Check the docs for details.

Ruby on the iPad

Since I wrote Thoughts on the iPad yesterday, that article has been getting lots of hits from people searching for “ruby on ipad” — or variations thereof.

If you’ve reached this post by searching for something similar, I’m guessing you want to do one of two things: either 1) run Ruby on an iPad, or 2) develop for the iPad using Ruby.

1) Run Ruby on the iPad

Never going to happen.

Like the iPod and the iPhone, the iPad is a closed system. The only near-possible way to run Ruby on an iPad would, I’m guessing, be to create an app which bundled Ruby and provided a command-line interface to it. But that’s not going to happen either. Can you imagine Apple approving an app which allowed users to run any code they liked — even within a sandbox? Neither can I.

2) Develop for the iPad using Ruby

This is less clear-cut: there’s obviously no support for Ruby in the Objective-C iPad SDK, but we do have MacRuby: “a version of Ruby 1.9, ported to run directly on top of Mac OS X core technologies”. I think the key words there are “Mac OS X technologies (my emphasis)”; Mac OS X is different to iPhone/iPad OS X, and right now there’s about as much chance of using MacRuby to develop iPad apps as there is of Bill Gates coming to work at Apple.

That might change though (the MacRuby thing, not Bill Gates) — which change would depend on MacRuby becoming a popular way to develop for the Mac. If enough developers use it, Apple may — may — decide it’s worth their time an effort to port MacRuby to their other platforms.

So, Googler: there’s some small hope.

Lessons Learnt With Rails

Some lessons I’ve learnt working on my latest Rails project, a piece of tidy-and-fix work on an existing Rails application. Working on this project has really taught me a lot about the right and wrong ways to use Rails.

1. Routes are important

The app that I was asked to rebuilt had no routes. Nothing.

That’s not to say that no URLs worked with the app, just that the mappings between URLs and controllers/actions was defined in the code itself — mostly using the old Rails convention:

This makes it very difficult to discover how a Rails app responds to a particular URL, without hunting through the controllers to find a corresponding action. It also makes working with REST a nightmare!

Lesson learnt: use routes.rb

2. Conventions are important

Rails is all about convention over configuration, of course. But when you’re coding a Rails app — especially if you’re new to Rails — it’s easy to ignore those conventions, or just be plain unaware of them.

This leads to a lot of unnecessary work. I’ve spent a lot of time over the past few months translating unconventional code into code that more closely fits the Rails way of doing things: the result is code that’s easier to test, easier to maintain, and much, much faster.

Lesson learnt: take some time to understand Rails’ conventions

3. Simplicity is important

The more I write code, the more I find myself thinking: complicated code is a Bad Thing. Of course, as a kind pedant once told me, there’s a difference between complicated and complex.

(If you don’t have a dictionary handy, “complicated” roughly means messy, difficult to understand; “complex” means many interconnected parts, or a large system. The key difference is that complex systems can be well designed: complicated systems are not.)

OK, dictionary rant over :) Messy, complicated Rails applications come about when a developer doesn’t take the time to think things through. Simplicity is normally easy if you take some time to plan your work upfront — messy code happens when things are rushed or not thought through.

Lesson learnt: think before you start coding

4. Ruby is important

Obvious, but very true: Ruby is important to Rails applications. If you’re new to coding, or new to Rails, then take some time to learn Ruby first: otherwise, you’ll miss out on the power (and beauty) of a great language and a great framework.

Lesson learnt: learn Ruby and Rails, not just Ruby on Rails!

You are important, too

Conclusions? All of the above (and more) is important when you’re developing a Rails app. And you, the developer, are important too — have fun, keep learning, and don’t work too hard. Rails should be fun :)

How to use Ruby in place of PHP

PHP has a great reputation as a hackers’ language, a tool for putting together websites with minimum fuss. It’s pretty easy to add new features to PHP-based websites too, as you scale. But what if you’re a Ruby fanatic, or just plain lazy, like me?

(more…)

Method Missing & Proxies in Ruby

Great article from John Nunemaker explaining how to create proxies — objects that act like other objects — in Ruby, using a little bit of method_missing magic.

If you need to seriously extend the functionality of existing Ruby classes, it’s much cleaner and safer to use proxies, so this article is a must-read.

Learn Ruby!

Ruby is a beautiful language: easy to write, simple to read, and powerful as hell. It’s also pretty easy to pick up the basics of Ruby without too much trouble — but save yourself some time by checking out the following resources that have helped me loads.

(more…)

Clone TinyURL (and friends) with Rails

tr.im is closing down, and the blogs are a-chatter about why URL-shortening services are probably a bad idea if you care about your links, and why you should roll your own service if you can.

Which is where Rails comes in.

(more…)

iPhone on Rails

It’s really simple to get a Rails application to serve custom views to an iPhone or iPod touch: so simple, in fact, that in a spare half-an-hour I wrapped the necessary code up into a tiny plugin, which will do all the work for you!

Update: if you’re using the plugin, have questions, or have found this post useful, take a moment to send me a message on Github, or email me (james at this domain). It’s always great to know how people are using my work :)

(more…)

Bowline: Desktop Apps with Ruby

Bowline is a Ruby GUI framework that allows you to build desktop applications using Ruby, HTML, CSS, and JQuery. Sounds interesting? I thought so too!

(more…)

Rails 3

Well, I’ve been away from WordPress for a while thanks to flu (swine? maybe), and I thought a good way to break the silence would be with a post on the upcoming release of Rails: version 3.

(more…)