7stud 7stud schrieb:
(...)
If I run the following code, I don't get any errors:
class MegaGreeter
attr_accessor :names
#constructor
def initialize(names = "world")
@names = names
end
#functions:
def say_hi
if @names.nil?
puts "..."
elseif @names.respond_to?("each")
@names.each do |name|
puts "Hello #{name}!"
end
else
puts "Hello #{@names}!"
end
end
end
if __FILE__ == $0
mg = MegaGreeter.new(["Sally", "Jane", "Bob"])
mg.say_hi
end
Hi 7stud,
when reading (compiling) your code, Ruby can only detect syntactic errors, and your code is syntactically correct. Other errors can only be determined at run time. Let me show you...
You get an error when you try your code with another instance:
mg2 = MegaGreeter.new(nil)
mg2.say_hi
Output:
...
in `say_hi': undefined method `elseif' (NoMethodError)
This error message shows that Ruby tried to execute the method #elseif, which obviously isn't defined. Ruby cannot decide in advance whether there will be an error or not:
mg3 = MegaGreeter.new(nil)
def mg3.elseif(arg)
puts "Hello from elseif with arg #{arg}"
end
mg3.say_hi
This code defines the method #elseif for the object mg3. The output is:
...
Hello from elseif with arg false
in `say_hi': undefined method `each' for nil:NilClass (NoMethodError)
You can see that the #elseif method is called, but then there's an error in the next line: because @names is nil in this case, we call the method #each on the object nil, which isn't defined.
I should have said: normally it isn't defined. We can change this:
def nil.each
yield "nil"
end
mg3.say_hi
This code defines the method #each for the object nil, so that it passes the string "nil" to the block. The output is:
...
Hello from elseif with arg true
Hello nil!
You can see that your code executes fine in this case. This can only be determined by actually running the code. Ruby is very dynamic, which sometimes isn't an advantage, as has been in your case. But it can be a very powerful tool, which is why we all hang out here.
Regards,
Pit