2013-12-01 3 views
1

У меня есть много методов, которые делают то же самое, но они должны быть определены каждый с определенным именем. Так что я попытался следующие внутри метода, который вызывает каждый отдельный format_ метод:define_method не возвращает никаких результатов

['street', 'postcode', 'email', 'type', 'subtype', 'dsc', 'duration'].each do |attribute| 
    define_method("self.format_#{attribute}") do |value| 
    return cleanup(value) 
    end 
end 

Раньше у меня был отдельный метод для каждого элемента в массиве, как, например:

def self.format_street value 
    return cleanup(value) 
end 

Как я могу получить первый блок для генерации методов для каждого элемента в массиве?


Вот новая реализация на основе ответа от Эндрю Маршалла:

def self.analyze_input! formatted_information, category 

    analyzed_information = {} 
    attributes = eval(category).attributes 

    ['inst_number', 'name', 'head_of_department', 'street', 'city', 'phone', 'classification', 'sub_classification'].each do |attribute| 
    define_singleton_method(:"analyze_#{attribute}") do |value| 
     value 
    end 
    end 

    formatted_information.each do |key, value| 
    if attributes.include?(key) 
     analyzed_information[:"#{key}"] = send("analyze_#{key}", value) 
    end 
    end 

end 
+0

Вы действительно хотите быть (пере) определение этих методов на каждом вызове 'analyze_input!'. Почему бы не определить все эти методы 'analysis_ ' вне этого метода, используя либо подход, предложенный ниже? –

+0

Нет, я не хочу этого делать. Ошибка, к сожалению, такая же. – Severin

ответ

4

self. Положив во имя метода определяется не имеют эффект, который вы хотите, он буквально создает метод с таким именем:

define_method(:'self.foo') { 'bar' } 
self.foo # undefined method 
send('self.foo') #=> "bar" 

Вместо опускаем self. и вместо этого использовать define_singleton_method:

attributes = %w[street postcode email type subtype dsc duration] 
attributes.each do |attribute| 
    define_singleton_method(:"format_#{attribute}") do |value| 
    cleanup(value) 
    end 
end 

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

+0

Я внедрил эти изменения, но теперь получаю: ArgumentError: попытался создать объект Proc без блока – Severin

+0

Я обновлю исходный вопрос, чтобы вы могли увидеть реализацию. – Severin

+0

@Severin Я считаю, что мой обновленный ответ должен исправить эту проблему, которая была связана с использованием 'return' внутри блока внутри метода. (Хотя я не могу воспроизвести вашу ошибку - какую версию Ruby вы используете?) –

1

Do:

class << self 
    ['street', 'postcode', 'email', 'type', 'subtype', 'dsc', 'duration'].each do |attribute| 
    define_method("format_#{attribute}") do |value| 
     cleanup(value) 
    end 
    end 
end 
+0

По-прежнему такая же проблема. Попробовал поместить блок в метод, который вызывает тот, который должен быть сгенерирован, и как первый в документе. Вы бы разместили этот блок? – Severin

+0

В вашем классе 'class Foo; класс << self; ... ' – apneadiving

+0

Это вызывает эту ошибку: ArgumentError: попытался создать объект Proc без блока – Severin

1

Поскольку методы идентичны, создание псевдонимов с Module#alias_method или с использованием BasicObject#method_missing было бы самым прямым.

Использование alias_method

NAMES= ['street', 'postcode', 'email', 'type', 'subtype', 'dsc', 'duration'] 

class Clean 
    class << self 
    def cleanup(value) 
     puts "cleanup #{value}" 
    end 

    NAMES.each {|n| alias_method "format_#{n}", :cleanup} 

    def doit 
     format_street(5) 
     format_type(13) 
    end 
    end 
end 

Clean.methods(false) # =>[:cleanup, :doit, :format_street, :format_postcode, \ 
        # => :format_email, :format_type, :format_subtype, \ 
        # => :format_dsc, :format_duration] 
Clean.doit 
    # => cleanup 5 
    # => cleanup 13 
Clean.format_dsc(3) # => cleanup 3 

Использование method_missing

class Clean 
    class << self 
    @names = NAMES.map {|e| "format_#{e}".to_sym} 

    def cleanup(value) 
    puts "cleanup #{value}" 
    end 

    def method_missing(name, *args) 
     if @names.include? name 
     cleanup args.first 
     else 
     super 
     end 
    end 

    def doit 
     format_street(5) 
     format_type(13) 
    end 
    end 
end 

Clean.doit 
    # => cleanup 5 
    # => cleanup 13 
Clean.format_email(7) # => cleanup 7 
Clean.cat(9) # NoMethodError: undefined method `cat' for Clean:Class 
Смежные вопросы