How to put your Ruby constructors on a diet

July 19, 2014

Why?

Coming from the .NET world constructors can get pretty messy when passing in more than three parameters to a constructor. The book Clean Code suggests that you create an object to use as a parameter once the constructor takes more than 3 arguments.

How?

So if we look at this Ruby code we can see how messy it is when you have a number of parameters passed to the initialize method. I went digging around in the book The Ruby Way and found what I think is a pretty clean solution

Messy Code:

class PersonalComputer
	attr_accessor :manufacturer,
				  :model, :processor, :clock,
				  :ram, :disk, :monitor, :colors,
				  :vres, :hres, :net

	def initialize(manufacturer, model, processor, 
				   clock, ram, disk, 
				   monitor, colors, vres, 
				   hres, net)

		@manufacture = manufacture
	    @model = model
	    @processor = processor
	    @clock = clock
	    @ram = ram
	    @disk = disk
	    @monitor = monitor
	    @color = color
	    @vres = vres
	    @hres = hres
	    @net = net
	end
end

Clean code:

class PersonalComputer
	attr_accessor :manufacturer,
				  :model, :processor, :clock,
				  :ram, :disk, :monitor, :colors,
				  :vres, :hres, :net

	def initialize(&block)
		instance_eval &block
	end
end

So this looks pretty clear but how do I set the properties using that &block parameter? Let’s have a look at this

1
2
3
4
5
6
7
8
9
10
11
12
13
macbook = PersonalComputer.new do 
	manufacture = = 'Apple'
    model = 'Macbook Pro'
    processor = 2.6       # GHz

    clock = 16            # Gb

    ram = 16              # Gb

    disk = 500            # Gb

    monitor = 15          # inches

    color = 16777216
    vres = 1280
    hres = 1600
    net = 'T3'
end

Bam! So to me this looks like an anonymous function. We can do any logic in this block so if we needed to call some service or read some file or database to get this data we could.

Here we see that we use accessors for our attributes that they are assigned to intuitively. Also, you need a reference to self as a setter method always needs an explicit receiver to distinguish the method call from an ordinary assignment to a local variable.

Conclusion

This is a nice way to set our properties, we could always create some object to carry these properties but then we add another class that will need to be maintained and tested. I am not sure how the .NET world would feel about setting properties using a Func but might be a useful tool to keep in the tool-belt.


Discussion, links, and tweets

My name is Deon Heyns and I am a developer learning things and documenting them in realtime. Python, Ruby, Scala, .NET, and Groovy are all languages I have written code in. I appeared in the New York Post once. I host my code up at GitHub and Bitbucket so have a look at my code, fork it and send those pull requests.

comments powered by Disqus