2009-08-29 3 views
1

Я хотел бы написать метод в ruby, который принимает класс с определенными методами и изменяет его поведение, добавляя методы или изменяя, как работают существующие методы. Я хотел бы сделать это таким образом, чтобы не изменять базовый класс, поэтому я хочу, чтобы функция, которая принимает класс, и возвращает новый модифицированный класс, не нанося вреда первому классу. Я уверен, что это возможно, но я не уверен, с чего начать.Расширения класса ruby ​​

ответ

2

У вас есть несколько вариантов:

  • вы можете использовать x = Class.new(Parent) { def meth; puts "hello"; super; puts "bye"; end } динамически определять класс и переопределить методы (& определить новые)
  • вы можете использовать Delegator

Так Например, если вы хотите динамически создавать классы, которые регистрировали определенные вызовы методов:

class Class 
    def logging_subclass(*methods) 
    Class.new(self) do 
     methods.each do |method| 
     define_method(method) do |*args,&blk| 
      puts "calling #{method}" 
      ret = super(*args,&blk) 
      puts "#{method} returned #{ret.inspect}" 
      ret 
     end 
     end 
    end 
    end 
end 

class One 
    def foo 
    "I'm foo!" 
    end 
end 

# this prints nothing 
One.new.foo #=> returns :foo 

# this prints: 
# > calling foo 
# > foo returned "I'm foo!" 
One.logging_subclass(:foo).new.foo #=> returns :foo 

Обратите внимание, что вам нужно ruby ​​1.9 для поддержки захвата do |&blk| (захват блоков в аргументах блока).

+0

Не можете ли вы вообще оставить список аргументов из супервызов? Супер должен использовать те же аргументы, что и текущий метод, если вы не дадите ему что-то еще. Но Class.new звучит точно так, что ищет Дэвид. – Chuck

+0

Вы можете в обычном определении, но не в 'define_method', это' Runtime Error: неявная передача аргумента super из метода, определяемого define_method(), не поддерживается. Указать все аргументы явно. Если davidk01 всегда переопределяет один и тот же метод, тогда будет работать обычный синтаксис 'def meth ... end'. – rampion

1

Я предлагаю использовать inheritance или a mixin; на мой взгляд, использование mixin было бы более разумной идеей, хотя использование наследования легче для новичков.

Помните, что вы всегда можете унаследовать класс и изменить поведение или обернуть его новым кодом.

class Mammal 
    def speak 
    "..." 
    end 
end 

class Cat < Mammal 
    def speak 
    "meow" 
    end 
end 

class Lion < Cat 
    def speak 
    "get ready for a big " + super + "!" 
    end 
end 

module Asexual_Critter 
    def reproduce(critter_list) 
    puts "*poink!*" 
    critter_list << self.clone 
    end 
end 

class Mutated_Kitty < Cat 
    include Asexual_Critter # inane example I know, but functional... 
end 

Просто помните, что если вы хотите играть с этим не делать:

critters = [Mutated_Kitty.new] 
begin 
    critters.each { |c| c.reproduce(critters) } 
end while critters.length > 0 

Или вы будете в течение долгого ожидания, пока вы бежите из памяти, или, возможно, выдаёт ошибку сегментации.

0

Прошу прощения, если я понимаю ваш вопрос неправильно, но google «ruby dsl», вы можете найти эту вещь очень полезной для своей проблемы. также проверьте вопросы, заданные здесь.

проверить эту статью, если и не знаю, как начать:

[http://www.jroller.com/rolsen/entry/building_a_dsl_in_ruby][1] 

я сделал что-то подобное раньше, сохранив изменения, которые я сделал в текстовый файл, и читать этот файл снова, когда программа перезапустила или перезагрузила свои настройки.

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