书接上回……
不过要先打个岔……
动态语言就是要动起来
Ruby被人说上亿遍是动态语言,所以咱就要动态给你们看
Array.class_eval do
def punch_horse_ass
puts "Piecehealth is a very tall, rich and handsome man!!!"
end
def say_truth
puts "OK, fine, acutally I'm a diaosi"
end
end
[1, 2, 3].punch_horse_ass
Array.class_eval {remove_method :say_truth}
[1, 2, 3].say_truth # undefined method `say_truth' for [1, 2, 3]:Array (NoMethodError)
上面这段代码只想表达,我们可以对一个类在任何时候为所欲为(说这个词的时候总是不自觉露出淫 荡的表情),于是,我们就要对刚才那个还非常嫩的类为所欲为了!
实现initialize方法:
这一步感觉没什么好说的,直接上代码吧
module Tool
def self.csv2class csv_name
klass_name = csv_name.gsub('.csv', '').gsub(/\s+/, '_').downcase.capitalize
klass = Object.const_set(klass_name, Class.new)
File.open(csv_name ) do |file|
attributes = file.readline.chomp.split(',')
klass.class_eval do
attr_accessor *attributes
define_method :initialize do |*args|
attributes.each_with_index do |attribute, i|
instance_variable_set("@#{attribute}", args[i])
end
end
end
end
end
end
Tool.csv2class "Friends.csv"
puts Friends.new('Lilei','M',26,'Worker').dept
相信有一定ruby基础的同学能看明白(看不明白的同学不用担心,上面的东西baidu google类似的内容很多,搜索一下吧),但是这些是经过我实践后得到的最佳解决方案。
我第一次接触这个时主要面临两个问题,我们一个一个说吧。
第一个是为什么一定要用define_method而不直接用def(像第一段代码一样),这样做除了装X还有什么好处?
好吧,为了不被雷劈,我们把define_method方法换成def,即
def initialize *args
attributes.each_with_index do |attribute, i|
instance_variable_set("@#{attribute}", args[i])
end
end
然后运行Tool.csv2class "Friends.csv"的时候报错:in `initialize': undefined local variable or method `attributes' for #<Friends:0x35b46d8> (NameError)
啊,原来class_eval相当于打开一个内环境,而attributes是内环境之外的,也就是说class_eval内外是两个不同的作用域,而且貌似没什么交集。
这就是我第二个问题,内环境外环境是如何交互的?
很显然用defing_method可以用到外面作用域的变量跟方法,而class_eval里面的实例变量,类变量赋值取值可以用instance_variable_set, instance_variable_get, class_variable_set, class_variable_get来实现,这样两套不同的体系在两个不同的作用域间各自运作,又可以相互通讯,实在是太妙了……貌似还缺一个洋气的名字,就叫扁平作用域吧!
(由于本人比较懒,写的时候随手写的,也没查阅什么资料,绝大部分都是凭借记忆,很多表达都不准确,只希望能帮大家理解元编程的一些东西)