I would like to define the [] method on a class of my own creation to take a block. I have done so as follows.
class A
def self.[](*args, &block)
puts "I am calling #{block} on #{args}."
block.(*args)
end
end
I can invoke this as follows.
# Explicit method invocation
A.[](1) { |x| puts x }
# With a procedure argument
arg = proc { |x| puts x }
A[2, &arg]
However, what I would like to be able to do is this.
A[3] { |x| puts x }
Which unfortunately seems to produce a syntax error. Is there a block syntax for the bracket method, or am I stuck with the first two ways of invoking it? In fact, more generally, which Ruby method names will allow blocks in their invocation, as it seems that there might be a limitation on when this is allowed?
There's not much you can do against a syntax error, so you'll have to change the syntax.
If you accept :
to define (i.e. pollute) an uppercase method inside Kernel (similar to Kernel#Array)
to use parens instead of brackets
You could write :
class A
def self.call_block_with_args(*args, &block)
puts "I am calling #{block} on #{args}."
block.call(*args)
end
end
module Kernel
def A(*args, &block)
A.call_block_with_args(*args, &block)
end
end
It works this way :
A(3) { |x| puts x }
#=>
# I am calling #<Proc:0x000000012b9c50#block_brackets.rb:14> on [3].
# 3
It's not clean, but it's probably the closest you can be to A[3] { |x| puts x }.
Blocks work with normal method calls only.
Ruby has plenty of operators, listing all of them here would be exhaustive, there are more than two dozens. Even `a` and !a and -a are method calls in Ruby. And obviously there are limitations to all these operators, eg + must take one parameter but not more, et cetera.
Fun fact, loop is a method call too.
Related
That title is not the best, so I will explain further here.
I have a Card class and a Deck class, and in Main, I am creating a Deck of Cards and then printing out all the Cards in the Deck. I've made a to_string method for Card (below):
def to_string
puts "#{self.rank} of #{self.suit}"
end
and then used that and a for/each statement in Main to print all the Cards in Deck:
for card in deck
puts card.to_string
end
But I received an error saying that there was an "undefined method 'each' for #Deck: (NoMethodError). I did some searching and found that the solution was to add this method to my Deck class:
def each(&block)
#deck.each(&block)
end
I do understand (or, I think I do) how .each works, as I used it in creating all the Card objects for my Deck--it will go through an array and grab each array item in turn. So it made sense that for card in deck is basically deck.each. But I'm not really sure what &block is doing here. I did some research on what blocks are (to my understanding, basically "anonymous code"--so for example, the instructions inside of a array.each statement. A method that isn't a formally written method) but I still don't know what &block itself does.
Every method in Ruby can (but doesn't have to) take an optional block argument, denoted with an ampersand & before the argument name. This argument is given the value of an explicit block when the method is called.
We can see this behavior explicitly by writing a function which simply returns its block.
def foo(&block)
p block
end
Then if we run
> foo() # Note: No block argument
nil
> foo { 1 } # Note: Block provided
#<Proc:0x...>
So if you pass an explicit block to a method, it gets passed as a Proc object to the method. This is how .each works. The line
[1, 2, 3].each { |x| puts x }
calls each on [1, 2, 3], passing a block argument whose call method runs puts x. You can think of it as similar to
[1, 2, 3].each(->(x) { puts x })
Here, we pass a regular argument which happens to be a lambda. This is not equivalent to the above (block arguments are treated as special), but we could theoretically have implemented each either way; the block syntax is just more convenient.
As you've correctly surmised, for loops desugar to something kind of like .each. Roughly speaking, the following two are equivalent.
for i in [1, 2, 3]
foo i
end
i = nil
[1, 2, 3].each do |i|
foo i
end
Note that for loops actually go to additional effort to ensure that the variable does escape the loop scope, whereas using .each directly produces a local-only variable that doesn't escape. For this reason, .each is generally considered more idiomatic in Ruby anyway, and most Ruby code shies away from explicit for loops in general. (IMO .each is also prettier and more consistent with all of the other aspects of Ruby syntax)
I'm not sure I succeed to clarify this properly, just a try...
Actually for item in deck is actually syntax sugar for those, that previously learned some procedural language, like Pascal or C, and is equivalent for method call: deck.each { |item| ... }. The part in curly brackets is a block or anynomous function. So, your code:
for card in deck
puts card
Is actually translated to call of each on deck object:
deck.each { |card| puts card }
What actually does this method - you define it for collection of something and it should pass its item one after another to given block. And inside block we can use those item as a variable with name we like (card in example).
You can actually ignore item in block, for example:
deck.each { puts "Hello" }
And if your deck has 52 cards, you'll see 52 times "Hello".
What is most interesting, is that having defined only this each method you actually can have a bunch of others, like count, min, max, map, etc. For this, you only need to include mixin Enumerable in your class.
Like this:
class Deck
include Enumerable
def each(&block)
#deck.each(&block)
And now, if you call deck.count it will actually return 52, or whatever is the number of cards, you've put there.
How it works: it actually executes something like:
c = 0
deck.each { c = c + 1 }
c
Well, hope that helps...
why do I need to specify an each method using &block in the class of the object I am iterating through?
You don't have to use the &block syntax.
each is supposed to yield each element to the given block, e.g.:
class Foo
def each
yield 1
yield 2
yield 3
end
end
foo = Foo.new
for i in foo
puts i
end
# or more idiomatic:
foo.each do |i|
puts i
end
Since you rarely yield hard-coded values, there's usually some kind of loop within each, e.g.:
class Foo
def each
1.upto(3) do |i|
yield i
end
end
end
In your case, the loop is based on #deck.each, so you could write:
def each
#deck.each do |card|
yield card
end
end
In order to make each more useful, it should also return an enumerator if no block is given:
def each
return enum_for(:each) unless block_given?
#deck.each do |card|
yield card
end
end
So what about that &block syntax?
If you read the documentation for Array#each you might notice that it already does all these things – it yields the elements to the block and returns an enumerator if no block is given. So you could avoid writing the above code just by passing the block that was given to your each along to Array#each.
But how can we refer to the given block? That's what the &block syntax is for – it assigns the block to a variable block which can be passed as a block argument to another method using the same &block syntax:
def each(&block)
#deck.each(&block)
end
Some considerations:
you should avoid for and prefer each-style loops
to_string should just return the string, not print it. You can omit self and you should call it to_s:
def to_s
"#{rank} of #{suit}"
end
which allows you to directly puts your card:
deck.each do |card|
puts card
end
it might be cleaner to call the method each_card
I'm writing a simple method that adds num to the return value of the block that is passed to it and I noticed that &block and &prc both work. I know that a proc is an object and can be assigned to a variable which could be handy. Is that the only difference though? Is there any difference between these two when it comes to performance, convention, or versatility? Is it ever better to use &block instead of &prc?
def adder(num = 1, &block)
yield + num
end
vs.
def adder(num = 1, &prc)
yield + num
end
Is there any difference between these two when it comes to
performance, convention, or versatility?
There is no difference between these, you able to name it as you want, it's just a name. Some devs call it &blk some &block or &b or &foo ...
>> def foo &foo
>> yield
>> end
=> :foo
>> foo do
?> puts '1'
>> end
1
Strictly saying & is an operator which you can apply to any object, and it will take care of converting that object to a Proc by calling to_proc().
>> def bar(&some_proc)
>> some_proc
>> end
=> :bar
>> p = bar { puts 'Call proc' }
=> #<Proc:0x005601e6d69c80#(irb):4>
>> p.call
=> Call proc
>> p.class
=> Proc
Only the one thing is important, the name should be informative.
Line any argument to your method the name is largely subjective. Typically you'll see &block used if only by convention, but the name itself can be anything you want so long as it's a valid variable name.
In your example you're declaring a block name but not actually using the name. Keep in mind that any Ruby method can be given a block, there's no way to restrict this, but it's up to the method itself to use the block if it wants. That block can be called zero or more times either immediately or at some point in the future. Giving the block to the method surrenders control, so be sure to read the documentation on any given method carefully. There can be surprises.
If you need to chain through a block, declare it with a name:
def passes_through(&block)
[ 1, 2, 3, 4 ].each(&block)
end
If you are going to yield on the block there's no need here:
def direct_call
[ 1, 2, 3, 4 ].each do |n|
yield n
end
end
If you're going to preserve the call and use it later, that's also a case for naming it:
def preserved_call(&block)
#callback = block
end
def make_callback
#callback and #callback.call
end
Any method can check if a block was supplied:
def tests_for_block
if (block_given?)
yield 'value'
else
'value'
end
end
There's a small but measurable cost to capturing a block by declaring it in the method signature, a lot of computation has to be done to properly capture all the variables that might be used in a closure situation. In performance sensitive code you'll want to avoid this.
You can dynamically create a block:
def captures_conditionally
if (block_given?)
#callback = Proc.new
end
end
The Proc.new method will assume control over whatever block has been supplied to the method if one has been.
in your example, there is not a difference between &block and &prc, because in each case you are just passing a block to be call into the method.
Block and proc are similar in that they are both blocks of code.
[1,2,3].each {|x| puts x }
everything within the {} is the block.
A proc is just a block of code that you can name and can be called at a later time.
put_element = Proc.new {|x| puts x}
then you use put_element as an argument in your function.
Is def greet; puts "hello"; end the only way to define a method on one line in Ruby?
You can avoid the need to use semicolons if you use parentheses:
def hello() :hello end
No Single-line Methods
From rubocop/ruby-style-guide#no-single-line-methods:
Avoid single-line methods. Although they are somewhat popular in the
wild, there are a few peculiarities about their definition syntax that
make their use undesirable. At any rate - there should be no more
than one expression in a single-line method.
NOTE: Ruby 3 introduced an alternative syntax for single-line method
definitions, that's discussed in the next section of the guide.
# bad
def too_much; something; something_else; end
# okish - notice that the first ; is required
def no_braces_method; body end
# okish - notice that the second ; is optional
def no_braces_method; body; end
# okish - valid syntax, but no ; makes it kind of hard to read
def some_method() body end
# good
def some_method
body
end
One exception to the rule are empty-body methods.
# good
def no_op; end
Endless Methods
From rubocop/ruby-style-guide#endless-methods:
Only use Ruby 3.0's endless method definitions with a single line
body. Ideally, such method definitions should be both simple (a
single expression) and free of side effects.
NOTE: It's important to understand that this guideline doesn't
contradict the previous one. We still caution against the use of
single-line method definitions, but if such methods are to be used,
prefer endless methods.
# bad
def fib(x) = if x < 2
x
else
fib(x - 1) + fib(x - 2)
end
# good
def the_answer = 42
def get_x = #x
def square(x) = x * x
# Not (so) good: has side effect
def set_x(x) = (#x = x)
def print_foo = puts("foo")
P.S.: Just to give an up-to-date full answer.
def add a,b; a+b end
The semicolon is the inline statement terminator for Ruby
Or you can use the define_method method. (Edit: This one's deprecated in ruby 1.9)
define_method(:add) {|a,b| a+b }
Ruby 3.0.0 adds "endless" definitions for methods with exactly one statement:
def greet = puts("hello")
Note that the one-statement limitation means that this can't be written as:
# NOT ALLOWED
def greet = puts "hello"
SyntaxError: unexpected string literal, expecting `do' or '{' or '('
def greet = puts "hello"
^
It seems that this change was intended to either encourage the use of one-line methods or adjust to the reality that they are very common but hard to read -- "this kind of simple method definition [is estimated to] account for 24% of the entire method definitions" of the ruby/ruby code base.
Another way:
define_method(:greet) { puts 'hello' }
May be used if you don't want to enter new scope for method while defining it.
Yet another way:
def greet() return 'Hello' end
I am trying to understand blocks and yield and how they work in Ruby.
How is yield used? Many of the Rails applications I've looked at use yield in a weird way.
Can someone explain to me or show me where to go to understand them?
Yes, it is a bit puzzling at first.
In Ruby, methods can receive a code block in order to perform arbitrary segments of code.
When a method expects a block, you can invoke it by calling the yield function.
Example:
Take Person, a class with a name attribute and a do_with_name method. When the method is invoked it will pass the name attribute to the block.
class Person
def initialize( name )
#name = name
end
def do_with_name # expects a block
yield( #name ) # invoke the block and pass the `#name` attribute
end
end
Now you can invoke this method and pass an arbitrary code block.
person = Person.new("Oscar")
# Invoking the method passing a block to print the value
person.do_with_name do |value|
puts "Got: #{value}"
end
Would print:
Got: Oscar
Notice the block receives as a parameter a variable called value. When the code invokes yield it passes as argument the value of #name.
yield( #name )
The same method can be invoked with a different block.
For instance to reverse the name:
reversed_name = ""
# Invoke the method passing a different block
person.do_with_name do |value|
reversed_name = value.reverse
end
puts reversed_name
=> "racsO"
Other more interesting real life examples:
Filter elements in an array:
days = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]
# Select those which start with 'T'
days.select do | item |
item.match /^T/
end
=> ["Tuesday", "Thursday"]
Or sort by name length:
days.sort do |x,y|
x.size <=> y.size
end
=> ["Monday", "Friday", "Tuesday", "Thursday", "Wednesday"]
If the block is optional you can use:
yield(value) if block_given?
If is not optional, just invoke it.
You can try these examples on your computer with irb (Interactive Ruby Shell)
Here are all the examples in a copy/paste ready form:
class Person
def initialize( name )
#name = name
end
def do_with_name # expects a block
yield( #name ) # invoke the block and pass the `#name` attribute
end
end
person = Person.new("Oscar")
# Invoking the method passing a block to print the value
person.do_with_name do |value|
puts "Got: #{value}"
end
reversed_name = ""
# Invoke the method passing a different block
person.do_with_name do |value|
reversed_name = value.reverse
end
puts reversed_name
# Filter elements in an array:
days = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]
# Select those which start with 'T'
days.select do | item |
item.match /^T/
end
# Sort by name length:
days.sort do |x,y|
x.size <=> y.size
end
In Ruby, methods can check to see if they were called in such a way that a block was provided in addition to the normal arguments. Typically this is done using the block_given? method but you can also refer to the block as an explicit Proc by prefixing an ampersand (&) before the final argument name.
If a method is invoked with a block then the method can yield control to the block (call the block) with some arguments, if needed. Consider this example method that demonstrates:
def foo(x)
puts "OK: called as foo(#{x.inspect})"
yield("A gift from foo!") if block_given?
end
foo(10)
# OK: called as foo(10)
foo(123) {|y| puts "BLOCK: #{y} How nice =)"}
# OK: called as foo(123)
# BLOCK: A gift from foo! How nice =)
Or, using the special block argument syntax:
def bar(x, &block)
puts "OK: called as bar(#{x.inspect})"
block.call("A gift from bar!") if block
end
bar(10)
# OK: called as bar(10)
bar(123) {|y| puts "BLOCK: #{y} How nice =)"}
# OK: called as bar(123)
# BLOCK: A gift from bar! How nice =)
It's quite possible that someone will provide a truly detailed answer here, but I've always found this post from Robert Sosinski to be a great explanation of the subtleties between blocks, procs & lambdas.
I should add that I believe the post I'm linking to is specific to ruby 1.8. Some things have changed in ruby 1.9, such as block variables being local to the block. In 1.8, you'd get something like the following:
>> a = "Hello"
=> "Hello"
>> 1.times { |a| a = "Goodbye" }
=> 1
>> a
=> "Goodbye"
Whereas 1.9 would give you:
>> a = "Hello"
=> "Hello"
>> 1.times { |a| a = "Goodbye" }
=> 1
>> a
=> "Hello"
I don't have 1.9 on this machine so the above might have an error in it.
I found this article to be very useful. In particular, the following example:
#!/usr/bin/ruby
def test
yield 5
puts "You are in the method test"
yield 100
end
test {|i| puts "You are in the block #{i}"}
test do |i|
puts "You are in the block #{i}"
end
which should give the following output:
You are in the block 5
You are in the method test
You are in the block 100
You are in the block 5
You are in the method test
You are in the block 100
So essentially each time a call is made to yield ruby will run the code in the do block or inside {}. If a parameter is provided to yield then this will be provided as a parameter to the do block.
For me, this was the first time that I understood really what the do blocks were doing. It is basically a way for the function to give access to internal data structures, be that for iteration or for configuration of the function.
So when in rails you write the following:
respond_to do |format|
format.html { render template: "my/view", layout: 'my_layout' }
end
This will run the respond_to function which yields the do block with the (internal) format parameter. You then call the .html function on this internal variable which in turn yields the code block to run the render command. Note that .html will only yield if it is the file format requested. (technicality: these functions actually use block.call not yield as you can see from the source but the functionality is essentially the same, see this question for a discussion.) This provides a way for the function to perform some initialisation then take input from the calling code and then carry on processing if required.
Or put another way, it's similar to a function taking an anonymous function as an argument and then calling it in javascript.
I wanted to sort of add why you would do things that way to the already great answers.
No idea what language you are coming from, but assuming it is a static language, this sort of thing will look familiar. This is how you read a file in java
public class FileInput {
public static void main(String[] args) {
File file = new File("C:\\MyFile.txt");
FileInputStream fis = null;
BufferedInputStream bis = null;
DataInputStream dis = null;
try {
fis = new FileInputStream(file);
// Here BufferedInputStream is added for fast reading.
bis = new BufferedInputStream(fis);
dis = new DataInputStream(bis);
// dis.available() returns 0 if the file does not have more lines.
while (dis.available() != 0) {
// this statement reads the line from the file and print it to
// the console.
System.out.println(dis.readLine());
}
// dispose all the resources after using them.
fis.close();
bis.close();
dis.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Ignoring the whole stream chaining thing, The idea is this
Initialize resource that needs to be cleaned up
use resource
make sure to clean it up
This is how you do it in ruby
File.open("readfile.rb", "r") do |infile|
while (line = infile.gets)
puts "#{counter}: #{line}"
counter = counter + 1
end
end
Wildly different. Breaking this one down
tell the File class how to initialize the resource
tell the file class what to do with it
laugh at the java guys who are still typing ;-)
Here, instead of handling step one and two, you basically delegate that off into another class. As you can see, that dramatically brings down the amount of code you have to write, which makes things easier to read, and reduces the chances of things like memory leaks, or file locks not getting cleared.
Now, its not like you can't do something similar in java, in fact, people have been doing it for decades now. It's called the Strategy pattern. The difference is that without blocks, for something simple like the file example, strategy becomes overkill due to the amount of classes and methods you need to write. With blocks, it is such a simple and elegant way of doing it, that it doesn't make any sense NOT to structure your code that way.
This isn't the only way blocks are used, but the others (like the Builder pattern, which you can see in the form_for api in rails) are similar enough that it should be obvious whats going on once you wrap your head around this. When you see blocks, its usually safe to assume that the method call is what you want to do, and the block is describing how you want to do it.
In Ruby, a block is basically a chunk of code that can be passed to and executed by any method. Blocks are always used with methods, which usually feed data to them (as arguments).
Blocks are widely used in Ruby gems (including Rails) and in well-written Ruby code. They are not objects, hence cannot be assigned to variables.
Basic Syntax
A block is a piece of code enclosed by { } or do..end. By convention, the curly brace syntax should be used for single-line blocks and the do..end syntax should be used for multi-line blocks.
{ # This is a single line block }
do
# This is a multi-line block
end
Any method can receive a block as an implicit argument. A block is executed by the yield statement within a method. The basic syntax is:
def meditate
print "Today we will practice zazen"
yield # This indicates the method is expecting a block
end
# We are passing a block as an argument to the meditate method
meditate { print " for 40 minutes." }
Output:
Today we will practice zazen for 40 minutes.
When the yield statement is reached, the meditate method yields control to the block, the code within the block is executed and control is returned to the method, which resumes execution immediately following the yield statement.
When a method contains a yield statement, it is expecting to receive a block at calling time. If a block is not provided, an exception will be thrown once the yield statement is reached. We can make the block optional and avoid an exception from being raised:
def meditate
puts "Today we will practice zazen."
yield if block_given?
end meditate
Output:
Today we will practice zazen.
It is not possible to pass multiple blocks to a method. Each method can receive only one block.
See more at: http://www.zenruby.info/2016/04/introduction-to-blocks-in-ruby.html
I sometimes use "yield" like this:
def add_to_http
"http://#{yield}"
end
puts add_to_http { "www.example.com" }
puts add_to_http { "www.victim.com"}
Yields, to put it simply, allow the method you create to take and call blocks. The yield keyword specifically is the spot where the 'stuff' in the block will be performed.
There are two points I want to make about yield here. First, while a lot of answers here talk about different ways to pass a block to a method which uses yield, let's also talk about the control flow. This is especially relevant since you can yield MULTIPLE times to a block. Let's take a look at an example:
class Fruit
attr_accessor :kinds
def initialize
#kinds = %w(orange apple pear banana)
end
def each
puts 'inside each'
3.times { yield (#kinds.tap {|kinds| puts "selecting from #{kinds}"} ).sample }
end
end
f = Fruit.new
f.each do |kind|
puts 'inside block'
end
=> inside each
=> selecting from ["orange", "apple", "pear", "banana"]
=> inside block
=> selecting from ["orange", "apple", "pear", "banana"]
=> inside block
=> selecting from ["orange", "apple", "pear", "banana"]
=> inside block
When the each method is invoked, it executes line by line. Now when we get to the 3.times block, this block will be invoked 3 times. Each time it invokes yield. That yield is linked to the block associated with the method that called the each method. It is important to notice that each time yield is invoked, it returns control back to the block of the each method in client code. Once the block is finished executing, it returns back to the 3.times block. And this happens 3 times. So that block in client code is invoked on 3 separate occasions since yield is explicitly called 3 separate times.
My second point is about enum_for and yield. enum_for instantiates the Enumerator class and this Enumerator object also responds to yield.
class Fruit
def initialize
#kinds = %w(orange apple)
end
def kinds
yield #kinds.shift
yield #kinds.shift
end
end
f = Fruit.new
enum = f.to_enum(:kinds)
enum.next
=> "orange"
enum.next
=> "apple"
So notice every time we invoke kinds with the external iterator, it will invoke yield only once. The next time we call it, it will invoke the next yield and so on.
There's an interesting tidbit with regards to enum_for. The documentation online states the following:
enum_for(method = :each, *args) → enum
Creates a new Enumerator which will enumerate by calling method on obj, passing args if any.
str = "xyz"
enum = str.enum_for(:each_byte)
enum.each { |b| puts b }
# => 120
# => 121
# => 122
If you do not specify a symbol as an argument to enum_for, ruby will hook the enumerator to the receiver's each method. Some classes do not have an each method, like the String class.
str = "I like fruit"
enum = str.to_enum
enum.next
=> NoMethodError: undefined method `each' for "I like fruit":String
Thus, in the case of some objects invoked with enum_for, you must be explicit as to what your enumerating method will be.
Yield can be used as nameless block to return a value in the method. Consider the following code:
Def Up(anarg)
yield(anarg)
end
You can create a method "Up" which is assigned one argument. You can now assign this argument to yield which will call and execute an associated block. You can assign the block after the parameter list.
Up("Here is a string"){|x| x.reverse!; puts(x)}
When the Up method calls yield, with an argument, it is passed to the block variable to process the request.
New to ruby, put on your newbie gloves.
Is there any difference (obscure or practical) between the following two snippets?
my_array = [:uno, :dos, :tres]
my_array.each { |item|
puts item
}
my_array = [:uno, :dos, :tres]
my_array.each do |item|
puts item
end
I realize the brace syntax would allow you to place the block on one line
my_array.each { |item| puts item }
but outside of that are there any compelling reasons to use one syntax over the other?
Ruby cookbook says bracket syntax has higher precedence order than do..end
Keep in mind that the bracket syntax
has a higher precedence than the
do..end syntax. Consider the following
two snippets of code:
1.upto 3 do |x|
puts x
end
1.upto 3 { |x| puts x }
# SyntaxError: compile error
Second example only works when parentheses is used, 1.upto(3) { |x| puts x }
This is a bit old question but I would like to try explain a bit more about {} and do .. end
like it is said before
bracket syntax has higher precedence order than do..end
but how this one makes difference:
method1 method2 do
puts "hi"
end
in this case, method1 will be called with the block of do..end and method2 will be passed to method1 as an argument! which is equivalent to method1(method2){ puts "hi" }
but if you say
method1 method2{
puts "hi"
}
then method2 will be called with the block then the returned value will be passed to method1 as an argument. Which is equivalent to method1(method2 do puts "hi" end)
def method1(var)
puts "inside method1"
puts "method1 arg = #{var}"
if block_given?
puts "Block passed to method1"
yield "method1 block is running"
else
puts "No block passed to method1"
end
end
def method2
puts"inside method2"
if block_given?
puts "Block passed to method2"
return yield("method2 block is running")
else
puts "no block passed to method2"
return "method2 returned without block"
end
end
#### test ####
method1 method2 do
|x| puts x
end
method1 method2{
|x| puts x
}
#### output ####
#inside method2
#no block passed to method2
#inside method1
#method1 arg = method2 returned without block
#Block passed to method1
#method1 block is running
#inside method2
#Block passed to method2
#method2 block is running
#inside method1
#method1 arg =
#No block passed to method1
Generally, the convention is to use {} when you are doing a small operation, for example, a method call or a comparison, etc. so this makes perfect sense:
some_collection.each { |element| puts element }
But if you have slightly complex logic that goes to multiple lines then use do .. end like:
1.upto(10) do |x|
add_some_num = x + rand(10)
puts '*' * add_some_num
end
Basically, it comes down to, if your block logic goes to multiple lines and cannot be fitted on the same line then use do .. end and if your block logic is simple and just a simple/single line of code then use {}.
There are two common styles for choosing do end vs. { } for blocks in Ruby:
The first and very common style was popularized by Ruby on Rails, and is based on a simple rule of single vs. multi-line:
Use braces { } for single-line blocks
Use do end for multi-line blocks
This makes sense because do/end reads badly in a one-liner, but for multi-line blocks, leaving a closing } hanging on its own line is inconsistent with everything else that uses end in ruby, such as module, class & method definitions (def etc.) and control structures (if, while, case, etc.)
The second, less-frequently seen style is known as semantic, or "Weirich Braces", proposed by the late, great rubyist Jim Weirich:
Use do end for procedural blocks
Use braces { } for functional blocks
This means that when the block is evaluated for its return value, it should be chainable, and the {} braces make more sense for method chaining.
On the other hand, when the block is evaluated for its side-effects, then the return value is of no consequence, and the block is just "doing" something, so it does not make sense to be chained.
This distinction in the syntax conveys visual meaning about the evaluation of the block, and whether or not you should care about its return value.
For example, here the return value of the block is applied to every item:
items.map { |i| i.upcase }
However, here it's not using the block's return value. It's operating procedurally, and doing a side-effect with it:
items.each do |item|
puts item
end
Another benefit of the semantic style is that you don't need to change braces to do/end just because a line was added to the block.
As an observation, coincidentally functional blocks are frequently a one-liner, and procedural blocks (e.g. config) are multi-line. So, following the Weirich style ends up looking almost the same as the Rails style.
I used the Weirich style for years, but just moved away from this to always use braces. I don't remember to ever have used the info from the block style, and the definition is kinda vague. For example:
date = Timecop.freeze(1.year.ago) { format_date(Time.now) }
customer = Timecop.freeze(1.year.ago) { create(:customer) }
Are these procudual or functional?
And the line count thing is just useless in my opinion. I know, whether there are 1 or more lines, and why exactly should I change the style just because I've added or removed lines?