What does absolute sign mean in Ruby? - ruby-on-rails

For example
func(#param) do |f|
some code here
end
and
#param.each do |sth|
some code here
end
What does the absolute value sign do here? I don't understand these two pieces of code.

It's the local variable within the block, so for the line:
#param.each do |sth|
you're iterating over #param right, well each item in #param is referred to singularly as sth.
So if #param refers to an array containing the numbers
[1,3,5,4]
During the first iteration sth will be 1, then 3, then 5, then 4.
Same goes for :
func(#param) do |f|
except now the local variable is called f! You could call it anything you want, even |ihavenoideawhatimdoing|

It's a local variable, it is saying that for the block of code between do...end, the variable f is defined.

It is a parameter to a block. The block is the part of the code between the do and the end. That block of code can use f or sth, which in your examples would probably have been set by func or each.
A tutorial on Ruby blocks will probably be helpful.
Labmda calculus - more abstract, but it was the context in which I first saw these things.

It signifies instance variables. You often see it interchanged if people are using attr_* methods like attr_accessor, which makes #someattr and self.some_attr equivalent in instance methods.

Related

Why isn't the args parameter used in ActionController::Instrumentation::render?

I am new to Ruby and to Rails, and am trying to understand fully what I'm reading.
I am looking at some of the Rails source code, in this case action_controller/metal/instrumentation.rb.
def render(*args)
render_output = nil
self.view_runtime = cleanup_view_runtime do
Benchmark.ms { render_output = super }
end
render_output
end
I understand that *args is using the splat operator to collect the arguments together into an array. But after that, it stops making much sense to me.
I can't fathom why render_output is set to nil before being reassigned to equal super and then called with no arguments. I gather that some speedtest is being done, but coming from other languages I'd expect this to just be something more like Benchmark.ms(render_output) or perhaps Benchmark.start followed by render_output followed by Benchmark.end. I'm having a hard time following the way it works here.
But more importantly, I don't really follow why args isn't used again. Why bother defining a param that isn't used? And I mean, clearly it is getting used-- I just don't see how. There's some hidden mechanism here that I haven't learned about yet.
In this context, it is important to note how super works, because in some cases it passes implicitly arguments and you might not expect that.
When you have method like
def method(argument)
super
end
then super is calling the overridden implementation of method implicitly with the exact same arguments as the current method was called. That means in this example super will actually call super(argument).
Of course, you can still define a method call that explicitly sends other arguments to the original implementation, like in this example:
def method(argument)
super(argument + 1)
end
Another important edge-case is when you want to explicitly call super without any arguments although the current method was called with arguments then you need to be very explicit like this
def method(argument)
super() # note the empty parentheses
end
Let me try to describe you what I think this code does.
*args*
is using the splat operator to collect the arguments together into an array
that is totally correct, however they don't use it, and if you will go to master branch, they just changed it to *. Asking why it is defined and not used, I think that's question about bad design. They should have called it _args or at least like it is now just single splat *.
render_output is set to nil because of scopes, it has to be explicitly defined out block, lambda, proc in order to store value in it, otherwise its visibility will be locked only to those lambda, proc, block execution. Refer to this article
Benchmark.start. Blocks are great ruby construction. You are totally correct that speedtest is done, we can see it is just decorator for benchmark library.
source.
You are wondering why we cannot just pass it as Benchmark.ms(render_output), that's because what will be given to benchmark ms function? It will be given result, like <div> my html </div. And how we can measure this string result - no how. That's why we calling super right in this block, we want to access parent class function and wrap it inside block, so we are not calling it, we just construct it, and it will be called inside benchmark lib, and measured execution like
class Benchmark
...
def realtime # :yield:
r0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
yield
Process.clock_gettime(Process::CLOCK_MONOTONIC) - r0
end
...
end
So here we can count realtime of function execution, this is the code from original library

Some questions about symbol and instance method in Ruby

I'm currently try to learn ruby on 'Learn Ruby The Hard Way'
Here's my question...
The following code are from exercise 40:
cities = {'CA'=> 'San Francisco', 'MI'=> 'Detroit', 'FL'=> 'Jacksonville'}
cities['NY'] = 'New York'
cities['OR'] = 'Portland'
def find_city(map, state)
if map.include? state
return map[state]
else
return 'Not found.'
end
end
cities[:find] = method(:find_city)
while true
print 'State? (ENTER to quit) '
state = gets.chomp
break if state.empty?
puts cities[:find].call(cities, state)
end
I played around with the code, and finally understand how it works.
But I still don't understand about two things:
first...
In about middle of the code,
it defined a variable
cities[:find] = method(:find_city)
As what I know for now, the :(colon) declare a symbol.
I want to know is it a better practice to name a variable as cities[:find]
instead of using cities_find in this case?
I'm not quite sure what's the differences, or maybe it's much readable for most rubyist?
And the second one is also about the same line.
method(:find_city)
I know it allows me to call the find_city method.
But again, why I have to put a colon before find_city?
Does this code means parse the arguments I put in to symbols?
I have to say that Learn Ruby The Hard Way gives us a really Really REALLY GOOD example of what we should NOT do. No rubyist will ever type such code in his/her projects. This piece of code is confusing, unreadable and is an abuse of metaprogramming.
Anyway, I dissect that code for you.
The confusing part starts with this line:
cities[:find] = method(:find_city)
Let's look at the right side of the =. It calls a method whose name is method, as you may guess, the return value of the method call is the method find_city, more precisely, a Method object that wraps the method find_city with its scope. Then that method is stored in the hash cities, with a symbol :find as the key. So the value of cities now become
{
'CA'=> 'San Francisco',
'MI'=> 'Detroit',
'FL'=> 'Jacksonville',
'NY' => 'New York',
'OR' => 'Portland',
:find => #<Method:main.find_city>
}
You can see that the last key-value pair is really really weird, and it shouldn't be there because the hash cities should only store states and their capitals. Heck!
Then here comes this even weirder expression cities[:find].call(cities, state). Let's see how this work.
cities[:find] simply retrieve the Method object from the hash (still remember what method it wraps?)
cities[:find].call(cities, state) invokes the method it wraps, which is find_city, in the scope that the Method object wraps, which is the top level object (a.k.a. main), Method#call returns whatever the method wrapped in returns. So this expression is just find_city(cities, state), written in an alien style.
cities[:find] = method(:find_city)
Here, cities is a hash and the method object returned by method(:find_city) is assigned to the hash key find which is a symbol.
I think it depends upon you and the context of program where you are writing this.
A simple method_var = method(:find_city) would work here as well.
method(:find_city)
I know it allows me to call the find_city method. But again, why I have to put a colon before find_city? Does this code means parse the arguments I put in to symbols?
Here, you are passing the method name as an argument, you have to either pass it as a symbol or string.
In Ruby, the method method creates a Method Object. This allow you to pass it around in your code and call it later using the .call method on your Method object.
Since calling method(my_method) would evaluate my_method and pass the result to method(...), you need a way to tell the method method which method to use. That's why you basically pass in the method name as a Symbol into the method method :D
So it actually defined a proc, and make :find and find_city sort like key and value...Probably...

Ruby on Rails method returning nothing

I'm new to ruby and just testing out how to define a method with two variable inputs from the user. Currently, it takes the values but it returns nothing.
Is there something I missing here?
puts "Tell me what you want to print."
word = gets.chomp
puts "How many times do you want it printed?"
number = gets.to_i
def print_x_times(word)
i = 0
while i < number
puts(word)
i += 1
end
end
A few nits here:
You've defined a new method, but you haven't invoked it. You're likely using something like IRB to interactively play around, but the fact remains that you've only defined that method.
You're going to confuse yourself if you use word and number as variables inside of that method, since they're not guaranteed to be the same as the ones you've defined outside of it.
If you want to pass two values to the method, then you have to specify two parameters:
def print_x_times(word, number)
# code
end
...then, you actually go about calling it with your variables.
print_x_times(word, number)
You should pass number as an argument to the function print_x_times as you do for word
moreover, this code defines a function but doesn't call it, you should call it too
You have two issues here...
You need to define the method to take two parameters, word and number.
Then you need to call that method with the two arguments you derived from user input.

What does it mean when a variable or method or constants has preceded with an underscore in Ruby?

What does it mean in Ruby when you see methods or variables with an underscore before them like this in Rails
submit_tag _('Enroll')
:notice => _('Update card.')
or
_session_id
Are most of these just conventions, or do they imply a functional difference in the behavior of the variables/methods?
There is no difference in bahavior. It is just convertion.
But let's have a closer look:
_('A string') is actually a method not a variable. The underscore method is defined by Gettext and translates a string.
#_foo is offen used to show other developers that there is something special about the variable, and therefore it should not be used. I saw that pattern a lot for variables that are used to cache values, like:
def expensive_operation
#_expensive_operation ||= begin
# long running code...
end
end
And the underscore is sometimes used to indicate that a variable is not used in a block. Like this:
a_hash.each do |_, value|
# do something with the value, not with the key
end
Those two cases are completely different.
The second looks like it is a local variable (although it might be a method call, it's impossible to tell without the context). Local variables that begin with an underscore will not generate an "unused variable" warning if they are unused, which is why they are used to indicate a variable that is intentionally not used (as opposed to a typo or pogramming error).
The first is a call to a method named _. What this method does, depends on the class of self at that point, you will have to look at the documentation for that class.
In IRb, _ is a method that returns the result of the last expression that was evaluated.

In ruby how do I write a 'do' method in ruby? [duplicate]

This question already has answers here:
Blocks and yields in Ruby
(10 answers)
Closed 9 years ago.
I keep writing the same pattern of code in Ruby, which seems like it would benefit from a 'do' style bit of code but I'm not sure how to write the method.
I keep doing this pattern of code, which starts and ends with the same lines of code...
x.increment!(:step_count) # same each time
# ...then some different code each
x.update_column(:step_description, "blerg message") # same each time
I feel it would benefit from a 'do' something that would look like this...
update_steps "blerg message" do
# ...then some different code each
end
And then inside the 'do' each time it does the common code.
How would I go about making a method where I can use a 'do'.
Thanks!
Edit: I think it's important to not close this because I didn't know to search for 'block' or 'yield'. People who may no know these terms may end up searching for 'do' instead.
Creating methods that accept a block is one of Ruby's most powerful features.
The common way to define such a method would be:
def foo(*args, &block)
# your code here
yield
# some more code
end
foo do
# This code runs when yield is called
end
There are a few things you should know about the above:
The &block parameter is not required. You can just use yield anyway. But there are a few reasons why you should add it to your method definition:
It makes it clear that your method accepts a block
The & basically transforms the block to a proc object. This could be handy since that way you can actually pass it around as a parameter to another method that accepts a block. You just need to re-apply the & to make it again a block.
Handling a proc object can be more powerful since you can also set its binding.
You can pass arguments to yield. The arguments you pass are the block local variables. For example in:
[1,2,3].each {|x| puts x}
yield is called with one of the array elements on every iteration. Calling yield with an argument is the same as block.call(a) where a is an argument.
If your method encounters a yield and there is no block given it will raise an exception. This might be correct in some cases. But if you want to have a different behavior if no block is given you can use the block_given? method to check it.
&block must be the last parameter in your method definition.
Pass it a block as an argument
def my_method(&block)
do_something_the_same
yield # calls whatever is inbetween "do" and "end"
end
Or you can also do this by calling block.call
def update_steps(&block)
block.call()
end

Resources