1
module Cnblog2jekyll
  class << self
    attr_accessor :username


    [:archive_links, :article_links].each do |method_name|
      define_method method_name do
        instance_value = instance_variable_get(("@" + method_name.to_s).to_sym)
        instance_value ? instance_value : send("get_" + method_name.to_s)
        # @archive_links ? @archive_links : get_archive_links
      end
    end

    binding.pry

    def test
      binding.pry
    end


  end
end

Please ignore meaning of most part code and mind the place of 'binding.pry'.

Here comes the question: I type in 'self' in the pry console just at the place of 'binding.pry', and it give this result:

From: /home/yanying/cnblog2jekyll/lib/cnblog2jekyll.rb @ line 20 :

    15:         instance_value = instance_variable_get(("@" + method_name.to_s).to_sym)
    16:         instance_value ? instance_value : send("get_" + method_name.to_s)
    17:         # @archive_links ? @archive_links : get_archive_links
    18:       end
    19:     end
 => 20:     binding.pry
    21: 
    22:     def test
    23:       binding.pry
    24:     end
    25: 

[1] pry(#<Class>)> self
=> #<Class:Cnblog2jekyll>
[2] pry(#<Class>)> self.class
=> Class
[3] pry(#<Class>)> self.ancestors
=> [#<Class:Cnblog2jekyll>, Module, Object, PP::ObjectMixin, Kernel, BasicObject]
[4] pry(#<Class>)> 
=> true
[2] pry(main)> Cnblog2jekyll.test

From: /home/yanying/cnblog2jekyll/lib/cnblog2jekyll.rb @ line 23 Cnblog2jekyll.test:

    22: def test
 => 23:   binding.pry
    24: end

[1] pry(Cnblog2jekyll)> self
=> Cnblog2jekyll
[2] pry(Cnblog2jekyll)> self.class
=> Module
[3] pry(Cnblog2jekyll)> self.ancestors
=> [Cnblog2jekyll]
[4] pry(Cnblog2jekyll)> 

So, my question is: Why the first result of 'self' is a 'Class'? But the second of it is a "Module"? What's the magic here?

yanyingwang
  • 117
  • 6

2 Answers2

4

Since you are using class << self, you open up a self singleton class, and methods inside this redefine the methods of the current self, which in your case is the module Cnblog2jekyll

if you had:

class Cnblog2jekyll
  def foo

  end

  class << self
    def bar

    end
  end
end

and you called Cnblog2jekyll.new.bar you would get an undefined_method, because bar is specified as a class method, not a object method. In your case, your methods are module methods, because the class << self is inside the module block.

Check out this question about the class << self idiom and also this article about it.

Community
  • 1
  • 1
1

Let me first answer the second part of your question. A class in ruby is not that special compared to other languages.

Thus, a class is just an object as all the others in Ruby. All classes in Ruby are instances of the Class class, including the Class class itself. Now, Module is also a class and incidentally the parent class of Class. In Ruby, you basically have this setup:

class BasicObject
  # The top-level base class. All objects in Ruby are an instance of BaseClass.
  # This class is effectively empty and is generally of little use on its own.
end

module Kernel
  # A module which is included about everywhere. It implements most of the basic
  # core methods of Ruby which you use every day including puts, raise and
  # require
end

class Object < BasicObject
  include Kernel

  # Almost all objects on ruby are instances of Object. Here, Ruby defines many
  # convenience methods available to about all objects, e.g., to_s, is_a? and
  # nil?
end

class Module < Object
  # A "special" class. All modules are an instance of this class. In fact, this:
  #
  #   module Foo
  #   end
  #
  # is mostly equivalent to
  #
  #   Foo = Module.new
end

class Class < Module
  # All classes are also modules. In fact, a class is basically a module which
  # can't be included or extended but can be instantiated.
  #
  # All objects in Ruby are instances of the Class class. This is where the
  # ring is closed. Because of this, you will see the ancestors chain the
  # way you got it from Pry.
end

You see, the base object model is a bit circular. This structure is hardcoded in order to bootstrap the so called meta model of the language. All objects (including classes) are build on this basic structure.

Now to the first part of your question: You are calling pry in the context of the class you are specifying, as such, self is the class you are currently creating. Please see the answer of Gabriel Lett for details about how this works.

Holger Just
  • 52,918
  • 14
  • 115
  • 123