Reputation: 3945
What is the best practice for expressing intent with Ruby method names?
For example, with the following:
class Formula
attr_accessor :steps
def find_step(key)
@steps.find {|s| s.name == key }
end
end
and:
class Step
attr_accessor :name
end
The Formula#find_step
method expects a Symbol
but it could just as easily take a Step
type and check that the names match. I could rename the method find_step_by_name
but it's still not clear what name
is. Is it a string or a symbol? Or is it matching the name on a Step
object?
Edit: marked as a possible duplicate of Does Ruby support type-hinting? I'm not asking if it's possible, I'm asking a question about naming.
Upvotes: 1
Views: 127
Reputation: 8247
I think the best answer to the question is good choice of the argument name. If you intend a symbol to be passed into your find_by method, why not do this:
def find_by(symbol)
@steps.find {|s| s.name == symbol }
end
However, I think this would be clearest option:
def find_by_name(symbol)
@steps.find {|s| s.name == symbol }
end
I don't agree that using a keyword solves this problem. All it does is change the way the string or symbol is passed into the method.
def find_by(name:)
puts name
end
find_by name: 'this' # name has to be passed in via hash
find_by name: :that
def find_by(name)
puts name
end
find_by 'this' # name is passed in directly
find_by :that
It doesn't get over the problem that 'name' doesn't imply what type of object is being passed in.
I think keywords are really useful if you are passing in multiple arguments into the method, as they makes the code much more readable at the point it is used.
def mass(width:, height:, density:)
width * height * density
end
mass width: 3, height: 11, density: 0.5
That means you don't have to go to the mass method definition each time it's used to work out what's being passed in. It also removes the necessity to get the argument order correct. This will work just as well:
mass width: 3, density: 0.5, height: 11
But for a method that has a single argument, I think you're just adding complexity by using keywords.
Upvotes: 1
Reputation: 441
after Ruby2.1 I think the following solution is nice.
def find_by(name:)
# and you can check if type of name is what you expect as you need.
# But that is not duck-typingy.
end
Upvotes: 1
Reputation: 106972
I would argue that find_step_by_name
makes it clear that is expects a name
and not a step
that might have a name. If you are unsure if to support strings or symbols then allow both:
def find_step_by_name(name)
@steps.find { |s| s.name == name.to_s }
end
Upvotes: 1