Preserving Named Arguments On Inheritance
I don't use inheritance very often, but sometimes it is the best solution. Ruby doesn't care very much carrying when you overwrite a method. The method is just replaced by the new method. It doesn't care about arguments at all.
Since 2.0, Ruby support named arguments. I'm starting to use them more and more. But they are a bit tricky when overwriting.
Let's say we have a class which creates user objects named UserBuilder
:
class UserBuilder
def create(name: )
puts "name: #{name}"
end
end
When I have to create a CustomerBuilder
, which creates customers (user with address), I can write it like:
class CustomerBuilder < UserBuilder
def create(address:, name:)
super name: name
puts "address: #{address}"
end
end
This works but creates a coupling between UserBuilder
and CustomerBuilder
. This coupling is a bit tricky to catch. Imagine the following scenarios:
name
become optional inUserBuilder
name
is renamed tofull_name
inUserBuilder
name
is split intofirst_name
andlast_name
inUserBuilder
In all of those cases change in UserBuilder
triggers changes in CustomerBuilder
.
Such dependencies are toxic. Here is a better solution:
class CustomerBuilder < UserBuilder
def create(address:, **args)
super **args
puts "address: #{address}"
end
end
Now we can add, change, remove named arguments to UserBuilder#create
and CustomerBuilder#create
is not affected. Named arguments are just delegated down the change.