RubyTalks.first

Damir Svrtan

Has anyone seen puts?

1. Method lookup

2. Eigenclass

3. Puts definition

4. Redefining puts

puts()/print()

Builtin function in Python and PHP

puts everywhere


    puts 'Starting our program!'

    class User
      puts 'Defining the User class'

      def initialize
        puts 'Registering a new user'
      end
    end

But how?

Is it a special global method? NO

Down to basics


  class User
    def initialize(name)
      @name = name
    end

    def name
      @name
    end
  end

  borko = User.new('Borko')

Ancestor chain


  User.ancestors

  => [User, Object, Kernel, BasicObject]

  class Student < User
  end

  Student.ancestors

  => [Student, User, Object, Kernel, BasicObject]

What's a superclass?


  Student.superclass
  => User

  User.superclass
  => Object

  Object.superclass
  => BasicObject

  BasicObject.superclass
  => nil

Ok, so where are borko's methods defined?

In it's class and all the ancestors of course!

one step to the right, then up!

Method lookup is done through the ancestor chain

again, one step to the right, then up!

What about the User class?

borko is an instance of the User class

User class is an instance of Class class

We can also define methods on the instance

Unlike other users, Borko can sing!


  borko  = User.new('Borko')
  zdenko = User.new('Zdenko')

  def borko.sing
    puts "I'm singing in the rain!"
  end

  borko.sing
  => "I'm singing in the rain!"

  zdenko.sing
  => undefined method `sing' for #<User:0x007fc8320bc528>

Eigenclass

The Eigenclass keeps all the singleton methods of an object

Hooks right into the ancestor chain

Does this syntax look familiar?


  def borko.sing
    puts "I'm singing in the rain!"
  end

  class User

    def self.new_from_omniauth(email)
      ...
    end

  end

Ever done sumthin' like this?


  class User

    class << self # What is self?
      # Defining the method on the eigenclass of self
      def new_from_omniauth(email)
        ...
      end
    end

  end

Or like this?


  class User

    class << self
      def new_from_omniauth(email)
        ...
      end
    end

    class << User
      def new_from_omniauth(email)
        ...
      end
    end

    def self.new_from_omniauth(email)
      ...
    end

    def User.new_from_omniauth(email)
      ...
    end
  end

  class << User
    def new_from_omniauth(email)
      ...
    end
  end

  def User.new_from_omniauth(email)
    ...
  end

Where is puts defined?


    show-source borko.puts

    From: io.c (C Method):
    Owner: Kernel
    Visibility: private
    Number of lines: 8

    static VALUE
    rb_f_puts(int argc, VALUE *argv, VALUE recv)
    {
        if (recv == rb_stdout) {
      return rb_io_puts(argc, argv, recv);
        }
        return rb_funcall2(rb_stdout, rb_intern("puts"), argc, argv);
    }
    borko.class.ancestors.include? Kernel
    => true

pry & pry-doc

Back to square one


    puts 'Starting our program!'

    class User
      puts 'Defining the User class'

      def initialize
        puts 'Registering a new user'
      end
    end

User

#<User:0x007f987>

main

Console main


    self
    => main

    self.class
    => Object

    self.class.ancestors.include? Kernel
    => true

    self.class.private_instance_methods.include? :puts
    => true

    self.private_methods.include? :puts
    => true 

    class User
    end

    User.class
    => Class
    User.class.ancestors.include? Kernel
    => true
    User.class.private_instance_methods.include? :puts
    => true

    borko = User.new

    borko.class
    => User
    borko.class.ancestors.include? Kernel
    => true
    borko.class.private_instance_methods.include? :puts
    => true

Why don't we redefine puts?


    puts 'Ruby is fun!'

    =>
     _________________________
    (      Ruby is fun!       )
     -------------------------
            o   ^__^
             o  (oo)\_______
                (__)\       )\/\/
                    ||----w |
                    ||     ||

Cow says mooooo!


    class Cow
      def moo
        puts 'mooooooo'
      end
    end

    milka = Cow.new

    def milka.puts(text)
      cow_output =
      "_________________________\n"\
      "(        #{text}        )\n"\
      "-------------------------\n"\
      "       o   ^__^\n"\
      "        o  (oo)\_______\n"\
      "           (__)\       )\/\/\n"\
      "              ||----w |\n"\
      "              ||     ||\n"

      super(cow_output)
    end

On the eigenclass!


    > show-source milka.puts

    From: user.rb @ line 49:
    Owner: #<Class:#<Cow:0x007fbc409ef940>>
    Visibility: public
    Number of lines: 13

    def milka.puts(text)
      cow_output =
      "_________________________\n"\
      "(        #{text}        )\n"\
      "-------------------------\n"\
      "       o   ^__^\n"\
      "        o  (oo)\_______\n"\
      "           (__)\       )\/\/\n"\
      "              ||----w |\n"\
      "              ||     ||\n"

      super(cow_output)
    end

    > milka.moo
    
    =>
    _________________________
    (        mooooooo        )
    -------------------------
           o   ^__^
            o  (oo)_______
               (__)       )//
                  ||----w |
                  ||     ||

    class Cow
        def puts(text)
          cow_output =
          "_________________________\n"\
          "(        #{text}        )\n"\
          "-------------------------\n"\
          "       o   ^__^\n"\
          "        o  (oo)\_______\n"\
          "           (__)\       )\/\/\n"\
          "              ||----w |\n"\
          "              ||     ||\n"

          super(cow_output)
        end
    end

On every cow!


    show-source Cow#puts

    From: (pry) @ line 3:
    Owner: Cow
    Visibility: public
    Number of lines: 13

    def puts(text)
      cow_output =
      "_________________________\n"\
      "(        #{text}        )\n"\
      "-------------------------\n"\
      "       o   ^__^\n"\
      "        o  (oo)\_______\n"\
      "           (__)\       )\/\/\n"\
      "              ||----w |\n"\
      "              ||     ||\n"

      super(cow_output)
    end

    > Cow.new.moo
    
    =>
    _________________________
    (        mooooooo        )
    -------------------------
           o   ^__^
            o  (oo)_______
               (__)       )//
                  ||----w |
                  ||     ||

    class Object
        def puts(text)
          cow_output =
          "_________________________\n"\
          "(        #{text}        )\n"\
          "-------------------------\n"\
          "       o   ^__^\n"\
          "        o  (oo)\_______\n"\
          "           (__)\       )\/\/\n"\
          "              ||----w |\n"\
          "              ||     ||\n"

          super(cow_output)
        end
    end

Everybody say moooo!


    puts 'moooooooo'

    class User
      puts 'moooooooo'

      def initialize
        puts 'moooooooo'
      end
    end

    User.new

    _________________________
    (        mooooooo        )
    -------------------------
           o   ^__^
            o  (oo)_______
               (__)       )//
                  ||----w |
                  ||     ||

    _________________________
    (        mooooooo        )
    -------------------------
           o   ^__^
            o  (oo)_______
               (__)       )//
                  ||----w |
                  ||     ||

    _________________________
    (        mooooooo        )
    -------------------------
           o   ^__^
            o  (oo)_______
               (__)       )//
                  ||----w |
                  ||     ||

Redefine rampage

  • print
  • raise
  • backticks ``
  • private/protected/public
  • eval
  • require

Fin.

madebydna.com/all/code/2011/06/24/eigenclasses-demystified.html

and visit:

Check your dropbox:

RubyTalks

By Damir Svrtan

RubyTalks

  • 1,288