Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Where does the variable "p" get it's value from in ruby if it's not defined explicitly?

Tags:

ruby

irb

jruby

Question: Where does p get it's value from below and why does it happen?

Consider this irb session:

me@somewhere:~$ irb
irb(main):001:0> a
NameError: undefined local variable or method `a' for main:Object
    from (irb):1
irb(main):002:0> foo
NameError: undefined local variable or method `foo' for main:Object
    from (irb):2
irb(main):003:0> p
=> nil
irb(main):004:0> p.class
=> NilClass
irb(main):005:0>

I never defined p - so why is it nil valued? Neither a nor foo were recognized so what's special about p? I also didn't find anything listed under Kernel#p

Context: I'm reading the so-called "28 bytes of ruby joy" and assumed p was a variable, as in: def p.method_missing *_ ...

(Don't worry: I'm not going to actually define method_missing on nil everywhere... just studying some ruby code...)

like image 915
Dafydd Rees Avatar asked Dec 23 '22 01:12

Dafydd Rees


2 Answers

p is just a method on Kernel which calls inspect on its arguments, producing human-readable representations of those objects. If you give it no arguments, it prints nothing. Regardless of what you pass it, though, it returns nil. See Kernel#p and Object#inspect.

Power tip: In Ruby 1.9, when you have a method and you don't know where it came from, use the method method:

ruby-1.9.1-p378 > method(:p)
 => #<Method: Object(Kernel)#p>

Putting it together one step at a time, we read this as:

 p                            # We found a method called p.
 #p                           # It's an instance method.
 Object ... #p                # It's available on Object.
 Object(Kernel)#p             # It came from the Kernel module.

Update: The OP provided some context from this article, where the author claims that your life will be easier if you add a method_missing to nil, by doing the following:

def p.method_missing*_;p;end

This somewhat obfuscated code should be read as:

  • Define a new method (def), called method_missing. This overrides the default method_missing handler on Object, which simply raises a NoMethodError when it encounters a method it doesn't understand.
  • This method will live on something called p.
  • It accepts any number of arguments (*) and stores them in a variable called _.
  • The result of these arguments is something called p.

The second bullet is the tricky part here. def p.method_missing means one of two things, depending on context:

  • A previously defined object called p which is in scope here.
  • A method called p which is in scope, and which is passed no arguments.

With def p.method_missing, we mean, "this method is being defined on the object which is the result of calling p with no arguments". In this case, that is NilClass; if you call p with no arguments, you get nil. So this is just a short, hacky way to define a method on NilClass.

Note: I definitely recommend against defining a method_missing on nil. This is a silly and dangerous tactic to use for the sake of saving a few lines of code, because it changes the behavior of nil. Don't do it!

like image 116
John Feminella Avatar answered Apr 28 '23 00:04

John Feminella


p is a method which prints the inspect value of its arguments and returns nil. Without arguments it simply does nothing.

Its documentation is under Kernel#p, not Kernel::p (because it's an instance method of Kernel).

like image 29
sepp2k Avatar answered Apr 28 '23 01:04

sepp2k