define_method没有返回任何结果

时间:2013-12-01 20:19:52

标签: ruby metaprogramming

我有很多方法完全相同,但需要使用特定名称定义它们。所以我在调用每个format_方法的方法中尝试了以下内容:

['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

如何获得第一个块来为数组中的每个元素生成方法?


这里的新实施基于Andrew Marshall的回答:

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

3 个答案:

答案 0 :(得分: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,因为它将从方法返回,而不是块。隐含的回报就足够了。

答案 1 :(得分:1)

执行:

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

答案 2 :(得分: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