为什么模块`ClassMethods`在同一名称空间中定义和扩展?

Rya*_*Mes 18 ruby gem

我试图理解来自github repo的代码.它是设置客户端的gem的主要模块.

module Github
  # more code
  class << self
    def included(base)
      base.extend ClassMethods # what would this be for?
    end
    def new(options = {}, &block)
      Client.new(options, &block)
    end
    def method_missing(method_name, *args, &block)
      if new.respond_to?(method_name)
        new.send(method_name, *args, &block)
      elsif configuration.respond_to?(method_name)
        Github.configuration.send(method_name, *args, &block)
      else
        super
      end
    end
    def respond_to?(method_name, include_private = false)
      new.respond_to?(method_name, include_private) ||
      configuration.respond_to?(method_name) ||
      super(method_name, include_private)
    end
  end

  module ClassMethods
    def require_all(prefix, *libs)
      libs.each do |lib|
        require "#{File.join(prefix, lib)}"
      end
    end
    # more methods ...
  end

  extend ClassMethods
  require_all LIBDIR,
    'authorization',
    'validations',
    'normalizer',
    'parameter_filter',
    'api',
    'client',
    'pagination',
    'request',
    'response',
    'response_wrapper',
    'error',
    'mime_type',
    'page_links',
    'paged_request',
    'page_iterator',
    'params_hash'

end
Run Code Online (Sandbox Code Playgroud)
  1. 为什么class << selfmodule ClassMethods使用,再延伸,而不是包含在class << self一部分?
  2. 有一种类方法def included(base).这似乎将类方法添加到特定对象中.为什么会这样?它可能与课程的功能有关,但我不明白.

art*_*pov 15

module MyModule
  class << self
    def included(base)
      base.extend ClassMethods # what would this be for?
    end
    <...>
  end
  <...>
end
Run Code Online (Sandbox Code Playgroud)

这实际上是Ruby中非常常见的做法.基本上,它所说的是:当某个对象执行时include MyModule,也可以使用它extend MyModule::ClassMethods.如果你想要一个mixin,它不仅可以为类的实例添加一些方法,而且可以添加到类本身,那么这样的专长很有用.

一个简短的例子:

module M
  # A normal instance method
  def mul
    @x * @y
  end

  module ClassMethods
    # A class method
    def factory(x)
      new(x, 2 * x)
    end
  end

  def self.included(base)
    base.extend ClassMethods
  end
end

class P
  include M
  def initialize(x, y)
    @x = x
    @y = y
  end

  def sum
    @x + @y
  end
end

p1 = P.new(5, 15)
puts "#{p1.sum} #{p1.mul}"

# Calling the class method from the module here!
p2 = P.factory(10)
puts "#{p2.sum} #{p2.mul}"
Run Code Online (Sandbox Code Playgroud)

  • 当'P`调用`include M`时,如果定义了,则ruby会自动调用`M`上的`included`.它是include方法的回调.这用于将模块的类方法扩展到`P`.请参阅:http://ruby-doc.org/core-2.2.0/Module.html#method-i-included (4认同)