What does the |variable| syntax mean? [duplicate] - ruby

This question already has answers here:
What are those pipe symbols for in Ruby?
(7 answers)
Closed 2 years ago.
What is the | | around profile below called, what does it mean, and why it is after do? I thought do is followed by a loop block or so.
ticks = get_all[0...MAX].map do |profile|
# ...
end

it's like a foreach, so profile will be a different value in each of the functions calls, one function call per element in get_all.
see this:
my_array = [:uno, :dos, :tres]
my_array.each do |item|
puts item
end

They are part of the syntax for defining a block. The way I like to explain it is that the pipes look like a slide and those variables inside the pipes "slide" down into the block of code below them.
Essentially the variables in the pipes are available to the block. In the case of iteration the variable would represent an element in whatever you are iterating over.

I'll use this example to try to explain the concept to you.
friends = ["James", "Bob", "Frank"]
friends.each { |friend| puts friend }
James
Bob
Frank
So here, we have an array of our friends: James, Bob, and Frank.
In order to iterate over them, we call the #each method on the array. The method will start with the first item in my array and call the block on it.
Essentially, the item that I'm currently iterating over is passed to the variable inside of the two pipe characters. You can call it |buddy| and change the block to { |buddy| puts buddy } and it would still do the same thing.

The pipe characters delimit the parameter list of a block definition just like parentheses delimit the parameter list of a method definition. So, in this code snippet:
def foo(bar, baz) end
some_method_that_takes_a_block do |bar, baz| end
The parentheses and the pipes have the exact same purpose.

Related

what is the difference between .capitalize and .capitalize!(or .map & .map!...etc.) and in ruby [duplicate]

This question already has answers here:
What is the purpose of "!" and "?" at the end of method names?
(5 answers)
Closed 6 years ago.
learning how to code with Ruby and was trying learn from test first.
and I stumbled something funny.
I was trying to capitalize every word but
title = 'stuart little'
a = title.split
a.each do |x|
x.capitalize
end
a.join(' ')
This one's result is 'stuart little'
but if I add the ! in capitalize
title = 'stuart little'
a = title.split
a.each do |x|
x.capitalize!
end
a.join(' ')
it ends up with the result I want which is 'Stuart Little'
just .capitalize should work shouldn't it? since I'm just capitalizing the words. and what makes .capitalize! work in this scenario?
When a method has a ! at the end in Ruby, it is commonly referred to as a bang-method. The exclamation point indicates that the method is the dangerous version of another method.
In this case, capitalize! will modify your string, while capitalize will return a new string object. Since you are later calling on your original objects (the strings in a), your code will only work with capitalize!. To make the code work with capitalize, you would have to set that index of the array to the result of the method, e.g. a[index] = x.capitalize
if you really want to learn I like to go to the source
for map for map!. the source would tell you what the difference is
map- Invokes the given block once for each element of self.
and
map! - Invokes the given block once for each element of self,
replacing the element with the value returned by the block.

What does |lang| part mean in this each method? Where does this come from?

I am reading through Chris Pine's Learn To Program chapter 7 Arrays and Iterators.
He introduces the each method with the following example:
languages = ['English', 'German', 'Ruby']
languages.each do |lang|
puts 'I love ' + lang + '!'
puts 'Don\'t you?'
end
puts 'And let\'s hear it for C++!'
puts '...'
It's not hard to understand how it works overall, but I can't figure out where the |lang| part is coming from so out of blue. Shouldn't it be assigned/named or something before it can be used like this? So the computer can know what the "lang" refers to? Does || do something wrapping around lang? Or does ruby just know what lang means?
I am afraid the question is too basic, but I am hoping someone might help me just a bit...
lang is a variable used to hold an element from the languages array. Any variable inside || will be used to grab single element from array. So, every time the loops executes, an element from the array is popped out and held in an variable named lang and data held by lang is displayed using puts method.
The each method yields every element one by one and it gets assigned to the variable lang.
Internally, the each method is implemented something like this:
def each
index = 0
while index < array.length
yield array[index]
index += 1
end
end
|lang| is a block variable. If you strip down your code, you can see that the .each method is iterating over the languages array and assigning array elements to the block variable:
languages = ['English', 'German', 'Ruby']
languages.each do |lang|
puts lang
end
#=> English
#=> German
#=> Ruby
Multi-line blocks use a do/end syntax (as in your example), and single-line blocks use a braces syntax. For example:
languages = ['English', 'German', 'Ruby']
languages.each { |lang| puts lang}
It sounds like, in the above example, you created an array storing multiple language variables.
You then iterated over all three elements in the array and represented each one with a variable called lang.
lang, which is inside the brackets is simply a variable.
Hope this helped you

What is the purpose of |element| in Ruby array operations syntax?

[1,2,3,4,5,6,7].delete_if{|i| i < 4 }
For example, in the above, why do you need to put |i| before i < 4?
I'm new to Ruby programming and the purpose of this element escapes me.
This is very basic Ruby syntax for a block. A block can sometimes take parameters which are given between the bars |. In your case:
[1,2,3,4,5,6,7].delete_if { |i| i < 4 }
The delete_if method for the type Array accepts a block as a parameter. When the bock is given, the block accepts the array element as a parameter. So it iterates i over each value within the array in this case. More specifically, an element will be deleted from the array if that element is < 4. The result will be:
[4,5,6,7]
You'll often see documentation for methods for Ruby types which say, for example:
delete_if { |item| block } -> Array
Which means that the method accepts a block with a parameter, the block being some code that uses the parameter, and the output being another array. The method's description explains more detail in the documentation (e.g., Ruby Array).
I recommend reading some Ruby getting started information online or a good introductory book which will explain this in more detail.
You have to put i there for the same reason you would put i in the first line here:
def plus_one(i)
return i + 1
end
You have to name your method argument, which you later use as a local variable in the method.
Ruby blocks are similar to methods, they can also receive arguments, and syntax for declaring them is slightly different: enclosing them in | |.
I've redone my answer, even though the OP's question has already been answered, because I thought of a new way to explain this that may help future SO users with the same question.
From high school algebra, you should remember functions like this: f(x) = x + 1.
Imagine putting curly braces around the x + 1: f(x) = { x + 1 }
Then move the (x) to inside the curly braces: f = {(x) x + 1 }
And then get rid of the name f: {(x) x + 1 }. This makes it an "anonymous function," i.e. a "lambda."
Here's the problem: The braces could contain arbitrary statements, which may themselves use parentheses: (x + 1) * 4. So how would Ruby know that the (x) is supposed to be an argument to the function, and not an expression to execute? Some other syntax had to be used. Hence the vertical bars: |x|. (At least I assume that was the thought process).
So {|i| i > 4 } is just like f(i) = i > 4, except that it has no name and is not defined in advance, so the parameter has to be defined "inside" the function itself, rather than being outside attached to the name.
Array#delete_if expects such a function (called a "block" when it's used like this) and knows what to do with it. It passes each member of the array [1,2,3,4,5,6,7] into the block as the argument i to see whether i > 4 is true for that member. It's equivalent to doing something like this:
def greater_than_four(x)
x > 4
end
arr = [1,2,3,4,5,6,7]
arr.each do |el|
arr.delete(el) if greater_than_four(el)
end
You could avoid defining the greater_than_four method in advance by defining a lambda on the fly like this:
arr = [1,2,3,4,5,6,7]
arr.each do |el|
arr.delete(el) if lambda{|i| i > 4}.call(el)
end
But since Array#delete_if already expects a block, and already knows to call it on each element, you can save yourself a whole lot of code:
[1,2,3,4,5,6,7].delete_if{|i| i < 4 }
The parameter which you are passing to the delete_if method is a block and the thing inside the parameter you pass to the block.
Think of the block as a method of sorts. The delete_if method iterates over the block and passes the current item as the parameter i to the block. If the condition evaluates to true then that element gets deleted.

Understanding Ruby symbol as method call [duplicate]

This question already has answers here:
How to understand symbols in Ruby
(11 answers)
Closed 10 years ago.
class A
def test
"Test from instance"
end
class << self
def test
"Test from class"
end
end
end
p A.send(:test) # "Test from class"
p A.new.method(:test).call # "Test from instance"
Here symbol works as expected, but here:
s="test"
s1=:s
p s1 # :s
why :s is printed here?? I dont understand the reason behind it.
Can anyone please explain for me ?
Symbols are sort of lightweight strings (though they are not strings). The send() and method() methods can take strings or symbols; one is converted to the other in the inner workings (not sure which) and then ruby executes the method with the matching name. Hence A.send(:text) is equivalent to A.text(). If you had a variable named methodName = :text, you could do A.send(methodName) but not A.methodName().
Symbols are not variables, so you can't assign a value to a symbol. In your example, the symbol :s is unrelated to the variable s (despite the fact that they have the same "name", preceding it with a colon makes it a symbol instead of a variable). You're assigning a string value to the variable s but telling it to print the symbol :s, which it does.
Symbols are just a special kind of stringlike value that's more efficient for the runtime to deal with than a regular string. That's it. They aren't methods or variables or anything like that.
When you do A.send(:test), all you are doing is saying "hey, A, call the method named 'test'". You aren't sending the method itself, just the name; it's the logic inside send that is responsible for looking up the actual method to call.
The same thing goes when you ask for method with A.new.method(:test). All you are passing to method is the name "test", not the method defined with that name. It's up to method to use the name and find the actual method so it can return it, and it's that return value - a Method object - that you are doing call on. You can't do call on a Symbol like :test, because it's just a name.
From https://stackoverflow.com/a/1255362/509710:
p foo does puts foo.inspect, i.e. it prints the value of inspect instead of to_s, which is more suitable for debugging (because you can e.g. tell the difference between 1, "1" and "2\b1", which you can't when printing without inspect).
s="test"
s1=:s
p :s.object_id #137448
p s.object_id #77489950
p s1.object_id #137448
I have understand it now. I was assigning a symbol but expecting a string.
You set the value of s1 to be :s, so why would you expect it to return anything different?
If you look at the ruby API for the Object class, you will see both Object#send and Object#method take a symbol as a parameter, so the top example is also totally expected.

How to use blocks properly?

I'm very new to Ruby, so please bear with me.
Why is it a syntax error to have "test" {|s| print s}? How about "test" do |s| print s end?
Thanks
You can't say this:
"test" { |s| print s }
because "test" is a string literal, not a method. The same would apply to your do/end version. You could say:
["test"].each { |s| print s }
though because Arrays are Enumerable and Enumerable has an each method.
The {} are usually used for one liners.
do/end for multiple lines.
But there is no rule, do what you prefer.
Notice:
If ever you need to pass several instructions in a one liner, separate them with ;
A block is just a chunk of code enclosed in braces or keywords do/end. As mentioned already, you typically use braces for one liners, and do/end for multiple lines of code. Blocks can appear only immediately after the calling of some method. You can think of a block as an anonymous method (one that doesn't have a method name).
In your code, you were placing a block immediately after a string literal, not a method invocation. Blocks can be used for looping, as such:
2.times { puts "hello" } # => 2
# >> hello
# >> hello
In the above code, times is a method that belongs to all integers (that is to say, it is a instance method of the Integer class). The times method executes the code in the block twice, and returns the object (2 in this case) you called it on. You can pass a block to any method, although methods that are not expecting them will simply ignore the block.
Blocks can take parameters. The parameters are placed between pipes (the '|' character). It turns out, the first example could have accepted a parameter as seen here:
2.times { |i| puts i.to_s + " hello" } # => 2
# >> 0 hello
# >> 1 hello
I've only just scratched the surface of the power of blocks. You can read more about blocks for free in the online version of Programming Ruby: The Pragmatic Programmer's Guide (aka PickAx Book). It is a couple editions old now, but for an introduction to Ruby, you should find it sufficient. Once you understand blocks, you can start using power features of Enumerable which is included in Arrays and Hashes.

Resources