What is the purpose of the “class << Class” (angle brackets) syntax?

夙愿已清 提交于 2020-05-29 02:55:47

问题


Why would I want to add anything to a class using class << Class syntax?

class Fun
    def much_fun
        # some code here
    end
end

class << Fun # the difference is here!
    def much_more_fun
        # some code here
    end
end

instead of using the monkey patching/duck punching method:

class Fun
    def much_fun
        # some code here
    end
end

class Fun # the difference is here!
    def much_more_fun
        # some code here
    end
end

While reading Why's Poignant Guide to Ruby I came across:

Why defines a class LotteryDraw:

class LotteryDraw
    # some code here
    def LotteryDraw.buy( customer, *tickets )
        # some code here as well
    end
end

and after a while adds a method to the LotteryDraw class:

class << LotteryDraw
    def play
        # some code here
    end
end

saying that:

When you see class << obj, believe in your heart, I’m adding directly to the definition of obj.

What is the purpose of this syntax? Why did Why decide to do it this way instead of using the monkey patching method?


These are some related questions and websites:

  • Adding a new method to the Array class
  • Yield in class << self in class method, which gives me a little bit of an idea why I would like to use class << Class syntax.
  • Open Classes in Ruby

回答1:


A little more explanation is needed. In ruby almost every single object can create a weird thing called an instance class. This thing is just like a normal class, the main difference is that it has only one single instance and that that instance is created before that class.

In short, having class A, you can do:

a = A.new
b = A.new

Both, a and b are now the instances of class A and have an access to all the instance method defined within this class. Now let's say, we want to add an extra method which can only be accesses by a, but not by b (this might be useful in some cases, but rather avoid it if possible). All the methods are defined within the classes, so it seems we need to add it to class A, but this way it will be accessible by b as well. In this case we need to create an instance class for a object. To do that, we use class << <object> syntax:

class << a
  def foo
  end
end

a.foo #=> nil
b.foo #=> undefined method

In short, class << <object> opens an instance class for given object, allowing to define additional instance methods for given instance, which will not be available on any other objects.

Now, with that being said: in Ruby, classes are jest instances of class Class. This:

class A
end

Is almost equivalent to (differences not important here)

A = Class.new

So if classes are objects, they can create their instance classes.

class << A
  def foo
  end
end

A.foo  #=> nil
Class.new.foo #=> undefined method

It is commonly used to add so-called class method to given class, the point however is that in fact you are creating an instance method on class' instance class.




回答2:


The first defines an instance method:

class Fun
  def much_fun
    puts 'hello'
  end
end

fun = Fun.new
fun.much_fun
#=> "hello"

Fun.hello
#=> NoMethodError: undefined method `hello' for Fun:Class

Whereas the << version defines a class method:

class Fun
  class << self # or Fun
    def much_more_fun
      puts 'hello'
    end
  end
end

fun = Fun.new
fun.much_more_fun
#=> NoMethodError: undefined method `much_more_fun' for #<Fun:0x007fafdb9ff0a0>

Fun.much_more_fun
#=> "hello"

Note that the second version could also be written as:

class Fun
  def self.much_more_fun
    puts 'hello'
  end
end



回答3:


I think class << Class is used to class methods and not instance methods:

class Foo
  class << Foo 
   def bar
   end
  end
end

Foo.bar #Bar is class method. Ruby has various ways to define class methods,eg :

 class Foo
  class << self 
    def bar
      p 'hi'
    end
  end
  def Foo.age
    p '24'
  end
  def self.gender
    p 'male'
  end
end
Foo.instance_eval do
  def name
    p 'hello'
  end
end
Foo.define_singleton_method(:status) do
  p 'single'
end

Foo.bar  #> 'hi'
Foo.name  #> 'hello'
Foo.age   #> '24'
Foo.gender  #>male
Foo.status  #>single


来源:https://stackoverflow.com/questions/33453063/what-is-the-purpose-of-the-class-class-angle-brackets-syntax

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!