- 浏览: 1653587 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (405)
- C/C++ (16)
- Linux (60)
- Algorithm (41)
- ACM (8)
- Ruby (39)
- Ruby on Rails (6)
- FP (2)
- Java SE (39)
- Java EE (6)
- Spring (11)
- Hibernate (1)
- Struts (1)
- Ajax (5)
- php (2)
- Data/Web Mining (20)
- Search Engine (19)
- NLP (2)
- Machine Learning (23)
- R (0)
- Database (10)
- Data Structure (6)
- Design Pattern (16)
- Hadoop (2)
- Browser (0)
- Firefox plugin/XPCOM (8)
- Eclise development (5)
- Architecture (1)
- Server (1)
- Cache (6)
- Code Generation (3)
- Open Source Tool (5)
- Develope Tools (5)
- 读书笔记 (7)
- 备忘 (4)
- 情感 (4)
- Others (20)
- python (0)
最新评论
-
532870393:
请问下,这本书是基于Hadoop1还是Hadoop2?
Hadoop in Action简单笔记(一) -
dongbiying:
不懂呀。。
十大常用数据结构 -
bing_it:
...
使用Spring MVC HandlerExceptionResolver处理异常 -
一别梦心:
按照上面的执行,文件确实是更新了,但是还是找不到kernel, ...
virtualbox 4.08安装虚机Ubuntu11.04增强功能失败解决方法 -
dsjt:
楼主spring 什么版本,我的3.1 ,xml中配置 < ...
使用Spring MVC HandlerExceptionResolver处理异常
meta-programming
1、Create a object on the fly.
我们已经凭空创建了一个类Person,现在我们想添加点方法:
好的我们打开这个类:
我们发现p1可以使用who?这个方法了。
我们用另一中方法打开这个类,从一个数组读取一个两个字段
的名字,然后往Person里面属性和访问方法:
我们发现class_eval这个block可以访问局部变量fields,这个block
在定义的时候与当前环境中的变量绑定了
同样我们可以看到define_method block也会和本地的变量绑定:
现在我们想让一个实例mixin一个module,而不影响这个类的其他实例
给Object添加属性和方法将会影响所有的地方:
我们希望从文件中读取一些数据来动态的创建一个类以及它的属性和方法:
例如people.txt文件
name,age,weight,height
"Smith, John", 35, 175, "5'10"
"Ford, Anne", 49, 142, "5'4"
"Taylor, Burt", 55, 173, "5'10"
"Zubrin, Candace", 23, 133, "5'6"
我们根据文件的名字创建一个类,然后读取文件的第一行,来添加一些属性,
然后定义一个read的类方法来把数据读出来创建Person对象保存到数组中
2、使用meta-class/singleton-class
我们给当个对象添加了一个方法,而不影响其他的对象,仅仅对这个对象添加了一个
方法所以叫做singleton-class,又叫meta-class:他对这个对象创建了一个虚的class
来存放singleton-method.
我们可能认为singleton-class并不常见,事实上所有的class method都是Class实例
的singleton-methods
使用<<定义singleton-class
我们想给Object创建一个更容易使用的meta-class
使用class-method来重写子类:
当我们想创建DSL来定义类的信息是,最常遇到的困难是如何表现信息来让框架的
其他部分使用,我们看看Rails的一个例子
set_table_name来告诉数据库的名字不是默认的products而是produce
它是怎么工作的呢?我们看看实现的代码:
我们比较关注的是define_attr_method,这里的singleton_class是kernal中的方法
我们首先为这个字段创建了一个别名,然后定义一个访问方法,这样ActiveRecord 需要一个具体类
的table name,他只需要使用这个访问方法即可
3、使用method_missing 来做一些有趣的事情:
除了block,ruby最有威力的特点可能要算method_missing机制了,有些情况下使用它能够极大的简化代码,
但很容易被滥用,写一个对hash的扩展来说明它的威力:
再看看Markaby的一段
body do
h1.header 'Blog'
div.content do
"hellu"
end
end
将会生成
如此优美的代码就是通过 method_missing 来实现的。
4、根据method的pattern来分发消息:
例如一个Unit Test类去调用任何一个以test_开头的测试方法:
5、使用alias,alias_method定义一个别名
在Java中我们常用super来调用父类的操作,然后在做一些自己的操作,来
覆写一些方法,在ruby中可以把一个方法定义别名,然后重写这个方法,
并且在这个方法中可以调用已定义的别名方法,这个别名方法保存了原始的
方法。例如
下面我们用这个技术来实现跟踪函数调用的方法:
6、使用NilClass来实现NullObject模式
Flowlers在重构那本书中提出了NullObject模式,在普通的面向对象语言中它通过子类化
来实现的。在ruby中可以使用NilClass,提供一个更简单的方法:
7、使用blocks创建Procs,并在周围使用他
确实蛮爽,楼主写的真不错啊。
连续两篇都看完了。
这个rails实现了一个alias_method_chain方法,可以很方便的实现aop。不过再折腾无非还是多用几次alias_method
1、Create a object on the fly.
Person = Class.new p1 = Person.new puts p1.class #Person
我们已经凭空创建了一个类Person,现在我们想添加点方法:
好的我们打开这个类:
class Person define_method :who? do puts "Me!" end end p1.who? #Me!
我们发现p1可以使用who?这个方法了。
我们用另一中方法打开这个类,从一个数组读取一个两个字段
的名字,然后往Person里面属性和访问方法:
fields = ["name","age"] Person.class_eval do attr_accessor *fields define_method :initialize do |*values| fields.each_with_index do |name,i| instance_variable_set("@"+name,values[i]); end end end p2 = Person.new("fuliang",25) puts p2.name
我们发现class_eval这个block可以访问局部变量fields,这个block
在定义的时候与当前环境中的变量绑定了
同样我们可以看到define_method block也会和本地的变量绑定:
Counter = Class.new shared_count = 0 Counter.send :define_method, :double_count do shared_count += 1 @count ||= 0 @count += 1 [shared_count,@count] end first_counter = Counter.new second_counter = Counter.new p first_counter.double_count #[1,1] p first_counter.double_count #[2,2] p second_counter.double_count #[3,1] p second_counter.double_count #[4,2]
现在我们想让一个实例mixin一个module,而不影响这个类的其他实例
o = Object.new.extend(Enumerable) puts o.is_a?(Enumerable) #true puts({}.is_a?(Enumerable)) #true puts Object.new.is_a?(Enumerable) #false
给Object添加属性和方法将会影响所有的地方:
class Test o = Object.new Object.send :define_method, :next_for_all do @count_for_all = (@count_for_all || 0) + 1 end puts o.next_for_all #1 puts o.next_for_all #2 puts @count_for_all == nil #true is also the Test member field puts String.next_for_all #1 puts String.next_for_all #2 puts "".next_for_all #1 end
我们希望从文件中读取一些数据来动态的创建一个类以及它的属性和方法:
例如people.txt文件
引用
name,age,weight,height
"Smith, John", 35, 175, "5'10"
"Ford, Anne", 49, 142, "5'4"
"Taylor, Burt", 55, 173, "5'10"
"Zubrin, Candace", 23, 133, "5'6"
我们根据文件的名字创建一个类,然后读取文件的第一行,来添加一些属性,
然后定义一个read的类方法来把数据读出来创建Person对象保存到数组中
class DataRecord def self.make(file_name) #根据文件的数据动态创建类 data = File.new(file_name) header = data.gets.chomp data.close class_name = File.basename(file_name,".txt").capitalize #people.txt -> People klass = Object.const_set(class_name,Class.new) #top-level的常量都是Object的一部分 names = header.split(",") klass.class_eval do #使用class_eval打开类 attr_accessor *names define_method(:initialize) do |*values| #使用define_method来定义initialize方法 names.each_with_index do |name, i| instance_variable_set("@"+name, values[i]); end end define_method(:to_s) do #使用define_method来定义to_s方法。 str = "<#{self.class}:" names.each{|name| str << "#{name}=#{self.send(name)}"} str << ">" end alias_method :inspect, :to_s #定义to_s的一个别名inspect end def klass.read #定义一个读取数据创建对象的类方法 array = [] data = File.new(self.to_s.downcase+".txt") data.gets data.each do |line| line.chomp! values = eval("[#{line}]") array << self.new(*values) #创建对象,添加到数组中 end data.close array end klass end end DataRecord.make("people.txt") list = People.read puts list[0] #<People:name=Smith, Johnage=35weight=175height=5'10>
2、使用meta-class/singleton-class
o,p = Object.new, Object.new def o.say_hi puts "hello!" end o.say_hi #hello! p.say_hi #NoMetodError
我们给当个对象添加了一个方法,而不影响其他的对象,仅仅对这个对象添加了一个
方法所以叫做singleton-class,又叫meta-class:他对这个对象创建了一个虚的class
来存放singleton-method.
我们可能认为singleton-class并不常见,事实上所有的class method都是Class实例
的singleton-methods
class Greeter def greet; 'hello!'; end def self.describe_greeting puts 'Mostly it''s just saying hello to people.' end end def Greeter.say_more puts 'saying hello more' end end p Greeter.singleton_methods.sort #['describe_greeting', 'say_more']
使用<<定义singleton-class
jim = Greeter.new class << jim def greet_enthu self.greet.upcase end end jim.greet_enthu #HELLO!
我们想给Object创建一个更容易使用的meta-class
class ::Object def metaclass class << self; self end end end hash = Hash.new puts hash.metaclass.is_a?(Class) #true puts hash.class != hash.metaclass #true puts( {}.metaclass == {}.metaclass ) #false 对象之间并不共享metaclass puts( {}.metaclass.superclass == Hash.metaclass )#true
使用class-method来重写子类:
当我们想创建DSL来定义类的信息是,最常遇到的困难是如何表现信息来让框架的
其他部分使用,我们看看Rails的一个例子
class Product < ActiveRecord::Base set_table_name 'produce' end
set_table_name来告诉数据库的名字不是默认的products而是produce
它是怎么工作的呢?我们看看实现的代码:
module ActiveRecord class Base def self.set_table_name name define_attr_method :table_name, name end def self.define_attr_method(name, value) singleton_class.send :alias_method, "original_#{name}", name singleton_class.class_eval do define_method(name) do value end end end end end
我们比较关注的是define_attr_method,这里的singleton_class是kernal中的方法
module Kernel def singleton_class class << self; self; end end end
我们首先为这个字段创建了一个别名,然后定义一个访问方法,这样ActiveRecord 需要一个具体类
的table name,他只需要使用这个访问方法即可
3、使用method_missing 来做一些有趣的事情:
除了block,ruby最有威力的特点可能要算method_missing机制了,有些情况下使用它能够极大的简化代码,
但很容易被滥用,写一个对hash的扩展来说明它的威力:
class Hash def method_missing(m,*a) if m.to_s =~ /=$/ self[$`] = a[0] elsif a.empty? self[m] else raise NoMethodError, "#{m}" end end end x = {'abc' => 123} x.abc # => 123 x.foo = :baz #调用method_missing,设置key-value x # => {'abc' => 123, 'foo' => :baz}
再看看Markaby的一段
body do
h1.header 'Blog'
div.content do
"hellu"
end
end
将会生成
<body> <h1 class="header">Blog</h1> <div class="content">Hellu</div> </body>
如此优美的代码就是通过 method_missing 来实现的。
4、根据method的pattern来分发消息:
例如一个Unit Test类去调用任何一个以test_开头的测试方法:
methods.grep /^test_/ do |m| self.send m end
5、使用alias,alias_method定义一个别名
在Java中我们常用super来调用父类的操作,然后在做一些自己的操作,来
覆写一些方法,在ruby中可以把一个方法定义别名,然后重写这个方法,
并且在这个方法中可以调用已定义的别名方法,这个别名方法保存了原始的
方法。例如
class String alias_method :original_reverse, :reverse def reverse puts "reversing, please wait..." original_reverse end end
下面我们用这个技术来实现跟踪函数调用的方法:
class Object def trace(*mths) add_tracing(*mths) yield remove_tracing(*mths) end def singleton_class class << self; self; end end def add_tracing(*mths) mths.each do |m| singleton_class.send :alias_method, "traced_#{m}", m singleton_class.send :define_method, m do |*args| puts "before #{m}(#{args.inspect})" ret = self.send("traced_#{m}",*args) puts "after #{m}-#{ret.inspect}" ret end end end def remove_tracing(*mths) mths.each do |m| singleton_class.send :alias_method, m ,"traced_#{m}" end end end str = "abc" str.trace(:reverse,:upcase){ str.reverse str.upcase }
6、使用NilClass来实现NullObject模式
Flowlers在重构那本书中提出了NullObject模式,在普通的面向对象语言中它通过子类化
来实现的。在ruby中可以使用NilClass,提供一个更简单的方法:
class << nil def name "default name" end def age "default age" end end x = nil puts x.name puts x.age
7、使用blocks创建Procs,并在周围使用他
def create_proc(&p) p end create_proc do puts "hello" end p1 = lambda{puts "hello"; return 1} p2 = Proc.new {puts "hello"} p1.call p2.call
评论
2 楼
orcl_zhang
2010-05-19
fuliang 写道
在上面例子在ActiveRecord::Base中定义set_table_name,最大的威力是在子类调用这个方法的时候,会在父类ActiveRecord::Base动态定义name这个访问方法,这样父类在定义的时候可以通过这个访问方法来做事情。
也就是说父类定义了一些可以被子类调用来动态添加方法的方法,这些方法名都是动态的,可以根据子类调用方法传来的参数来得到方法名,这就是威力之所在。
Rails最让人感到爽的动态的查询:find_by_name,find_by_age,find_by_name_and_age都是通过Method Missing机制来实现的。
也就是说父类定义了一些可以被子类调用来动态添加方法的方法,这些方法名都是动态的,可以根据子类调用方法传来的参数来得到方法名,这就是威力之所在。
Rails最让人感到爽的动态的查询:find_by_name,find_by_age,find_by_name_and_age都是通过Method Missing机制来实现的。
确实蛮爽,楼主写的真不错啊。
连续两篇都看完了。
引用
下面我们用这个技术来实现跟踪函数调用的方法:
这个rails实现了一个alias_method_chain方法,可以很方便的实现aop。不过再折腾无非还是多用几次alias_method
1 楼
fuliang
2009-02-24
在上面例子在ActiveRecord::Base中定义set_table_name,最大的威力是在子类调用这个方法的时候,会在父类ActiveRecord::Base动态定义name这个访问方法,这样父类在定义的时候可以通过这个访问方法来做事情。
也就是说父类定义了一些可以被子类调用来动态添加方法的方法,这些方法名都是动态的,可以根据子类调用方法传来的参数来得到方法名,这就是威力之所在。
Rails最让人感到爽的动态的查询:find_by_name,find_by_age,find_by_name_and_age都是通过Method Missing机制来实现的。
也就是说父类定义了一些可以被子类调用来动态添加方法的方法,这些方法名都是动态的,可以根据子类调用方法传来的参数来得到方法名,这就是威力之所在。
Rails最让人感到爽的动态的查询:find_by_name,find_by_age,find_by_name_and_age都是通过Method Missing机制来实现的。
发表评论
-
松本行弘的程序世界
2011-10-02 16:49 1389全书涉及到程序设计的方方面面,买这边书的目的希望能看到看看Ru ... -
Ruby HTTP/HTML parser相关资源
2011-09-28 12:04 1840Net::HTTP: http://ruby-doc.org ... -
命令行词典
2011-09-27 14:50 2021经常要查单词,所以利用qq dict api写了一个命令行词典 ... -
构建自己的DSL之三 抓取文件管理
2011-07-18 23:26 1744转载请标明出处:http://fuliang.iteye.co ... -
构建自己的DSL之二 抓取文本处理
2011-07-11 23:18 2293转载请标明出处:http://fuliang.iteye.co ... -
构建自己的DSL之一 Simple Crawler
2011-07-11 22:08 3010转载请标明出处:http://fuliang.iteye.co ... -
轻松删除所有安装的gem
2011-06-13 12:28 7978删除安装所有的gem: gem list | cut -d ... -
Ruby发送json请求
2011-05-05 18:37 5852require 'net/http' require ' ... -
写个简单的汉语bigram tokenizer
2011-01-23 23:29 1612写个简单的汉语bigram tokenizer,基本能够满足文 ... -
写段代码看看别人都怎么称呼你网站的?
2011-01-23 20:49 2163步骤很简单: 1)使用google的搜索inlink的语法li ... -
Ruby1.9 lambda操作符
2011-01-09 13:35 1389Ruby1.9提供了lambda操作符,使得lambda表达式 ... -
Ruby 1.9 regex (named capture group)
2011-01-08 22:57 2100Ruby 1.9正则增加了支持命名组,这样使得正则具有更好的可 ... -
Ruby Enumerators
2011-01-02 21:13 2345一个enumerator是一个用来枚举其他对象的Enumera ... -
Ruby Coroutine
2011-01-02 15:51 2743Ruby1.9提供了Fiber,提供了Coroutine的功能 ... -
Ruby Proc curry化
2011-01-01 23:11 1646Ruby 1.9 Proc增加了curry方法,可以将Proc ... -
Lazy evaluation in Ruby
2011-01-01 21:49 12271.使用||延迟初始化 def fib(n) ... -
One line Ruby code
2010-12-31 23:03 1223经常使用perl来代替一行的sed awk,主要是想使用per ... -
函数对象作为case语句中的条件
2010-12-31 22:28 1116Ruby 1.9的Proc#===作为call的一个别名,所以 ... -
从hash快速生成URL参数
2010-12-31 21:03 1956key_values = { :key1 => ... -
生成长度为n的随机字符串
2010-12-31 20:50 1646包含数字和小写字母的随机串 def gen_random_ ...
相关推荐
src-oepkgs/ruby-ruby2rubysrc-oepkgs/ruby-ruby2rubysrc-oepkgs/ruby-ruby2rubysrc-oepkgs/ruby-ruby2rubysrc-oepkgs/ruby-ruby2rubysrc-oepkgs/ruby-ruby2rubysrc-oepkgs/ruby-ruby2rubysrc-oepkgs/ruby-ruby2...
官方离线安装包,测试可用。使用rpm -ivh [rpm完整包名] 进行安装
ruby安装包-rubyinstaller-devkit-3.0.2-1-x64安装文件 Ruby是一种面向对象、动态类型的脚本语言,由Yukihiro "Matz" Matsumoto于1995年创建。它以其简洁、优雅的语法和强大的编程能力而闻名,广泛应用于Web开发、...
ruby-1.8.7-p358-doc-chm.7z 3.65 MB 1,399 Other Other ruby-1.8.7-p358-i386-mingw32.7z 5.12 MB 1,503 i386 Other rubyinstaller-1.8.7-p358.exe 11.69 MB 13,534 i386 .exe (Windows executable)
Ruby+Selenium-Webdriver是一个强大的自动化测试工具组合,用于模拟真实用户在浏览器中与网页进行交互。Ruby是一种动态、面向对象的编程语言,而Selenium WebDriver是一个开源的自动化测试框架,支持多种浏览器和...
ruby-debug-base19-0.11.26.gem
Ruby是一种面向对象、动态类型的脚本语言,由Yukihiro "Matz" Matsumoto于1995年创建。它以其简洁、优雅的语法和强大的编程能力而闻名,广泛应用于Web开发、脚本自动化、服务器管理等领域。RubyInstaller是Windows...
ruby-oci8-2.1.5-x86-mingw32.gem,ruby连接oracle数据库gem包
Ruby-Functional-Programming, 来自 Conferencia Rails 2011 通过 Arnau Sanchez实现的ruby 函數式程式設計簡介理論部分Ruby的函數式程式設計不要更新變數不要重用變量用阻止作為高階函數物件導向與函數式程式設計萬...
《Programming Ruby 1.9》是一本经典的Ruby编程语言教程,其源代码包含了大量实例和示例,旨在帮助读者深入理解Ruby的语法、特性以及编程实践。这些源代码是学习和探索Ruby语言的重要资源,涵盖了从基础语法到高级...
在本压缩包“ruby-1.9.1-p0-i386-mswin32.rar”中,包含的是针对i386架构的Windows 32位系统的Ruby安装程序。这个版本(p0)意味着它是1.9.1主版本下的一个特定补丁级别,通常包括了一些错误修复和优化。 Ruby的...
标题中的"ruby笔记1ruby笔记1ruby笔记1"暗示了这是一份关于Ruby编程语言的学习笔记,可能包含了作者在学习过程中的重点、难点以及心得体验。描述中的内容重复了标题,进一步强调了这是关于Ruby的深入学习记录。标签...
ruby-debug-ide19-0.4.12.gem
"ruby-1.9.2-preview1-x64-mswin64-80.zip" 是一个针对Windows平台的64位版本的Ruby 1.9.2预览版1的压缩包。这个版本在当时是一个重要的更新,因为它引入了许多改进和新特性。 1. **Ruby 1.9.2**: Ruby 1.9是Ruby...
官方离线安装包,亲测可用。使用rpm -ivh [rpm完整包名] 进行安装
《Programming Ruby》是一本关于Ruby编程语言的经典书籍,它的第三章深入探讨了Ruby的基本语法和核心概念。在这一章中,作者介绍了变量、常量、符号、数组、哈希等核心数据类型,以及控制流(条件语句和循环)和方法...
ruby安装包-rubyinstaller-devkit-3.0.2-1-x64安装包 Ruby是一种面向对象、动态类型的脚本语言,由Yukihiro "Matz" Matsumoto于1995年创建。它以其简洁、优雅的语法和强大的编程能力而闻名,广泛应用于Web开发、脚本...
ruby-oci8-1.0.3-x86-mswin32.gem
"ruby-1.9.1-p0-i386-mswin32.zip" 是一个针对Windows操作系统编译的Ruby编程环境的压缩包,发布于2009年6月20日,当时是Ruby 1.9.1版本的最新版。 Ruby 1.9.1是一个重要的版本更新,引入了许多改进和新特性,包括...
7. **meta-ruby**: 为 Ruby 开发者提供所需的环境。 8. **meta-openwrt**: 提供 OpenWRT 相关的软件包和配置。 **镜像(mirror)与 BitBake** 在描述中提到了 "mirror BitBake",这可能是指使用镜像站点来加速 ...