2016-07-30 4 views
-3

Как я могу динамически и легко вставлять код в начало каждого метода класса и подклассов без фактической вставки его вручную? Я хочу что-то вроде макросов.Вставить код в начало каждого метода класса

class C1 
    def m1 
    @i_am = __method__ 
    end 

    def m2 
     @i_am = __method__ 
    end 
end 

Это один из примеров, когда я хочу избежать повторения.

+0

Цель ваших примеров не ясна. – sawa

+0

@sawa, нет, это не так. – Ramano

+1

Рамано, акисты не в лучшем положении, чтобы определить, ясно ли их вопрос читателям. Я с @sawa на этом. –

ответ

1

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

class C1 
    [:m1, :m2].each do |m| 
    define_method(m) do |name| 
     @i_am = __method__ 
     puts "I'm #{name} from method #{@i_am}" 
    end 
    end 
end 

C1.instance_methods(false) 
    #=> [:m1, :m2] 
c1 = C1.new 
    #=> #<C1:0x007f94a10c0b60> 
c1.m1 "Bob" 
    # I'm Bob from method m1 
c1.m2 "Lucy" 
    # I'm Lucy from method m2 

Мое первоначальное решение следующим образом.

class C1 
    def add_code_to_beginning(meth) 
    meth = meth.to_sym 
    self.class.send(:alias_method, "old_#{meth}".to_sym, meth) 
    self.class.send(:define_method, meth) do 
     yield 
     send("old_#{meth}".to_sym) 
    end 
    end 
end 

Module#alias_method и Module#define_method являются частными; следовательно, необходимо использовать send.

c = C1.new 
    #=> #<C1:0x007ff5e3023650> 
C1.instance_methods(false) 
    #=> [:m1, :m2, :add_code_to_beginning] 

c.add_code_to_beginning(:m1) do 
    puts "hiya" 
end 

C1.instance_methods(false) 
    #=> [:m1, :m2, :add_code_to_beginning, :old_m1] 
c.m1 
    # hiya 
    #=> :m1 
+0

, как это проще, чем вставлять один и тот же код в каждый метод вручную? – Ramano

+0

Хорошая точка. Я упаковал код в метод. –

+0

, который создает новый открытый метод в классе, я не хочу этого. – Ramano

-1

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

Пример:

module MyModule 
    def test_method 
    puts "abc" 
    end 
end 

class MyClass 
    include MyModule 
    def my_method 
    puts "my method" 
    end 
end 

inst = MyClass.new 
inst.test_method # => should print "abc" 
inst.my_method # => should print "my method" 
0

Вы можете использовать рельсы, как класс декораторов к этому. Часть кода ниже представляет собой метод, называемый before_action, определенный в базовом классе модуля ActiveRecord. Класс Test унаследован от ActiveRecord. define_method используется, если мы хотим вызвать что-то явно из базового класса.

module ActiveRecord 
    class Base 

     def self.before_action(name) 
      puts "#{name}" 
      puts "inside before_action of class Base" 

      define_method(name) do 
       puts "Base: rendering code from Base class" 
      end 
     end 
    end 
end 

class Test < ActiveRecord::Base 

    before_action :hola 

    def render() 
     puts "inside render of class Test" 
    end 

end 

test = Test.new 
test.render 
test.hola 

имеет выходной сигнал

hola 
inside before_action of class Base 
inside render of class Test 
Base: rendering code from Base class 

Итак, перед запуском метода render он запускает метод before_action в Base классе. Он может применяться ко всем другим методам класса Test. Это способ представления макросов в рубине.

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