Better ruby defaults for hash-based options
2014-06-17 · ruby
Almost every ruby, Ruby on Rails project has some kind of a global configuration. Sometimes it’s a YAML file loaded ‘as-is’, other times it’s a model or designated configuration class.
There are cases when we have to fallback to default values. In a model or
configuration class the easiest way is to use accessor with the or
operator:
However this approach have a major drawback: what if we wanted a nil
as the
option value?
We get the same problem for false
value:
Hash#fetch
to the rescue
There is an elegant solution to the nil
values: Hash#fetch
.
This method returns the key value or throws an error (KeyError
) if they key
wasn’t found.
We have several ways for handling default values:
- method with two params:
Hash#fetch(key, default)
- method with a param and a block:
Hash#fetch(key) { default }
- method with a param and a
Proc
as param:Hash#fetch(key, &block)
Implementing option accessor with any of the mentioned methods gives us
possibility to use nil
and false
as option values.
The Pitfall
There’s a little niuance in providing default values via #fetch
most coders
aren’t aware of: When the default value is evaluated?
In the two params version (the one without block param) both parameters are ALWAYS evaluated. That’ right: even if there is a value provided, the default value will be evaluated.
Thankfully the block version evaluates block only if there is no value.
In this simple example evaluating default value isn’t a big thing. However imagine a situation when you perform time-consuming operation like searching through the huge database or retrieving OAuth access token from the server.
Now every call to your config’s #access_token
method will send a request to
the server even if the token was obtained on the first call. For the sake of
time and good practices you don’t want to send a request to remote machine
every time you want to use a token. Good practice is to pass a lambda
as 2nd
parameter instead of defining a block. That will save you time when you have
the same default value in the many places.
Being aware of this issue can save you lots of time trying to debug the performance issues in your application.
Conclusion
When it comes to manage configuration it’s almost always better to use the
#fetch
method over the or
operator. Not only because it allows nil
values.
It also helps you discovering missing configuration parts and handle missing
keys with ease.
Autor: Tomasz Wójcik
Programista, konsultant IT. W pracy zajmuje się głównie Javą, skrupulatnie zgłębia tajniki Rubyego na szynach. Kiedyś programował gry w C, Objective-C i ActionScript 3 (oraz sterowniki w asemblerze), teraz robi to wyłącznie po pracy. Wielki zwolennik gita.