Should I Define a Main Method in My Ruby Scripts

Should I define a main method in my ruby scripts?

I usually use

if __FILE__ == $0
x = SweetClass.new(ARGV)
x.run # or go, or whatever
end

So yes, you can. It just depends on what you are doing.

Is there a main method in Ruby like in C?

@Hauleth's answer is correct: there is no main method or structure in Ruby. I just want to provide a slightly different view here along with some explanation.

When you execute ruby somefile.rb, Ruby executes all of the code in somefile.rb. So if you have a very small project and want it to be self-contained in a single file, there's absolutely nothing wrong with doing something like this:

# somefile.rb

class MyClass
def say_hello
puts "Hello World"
end
end

def another_hello
puts "Hello World (from a method)"
end

c = MyClass.new
c.say_hello
another_hello

It's not that the first two blocks aren't executed, it's just that you don't see the effects until you actually use the corresponding class/method.

The if __FILE__ == $0 bit is just a way to block off code that you only want to run if this file is being run directly from the command line. __FILE__
is the name of the current file, $0 is the command that was executed by the shell (though it's smart enough to drop the ruby), so comparing the two tells you precisely that: is this the file that was executed from the command line? This is sometimes done by coders who want to define a class/module in a file and also provide a command-line utility that uses it. IMHO that's not very good project structure, but just like anything there are use cases where doing it makes perfect sense.

If you want to be able to execute your code directly, you can add a shebang line

#!/usr/bin/env ruby

# rest of somefile.rb

and make it executable with chmod +x somefile.rb (optionally rename it without the .rb extension). This doesn't really change your situation. The if __FILE__ == $0 still works and still probably isn't necessary.

Edit

As @steenslag correctly points out, the top-level scope in Ruby is an Object called main. It has slightly funky behavior, though:

irb
>> self
=> main
>> self.class
=> Object
>> main
NameError: undefined local variable or method `main' for main:Object
from (irb):8

Don't worry about this until you start to dig much deeper into the language. If you do want to learn lots more about this kind of stuff, Metaprogramming Ruby is a great read :)

Where do I write the main function in Ruby?

There is no such thing in Ruby. The interpreter executes code from top to bottom so your main script is implicitly the body of "main". For example, suppose you have two files script_a.rb and script_b.rb. And suppose the contents of script_a.rb is as follows:

require_relative './script_b'

puts 1 + 1

Now if you run ruby script_a.rb what you will get in terms of actual code execution will be as follows: Find script_b.rb, execute the contents of script_b.rb, execute puts 1 + 1.

What is main in Ruby?

Everything in Ruby occurs in the context of some object. The object at the top level is called "main". It's basically an instance of Object with the special property that any methods defined there are added as instance methods of Object (so they're available everywhere).

So we can make a script consisting entirely of:

puts object_id
@a = 'Look, I have instance variables!'
puts @a

and it will print "105640" and "Look, I have instance variables!".

It's not something you generally need to concern yourself with, but it is there.

Ruby methods at bottom of script?

You can do initializing code in one or more BEGIN-blocks (inherited from Perl, which inherited them from awk).

can_i_do_this? #=>yes

BEGIN {
def can_i_do_this?
puts "yes"
end
}

And for completeness, there are also END-blocks:

END {
can_i_do_this? #=> yes
}

def can_i_do_this?
puts "yes"
end

Ruby - when I should use parenthesis or not when calling a function/method

There isn't an official standard for Ruby code best practices. However, a set of preferred styles has evolved in the Ruby community. It's a good idea to follow those preferred styles, just because it makes your code more easily readable by other Ruby programmers.

Nick Roz has given you a link to the style guide. I would also recommend that you consider installing and using rubocop. It will give you feedback on when and when not to parenthesize arguments, many other formatting matters such as proper indenting, and which of the often several different syntax options to choose in a particular situation.

To answer your specific question about whether or not to use parentheses for method arguments, the answer is yes, in general. Exceptions are, as the guide says, "methods that have 'keyword' status in Ruby." An example is puts (actually the Kernel.puts method). Most people don't use parentheses here, but the guide states that they are optional.

Another example, as Nick has said (although "methods with keyword arguments" isn't quite correct; in that case the arguments are symbols that represent methods rather than keywords), is attr_accessor, which is actually Module.attr_accessor.

So, as a general rule, if it looks like a "command" (a "keyword," if you will), but is actually a method, omit the parentheses. Otherwise, use them. And if you're not sure of the difference, get in the habit of using rubocop.

Scripting in Ruby

When I write a one off script, I often wrap it in a class. You've pointed out some advantages of doing this including reuse and cleaner documentation.

I find that there are several levels of polish for scripts depending on how they are going to be used. If the script is run once and never used again, I may not wrap it in a class. If it's important (taking backups of production systems), it's probably worth putting it in full gem form and writing tests. Somewhere in the middle is the single purpose class. Generally this means you're taking the code that's not in a method and putting it in the class constructor.

This:

#!ruby

def amethod(i)
i+1
end

ARGF.each do |l|
if l.chomp.to_i > 0
puts amethod(l.chomp.to_i)
end
end

Becomes:

#!ruby

class OneAdder
def amethod(i)
i+1
end

def initialize
ARGF.each do |l|
if l.chomp.to_i > 0
puts amethod(l.chomp.to_i)
end
end
end
end

OneAdder.new

execute a method in a ruby file

A couple of reasons this doesn't work as you have written it.

  1. The method foo hasn't been declared before you attempt to call it.
  2. The method foo, as you have declared it, is an instance method. You're not invoking it on an instance of the class.

This would work:

class Bar
def self.foo
end

foo
end

As others have said, though, you probably don't need to wrap this in a class.

Needing forward declaration in Ruby

You just need the functions you call to be defined when your main function runs, not when it's defined. So, the easiest solution is to write the main function at the script's beginning, but call it at the end.

def main
foo(42)
bar(24)
end

# definitions of foo and bar

main


Related Topics



Leave a reply



Submit