расширения класса ruby - PullRequest
       7

расширения класса ruby

2 голосов
/ 29 августа 2009

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

Ответы [ 3 ]

3 голосов
/ 29 августа 2009

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

  • вы можете использовать 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| (захват блоков в аргументах блока).

1 голос
/ 29 августа 2009

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

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

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

Или же вам придется долго ждать, пока не закончится ОЗУ, или, возможно, segfault.

0 голосов
/ 29 августа 2009

Извините, если я неправильно понял ваш вопрос, но Google "ruby dsl", вы можете найти эту вещь очень полезной для вашей проблемы. Также ознакомьтесь с вопросами об этой вещи здесь.

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

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

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

...