2015-01-08 2 views
12

Я пытаюсь понять функцию Ruby's reflections, и я столкнулся с сценарием, который я не понимаю.Уточнения применяются только к методам экземпляра?

Возьмите этот пример кода:

class Traveller 
    def what_are_you 
    puts "I'm a Backpacker" 
    end 

    def self.preferred_accommodation 
    puts "Hostels" 
    end 
end 


module Refinements 
    module Money 
    def what_are_you 
     puts "I'm a cashed-up hedonist!" 
    end 

    module ClassMethods 
     def preferred_accommodation 
     puts "Expensive Hotels" 
     end 
    end 

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

    refine Traveller do 
    include Money 
    end 
end 

Теперь, когда я делаю это в РЕПЛ:

Traveller.new.what_are_you   # => I'm a Backpacker 
Traveller.preferred_accommodation # => Hostels 

using Refinements 

Traveller.new.what_are_you   # => I'm a cashed-up hedonist! 
Traveller.preferred_accommodation # => Hostels (???) 

Почему #what_are_you рафинированные, но .preferred_accommodation нет?

+1

'Traveller.preferred_accommodation' - метод класса. 'Traveller.new.preferred_accommodation' будет печатать то, что вы ожидаете (поскольку у вас есть базовый класс, расширенный при включении.) Но' Traveller' является экземпляром класса Class. Если вы хотите, чтобы «Traveller.preferred_accommodation» был уточнен, вы должны _refine класс Class_. – mudasobwa

+1

@mudasobwa, вы могли бы это сделать, но разве это не сделало бы утонченные версии методов доступными для всех классов? Разве это не та же проблема, что и создание методов класса, определяя методы экземпляра в классе 'Class': они становятся методами класса для всех классов? Я не вижу никакого преимущества в том, чтобы перерабатывать одноэлементные классы и очевидные недостатки. –

+1

@ CarySwoveland Конечно, вы правы. Я бы сказал, что ** не следует делать ** с уточнением класса; причина, по которой я отказал комментарий, а не ответ: я хотел пролить свет на то, что происходит, но не дать рецепт. – mudasobwa

ответ

15

Как объяснил @MasashiMiyazaki, вам необходимо уточнить два класса: Traveller и Traveller - одноэлементный класс. Это на самом деле позволяет упростить код совсем немного:

module Money 
    refine Traveller do 
    def what_are_you 
     puts "I'm a cashed-up hedonist!" 
    end 
    end 

    refine Traveller.singleton_class do 
    def preferred_accommodation 
     puts "Expensive Hotels" 
    end 
    end 
end 

Traveller.new.what_are_you   #=> I'm a Backpacker 
Traveller.preferred_accommodation #=> Hostels 

using Money 
Traveller.new.what_are_you   #=> I'm a cashed-up hedonist! 
Traveller.preferred_accommodation #=> Expensive Hotels 

Кроме того, поставив выше три заявления в модуле, утонченные версии двух методов ограничиваются этим модулем:

module M 
    using Money 
    Traveller.new.what_are_you   #=> I'm a cashed-up hedonist! 
    Traveller.preferred_accommodation #=> Expensive Hotels 
end 

Traveller.new.what_are_you   #=> I'm a Backpacker 
Traveller.preferred_accommodation #=> Hostels 
+1

Я понял, что «методы класса» - это просто «методы экземпляра для одноэлементного класса», но почему-то пропустили эту импликацию. Думая о объектной модели Ruby еще немного, это имеет смысл. Благодаря! – andrewdotnich

5

Чтобы переопределить методы класса, вам необходимо вызвать уточнение Traveler с областью Singleton_class. Добавив следующий код в модуль Refinements вместо self.included, вы можете получить ожидаемый результат.

module Refinements 
    refine Traveller.singleton_class do 
    include Money::ClassMethods 
    end 
end 

Эта статья (http://timelessrepo.com/refinements-in-ruby) поможет вам понять Уточнения больше.

 Смежные вопросы

  • Нет связанных вопросов^_^