Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Combinatory method like tap, but able to return a different value?

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.

like image 658
d11wtq Avatar asked Oct 24 '11 16:10

d11wtq


People also ask

What do Ruby methods return?

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.

What is the tap method in Ruby?

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 .


2 Answers

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 
like image 117
tokland Avatar answered Oct 27 '22 23:10

tokland


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

like image 34
kuboon Avatar answered Oct 27 '22 23:10

kuboon