Ruby Code Not in Any Method

Ruby Code not in Any Method

Methods like attr_accessor and has_many are often called "mimic methods" because they kinda look like ruby keywords (mimic them) but they're in fact, as you and others have correctly pointed out, method calls.

dd = DooDad.new
dd.foo

outputs nil, and never spits out any puts stuff

How exactly does all that work?

When you're inside of a class definition the implicit receiver of all method calls and "variable definitions" is self, which in your case is DooDad.

So when you're writing

class DooDad
@foo = 1
end

you're actually defining an instance variable on self, that happens to be the class itself , since you're inside of that classes definition. (and outside of any other class, module or method definitions)

The method attr_accessor on the other hand generates, with some help of metaprogramming, accessor methods for an instance variable of the objects that are instantiated from class DooDad.

Back to your example:

class DooDad
attr_accessor :foo
puts "I happened!"
@foo = 7
end

With the stuff mentioned above, you should now understand that you're dealing with two different @foo variables, one for instances of class DooDad (i.e DooDad.new), the other (the one you created by writing @foo = 7) for the class DooDad itself!

When calling the new method on a class, you create an instance of it.

dd = DooDad.new 
#=> dd is now an object of class DooDad

dd.foo
#=> You just called the "getter" method for an instance variable foo of object dd, which was never defined before, that's why it's returning nil.

The puts "I happened!" statement, just as the other two in fact, gets evaluated as soon as the class is loaded, but not when you call new on it.
If you want the behaviour you described (doing stuff when calling new), I suggest implementing an initialize() method for DooDad, which will get called when you call new:

class DooDad
attr_accessor :foo

def initialize()
puts "I happened!"
@foo = 7
end
end

dd = DooDad.new
#=> outputs "I happened!" and sets dd.foo = 7

dd.foo
#=> 7

But why does @foo = 7 now set the instance variable of dd and not DooDad?
When you define a method with the keyword def, you enter a new scope (you pass a scope gate). self is now no longer the class, but instead an instance of that class, that you created with new, just like dd. So when you're writing @foo = 7 inside of a method definition, you're talking about variables for an instance of class DooDad, not the class itself.

This post is probably way too long and might not even satisfy as an answer, but I hope it was somewhat comprehensive.

Ruby code not executed after method call

@agent.get(url) will fail with a bad url or network outage.

The problem in your code could be written as follows:

def do_something
begin
raise
puts "I will never get here!"
rescue
end
end

Since you can't get rid of the raise, you need to do something inside the rescue (most likely log it):

begin
@agent.get(url)
# ...
rescue Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, EOFError,
Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError,
Net::ProtocolError => e
log(e.message, e.callback)
end

Why can some classes and/or methods be called without instances of their parent class?

First of all, your intuition is correct.

Every methods must be an instance method of some receiver.

Global methods are defined as private instance methods on Object class and hence seem to be globally available. Why? From any context Object is always in the class hierarchy of self and hence private methods on Object are always callable without receiver.

def fuuuuuuuuuuun
end

Object.private_methods.include?(:fuuuuuuuuuuun)
# => true

Class methods are defined as instance methods on the "singleton class" of their class instance. Every object in Ruby has two classes, a "singleton class" with instance methods just for that one single object and a "normal class" with method for all objects of that class. Classes are no different, they are objects of the Class class and may have singleton methods.

class A
class << self # the singleton class
def example
end
end
end

A.singleton_class.instance_methods.include?(:example)
# => true

Alternative ways of defining class methods are

class A
def self.example
end
end

# or

def A.example
end

Fun fact, you can define singleton methods on any object (not just on class objects) using the same syntax def (receiver).(method name) as follows

str = "hello"

def str.square_size
size * size
end

str.square_size
# => 25

"any other string".square_size
# => raises NoMethodError

Some programming language history — Singleton classes are taken from the Smalltalk language where they are called "metaclasses". Basically all object-oriented features in Ruby (as well as the functional-style enumerators on Enumerable) are taken from the Smalltalk language. Smalltalk was an early class-based object-oriented language created in the 70ies. It was also the language that invented graphical user interfaces like overlapping windows and menus et cetera. If you love Ruby maybe also take a look at Smalltalk, you might fall in love yet again.

Is there any way to call all the methods inside the class with the single line code in Ruby?

is it possible to call all the methods by a single line code

Yes, that is possible.

Personally, I don't get the obsession with squeezing everything into a single line. It does not make code smaller, it does not make code better, it does not make code easier to read. But it is technically possible.

In Ruby, line breaks are always optional. They can always be replaced with something else. If the line break is used as an expression separator, it can be replaced with a semicolon (;), which is also an expression separator. If the line break is used to terminate some syntactic element, it can be replaced with either a semicolon (;), a keyword (for example then in if and unless, when in case, do in for, while, and until, and so on), and sometimes just whitespace.

So, you could write your code in a single line like this:

object = Sample.new(par1, par2); object.method1; object.method2; object.method3; object.method4; # … etc …

calling the methods one by one using the object.method_name(parameter) is really hard and taking very long space and time.

Whether you write the code on one line or multiple lines has no effect on the space or time requirements of your program.

If you execute the methods sequentially, the space requirement will be the maximum of the space requirements of all the methods and the time requirement will be the sum of the time requirements of all the methods.

You can execute the methods in parallel. In that case, the space requirement will be the sum of the space requirements of all the methods and the time requirement will be the maximum of the time requirements of all the methods plus any time needed to coordinate the parallel execution and merge the results back together. Also, executing the methods in parallel will change the result of the program!

Either way, you can only improve either space or time, not both.



Related Topics



Leave a reply



Submit