In some part of my code I ended writing the following: [ruby] self.count_processed ||= 0 self.count_processed += 1 [/ruby] where
self is some ActiveRecord model, and
count_processed is an attribute of that model (and stored in the database). What am i trying to achieve (if it is not blatantly obvious):
count_processedis not initialised, make it zero
count_processedImho this code is clear and readable, but I had the feeling it could be more concise/prettier. So I asked that question on our campfire, to see if we could come up with something shorter. Very nice to be working in a team where you can just throw up questions like these and a very useful, educational discussion unfolds. In short we came up with the following solutions.
[ruby] self.count_processed = self.count_processed.to_i + 1 [/ruby] Nifty! Isn't it? Use
to_i because it will handle the
nil correctly. But for me this looked wrong. If I would return to this code after a few weeks, months, I would wonder why I did this way, and not just wrote
self.count_processed += 1. So while the code is correct, the intent of the code is not clear.
Solution 2: concise!
[ruby] self.count_processed = (self.count_processed || 0) + 1 [/ruby] This is very beautiful, and the intent is also very clear. If it is not initialised, use the zero, else just use the value and add 1. Awesome.
Solution 3: change the getter
And alternative solution would be to overwrite the getter, like this [ruby] def count_processed self[:count_processed] ||= 0 end [/ruby] Note the notation we used: we use
self[:count_processed] because this will fetch the value from the database column. If this was a normal getter, we would write
@count_processed (but that does not work for an ActiveRecord model). After redefining the getter, we can just write: [ruby] self.count_processed += 1 [/ruby] While this will work always, does it express its intent more clearly or not? Actually you no longer have to worry about the initialisation, because it is handled, and we can focus on what we really want: increment the counter. I opted for this solution.
What about you?
Which version do you prefer? Do you have any alternative suggestions?