Mutating version of tap -- or a way to pipe expressions? - ruby

tap yields self to the block passed to it, and returns self unaltered. I often find myself wishing there was a version of tap which returned the return value of the block, rather than self. For example:
[1,2].inject(:+).tap {|x| x * 3} #=> returns 3, but I want 9
Is there any builtin method that will accomplish this?
The typical solution -- create a temporarily local var to store the output of [1,2].inject(:+), and multiply that by 3 -- seems kludgy.

There is no built in method for that, but you can add Kernel#ergo from Ruby Facets:
"a".ergo.upcase #=> "A"
nil.ergo.foobar #=> nil
"a".ergo { |o| o.upcase } #=> "A"
nil.ergo { |o| o.foobar } #=> nil
This is like #tap, but #tap yields self and returns self, where as #ergo yields self but returns the result.

This is an older question, but you can now use yield_self to do this.

You could do this yourself.
class Object
def my_tap
return yield self if block_given?
self
end
end
[1,2].inject(:+).my_tap {|x| x * 3}
=> 9

Related

How does the &.method syntax (safe navigation operator) works in Ruby?

I noticed if you type:
object &, you get the object back.
For example:
1.class # => Integer
1 &.class # => Integer
'hello'.then { |x| x.equal?(x &.itself) } # => true
[1, 2, 3] &.map(&:next) # => [2, 3, 4]
I am unable to find a documentation for the syntax for object &.method
How does this syntax work?
There are 2 seperate operators here:
Safe navigation operator &. - It is safe navigation operator which was introduced in Ruby 2.3.0. It basically returns nil if the callee is nil instead of raising excecption undefined method called for Nil class. eg:
a = 1
a.next
# => 2
a&.next
# => 2
a = nil
a.next
# => NoMethodError (undefined method `next' for nil:NilClass)
a&.next
# => nil ## No exception, returns nil
You can read about it more here and documentation
Unary & : This operator is a little more complex. It is almost equivalent to calling #to_proc but not quite that. But for this discussion let us think like that. So, if you have a Proc, calling with & in front of it will call #to_proc on the Proc and convert it into a block
multiply_by_2 = Proc.new { |x| x * 2 }
# => #<Proc:0x00007fb4771cf560>
# &multiply_by_2 almost equivalent to { |x| x * 2 } but is not correct syntax
[1, 2].map(&multiply_by_2)
# => [2, 4]
# equivalent to [1, 2].map { |x| x * 2 }
But what happens if we give a symbol like :abc to & operator instead of a proc. It will try to call #to_proc on the symbol and ruby has defined Symbol#to_proc which roughly translates to something like this:
def to_proc
# this will return some block like { |x| x.send(:abc) }
lambda { |x| x.send(self) }
end
So &:abc roughly translates to this block { |x| x.abc } using the below transformation
&:abc =====> :abc.to_proc =====> { |x| x.send(:abc) } ====> { |x| x.abc }
So, instead of doing [1, 2, 3].map { |x| x.next }, you could do [1, 2, 3].map(&:next) as &:next is roughly equivalent to the block { |x| x.next }.
See unary & (which is the main source of what I have written here) for more reading.
It's ruby syntax, & calls to_proc on the object and passes the result as a block to the method.
An explanation from the pickaxe book, programming Ruby 1.9 and 2.0
Blocks Can Be Objects
Blocks are like anonymous methods, but there’s
more to them than that. You can also convert a block into an object,
store it in variables, pass it around, and then invoke its code later.
Remember we said that you can think of blocks as being like an
implicit parameter that’s passed to a method? Well, you can also make
that parameter explicit. If the last parameter in a method definition
is prefixed with an ampersand (such as &action ), Ruby looks for a
code block whenever that method is called. That code block is
converted to an object of class Proc and assigned to the parameter.
You can then treat the parameter as any other variable. Here’s an
example where we create a Proc object in one instance method and store
it in an instance variable. We then invoke the proc from a second
instance method.
class ProcExample
def pass_in_block(&action)
#stored_proc = action
end
def use_proc(parameter)
#stored_proc.call(parameter)
end
end
Use it like so
eg = ProcExample.new
eg.pass_in_block { |param| puts "The parameter is #{param}" }
eg.use_proc(99)
produces:
The parameter is 99

Way to refer to the receiver of 'Array#each'

I am iterating over an array, and I'm wondering if there's a shorthand to refer to the receiver of #each (or #each_with_index) method from within the iteration.
self returns main.
You should be able to just reference it:
my_thing.each {|one_thing| puts my_thing }
This is pretty similar to the answer I gave here https://stackoverflow.com/a/45421168/2981429 but slightly different.
First off, you can create a scope with self bound to the array, and then execute the each in that scope:
[1].instance_exec do
# in this scope, self is the array
# thus we can use just 'each' because the self is inferred
each do |x|
# note that since 'class' is a special keyword,
# it needs to be explicitly namespaced on self
puts self.class, x
end
end
# => prints Array, 1
You can create a utility function to do this, if you want:
def bound_each(enumerable, &blk)
enumerable.instance_exec { each &blk }
end
bound_each([1]) { |x| puts self.class, x }
# prints Array, 1
You can call your each method within an Object#tap block and reference the original receiver like that.
[1, 2, 3].tap { |i| i.each { |j| p i.dup << j } }
# [1, 2, 3, 1]
# [1, 2, 3, 2]
# [1, 2, 3, 3]
#=> [1, 2, 3]
Here the receiving object is [1, 2, 3] and is passed to the block-variable i which we can use locally or in nested scopes such as each's block.
Avoid modifying the receiving object else you may end up with undesired results such as an infinite array. Using dup could allay this possibility.
This is an interesting question. As far as I know it's not possible – the closest I can come up with would be to use inject (or reduce) and explicitly pass the receiver as an argument. A bit pointless, but there might be a use-case for it that I'm not seeing:
a = [1,2,3]
a.inject(a) do |this, element|
this == a #=> true
this.include?(element) #=> true
this
end
Apart from looking a bit redundant, you have to be very sure to return this at the end of each iteration, as the return value will become this in the next iteration. For that reason (and the fact that you could just reference your collection in an each block, as in David's answer) I don't recommend using this.
Edit - as Simple Lime pointed out in the comments – I missed the obvious Enumerator#with_object, which has the same (rather pointless) effect, but without the drawback of having to return this at the end of each iteration. For example:
a = [1,2,3]
a.map.with_object(a) do |element, this|
this == a #=> true, for each iteration
end
I still don't recommend that you use this though.

How can I create an enumerator that does certain things after iteration?

How can I create an enumerator that optionally takes a block? I want some method foo to be called with some arguments and an optional block. If it is called with a block, iteration should happen on the block, and something should be done on it, involving the arguments given. For example, if foo were to take a single array argument, apply map on it with the given block, and return the result of join applied to it, then it would look like:
foo([1, 2, 3]){|e| e * 3}
# => "369"
If it is called without a block, it should return an enumerator, on which instance methods of Enumerator (such as with_index) should be able to apply, and execute the block in the corresponding way:
enum = foo([1, 2, 3])
# => Enumerator
enum.with_index{|e, i| e * i}
# => "026"
I defined foo using a condition to see if a block is given. It is easy to implement the case where the block is given, but the part returning the enumerator is more difficult. I guess I need to implement a sublass MyEnum of Enumerator and make foo return an instance of it:
def foo a, &pr
if pr
a.map(&pr).join
else
MyEnum.new(a)
end
end
class MyEnum < Enumerator
def initialize a
#a = a
...
end
...
end
But calling MyEnum.new raises a warning message: Enumerator.new without a block is deprecated; use Object#to_enum. If I use to_enum, I think it would return a plain Enumerator instance, not the MyEnum with the specific feature built in. On top of that, I am not sure how to implement MyEnum in the first place. How can I implement such enumerator? Or, what is the right way to do this?
You could do something like this.
def foo a, &pr
if pr
a.map(&pr).join
else
o = Object.new
o.instance_variable_set :#a, a
def o.each *y
foo #a.map { |z| yield z, *y } { |e| e }
end
o.to_enum
end
end
Then we have
enum = foo([1,2,3])
enum.each { |x| 2 * x } # "246"
or
enum = foo([1,2,3])
enum.with_index { |x, i| x * i } # "026"
Inspiration was drawn from the Enumerator documentation. Note that all of your expectations about enumerators like you asked for hold, because .to_enum takes care of all that. enum is now a legitimate Enumerator!
enum.class # Enumerator

ruby enumerables: is there a detect for results of block evaluation?

I'm looking for something similar to #detect in enumerables, but not quite. This is what enumerable does:
[1, 2, 3].detect {|i| i > 1 } #=> 2
it returns the first instance of the array which matches the condition. Now, my purpose is to return the value of the block. Concern is not exactly the conditions, but for instance, the first which is not nil. Something like this:
[var1, var2, var3].wanted_detect {|var| another_function(var) }
in which the function would return the first result of another_function call which isn't nil.
Mapping the values of applying the method on the variables and then using detect is not an option. This one would ideally have to work in lazy enumerators, for which the early mapping of all possible values is a no-go
[var1, var2, var3].lazy.map { |var| another_function(var) }.reject(&:nil?).first
If you don't have access to Enumerable#lazy, it is easy enough to implement what you want:
module Enumerable
def wanted_detect
self.each do |obj|
val = yield obj
return val if val
end
end
end
Demo:
[1, 2, 3, 4].wanted_detect { |x| x*x if x > 2 }
# => 9
EDIT: Sorry, I missed the last paragraph till falsetru pointed it out.
Thanks for the comments, falsetru.

How to implement an enumerator in Ruby?

For example:
a = [1,2,3,4,5]
a.delete_if { |x| x > 3 }
is equivalent to:
a = [1,2,3,4,5]
a.delete_if.each.each.each.each { |x| x > 3 }
I know a.delete_if returns an enumerator. But how does it know it should delete object when the each block returns true? How to implement delete_if by hand(and in Ruby)?
You can take a look at the Rubinius source code: enumerable module
Here an example of the reject method:
def reject
return to_enum(:reject) unless block_given?
ary = []
each do |o|
ary << o unless yield(o)
end
ary
end
In the implementation of delete_if, the code can verify the value returned from yield to decide whether or not to delete the given entry from the array.
You can read Implementing Iterators in the Programming Ruby guide for more details, but it would looks something like:
class Array
def delete_if
reject { |i| yield i }.to_a
end
end
The above uses yield to pass each item in the array to the block associated with the call to delete_if, and implicitly returns the value of the yield to the outer reject call.

Resources