2015-06-10 21 views
10

Próbuję zrozumieć kod z github repo. To główny moduł klejnotu do ustawienia klienta.Dlaczego moduł `ClassMethods` zdefiniowany i rozszerzony w tej samej przestrzeni nazw?

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 
  1. Dlaczego class << self i module ClassMethods używane, a następnie rozszerzony zamiast być zawarte w class << self części?
  2. Istnieje metoda klasy def included(base). To wydaje się dodawać metody klasy do określonego obiektu. Dlaczego tak jest? Może odnosić się do funkcjonalności klasy, ale ja jej nie rozumiem.

Odpowiedz

5
module MyModule 
    class << self 
    def included(base) 
     base.extend ClassMethods # what would this be for? 
    end 
    <...> 
    end 
    <...> 
end 

Jest to dość powszechna praktyka w języku Ruby. Zasadniczo, co to jest: gdy jakiś obiekt wykonuje include MyModule, spraw, aby był również extend MyModule::ClassMethods. Taki wyczyn jest przydatny, jeśli chcesz mixin, który dodaje pewne metody nie tylko do instancji klasy, ale do samej klasy.

Krótki przykład:

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}" 
+1

to ma sens. Jestem trochę zdezorientowany z powodu metody "self.included (base)", czy mógłbyś wyjaśnić, po co to jest i jak to się odnosi do modułu 'M' lub klasy' P' –

+4

, gdy 'P' nazywa' to M', ruby automatycznie wywołuje 'włączone' na' M' jeśli jest zdefiniowane. Jest to wywołanie zwrotne metody include. Jest to użyteczne do rozszerzenia metod klasy modułu na 'P'. Zobacz: http://ruby-doc.org/core-2.2.0/Module.html#method-i-included – DGM

+0

Czy jest jakaś szansa, aby wskazać mi praktyczny przykład tego? Wciąż nie jestem jasny w sprawie sytuacji, w których byłby wykorzystywany. Jestem pewien, że po prostu muszę zobaczyć praktyczny przykład, aby zrozumieć jego prawdziwą aplikację. –

1

Patrząc bardziej na repo jest inna klasa Github::API. Ta klasa wydaje się wymagać funkcjonalności modułu Github::ClassMethods.

module Github 
    # Core class responsible for api interface operations 
    class API 
    extend Github::ClassMethods 

Ma to sens, że jest to własny moduł. Daje możliwość importowania tylko tych metod. Jeśli uwzględnione zostałyby metody z class << self, staną się dostępne, co prawdopodobnie nie jest pożądane.

Być może lepiej mieć moduł w swojej klasie lub nazwać coś innego. Ale myślę, że to tylko osobisty wybór.

Powiązane problemy