how does this ruby code work for setting configuration - ruby-on-rails

I see ruby code that looks like the following. It seems to be some sort of idiom for creating configuration or settings but I don't really understand it. Also, how would the Application.configure part of this code look?
MyApp::Application.configure do
config.something = foo
config.....
config....
.
config....
end

First of all, that configuration way is not specific to Ruby ; it's the applications (or libraries, gems) that choose to use it or not.
To explain you what does that code do, I'll take your snippet as an example:
MyApp::Application.configure do
config.something = foo
end
Here, you are calling MyApp::Application.configure method, with no parameter. After the call, you're giving it a block.
You can think of blocks as a piece of code that you can use however you want.
They can be written in one single line or many:
{ puts 'hello' }
{ |param| puts param } # with passing it a param
# or
do |param|
puts param
end
(remember my_array.each do ... end? It's a block you pass it. ;) )
Now, that block would be called inside the configure method thanks to yield.
yield uses (or executes) the instructions of the block that has been passed to the method.
Example: Let's define a method with a yield inside of it:
def hello
puts "Hello #{yield}"
end
If you call this method, you'd get a 'hello': no block given (yield) (LocalJumpError)'.
You need to pass it a block: hello { :Samy }.
The result would then be Hello Samy. As you can see, it simply used what was in the block passed to the method.
That's exactly what's happening in the Rails configuration code. You simply set config.something (config is a method) to some value, and that same config.something = foo is execute inside configure.
You can learn more about yield and blocks here, and on this great book.

The part from "do" until "end" is called a block, and is getting passed to the configure class method on Application. (all ruby methods can accept arguments and a block)
so the Application.configure method is creating a configuration object with a set of defaults, and then calling the block. The block is then setting the values you see, having the effect of overriding them.
It's then setting that configuration object as a class variable (like a global variable) so that other classes can use the configuration object later in the application lifecycle.
Hope that simplified description helps!

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

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

What is the purpose of options.dup in Ruby on Rails?

Browsing through the Rails codebase I find numerous references to options.dup.
def to_xml(options = {})
require 'builder' unless defined?(Builder)
options = options.dup
....
end
Obviously options.dup is duplicating the options hash, but why would you wish to do this in this context?
dup clones an object. When you pass an object to a method, anything that changes the internal state of that object will be reflected in the calling scope. For example, try this code:
def replace_two(options)
options[:two] = "hi there"
end
options = { one: "foo", two: "bar" }
replace_two(options)
puts options[:two]
That will print hi there, because replace_two() modified the hash contents.
If you want to avoid changing the passed-in options, you can call .dup on it, and then any changes made to the clone won't be reflected in the calling scope:
def replace_two(options)
options = options.dup
options[:two] = "hi there"
end
options = { one: "foo", two: "bar" }
replace_two(options)
puts options[:two]
Will print bar. This is a common pattern that follows the Principle of Least Astonishment . In Ruby, methods that modify their arguments are usually named with a ! suffix to alert the user that they are destructive/modifying actions. The non-dup version of the method should have been called replace_two! to indicate this side-effect.
dup creates a shallow copy of an object. It's ruby core stuff. Since in ruby objects like Hash and Array are passed by reference, when you change object inside of a function this will change original object. If this is not desired behavior - you create a copy... So that code does.
See ruby-doc
UPDATE
One more thing. Since object are passed by reference, options = options.dup will assign to options variable reference to newly created copy. Reference to original object is lost inside to_xml. But it is still probably referenced in code that invoke to_xml

Module.new with class_eval

This is a large commit. But I want you to concentrate on this change block. http://github.com/rails/rails/commit/d916c62cfc7c59ab6411407a05b946d3dd7535e9#L2L1304
Even without understanding the full context of the code I am not able to think of a scenario where I would use
include Module.new {
class_eval <<-RUBY
def foo
puts 'foo'
end
RUBY
}
Then end result is that in the root context (self just before include Module.new) a method called foo has been added.
If I take out the Module.new code and if I only leave class_eval in that case also I will have a method called foo in self.
What am I missing.
If you dig in the documentation you find that including a module will add the methods therein only if they are not already defined. So this approach will not overwrite the method in case it is already there.
This ActiveRecord code has been asked about in another question, where it received an excellent answer. https://stackoverflow.com/a/3473479/420947
However, the simplified eval string here removes the motivation to write this code, which is why it appears confusing. In the unchanged code, the block binding captures a local variable used to reflect on the association: #{reflection.name}.clear.

Variables in ruby method names

I have the following code:
for attribute in site.device_attributes
device.attribute
end
where I would like the code to substitute the value of "attribute" for the method name.
I have tried device."#{attribute}" and various permutations.
Is this completely impossible? Am I missing something?
I have considered overriding method_missing, but I can't figure out how that would actually help me when my problem is that I need to call an "unknown" method.
You can use #send method to call object's method by method's name:
object.send(:foo) # same as object.foo
You can pass arguments with to invoked method:
object.send(:foo, 1, "bar", 1.23) # same as object.foo(1, "bar", 1.23)
So, if you have attribute name in variable "attribute" you can read object's attribute with
object.send(attribute.to_sym)
and write attribute's value with
object.send("#{attribute}=".to_sym, value)
In Ruby 1.8.6 #send method can execute any object's method regardless of its visibility (you can e.g. call private methods). This is subject to change in future versions of Ruby and you shouldn't rely on it. To execute private methods, use #instance_eval:
object.instance_eval {
# code as block, can reference variables in current scope
}
# or
object.instance_eval <<-CODE
# code as string, can generate any code text
CODE
Update
You can use public_send to call methods with regard to visibility rules.
object.public_send :public_foo # ok
object.public_send :private_bar # exception
The "send" method should do what you're looking for:
object = "upcase me!"
method = "upcase"
object.send(method.to_sym) # => "UPCASE ME!"
Matt and Maxim are both correct, but leave out a detail that might help you get your head around the #send syntax: In Ruby, calling a method is really sending a message. Softies on Rails has a relatively straightforward explanation of that.
you can also do
device.instance_eval(attribute)

Resources