class << self vs self.method with Ruby: what's better?

前端 未结 6 590
囚心锁ツ
囚心锁ツ 2020-11-30 21:33

This Ruby Style Guide tells that is better using self.method_name instead of class method_name. But Why?

class TestClass
  # bad
           


        
相关标签:
6条回答
  • 2020-11-30 21:35

    So far the question and answers only discuss these two options:

    class MyClass
      def self.method_name
        ..
      end
    end
    
    class MyClass
      class << self
        def method_name
          ..
        end
      end
    end
    

    There's a third option to consider for class methods:

    class MyClass
      def MyClass.method_name
        ..
      end
    end
    

    It's not popular and is more verbose, but it's the most explicit option.

    It's also less confusing if you mix up self behaviour between Python and Ruby.

    0 讨论(0)
  • 2020-11-30 21:44

    class << self is good at keeping all of your class methods in the same block. If methods are being added in def self.method form then there's no guarantee (other than convention and wishful thinking) that there won't be an extra class method tucked away later in the file.

    def self.method is good at explicitly stating that a method is a class method, whereas with class << self you have to go and find the container yourself.

    Which of these is more important to you is a subjective decision, and also depends on things like how many other people are working on the code and what their preferences are.

    0 讨论(0)
  • 2020-11-30 21:50

    I assume that they think self.* is better because you can say for sure, it's a class or instance method, without having to scroll up and seaching this class << self string.

    0 讨论(0)
  • 2020-11-30 21:55

    Whichever you want. Both are very clear for what you do. But I think of some recommendations for this.

    When there're only one class method to define, Use def self.xxx. Because for defining only one method, increasing indent level probably become cluttering.

    When there're more than one class method to define, Use class << self. Because writing def self.xxx, def self.yyy and def self.zzz is certainly repetition. Create a section for these methods.

    When all methods in a class are class method, you can use module with module_function instead of class. This let you define module functions just use def xxx.

    0 讨论(0)
  • As noted above, both styles seem to be equivalent, however using class << self allows one to mark class methods as private or protected. For example:

    class UsingDefSelf
      def self.a; 'public class method'; end
      private
      def self.b; 'public class method!'; end
    end
    
    class UsingSingletonClass
      class << self
        def a; 'public class method'; end
        private
        def b; 'private class method'; end
      end
    end
    

    private only affects instance methods. Using the singleton class, we are defining instance methods of that class, which turn into class methods of the containing class!

    We can also mark class methods as private with def self:

    class UsingDefSelf
      def self.a; 'private class method'; end
      def self.b; 'private class method!'; end
      private_class_method :a, :b
      # In Ruby 2.1 there is an alternative syntax
      private_class_method def self.c; 'private class method!'; end
    end
    

    But we cannot mark them as protected, there is no protected_class_method. (However, since class is the only instance of its singletonclass, private class method and protected class methods are almost the same except their calling syntax is different.)

    Also it is less easier than using class << self to mark private class methods, since you have to list all method names in private_class_method or prefix private_class_method to every private class method definition.

    0 讨论(0)
  • 2020-11-30 22:02

    Generally, class << self is used in metaprogramming to set the class as self for a prolonged period of time. If I'm trying to write 10 methods, I would use it like so:

    METHOD_APPENDICES = [1...10]
    class << self
      METHOD_APPENDICES.each do |n|
        define_method("method#{n}") { n }
      end
    end
    

    This would create 10 methods (method1, method2, method3, etc.) that would just return the number. I would use class << self for clarity in this case because in metaprogramming self is crucial. Littering self. inside there would actually make things less readable.

    If you're just defining class methods normally, stick to self.class_method_name because more people are likely to understand it. No need to bring in meta-syntax unless you expect your audience to understand it.

    0 讨论(0)
提交回复
热议问题