What are the reserved words BEGIN or END used for in Ruby?
Asked Answered
M

6

23

This is a very hard to find word because in most cases they are not sensitive during a search. The best I could find outside of documentation is a test in IRB.

 BEGIN{puts x = 10}
 10
Mclean answered 10/3, 2013 at 18:54 Comment(8)
Many thanks for all your answers. Where or how could I find this in Ruby documentation? The pickax book was a good answer for that reason.Mclean
See my updated answer for direct links to documentationSegalman
Thisx relates to my other question so feel free to answer it. #14885918Mclean
Sheesh, from accepted answer to downvote... Mighty nice of youSegalman
Sorry Mchl, it was just an experiment. It let me and I didn't expect it to. Sorry Victor, I hope you understand.Mclean
@all btw I have rearranged all the code samples from the 2nd edition of the Ruby Pragmatic book if anyone is interested. github.com/DouglasAllen/code-Programming_Ruby_2nd_edMclean
@Segalman I put it back and here is where I found code that looks a lot like yours. docs.ruby-doc.com/docs/ProgrammingRuby/html/language.html#UAMclean
Small wonder. That's where I quoted it from. There's a link in my answer. ;)Segalman
S
23

As all keywords BEGIN and END are documented as public instance methods of Object (even though you won't see them returned from Object.public_instance_methods)

BEGIN Designates, via code block, code to be executed unconditionally before sequential execution of the program begins. Sometimes used to simulate forward references to methods.

puts times_3(gets.to_i)

BEGIN {
  def times_3(n)
    n * 3
  end
}

END Designates, via code block, code to be executed just prior to program termination.

END { 
  puts "Bye!" 
}

Some more detailed explanation from Programming Ruby The Pragmatic Programmer's Guide

BEGIN and END Blocks

Every Ruby source file can declare blocks of code to be run as the file is being loaded (the BEGIN blocks) and after the program has finished executing (the END blocks).

BEGIN {   
  begin code 
}

END {
  end code 
}

A program may include multiple BEGIN and END blocks. BEGIN blocks are executed in the order they are encountered. END blocks are executed in reverse order.

Segalman answered 10/3, 2013 at 19:3 Comment(4)
Yes! Thanks. I found it under The Ruby Language chapter and page 303 of the book. This is about the only place that even mentions this and that is just a paragraph. So you see how obscure it is? That is why I'm relying on this site and the web.Mclean
@DouglasG.Allen It's mentioned in a number of books on Ruby and in a number of web tutorials. But it is damn hard to search for because of case insensitivity problems.Fortney
@steenslag your Runpaint might be getting redirected? I end up at random stuff. How can I use it?Mclean
@DouglasG.Allen Sadly all of Runpaint's sites seem to be gone (the author had good material on Vim and Ruby). But you can still get at the material indirectly, from GitHub repos.Fortney
F
19

One thing that hasn't been mentioned is that in earlier versions of Ruby, BEGIN was unconditional:

if false
  BEGIN { puts "Up is down, hot is cold, good is evil!" }
end

If you try that with Ruby 1.8.7, the sentence is printed, even though it's in the branch of if that isn't taken.

Under Ruby 2.0.0, it's a syntax error to use BEGIN outside of the top-level (a much smarter way to handle that):

unconditional.rb:2: BEGIN is permitted only at toplevel
  BEGIN { puts "Up is down, hot is cold, good is evil!" }
       ^

Edit: In a way, nobody has answered the question you raise in your comment: Why does Ruby have BEGIN at all? I'll try. BEGIN comes to Ruby (like many things) from Perl. Perl has it because it existed in awk. It made a ton of sense in awk because by default, an awk file consists of a series of patterns and actions:

/foo/ { print $1 }
/bar/ { print $2 }

Every pattern is checked for every line. If the pattern matches, then the action is performed. Otherwise, awk moves on to the next pattern. So in the mini script above, if the line matches 'foo', then the first field is printed. If the line matches 'bar', then the second field is printed.

But by now you can see the gap that BEGIN (and END) blocks fill: What if you want to do something unconditionally before any intput has been tested or after all the input has been seen (like print a header at the top of your report or print a row of totals at the end of the report)? Normal awk lines of pattern + action can't help you there.

That's why BEGIN and END exist. But I'm not sure how useful they are for modern, idiomatic Ruby scripts. But as dbenhur points out in the comments, you can still use Ruby very well for awk-like one-liners. (I also have a recollection that MiniTest, the standard Ruby testing library, used to use an at_exit function for testing, but I'm not sure it does any longer.)

Two good links about Ruby, awk and Ruby one-liners:

Fortney answered 10/3, 2013 at 20:3 Comment(4)
I'm beginning to see a use for this, Thanks. Let's say you just start writing code without thinking of any order and just letting it flow but then you realize that the order is wrong. Perhaps this would be useful in that sense? Just a thought. Could we ask 'Matz' what he had in mind? Maybe he didn't even do it. Who did then?Mclean
@DouglasG.Allen I've updated my answer to try to explain the history of BEGIN and END in Ruby.Fortney
"I'm not sure how useful they are for modern, idiomatic Ruby." Ruby still has an awk-mode -an or -ap. It's quite useful for composing awkish cmdline one-liners and often more capable and expressive than awk itself.Chrysalid
@Chrysalid I agree as far as that goes, but I meant Ruby in script form rather than the one-liners. I'll add that to my answer though, thanks.Fortney
N
7

From The Ruby Programming Language:


BEGIN and END Blocks

Every Ruby source file can declare blocks of code to be run as the file is being loaded (the BEGIN blocks) and after the program has finished executing (the END blocks).

BEGIN {
  # begin code
} 
END {
  # end code
}

A program may include multiple BEGIN and END blocks. BEGIN blocks are executed in the order they are encountered. END blocks are executed in reverse order.


So:

$ cat beginend.rb
END { puts :end }
BEGIN { puts :begin }
END { puts :end2 }
BEGIN { puts :begin2 }

puts :run
$ ruby beginend.rb 
begin
begin2
run
end2
end
Novikoff answered 10/3, 2013 at 19:3 Comment(0)
F
5

The BEGIN block is exactly what you may assume, and that is that the block given will run before the rest of the code in your program.

This being an example.

puts "Goodbye cruel world!"

BEGIN {
puts "Hello World!"
}

I hope that helps.

There is a working example of this in a minitest where a collection of values is put out of the way at the end of the file, but evaluated first.

Foreshorten answered 10/3, 2013 at 19:3 Comment(2)
Good example Victor. May I use this in my wiki about reserved words?Mclean
As per the licensing of this site, I would have to guess that you should feel restricted only by that license.Foreshorten
S
2

the BEGIN/END is really handy when using the -e option to process a stream. For example, to total a file of numbers:

cat <<EOF > numbers
1
5 
10
20
EOF

cat numbers | ruby -ane 'BEGIN { $t=0}; END {puts $t}; $t += $_.to_i'

note how the BEGIN zeros out the global, and the END prints the result.

Starveling answered 16/7, 2014 at 1:40 Comment(0)
R
0

BEGIN and END is also used to comment such as:

=begin
This is a comment line
It can explain what the rest of the program is about
This was inspired from the perl style of programming
=end

You can check the same here: https://en.wikipedia.org/wiki/Comparison_of_programming_languages_(syntax)#Comments

Reformatory answered 6/1, 2017 at 14:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.