how rails delegate method works?

后端 未结 2 749
死守一世寂寞
死守一世寂寞 2021-02-05 12:50

After reading the answer by jvans below and looking at the source code a few more time I get it now :). And in case anyone is still wondering how exactly rails delegates works.

相关标签:
2条回答
  • 2021-02-05 13:11

    Ruby isn't reopening the module class here. In ruby the class Module and the class Class are almost identical.

        Class.instance_methods - Module.instance_methods #=> [:allocate, :new, :superclass]
    

    The main difference is that you can't 'new' a module. Module's are ruby's version of multiple inheritance so when you do:

     module A
     end
     module B
     end
    
     class C
       include A
       include B
     end
    

    behind the scenes ruby is actually creating something called an anonymous class. so the above is actually equivalent to:

     class A
     end
     class B < A
     end
     class C < B
     end
    

    module_eval here is a little deceptive. Nothing from the code you're looking at is dealing with modules. class_eval and module_eval are the same thing and they just reopen the class that they're called on so if you want to add methods to a class C you can do:

     C.class_eval do 
        def my_new_method
        end
      end
    

    or

     C.module_eval do 
        def my_new_method
        end
      end
    

    both of which are equivalent to manually reopening the class and defining the method

      class C
       end
      class C
         def my_new_method
         end 
      end
    

    so when they're calling module_eval in the source above, they're just reopening the current class it's being called it and dynamically defining the methods that you're delegating

    I think this will answer your question better:

     Class.ancestors #=> [Module, Object, PP::ObjectMixin, Kernel, BasicObject]
    

    since everything in ruby is a class, the method lookup chain will go through all of these objects until it finds what it's looking for. By reoping module you add behavior to everything. The ancestor chain here is a little deceptive, since BasicObject.class #=> Class and Module is in Class's lookup hierarchy, even BasicObject inherits behavior from repening module. The advantage of reopening Module here over Class is that you can now call this method from within a module as well as within a class! Very cool, learned something here myself.

    0 讨论(0)
  • 2021-02-05 13:24

    After reading the answer by jvans below and looking at the source code a few more time I get it now :). And in case anyone is still wondering how exactly rails delegates works. All rails is doing is creating a new method with (module_eval) in the file/class that you ran the delegate method from.

    So for example:

      class A
        delegate :hello, :to => :b
      end
    
      class B
        def hello
         p hello
        end
      end
    

    At the point when delegate is called rails will create a hello method with (*args, &block) in class A (technically in the file that class A is written in) and in that method all rails do is uses the ":to" value(which should be an object or a Class that is already defined within the class A) and assign it to a local variable _, then just calls the method on that object or Class passing in the params.

    So in order for delegate to work without raising an exception... with our previous example. An instance of A must already have a instance variable referencing to an instance of class B.

      class A
        attr_accessor :b
    
        def b
          @b ||= B.new
        end
    
        delegate :hello, :to => :b
      end
    
      class B
        def hello
         p hello
        end
      end
    
    0 讨论(0)
提交回复
热议问题