tags:

views:

204

answers:

5

Studying Ruby and the Do block. Coming from much c# I didn't see much that reminded me of Do, but then VB came to mind with the With statement and one which I wish was in c# (maybe it is and I never saw it?). The two statements, Do and With, appear similar.

Is the With statement in VB the same as a Do block in Ruby?

EDIT:

Take this example, ActiveRecord object TheBook, maps to database table:

TheBook.new do |book|
 book.title = "my book"
 book.writer = "some author"
end

I understand what I will get just from looking at it. I know that I will get a new record in my database with the above information, but I do not know why. Why did book become TheBook.new? Do I read it from right to left?

+7  A: 

No. Ruby blocks (what you're delimiting with do and end) are basically closures. with in VB is just syntactic sugar to prevent you from needing to type the variable name over and over again.

Hank Gay
+2  A: 

It is not the same. A Ruby block is an anonymous function (a closure, technically), that can be executed by the method it is passed to. For example, a snippet to get even numbers up to 100:

(1..100).select do |num| 
  num % 2 == 0
end

The select method calls the block with each number in the sequence as an argument to determine whether that number matches the selection criteria.

(Normally this would be written as (1..100).select {|num| num%2 == 0} — it makes no difference. The do syntax is exactly equivalent to the braces.)

Chuck
I think one thing that throws me on this is that |num| is on the same line as do. I have see others like yours that make more sense and some that have do { |somevar|...} that make more sense.
johnny
It's an argument. Think of it as the same as how a method's arguments are on the same line when you write `def mymethod(arg)`. The do-syntax is usually for multi-line blocks while the braces are usually used for single-line cases like this.
Chuck
+5  A: 

Being mainly a C# developer without much Ruby experience myself, I understand your confusion.

If you are familiar with the concept of anonymous delegates in C# 2.0 and lambda expressions in C# 3.0, this makes a lot more sense.

Your Ruby ActiveRecord example could be expressed in C# 2.0 using anonymous delegates:

TheBook.New ((delegate TheBook book){
  book.title = "my book";
  book.author = "some author";
});

Or in C# 3.0 using a lambda expression as follows:

TheBook.New (book => {book.title = "my book"; book.author = "some author"});

Essentially the "do" block comes into play when you have methods that expect a function as an argument, or a delegate in C#.

Jose Basilio
+1  A: 

You can actually learn a bit about what this method is doing by looking at the source. From ActiveRecord::Base:

def initialize(attributes = nil)
  @attributes = attributes_from_column_definition
  @attributes_cache = {}
  @new_record = true
  ensure_proper_type
  self.attributes = attributes unless attributes.nil?
  self.class.send(:scope, :create).each { |att,value| self.send("#{att}=", value) } if self.class.send(:scoped?, :create)
  result = yield self if block_given?
  callback(:after_initialize) if respond_to_without_attributes?(:after_initialize)
  result
end

The line of interest for this question is result = yield self if block_given?. In ruby, the yield method calls the block which has been passed into the function (in the example you gave, that would be the portion between do and end) with any parameters used. In this case, the parameter yielded to the block is self. This particular instance of a block, then, actually ends up replicating the with functionality you mentioned in Visual Basic, because it happens to pass the block the newly created ActiveRecord object - but, as discussed in other answers, Ruby blocks have many more uses than that.

Greg Campbell
+1  A: 

I think it was WhyPoignant in his tutorial who explained it like this :

|varname| is like a pipe to direct the value of each iteration to the block.

let say you want to read each line of a file :

file.each_line do |line|
  puts line
end

file.each_line give you some data, and you will use |line| to direct that data to the block (here just puts line)

Literraly : Read the file and for each line puts it on the screen (stdout to be precise)

I often write my code like that : elements.each do |element| ...

Yoann Le Touche