how do I write a bubble sort that will accept a proc?
it seems like we can't .call when writing a method for a class?
help!
class Array
def bubble_sort!
flag = true
while flag
flag = false
self.each_with_index do |x, y|
case x <=> self[y + 1]
when 1
self[y], self[y + 1] = self[y + 1], self[y]
flag = true
end
end
end
self
end
def bubble_sort!(&prc)
# With a proc
end
end
The &prc in a method signature:
def m(&prc)
is really just a way to convert the block to a Proc and give it a name; this is why you usually see it called &blk where "blk" is short for "block". You usually do this when you want to pass the block to another method:
# This is a highly contrived example of course.
def m1
# Do something with the "anonymous" block
yield
end
def m2(&blk)
m1(&blk)
end
m2 { "This is the block" }
So if your bubble_sort! method wants to take a block then you would name it all, you'd just yield with the appropriate arguments inside the method:
def bubble_sort!
self.each_with_index do |x, y|
# ...
something = yield x, y
# ...
end
end
If your bubble_sort! needed to pass the block to another method then you'd say def bubble_sort!(&blk) and some_other_method(&blk):
def bubble_sort!(&blk)
self.each_with_index do |x, y|
# ...
something = some_other_method(&blk)
# ...
end
end
and if you also needed to execute the block as well as passing it to another method, you'd treat it like any other Proc and say blk.call.
Related
I have class (highly simplified for the sake of this discussion)
class MyClass
def initialize
#myrecs = %w(a b c d)
end
def each_rec
#myrecs.each {|r| yield(r)}
end
end
and use it as
x = MyClass.new
x.each_rec { |r| .... }
Since my method each_rec basically does just a myrecs.each, I wanted to define somehow that each_rec just forwards to each. I can achieve the desired effect by explicitly passing the block, i.e.
def each_rec(&block)
#myrecs.each(&block)
end
but I wonder wether it is also possible to achieve my goal without having the block as explicit parameter. I tried the following approaches without success:
(1) Exploit the fact that each returns an Enumerator when called without a block:
def each_rec
#myrecs.each
end
(2) Create an Enumerator:
def each_rec
#myrecs.enum_for(:each)
end
In both cases, I did not get an error, but the block passed to each_rec was simply not entered.
In Ruby, if you call Proc.new without a block inside a method that received a block, it'll convert that method's passed block to a proc. So, you can do:
class MyClass
def initialize
#myrecs = %w(a b c d)
end
def each_rec
#myrecs.each(&Proc.new)
end
end
x = MyClass.new
x.each_rec { |r| puts r }
and now, you no longer need an explicit parameter to your each_rec method. Now, however, you must supply a block to the method, or get an ArgumentError ("tried to create Proc object without a block"). We can fix that with a guard clause:
def each_rec
return #myrecs.each unless block_given?
#myrecs.each(&Proc.new)
end
and can now use it just like each:
x = MyClass.new
x.each_rec { |r| p r }
x.each_rec.with_index { |r, i| p [r, i] }
I understand that
def a(&block)
block.call(self)
end
and
def a()
yield self
end
lead to the same result, if I assume that there is such a block a {}. My question is - since I stumbled over some code like that, whether it makes any difference or if there is any advantage of having (if I do not use the variable/reference block otherwise):
def a(&block)
yield self
end
This is a concrete case where i do not understand the use of &block:
def rule(code, name, &block)
#rules = [] if #rules.nil?
#rules << Rule.new(code, name)
yield self
end
The only advantage I can think of is for introspection:
def foo; end
def bar(&blk); end
method(:foo).parameters #=> []
method(:bar).parameters #=> [[:block, :blk]]
IDEs and documentation generators could take advantage of this. However, it does not affect Ruby's argument passing. When calling a method, you can pass or omit a block, regardless of whether it is declared or invoked.
The main difference between
def pass_block
yield
end
pass_block { 'hi' } #=> 'hi'
and
def pass_proc(&blk)
blk.call
end
pass_proc { 'hi' } #=> 'hi'
is that, blk, an instance of Proc, is an object and therefore can be passed to other methods. By contrast, blocks are not objects and therefore cannot be passed around.
def pass_proc(&blk)
puts "blk.is_a?(Proc)=#{blk.is_a?(Proc)}"
receive_proc(blk)
end
def receive_proc(proc)
proc.call
end
pass_proc { 'ho' }
blk.is_a?(Proc)=true
#=> "ho"
Example:
a = Proc.new do
b = 'hey'
end
def a_method
yield
end
a_method(&a) #=> 'hey'
I understand that yield (or block.call) can be used as a simple co-routine, but I was wondering, are there any more (practical) uses for it beyond simply getting the return value from it? Can we get some of the local variables from the proc into the main method etc.?
If you're not picky about the return value of the block, you can do it using binding.
a = Proc.new do
b = 'hey'
binding
end
def a_method
new_binding = yield
p new_binding.eval("b")
end
a_method(&a)
# => "hey"
If you're using a version of Ruby >= 2.1.0, you can avoid the ickiness of eval by using local_variable_get instead:
p new_binding.local_variable_get(:b)
There are a lot of uses for Procs. For example, you can use it to give instructions to an object. I made a bubble sort using a proc that tells it how to sort. Here it is monkey patched in the array class:
class Array
def bubble_sort(&prc)
self.dup.bubble_sort!(&prc)
end
def bubble_sort!(&prc)
return self if count <= 1
prc = Proc.new { |x, y| x <=> y } unless prc.class == Proc
(0...self.count).each do |x|
((x + 1)...self.count).each do |y|
self[x], self[y] = self[y], self[x] if prc.call(self[x], self[y]) == 1
end
end
self
end
end
I have a method that accepts a method as an argument:
def acceptor_method(received_method)
an_arry.each do |attr|
received_method if some_condition
end
end
This works well if all the received_method does is run through some code:
def some_method
do_something
end
Which is the equivalent of:
def acceptor_method(received_method)
an_arry.each do |attr|
do_something if some_condition
end
end
But what if I want the received_method to break the loop and return a value, as with:
def acceptor_method(received_method)
an_arry.each do |attr|
return true if some_condition
end
end
Unfortunately, this doesn't work:
def some_method
return true
end
As it only returns true for some method, not for acceptor_method--which continues to play through the loop.
So is there a way to send a method that when run is the equivalent of return true?
def acceptor_method
[1, 2, 3, 4].each do |attr|
ret = yield attr
puts attr
end
end
test = acceptor_method do |attr|
break 'test' if attr == 3
end
puts test
outputs:
1
2
test
You can do this using blocks rather than methods. See How can I return something early from a block?
Basically if you have a block with break value and yield to it, the function will return value. Unfortunately I don't see a way to do this using methods, since Ruby really doesn't like having break outside of a block or loop.
Could anyone please help me to understand the difference between "yield self" and "yield"?
class YieldFirstLast
attr_accessor :first, :last
def initialize(first = nil, last = nil)
#first = first
#last = last
yield self if block_given?
end
def hello
puts "#{#first} #{#last} says hello!"
end
end
In the case of yield self, self is the argument passed to the block. With simply yield, no argument is passed. self is not special here, anything could be yielded, e.g.
class Foo
def a() yield self end
def b() yield end
def c() yield "Bar" end
def d() yield 1, 2, "scuba" end
def to_s() "A!" end
end
Foo.new.a {|x| puts x } #=> A!
Foo.new.b {|x| puts x } #=> (a blank line, nil was yielded)
Foo.new.c {|x| puts x } #=> Bar
Foo.new.d {|x, y, z| puts z } #=> scuba
yield self enters block, associated with method call, passing current object as argument to the block, plain yield just enters the block without passing any arguments.
Think of yield as invoking your block and yield self is invoking your block with the current instance as the parameter.