user482594
user482594

Reputation: 17486

Undefined method error when the method is called within 'main' method in Ruby?

I am wondering if it is possible to call class methods within 'main' method in Ruby.

Below codes produces an error.

test.rb

class Client
    def printtwo
        puts 2
    end

    if __FILE__ == $0       #if this file gets run by an interpreter, run below codes
                            #just like main() method in java

        printtwo()           #this throws below error
                            #undefined method `printtwo' for Client:Class (NoMethodError)
    end
end

While codes without class declaration runs fine if I run them

test2.rb

def printtwo
    puts 2
end

if __FILE__ == $
    printtwo()           #this prints 2
end

The reason that I want to use this executable inside a class declaration is because, I want to use class variables by setting attr_accessor. I believe this attr_accessor has to be used in a class. right?

How can I resolve this problem so that method call will not produce an error?

Upvotes: 1

Views: 2558

Answers (4)

Nicolas Guillaume
Nicolas Guillaume

Reputation: 8434

Ok so it's not surprising. You can't call a method if there is no instance of the class (which is the case in your example)

You can try to make the method static (by using self) it should work.

class Client
    def self.printtwo
        puts 2
    end

    if __FILE__ == $0       #if this file gets run by an interpreter, run below codes
                            #just like main() method in java

        printtwo()           #this throws below error
                            #undefined method `printtwo' for Client:Class (NoMethodError)
    end
end

Also note that you cannot access instance attributes (@var) into a static class because you don't have any instance. You can only class attributes (@@var).

This said, you can set new attr_accessor in your object at any time. Ruby allows you to have code writing code... Pretty awesome language for meta programming.

Here is a question explaining how to do create a attr_accessor through a method.

Upvotes: 0

Carl Suster
Carl Suster

Reputation: 6066

In addition to the other answers, I'd add that any code inside if __FILE__ == $0 would typically be only a few lines at the end, starting your program after doing all the definition work above:

class Client
  def printtwo
     puts 2
  end
end

if __FILE__ == $0
  Client.new.printtwo
end

It would get too unmanageable if you had the if __FILE__ == $0 condition appearing inside every class definition. That code only works by definition if you run the file explicitly, but for flexibility you'd generally want any code you've written to be available (via include) to other parts of the program and to other programs. Instead just keep it small and in one place in the main context of your file.

Also, it's uncommon to run any code inside a class context other than method definition and instance/class variable declaration, even when you're meta-programming, not that there's necessarily an issue with this, it just doesn't tend to crop up much in Ruby.

Upvotes: 0

Charles Caldwell
Charles Caldwell

Reputation: 17179

This is because printtwo is an instance method. It can be called from other instance methods within the Client class but since you are calling the method outside of any other methods, it won't work.

When you load the file, the class is read and hence the printtwo method is called before the Client class is instantiated. In order to call printtwo as you do, you will have to define it as:

def self.printtwo
   # code
end

http://repl.it/Bax/1

Notice in the example I made which method gets called within the class and which gets called outside.

Upvotes: 2

Xavier Holt
Xavier Holt

Reputation: 14619

If you define that method like you do in your first example, it's an instance method rather than a class method, and that's why you can't call it - because you don't have an instance to call it on. But if you make it a class method, by prepending self. to the method name, it'll work:

class Client
    def self.printtwo
        puts 2
    end

    printtwo
end

But I get the impression you might want to think a little more about what you're doing. You rarely need to run code like that inside a class declaration (unless, say, you're programatically defining a bunch of functions or instance variables). You should look into attr_accessor a little more - something like this is usually all you need:

class Client
    attr_accessor :ivar_one
    attr_accessor :ivar_two
end

Hope this helps!

Upvotes: 4

Related Questions