using print inside def having yield statement - ruby-on-rails

I am trying to print inside a function.
The function is used for invoking a block.
But I don't see the print happening in the function definition.
Please shed a light on this. Basically I am not clear with the control flow.
def find_all
matching_items = []
self.each do |item|
if yield(item)
puts "after yield" #print not happening
matching_items << item
end
end
matching_items
end
p ['a', 'b','c','c'].find_all { |item|
if item == 'a'
true
end
}

If your code is exactly as written, you are defining and independent method find_all defined on main. When you type [1,2,3,4].find_all, you are calling the find_all method on Array, which is defined in the Enumerable method. So you are not calling your method at all.
What you are probably trying to do is
class Array
def find_all
...
end
end
This way, [1,2,3,4].find_all will call this method.
However, note that this is probably a bad idea: you're overriding a core method that in a class that isn't yours, so that could have consequences in other code that you are not able to anticipate if any other code uses the find_all method.
What you might try instead is to define a method that takes the array in as an argument. You might move this to a module, but for now:
def find_all(array)
matching_items = []
array.each do |item|
if yield(item)
puts "after yield" #print not happening
matching_items << item
end
end
matching_items
end
Of course, this is basically what Enumerable#find_all already does, but less efficiently: so perhaps this is just an academic exercise, in which case, great!, but otherwise, why not just use the existing method?

If you are trying to re-open the class Array then, this is how you can do it
class Array
def find_all(matching_items = [])
self.each do |item|
if yield(item)
puts "after yield" #print not happening
matching_items << item
end
end
matching_items
end
end
p ['a', 'b', 'c', 'c'].find_all { |item|
if item == 'a'
true
end
}
Output
after yield
["a"]

Related

yield to an anonymous block two functions up

there is probably a simple way to do this.
I'm trying to refactor something like the following
def foo(baz)
baz.update_first
if baz.has_condition?
yield baz.val if block_given?
baz.a
else
baz.b
end
end
called like
foo(baz) {|b| b.modify}
to something like
def foo(baz)
baz.update_first
bar(baz) {|i| yield i if block_given? }
end
def bar(baz)
if baz.has_condition?
yield baz.val if block_given?
baz.a
else
baz.b
end
end
Will that work? How?
I think it will, but I'd appreciate a clear explanation of how yielding inside a block works... reading through proc.c and vm.c and a relevant git commit in the ruby source code , I think when bar is called in foo it executes until it yields, and then you walk up the frame stack to the local environment pointer for block defined in foo, which is called, where the yield walks up to the block foo is called with, executes it, and then you are back in bar. Is that correct? Is there a better way to do this?
This feels a little weird to me, like inverting control, and it requires foo to know about baz more then I'd like, but I unfortunately can't simply pass a proc or lambda in this code.
I think maybe the concept of yield will be more clear if you look at an alternative syntax, which is converting the bloc to a proc argument.
For example, the following examples are the same
def my_each(arr)
arr.each { |x| yield x }
end
def my_each(arr, &blk)
arr.each { |x| blk.call(x) }
end
# Both are called the same way
my_each([1,2,3]) { |x| print x }
# => 123
When using yield, the variable is available in the method without declaring it in the parameters list. Prepending an & sign to a parameter converts it to a proc, so in the method it can be run with .call.
Here's an example of providing a block to one method then executing it two scopes in:
def method_a(number, &blk)
method_b do
method_c do
blk.call(number)
end
end
end
def method_b(&blk)
blk.call
end
def method_c(&blk)
blk.call
end
method_a(1) { |num| puts num + 1 }
# => 2
Note that blk is not a magic word - you can name the variable whatever you want.
Here's the same thing with yield:
def method_a(number)
method_b do
method_c do
yield number
end
end
end
def method_b
yield
end
def method_c
yield
end
method_a(1) { |num| puts num + 1 }
# => 2
I think using the &blk syntax is clearer because it assigns a variable to the proc. Just because a proc is used in the method doesn't mean you have to ever run Proc.new. The block is automatically converted to a proc.

RSpec testing model method

I have this method in my models/images.rb model. I am starting with testing and having a hard time coming up with tests for it. Would appreciate your help.
def self.tags
t = "db/data.csv"
#arr = []
csvdata = CSV.read(t)
csvdata.shift
csvdata.each do |row|
row.each_with_index do |l, i|
unless l.nil?
#arr << l
end
end
end
#arr
end
First off a word of advice - CSV is probably the worst imaginable data format and is best avoided unless absolutely unavoidable - like if the client insists that manipulating data in MS Excel is a good idea (it is not).
If you have to use CSV don't use a method name like .tags which can confused for a regular ActiveRecord relation.
Testing methods that read from the file system can be quite difficult.
To start with you might want to alter the signature of the method so that you can pass a file path.
def self.tags(file = "db/data.csv")
# ...
end
That way you can pass a fixture file so that you can test it deterministically.
RSpec.describe Image do
describe "tags" do
let(:file) { Rails.root.join('spec', 'support', 'fixtures', 'tags.csv') }
it 'returns an array' do
expect(Image.tags(file)).to eq [ { foo: 'bar' }, { foo: 'baz' } ]
end
end
end
However your method is very ideosyncratic -
def self.tags
t = "db/data.csv"
#arr = []
self.tags makes it a class method yet you are declaring #arr as an instance variable.
Additionally Ruby's enumerable module provides so many methods for manipulating arrays that using an outer variable in a loop is not needed.
def self.tags(file = "db/data.csv")
csv_data = CSV.read(file)
csv_data.shift
csv_data.compact # removes nil elements
end

Ruby - collection of methods

I have inherited a bunch of methods that are not wrapped by any classes or modules, and are just listed in an .rb file. This was made possible due to the file being used inside a Cucumber test suite. I want to take a collection of all these methods and iterate over each method call, doing some work on each one as they are called.
EX:
def call_all_methods
method1
method2
method3(true)
method3(false)
method4('Y', true)
method4('N', true)
method4('Y', false)
method4('N', false)
end
What i want to be able to do is wrap these all in an array and call them individually with a begin/rescue block around them
$all_methods.each do |method|
begin
method.call
rescue Exception1
handle_exception1
rescue Exception2
handle_exception2
end
end
I've tried putting them all in an array using %w
call_all_methods = %w(...)
and that works but it makes the methods ugly to look at in the IDE
I've tried doing a readlines on the file, but the methods get executed while the file is being read.
I could create methods to wrap each call, but then I have a method to call another method (one line) which isn't right either.
I have looked at Ruby: methods as array elements - how do they work? but neither of those solutions seemed like good solutions for what I'm trying to do, as it would dirty the code
If I understand what you're asking correctly, you could just wrap those methods in a class.
class MyMethods
# all those methods that you have in that file
end
You could then list them all by doing
all_methods = MyMethods.instance_methods(false)
To execute them, you can do all_methods.each {|m| MyMethods.new.send(m)}
You could do something like this:
def execute_several(arr)
arr.each do |method, *args|
begin
v = send(method, *args)
puts "for method '#{method}': #{v}"
rescue ArgumentError => e
puts "for method '#{method}': #{e.message}"
end
end
end
arr = [
[:class],
[:rand, 20],
[:Integer, "20"],
[:Integer, 'cat']
]
execute_several(arr)
# for method 'class': Object
# for method 'rand': 17
# for method 'Integer': 20
# for method 'Integer': invalid value for Integer(): "cat"
Here's an example of how that would be done within a class:
class Array
def execute_several(arr)
arr.each do |method, args|
begin
v = args ? send(method, args) : send(method)
puts "for method '#{method}': #{v}"
rescue TypeError => e
puts "for method '#{method}': #{e.message}"
end
end
end
end
arr = [
[:reverse],
['first'],
[:&, [2,3,4]],
[:|, 'cat']
]
[1,2,3].execute_several(arr)
# for method 'reverse': [3, 2, 1]
# for method 'first': 1
# for method '&': [2, 3]
# for method '|': no implicit conversion of String into Array
I ended up making an array of procs

blocks in silly blocks rspec testing

I had the following tests given to me as an exercise:
require "silly_blocks"
describe "some silly block functions" do
describe "reverser" do
it "reverses the string returned by the default block" do
result = reverser do
"hello"
end
result.should == "olleh"
end
it "reverses each word in the string returned by the default block" do
result = reverser do
"hello dolly"
end
result.should == "olleh yllod"
end
end
describe "adder" do
it "adds one to the value returned by the default block" do
adder do
5
end.should == 6
end
it "adds 3 to the value returned by the default block" do
adder(3) do
5
end.should == 8
end
end
describe "repeater" do
it "executes the default block" do
block_was_executed = false
repeater do
block_was_executed = true
end
block_was_executed.should == true
end
it "executes the default block 3 times" do
n = 0
repeater(3) do
n += 1
end
n.should == 3
end
it "executes the default block 10 times" do
n = 0
repeater(10) do
n += 1
end
n.should == 10
end
end
end
I was able to solve them with the following code:
def reverser
k = []
x = yield.split(" ")
x.each do |y|
n = y.reverse
k.push(n)
end
m = k.join(" ")
m
end
def adder(num=1, &block)
block.call + num
end
def repeater(num=1, &block)
for i in (1..num) do
block.call
end
end
However I some of these concepts I do not understand all that well. For example:
What exactly does the & symbol in the &block parameter mean?
Similarly what is block.call and where is the actual block object I am assuming its calling?
Could I theoretically use another method on block if I wanted to achieve something else?
Also where can I learn a bit more about blocks
This exercise was a bit above my current knowledge.
It means "this is the block parameter". You are not bound to calling it &block, so there needs to be a way to separate it from the other arguments. The same notation is used to pass arguments to a function as block as opposed to normal arguments (see below)
block.call is exactly the same thing as yield. The difference is that you can use block to access the block itself without calling it immediately. For example, you could store the block for later execution. This is a common pattern known as lazy evaluation.
Yes, you can also pass different things than a do/end block as the &block parameter. See below for some examples.
#UriAgassi gave you an excellent link.
Here are some other things you can pass as block argument. First, just a simple method that takes a block for demonstration:
def reverser(&block)
block.call.reverse
end
You can now pass a standard block
reverser do
"hello"
end
#=> "olleh"
Or, in alternative block syntax, used for inline style
reverser { "hello" }
#=> olleh
You can also pass a lambda or proc, which is similar to a block.
By using the &block notation you can pass a variable as block argument:
my_block = lambda { "hello world!" }
reverser(&my_block)
#=> "!dlrow olleh"
Or, in alternative lambda syntax
my_block = -> { "hello world!" }
reverser(&my_block)
#=> "!dlrow olleh"
You can even take an existing method and pass it as block argument
here you can see the great advantage of blocks: They are evaluated
when block.call is executed, not when the code is loaded. Here this
means that the string will change every time accordingly.
def foobar
"foobar at #{Time.now}"
end
reverser(&method(:foobar))
#=> "0020+ 15:42:90 02-50-4102 ta raboof"
#=> "0020+ 31:52:90 02-50-4102 ta raboof"
You can do cool stuff with this, for example:
[1, 2, 3].each(&method(:puts))
1
2
3
#=> [1, 2, 3]
But remember not to overdo it, Ruby is all about expressive and readable code. Use these techniques when they enhance your code, but use simpler ways if possible.
Finally, here is also an example of lazy evaluation:
class LazyReverser
def initialize(&block)
#block = block
end
def reverse
#block.call.reverse
end
end
reverser = LazyReverser.new do
# some very expensive computation going on here,
# maybe we do not even need it, so lets use the
# lazy reverser!
"hello dolly"
end
# now go and do some other stuff
# it is not until later in the program, that we can decide
# whether or not we even need to call the block at all
if some_condition
reverser.reverse
#=> "yllod olleh"
else
# we did not need the result, so we saved ourselves
# the expensive computation in the block altogether!
end

Writing an around_each filter in ruby for every method within a block.

I need a method that takes a block, and performs something similar to an around_each filter for every method within the block.
For instance:
def method_that_takes_block
(#threads ||= Array.new) << Thread.new {yield if block.given?}
end
method_that_takes_a_block do
method_one
method_two
method_three
end
In this instance I would like my method that takes a block to Thread each method within the block and pushes that thread to the #threads array. Essentially I'm just looking for a DRY way to wrap a thread around every method called within a block.
You can't directly wrap a thread around each statement in the block body, if they can be arbitrary statements; there's no way to get that sort of control over the execution of a block body in Ruby. If you can restrict what goes in the block body, you have some more flexibility.
If each of the statements you are executing is simply a method call, as you imply in your example, you can use instance_exec to execute that block on a proxy object, which uses method_missing to spawn a new thread and then forward the method call on to the real object (or do whatever wrapper you're interested in; for the sake of example, I'll just wrap with some print statements):
class Proxy
def initialize obj
#obj = obj
end
def method_missing method, *args
puts "<wrapper>"
#obj.send method, *args
puts "</wrapper>"
end
end
class MethodWrapper
def tell_me_a_joke
puts "Knock, knock?"
end
def whos_there
puts "Orange"
end
def orange_who
puts "Orange you glad I didnt say banana?"
end
def wrap_around &blk
Proxy.new(self).instance_exec &blk
end
end
And here's how you can use it:
>> MethodWrapper.new.wrap_around { tell_me_a_joke; whos_there; orange_who }
<wrapper>
Knock, knock?
</wrapper>
<wrapper>
Orange
</wrapper>
<wrapper>
Orange you glad I didnt say banana?
</wrapper>
=> nil
The previous follows the pattern that you gave in your question, but it's less than ideal as only methods that are forwarded to the underlying object get wrapped:
>> MethodWrapper.new.wrap_around { tell_me_a_joke; puts "something" }
<wrapper>
Knock, knock?
</wrapper>
something
=> nil
You could instead just use instance_exec directly, and call the a wrapper method that takes a block, to get almost the same effect, though slightly less DRY as you need to call your wrapper method each time:
class SimpleWrapper
def tell_me_a_joke
puts "Knock, knock?"
end
def whos_there
puts "Interrupting cow"
end
def interrupting_co
puts "Moooooo!"
end
def wrap
puts "<wrap>"
yield
puts "</wrap>"
end
end
And in use:
>> SimpleWrapper.new.instance_exec do
wrap { tell_me_a_joke }
wrap { whos_there }
wrap { interrupting_co }
wrap { puts "Something" }
end
<wrap>
Knock, knock?
</wrap>
<wrap>
Interrupting cow
</wrap>
<wrap>
Moooooo!
</wrap>
<wrap>
Something
</wrap>
=> nil
You can also do it like this:
%w(method_one method_two method_three).each do |method|
(#threads ||= Array.new) << Thread.new { self.send(method) }
end

Resources