Pry and IRB both have an interesting property. In these consoles, there’s a possibility to correctly define a method or a class and get an exception. All in the one go. I’ll be using Pry for the demonstration.
Let’s define and use a method.
[1] pry(main)> HELLO!!!
| def foo
| :HI!
| end
NoMethodError: undefined method `HELLO!' for main:Object
from (pry):4:in `__pry__'
[2] pry(main)> foo
=> :"HI!"
It works! But what about blocks?
It doesn’t work.
[2] pry(main)> HELLO!!!
| [1, 2, 3].map { |n|
| n + 100
| }
NoMethodError: undefined method `HELLO!' for main:Object
from (pry):6:in `__pry__'
Now it makes more sense, right? Tell me what sense to you makes this snippet.
[3] pry(main)> HELLO!!!
| [1, 2, 3].map { |n|
| HI!!!
| n += 100
| }
NoMethodError: undefined method `HI!' for main:Object
from (pry):14:in `block in __pry__'
Suddenly, the exception being raised is about the absense of the HI!
method,
not of the HELLO!
one. Finally, the most outstanding example. Let’s define
some crazy classes.
[1] pry(main)> CLASSY!!!
| class A
| AWESOME!!!
| class B
| MARVELOUS!!!
| def great
| 'awful :-('
| end
| end
| end
NoMethodError: undefined method `MARVELOUS!' for A::B:Class
from (pry):7:in `<class:B>'
[2] pry(main)> A
=> A
[3] pry(main)> A::B
=> A::B
[4] pry(main)> A::B.new.great
=> "awful :-("
A few things to note. Firstly, the raised exception knows about the existence of
the A
and B
classes. Secondly, we’ve just defined a normal class that
we can instantiate.