I am struggling with Ruby do/end blocks.
For instance, I have the following example:
::ApplicationController.class_eval do
def close_sdb_connection
puts "Closing sdb connection."
end
end
What this piece of code does? Why we need blocks? What would be the equivalent code without the do/end blocks?
do and end are reserved words. They have no generic higher purpose (at least until Matz goes nuts like Larry Wall and says they do). In your sample code, the external do ... end means the code block – same as { ... }. The internal end serves as the right delimiter of the def ... end method definition.
In the context of class_eval, the code sample in the OP does exactly the same thing as:
class ::ApplicationController
def close_sdb_connection
puts "Closing sdb connection."
end
end
However, block statements, such as Foo.class_eval do ... end significantly differ from non-block statements, such as class Foo; ... end, as the blocks are closures over local variables.
It is interesting to note, that not each do ... end indicates a block.
In general, a do ... end or { ... } block is used to put code inside that is not to be evaluated in the same way as the rest of the code. In particular, a block is evaluated under a certain binding (i.e., a certain assignment of local variables and the self keyword) at a certain timing for a certain number of times, all of which is controlled by the method that the block is attached to.
In this particular case, the block is evaluated with a binding different from the outside. Particularly, the code inside would be evaluated as if it were inside the class body of the receiver ::ApplicationController.
Related
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
I accidentally came across this piece of code in Ruby's Postgresql gem:
### Convenience alias for PG::Connection.new.
def self::connect( *args )
return PG::Connection.new( *args )
end
I played around a bit and turns out that this thing is used just like a normal module class method (it's called like this: PG.connect). In fact we could instead say def self.connect ( #args ) ... end and it would work just the same.
Since self::whatever is a first for me I'm wondering what exactly does self namespaces in such a context and what is its true purpose in this case. Can anyone help shed some light on this?
:: is the scope resolution operator. So self::connect resolves connect from self. Which means that its equivalent to self.connect. You can see how it works from this very contrived example:
class Foo; end
class Bar
def Foo::baz
"Hello World"
end
end
puts Foo.baz # "Hello World"
Of course we could also just use def Foo.baz to get the exact same result.
Using double colons for method definition is discouraged by the Ruby Style guide:
Do not use :: to define class methods.
# bad
class Foo
def self::some_method
end
end
# good
class Foo
def self.some_method
end
end
Its also not recommended for anything other than referencing constants and constructors:
Use :: only to reference constants (this includes classes and modules)
and constructors (like Array() or Nokogiri::HTML()). Do not use :: for
regular method invocation.
:: is, in some situations, somewhat equivalent to .. (I will leave out a precise definition in which exact situations it is equivalent and to what degree, because I freely admit I don't fully know it myself, nor is it well-documented.)
Here is an example of where :: and . behave differently:
module Foo
def self.Bar
'method'
end
Bar = 'constant'
def self.Qux; end
end
Foo.Bar
#=> 'method'
Foo::Bar
#=> 'constant'
Foo::Bar()
#=> 'method'
Foo.Qux
Foo::Qux
# NameError (uninitialized constant Foo::Qux)
Foo::Qux()
[Note: this is not a perfect example, since this is about the message sending side of things whereas your example is about the method definition side of things. I believe on the method definition side, they are 100% identical since def never defines a constant and thus there is no ambiguity.]
All Style Guides heavily advocate against this usage, from strongly advising against the message sensing part of it to flat out forbidding both usages of it. The main reason for this is the fact that the two behave differently for message sends, and this may lead to confusion. It is also simpler to explain the conceptual difference between method lookup (dynamic, upwards in the inheritance chain) and constant lookup (first static, lexically outward, then dynamic, upwards in the inheritance chain) when not using the same operator for both.
The typical style used by many Rubyists is:
NEVER use :: for singleton method definition, always use ..
ALWAYS use :: for referencing singleton methods in documentation, never use ..
ALWAYS use . for usage examples of message sends (including singleton methods) in documentation, never use ::.
NEVER use :: for message sends (including singleton methods), always use ..
Those last two are sometimes softened to allow for methods that are supposed to return modules or classes, and to allow for methods that act as factories (e.g. Nokogiri::XML) to be invoked via message sends that "look like" constant lookup, (e.g. Nokogiri::XML('<root/>') instead of Nokogiri.XML('<root/>')).
There was a feature request for removing this usage of ::, but it was rejected mostly because of backwards-compatibility concerns.
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
I have two examples that give the same result.
With block:
def self.do_something(object_id)
self.with_params(object_id) do |params|
some_stuff(params)
end
end
def self.with_params(object_id, &block)
find_object_by_id
calculate_params_hash
block.call(params_hash)
end
and with method:
def self.do_something(object_id)
some_stuff(self.get_params(object_id))
end
def self.get_params(object_id)
find_object_by_id
calculate_params_hash
params_hash
end
The second solution seems more straightforward, but I found some usages of the first one in our application code. My question is: in which situation the first one is recommended? What are the pros and cons of each one?
Normally people use blocks when they want to run a piece of code inside of another piece of code. Examples:
DB.with_shard_for_user(user_id) do |db|
# perform operations on a user's shard
end # shard is reverted back to original value
File.new(filename) do |file|
# work with file
end # file is closed automatically
User.transaction do
# run some operations as a single transaction
end
These blocks are closed on their lexical context (they capture variables from where the block is declared, and carry them over to the place when blocks are called).
Schematic structure of a method that accepts a block.
def transaction
open_transaction # pre- part
yield if block_given? # run provided code
commit_transaction # post- part
rescue
rollback_transaction # handle problems
end
In your first example, use of a block is probably unjustified (IMHO). Too complex for no apparent reason.
The main difference between a block and function as per your example is that the block runs within the context of the calling function.
So if your example was as:
def self.do_something(object_id)
x = "boogy on"
self.with_params(object_id) do |params|
some_stuff(params)
puts x
end
end
The code within the block can access the variable x that was defined outside the block. This is called a closure. You couldn't do this if you were just calling a function as per your second example.
Another interesting thing about blocks is they can affect the control flow of the outer function. So it is possible to do :
def self.do_something(object_id)
self.with_params(object_id) do |params|
if some_stuff(params)
return
end
end
# This wont get printed if some_stuff returns true.
puts "porkleworkle"
end
If the some_stuff call within the block returns a true value, the block will return. This will return out of the block and out of the dosomething method. porkleworkle would not get output.
In your examples you don't rely on either of these, so using function calls is probably much cleaner.
However, there are many situations where using blocks to allow you to take advantage of these things is invaluable.
When you call with_params(), you are not only sending in data, you are also providing some code to run. See if different blocks are sent into the with_params() call:
...
self.with_params(object_id) do |params|
some_other_stuff()
some_stuff(params)
end
...
and somewhere else:
...
self.with_params(object_id) do |params|
even_more_stuff(params)
end
...
If the blocks are all the same or with_params() is just called from one place then you might consider eliminating the blocks.
To sum up: use blocks if you want to pass into the method different bits of code(blocks) as well as data: hey with_params, take this data(object_id) and, by the way, run this code(block) while you're at it.
BTW you are doing different things in the two examples: with_params() returns
some_stuff(params_hash)
after evaluating the block. And get_params() just returns
params_hash
A block totally rely on your code, but a function has its own code.
So, if your code varies situation by situation, use block.
If not, build a function and use it as a block box.
My basic logic is to have an infinite loop running somewhere and test it as best as possible. The reason for having an infinite loop is not important (main loop for games, daemon-like logic...) and I'm more asking about best practices regarding a situation like that.
Let's take this code for example:
module Blah
extend self
def run
some_initializer_method
loop do
some_other_method
yet_another_method
end
end
end
I want to test the method Blah.run using Rspec (also I use RR, but plain rspec would be an acceptable answer).
I figure the best way to do it would be to decompose a bit more, like separating the loop into another method or something:
module Blah
extend self
def run
some_initializer_method
do_some_looping
end
def do_some_looping
loop do
some_other_method
yet_another_method
end
end
end
... this allows us to test run and mock the loop... but at some point the code inside the loop needs to be tested.
So what would you do in such a situation?
Simply not testing this logic, meaning test some_other_method & yet_another_method but not do_some_looping ?
Have the loop break at some point via a mock?
... something else?
What might be more practical is to execute the loop in a separate thread, assert that everything is working correctly, and then terminate the thread when it is no longer required.
thread = Thread.new do
Blah.run
end
assert_equal 0, Blah.foo
thread.kill
in rspec 3.3, add this line
allow(subject).to receive(:loop).and_yield
to your before hook will simple yield to the block without any looping
How about having the body of the loop in a separate method, like calculateOneWorldIteration? That way you can spin the loop in the test as needed. And it doesn’t hurt the API, it’s quite a natural method to have in the public interface.
You can not test that something that runs forever.
When faced with a section of code that is difficult (or impossible) to test you should:-
Refactor to isolate the difficult to test part of the code. Make the untestable parts tiny and trivial. Comment to ensure they are not later expanded to become non-trivial
Unit test the other parts, which are now separated from the difficult to test section
The difficult to test part would be covered by an integration or acceptance test
If the main loop in your game only goes around once, this will be immediately obvious when you run it.
What about mocking the loop so that it gets executed only the number of times you specify ?
Module Object
private
def loop
3.times { yield }
end
end
Of course, you mock this only in your specs.
I know this is a little old, but you can also use the yields method to fake a block and pass a single iteration to a loop method. This should allow you to test the methods you're calling within your loop without actually putting it into an infinite loop.
require 'test/unit'
require 'mocha'
class Something
def test_method
puts "test_method"
loop do
puts String.new("frederick")
end
end
end
class LoopTest < Test::Unit::TestCase
def test_loop_yields
something = Something.new
something.expects(:loop).yields.with() do
String.expects(:new).returns("samantha")
end
something.test_method
end
end
# Started
# test_method
# samantha
# .
# Finished in 0.005 seconds.
#
# 1 tests, 2 assertions, 0 failures, 0 errors
I almost always use a catch/throw construct to test infinite loops.
Raising an error may also work, but that's not ideal especially if your loop's block rescue all errors, including Exceptions. If your block doesn't rescue Exception (or some other error class), then you can subclass Exception (or another non-rescued class) and rescue your subclass:
Exception example
Setup
class RspecLoopStop < Exception; end
Test
blah.stub!(:some_initializer_method)
blah.should_receive(:some_other_method)
blah.should_receive(:yet_another_method)
# make sure it repeats
blah.should_receive(:some_other_method).and_raise RspecLoopStop
begin
blah.run
rescue RspecLoopStop
# all done
end
Catch/throw example:
blah.stub!(:some_initializer_method)
blah.should_receive(:some_other_method)
blah.should_receive(:yet_another_method)
blah.should_receive(:some_other_method).and_throw :rspec_loop_stop
catch :rspec_loop_stop
blah.run
end
When I first tried this, I was concerned that using should_receive a second time on :some_other_method would "overwrite" the first one, but this is not the case. If you want to see for yourself, add blocks to should_receive to see if it's called the expected number of times:
blah.should_receive(:some_other_method) { puts 'received some_other_method' }
Our solution to testing a loop that only exits on signals was to stub the exit condition method to return false the first time but true the second time, ensuring the loop is only executed once.
Class with infinite loop:
class Scheduling::Daemon
def run
loop do
if daemon_received_stop_signal?
break
end
# do stuff
end
end
end
spec testing the behaviour of the loop:
describe Scheduling::Daemon do
describe "#run" do
before do
Scheduling::Daemon.should_receive(:daemon_received_stop_signal?).
and_return(false, true) # execute loop once then exit
end
it "does stuff" do
Scheduling::Daemon.run
# assert stuff was done
end
end
end
:) I had this query a few months ago.
The short answer is there is no easy way to test that. You test drive the internals of the loop. Then you plonk it into a loop method & do a manual test that the loop works till the terminating condition occurs.
The easiest solution I found is to yield the loop one time and than return. I've used mocha here.
require 'spec_helper'
require 'blah'
describe Blah do
it 'loops' do
Blah.stubs(:some_initializer_method)
Blah.stubs(:some_other_method)
Blah.stubs(:yet_another_method)
Blah.expects(:loop).yields().then().returns()
Blah.run
end
end
We're expecting that the loop is actually executed and it's ensured it will exit after one iteration.
Nevertheless as stated above it's good practice to keep the looping method as small and stupid as possible.
Hope this helps!