【问题标题】:Metaprograming: custom initialize元编程:自定义初始化
【发布时间】:2014-11-19 23:12:07
【问题描述】:

我必须在Class 类中编写一个my_initialize 方法,以便它在这个庄园中工作,当在另一个类中使用时:

class Person my_initialize :name, :surname end

相当于:

class Person def initialize(name, surname) @name, @surname = name, surname end end

如果传递了错误数量的参数,它还必须引发ArgumentError。例如Person.new("Mickey") 无效。我知道我的代码应该类似于:

class Class
  def my_initialize(*args)
    args.each do |arg|      
     self.class_eval("?????")          
    end
  end 
end

我刚开始阅读元编程,但找不到任何对我的问题有用的东西。任何想法如何完成这项任务?

【问题讨论】:

  • 继续阅读,直到您发现 define_method。 :)

标签: ruby class metaprogramming


【解决方案1】:
class Class
  def my_initialize(*vars)
    define_method :initialize do |*args|
      if args.length != vars.length
        raise ArgumentError, 'wrong number of arguments'
      end
      vars.zip(args).each do |var, arg|
        instance_variable_set :"@#{var}", arg
      end
    end
  end
end

class C
  my_initialize :a, :b
end

Module#define_method 方法采用方法名称和块并定义该模块的方法。在这种情况下,模块是CObject#instance_variable_set 方法接受一个实例变量名称和一个值并设置它。在这种情况下Object 的实例将是C 的实例。

顺便说一句,最好避免使用传递一串代码以进行评估的方法。我建议改为传递块。

【讨论】:

  • 好,阿德里安!我认为您可能必须将 initialize 设为私有,但不,Ruby 会处理这一点:C.private_instance_methods(false) => [:initialize]
【解决方案2】:

这是不使用define_method的另一种方式。

class Class
  def my_initialize(*vars)
    str = "def initialize(*args)
             raise ArgumentError if args.size != #{vars.size}
             #{vars}.zip(args).each do |var, arg|
               instance_variable_set(\"@\#{var}\", arg)
             end
           end"
    class_eval str
  end
end

class C
  my_initialize :a, :b
end

c = C.new("Betty", "Boop")
  #=> #<C:0x00000102805428 @a="Betty", @b="Boop">

C.private_instance_methods(false)
  #=> [:initialize]
c.instance_variables
  #=> [:@a, :@b]

C.new("Betty")
  #=> ArgumentError

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-05-16
    • 2011-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多