I'm going through a phase of trying to avoid temporary variables and over-use of conditional where I can use a more fluid style of coding. I've taken a great liking to using #tap
in places where I want to get the value I need to return, but do something with it before I return it.
def fluid_method something_complicated(a, b, c).tap do |obj| obj.update(:x => y) end end
Vs. the procedural:
def non_fluid_method obj = something_complicated(a, b, c) obj.update(:x => y) obj # <= I don't like this, if it's avoidable end
Obviously the above examples are simple, but this is a pretty common coding style in the ruby community nonetheless. I'll sometimes use #inject
to pass an object through a series of filters too:
things.inject(whatever) do |obj, thing| thing.filter(obj) end
Vs. the procedural:
obj = whatever things.each do |thing| obj = thing.filter(obj) end obj
Now I'm facing repeated use of a condition like the following, and looking for a more fluid approach to handling it:
def not_nice_method obj = something_complex(a, b, c) if a_predicate_check? obj.one_more_method_call else obj end end
The (slightly) cleaner solution is to avoid the temporary variable at the cost of duplication:
def not_nice_method if a_predicate_check? something_complex(a, b, c).one_more_method_call else something_complex(a, b, c) end end
I can't help but feeling the desire to use something almost like #tap
here though.
What other patterns might I follow here. I realise this is all just nonsensical sugar to some people and that I should just move onto more interesting problems, but I'm trying to learn to write in a more functional style, so I'm just curious what long-term rubyists have determined to be good ways to tackle situations like this. These examples are hugely simplified.
Ruby methods ALWAYS return the evaluated result of the last line of the expression unless an explicit return comes before it. If you wanted to explicitly return a value you can use the return keyword.
tap method. This method allows you to "tap" into the result of a method call, usually to perform additional operations on that result, or to debug that result (i.e. by printing to the console). A quick Google search for ruby tap method will return a lot of articles and StackOverflow discussions about when to use .
Define Object#as
:
class Object def as yield self end end
And now you can write:
def not_sure_this_is_nice_enough_method1 something_complex(a, b, c).as do |obj| a_predicate_check? ? obj.one_more_method_call : obj end end
def best_nice_method something_complex(a, b, c).tap |obj| break obj.one_more_method_call if a_predicate_check? end end
The magic is break
in tap
returns another value.
new
ruby 2.5 has yield_self
which exactly you want. https://stackoverflow.com/a/47890832/683157
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With