当前位置: 首页 > 图文教程 > 网络编程 > ASP.NET > .NET程序员新方向 Ruby核心语法入门

ASP.NET
不同映射模式下的直线输出的效果问题
ASP.NET开发下的MVC设计模式的实现
ASP.NET编写应用程序的十大技巧
ASP.NET中使用AJAX的简单方法
ASP.NET MVC实现自己的视图引擎
认识asp.net会话状态
ASP.NET实现页面传值的几种方法
.NET中容易混淆的几组重要概念
详解.NET中的动态编译技术
如何使用ASP.Net加密Cookie
ASP.NET 2.0跨网页提交的三种方法
ASP.NET 2.0创建母版页引来的麻烦
.Net整合其他平台的一些探讨
ASP.NET编程经验技巧10则
最佳实践 ADO.NET实用经验无保留曝光
在.NET上执行多线程操作要考虑的两大因素
.Net开发 细说Visual Basic.Net
ASP.NET网络编程中经常用到的27个函数集
ASP.NET防止用户多次登录的方法
对ASP.NET MVC项目中的视图做单元测试

ASP.NET 中的 .NET程序员新方向 Ruby核心语法入门


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-09-23   浏览: 218 ::
收藏到网摘: n/a

本文的目的是为了找出为什么.NET程序员都想学习并使用Ruby,并探索Ruby语言的核心语法。

微软的IronRuby项目为Windows平台带来了强大的动态语言,Ruby编程语言是一个现代的,面向对象的基本语言,它的语法灵感来自Perl和Smalltalk语言,它是由一名日本人松本行弘(外号Matz)发明的,用他的话说,他是想发明一种语言比Perl更强大,同时比Python更面向对象的编程语言,在“http://www.linuxdevcenter.com/pub/a/linux/2001/11/29/ruby.html”有一篇对松本行弘专访文章,大家可以去看看。于是Ruby被设计为非常贴近自然语言,作者的原意就是要减少编程时候的不必要的琐碎时间,令编写程序的人高兴,他于1996年发布了1.0版本。

这么多年来,Ruby一直鲜为人知,但它的功能已经远远超出了最初设计时的想法:以最简化的方法操作数据和环境。我第一次“玩”它还是在几年前,那时我正在寻找一种替换处理自动管理任务的批处理文件的方法。

Ruby真正开始流行还得从一个来自伊利诺斯洲芝加哥市的名叫37signals小公司说起,它们发布了一个名叫Rails的Web应用程序框架,这个新的框架吸取了已经被证明是可靠的Model-View-Controller和ActiveRecord模型的经验,并且添加了一些新的思想,如convention over configuration,导致它实现了太多的目标,几乎不需要编码了。

RubyCLR和IronRuby

在2006年早些时候,John Lam发布了一个开源项目,叫做RubyCLR,它在Ruby和.NET之间起到一个桥梁的作用,它允许用户可以直接从Ruby访问.NET平台丰富的资源,甚至将Ruby对象都暴露给CLR了,这个项目非常有雄心,但它没有打算将Ruby向.NET靠拢,而是打算让这两个世界相互对话,你仍然需要在你的机器上按照Ruby运行时环境。

RubyCLR项目为人们理解如何将Ruby和.NET和谐地溶合到一起迈出了关键的第一步,John的工作没有引起人们的注意,2006年末,他在他的博客上宣布加入微软新成立的动态语言运行时环境(DLR)团队,在John宣布前几个月,微软发布了IronPython的1.0版本,它是Python语言在.NET框架上一个新的实现,动态语言运行时环境在IronPython上工作,它在.NET框架构建了一个运行环境,允许动态语言进入.NET。

John和他的团队在2007年的MIX大会上宣布了IronRuby,可能真正让人吃惊的是IronRuby项目本身是微软的第一个真正意义上的开源.NET语言,不仅可以得到源代码,而且还可以获取来自社区的贡献。

IronRuby仍然处于发展阶段,然而偶然也会删掉已经可以利用的东西,这些东西通常是其它项目的一部分,如最近发布的Silverlight 2.0 Beta 2,这些后续的项目也放在源代码树中了,并且也有相应的邮件列表。

为什么要学习Ruby?

我最喜欢的一本书叫做《程序员实务:从熟练工到大师》【英文名是《The Pragmatic Programmer: From Journeyman to Master》】,该书的作者鼓励程序员每年学习一门新的编程语言,对于我而言,当我学习了Ruby语言后,大大地改变了我的专业范围。

Ruby是一门完全面向对象的语言,这意味着在系统中每一样打交道的东西都是对象,包括直接的值,如数字,即使是类,也是由新创建的对象实例组成的模板。

因为Ruby是一个动态语言,你会发现类型已经变得不太重要了,当一个类函数以参数形式获取到一个对象时,不需要指定对象需要的类型。实际上,Ruby没有编译器,因此,可能直到传递给类函数的对象不满足方法的需要时,你才会发现这一点。

如果你象我几年前那样,你也许会发现这个概念让你不安,如果没有编译器,那么你可能要尽可能最快地在运行前就了解代码中的错误,而不用等到运行时才知道。如果你还是习惯于让编译器告诉你错误,那你就不用选择Ruby了。
正是由于以前编译器能够报告错误,如类型不匹配,当你编写一个类函数时,你可能希望“这里的对象必须能够做到foo和bar”,然后创建一个接口叫做IFooBar,看起来这是一个不错的解决方案,但当你想使用其它的在IfooBar之前创建的类时(特别是那些来自框架的类型),你就会失败了。

作者提醒:IronRuby还没有成为主流的工具,你可以使用Ruby的标准版本进行学习,如果你想实验后面的例子,可以从http://rubyinstaller.rubyforge.org/下载。

Ruby示例

学习Ruby或一门新的编程语言最好的方法就是多练习,研究它的交互接口,大多数动态语言都有交互提示符,称之为读-执行-打印环(即REPL,Read-Execute-Print Loop),Ruby中的REPL程序叫做irb(即交互式Ruby,interactive Ruby)。

当你执行irb程序时,你会看到一个irb提示符,如:

C:\Users\Brad> irb
irb(main):001:0>
 

当你在irb提示符后敲入命令时,Ruby解释程序就会评估它们,并将结果输出到你屏幕上,与irb类似的REPL是学习一门语言的优秀方法:每次一条语句。

下面对irb做一个简单的介绍,在irb提示符后,敲入5+2,并回车,告诉Ruby计算这个表达式的值:

irb(main):001:0> 5 + 2
=> 7
 

irb(main):001:0>部分是irb的提示符,当你敲入5+2并回车时,irb就将结果输出到屏幕上,如这里的=> 7,=> 是irb显示输出结果时使用的提示符。

如果Ruby认为你还没有完成表达式的书写,它允许你继续换行书写,如当你敲入5+2+时就按了回车,Ruby认为你还有一部分没有输入完毕,它会继续让你在下一行输入,如:

irb(main):002:0> 5 + 2 +
irb(main):003:0* 13
=> 20
 

第二行的提示符变为星号(*)了,而不是“>”,这样你就知道你在完成前面没有完成的表达式。

基础类型

如果一门编程语言不能处理数字,那就不值得学习和使用,Ruby当然能够满足算术运算了,如:

irb(main):004:0> 3 + 4
   => 7
   irb(main):005:0> 3 * 4
   => 12
   irb(main):006:0> 3 - 4
   => -1
   irb(main):007:0> 3 / 4
   => 0
   irb(main):008:0> 3.0 / 4.0
   => 0.75
   irb(main):009:0> 0xF
   => 15
   irb(main):010:0> 0x3 * 0xA
   => 30
 
正如你所看到的,Ruby支持整数和浮点类型,甚至可以接收常用的十六进制整数,但0x3 * 0xA的结果是以十进制的形式显示的,即显示结果是30而不是0x1E。

因为在.NET中,数字也是真实的对象,因此,你可以在它们上面调用类函数,如:

irb(main):011:0> 14.to_s
   => "14"

在c++中不要这样做。

to_s类函数的功能是将一个对象转换成一个字符串,因此,14.to_s返回的结果是"14",和.NET中的to_string()函数一样,to_s函数实际上是一个对象函数,因此,在Ruby中你可以将任何东西转换成字符串。

字符串

Ruby的字符串具备完整的操作支持,如:

irb(main):012:0> "hello" + "there"
  => "hellothere"
   irb(main):013:0> "Reader".length
   => 6
   irb(main):014:0> "Reader".reverse
   => "redaeR"
   irb(main):015:0> "reader".capitalize
   => "Reader"
   irb(main):016:0> "Reader".include?("foo")
   => false
   irb(main):017:0> "Reader".include?("ade")
   => true
   irb(main):018:0> "  Reader  ".strip
   => "Reader"
   irb(main):019:0> "Reader".gsub("e", "f")
   => "Rfadfr"
   irb(main):020:0> "Reader".delete("ea")
   => "Rdr"
   irb(main):021:0> "a" < "b"
   => true
 
几乎可以使用所有的字符串操作符,可能有的你还从来都没有使用过,如下面的代码按字母顺序测试某个字符串是否位于其他两个之间:

irb(main):022:0> "Bob".between? "Adam", "Chris"
   => true
 
乘法操作符可以让给定的字符串重复显示指定的数量,如:

irb(main):023:0> "hi" * 5
   => "hihihihihi"
 
Crypt函数为字符串提供了一个单向哈希加密功能,在存储敏感数据如密码时就可以使用它,如:

irb(main):024:0> "Reader".crypt("ab")
   => "abofgDjq6JNJo"
 
字符

Ruby没有内置的字符类型,它象数字一样表现字符,可以是?语法来表示一个字符常量,你可以使用chr函数将一个数字转换成一个等价的字符串,如:

irb(main):025:0> "Reader"[2]
   => 97
   irb(main):026:0> ?a
   => 97
   irb(main):027:0> 97.chr
   => "a"
 
赋值

其实执行这个操作并没什么用途,除非你可以将其存储起来方便后面使用,如:

irb(main):028:0>x = 42
   =>42
 
字符串有一个特殊的语法,允许嵌入式赋值,这个赋值不仅仅局限于简单的变量替换,它是一个完整的赋值,如:

irb(main):029:0> "The answer is #{x}!"
   => "The answer is 42!"
   irb(main):030:0> "The answer is #{6 * 7}!"
   => "The answer is 42!"
 
可以使用单引号将字符串引起来避免这种赋值,注意是单引号,不是双引号,如:

irb(main):031:0> 'The answer is #{x}!'
   => "The answer is \#{x}!"

数组

Ruby中的数组与.NET 1.0中的ArrayList类很接近,它们的大小都是可变的,用于存储任意类型的数据,从0开始编号,如:

irb(main):032:0> a = ["hello", 42, "world"]
   => ["hello", 42, "world"]
   irb(main):033:0> a << 5.0 * 7.5
   => ["hello", 42, "world", 37.5]
   irb(main):034:0> a[0]
   => "hello"
   irb(main):035:0> a[6] = 'hi' * 2
   => "hihi"
   irb(main):036:0> a
   => ["hello", 42, "world", 37.5, nil, nil, "hihi"]
   irb(main):037:0> a[99]
   => nil
 
前面的代码显示了如何使用<<操作符向数组末尾追加项目,以及获取或设置值使用的指针操作符[],当你向数组末尾添加一个项目时,Ruby使用零值填充数组中的“洞”,当你访问数组外的值时,Ruby返回零值而不是异常。

你可以使用一个范围的指针将数组分片,也可以使用负的指针从后向前访问数组,-1就是最后一项,-2是倒数第二项,以此类推,但不能使用反向范围获取反向分片,你可以使用一个正向范围,然后调用reverse方法,如:

irb(main):038:0> a[-1]
   => "hihi"
   irb(main):039:0> a[1..3]
 =>[42, "world", 37.5]
   irb(main):040:0>a[2..-2]
   =>["world", 37.5, nil, nil]
   irb(main):041:0>a[-4..-1]
   =>[37.5, nil, nil, "hihi"]
   irb(main):042:0>a[-1..-4]          # 不能工作
   =>[]
   irb(main):043:0>a[-4..-1].reverse  # 能够工作
   =>["hihi", nil, nil, 37.5]
 
和字符串一样,你会发现有多个唯一对数组有用的类函数,如:

irb(main):044:0> a
   => ["hello", 42, "world", 37.5, nil, nil, "hihi"]
   irb(main):045:0> a.compact
   => ["hello", 42, "world", 37.5, "hihi"]
   irb(main):046:0> a.join
   => "hello42world37.5hihi"
   irb(main):047:0> [10, 75, 6, 29].sort
   => [6, 10, 29, 75]
   irb(main):048:0> [[1, 2, 3], [4, 5, 6]]
   => [[1, 2, 3], [4, 5, 6]]
   irb(main):049:0> [[1, 2, 3], [4, 5, 6]].flatten
   => [1, 2, 3, 4, 5, 6]
 
散列

Ruby的最后一个核心数据结构是散列,与.NET 1.0中的散列表类似,它是一个联合数组,它的键值可以是任意类型的值,它们指向的数据也可以是任意类型的数据,实际上,大部分散列使用的是符号作为键值。

使用{}语法声明散列,并且使用key => value格式声明初始值,在散列中获取或设置值时都可以使用键值操作符,如:

irb(main):050:0> h = {:foo=>'bar', :baz=>'biff'}
   => {:foo=>"bar", :baz=>"biff"}
   irb(main):051:0> h[:foo]
   => "bar"
   irb(main):052:0> h[:unknown]
   => nil
   irb(main):053:0> h[:baz] = "new"
   => "new"
   => {:foo=>"bar", :baz=>"new"}
   irb(main):054:0> h.entries
   => [[:foo, "bar"], [:baz, "new"]]
 
变量

Ruby中的变量和类函数名都是以小写字母开头的,可以包括字母、数字和下划线。本地变量没有前缀,实例变量以@开头,全局变量以$开头。
在使用变量前无需声明,未初始化的变量有一个零值,下面是几个预定义的变量:

nil表示一个“无”对象,与.NET中的null类似,除了nil是一个实例化的NilClass类外。

true和false分别是实例化的TrueClass和FalseClass。

在类函数中使用时,self指向调用类函数的对象实例;在一个类中使用时,它指的是实例化的类对象本身。

__FILE__ 和__LINE__返回当前执行文件和那个文件中的行号。

符号

Ruby有一个特殊类型的字符串,叫做符号,因为字符串在Ruby中是可以被修改的,使用它们作为散列键是很慢的,而且有一些情况是不能预测的。
除了它们是以冒号(:)开头外,符号的命名规则和变量的命名规则一致,你不能改变符号的值,两个名字相同的符号它们的身份就一样,它们可以作为优秀的散列键,查找请求只需要比较整数值,而不是与一个可变长字符串的值进行对比。

Ruby中的所有事物都是对象,所有对象都是类的实例,为了探索类是个什么东西,在它上面调用类函数:

5.class
   => Fixnum
   (2 ** 96).class
   => Bignum
   7.5.class
   => Float
   (1..10).class
   => Range
   "foo".class
   => String
   /^foo[a-e]$/.class
   => Regexp
   :foo.class
   => Symbol
   [].class
   => Array
   {}.class
   => Hash
 
块和闭包

虽然这与.NET 1.X中的事件处理程序类似,但当你想处理它们时还是必须要定义完整的类函数来连接这些事件,这就导致需要创建大量的类函数,因为框架需要它。

.NET 2.0引入了匿名委派的概念,它们起的作用与Ruby中的块类似,如:

irb(main):001:0> h = {:foo=>'bar', :hi=>'there'}
   => {:foo=>"bar", :hi=>"there"}
   irb(main):002:0> h.each_key {|k| puts k}
   foo
   hi
   => {:foo=>"bar", :hi=>"there"}
   irb(main):003:0> h.each {|k,v| puts "#{k}: #{v}"}
   foo: bar
   hi: there
   => {:foo=>"bar", :hi=>"there"}
 
正如你所看到的,Ruby中块的语法是相当简洁的:通常使用一对大括号打开块和关闭块,使用|x,y|语法标出传递给块的变量。

Ruby中的块和闭包类似,正如.NET 2.0中的匿名委派,这意味着它们有权访问它们封装作用域的值,即使那个作用域退出后也可以访问。下面是一个将几个值相乘的闭包示例:

irb(main):004:0> n = [5, 6, 10]
   => [5, 6, 10]
   irb(main):005:0> t = 1
   => 1
   irb(main):006:0> n.each { |i| t *= i }
   => [5, 6, 10]
   irb(main):007:0> t
   => 300
 
你甚至可以将引用存储在块中,方便以后使用,如:

irb(main):008:0> t = 1
   => 1
   irb(main):009:0> f = lambda { |i| t *= i }
   => # 函数Ruby中函数的定义比.NET简单多了,因为不需要指定类型,如:

irb(main):001:0> def greet(name)
   irb(main):002:1>   puts "Hello, #{name}!"
   irb(main):003:1> end
   => nil
   irb(main):004:0> greet "Reader"
   Hello, Reader!
   => nil
   irb(main):005:0> greet 42
   Hello, 42!
   => nil

Ruby执行的某些东西叫做“鸭式输入”:如果它走起路来像鸭子或声音也像鸭子,那它一定就是鸭子。你不用问它“你是一只鸭子吗?”,你只需要将它当做鸭子对它呷呷地叫就可以了,如果你渴望成为一只鸭子,只要你能呷呷地叫的就可以加入这个party。

注意greet函数定义时没有对对象的类型做任何限制,因为它只打印它们—Ruby中任何事物都是支持打印的,这得益于to_s类函数的优点,它可以将任何对象转换成字符串,最终结果就是你可以greet它们。

下面是另一个例子:

irb(main):006:0> def print_len(item)
   irb(main):007:1>   puts "Len = #{item.length}"
   irb(main):008:1> end
   => nil
   irb(main):009:0> print_len "Reader"
   Len = 6
   => nil
   irb(main):010:0> print_len [1, 4, 9]
   Len = 3
   => nil
   irb(main):011:0> print_len 42
   NoMethodError: undefined method <span class="pf">'</span>length' for
   42:Fixnum
           from (irb):7:in <span class="pf">'</span>print_len'
           from (irb):11

这里的print_len函数做的事情更多了:它调用了length函数。因此传递给print_len的是length函数的返回值,可以传递一个字符串或一个数组,因为它们都有对应的length函数,但是不能传递一个数字,因为没有对应数字的length函数。

为了在.NET中编写一个类似的函数,你可能需要创建一个IHaveLength接口作为你的参数类型,由于在你创建接口前类就已经创建好了,所以不幸的是,可能你需要创建一个类型转换器。

从另一方面来看,至少你已经有了IHaveLength,并且知道函数需要什么东西,既然类型担当的是某种格式文档的角色,在动态语言中你需要一个取舍,这样你会在编写文档和单元测试时更自信,可以帮助你识别类或函数是如何使用的。

Ruby支持默认的参数值,如:

irb(main):012:0>def repeat(val, times = 5)
   irb(main):013:1>val.to_s * times
   irb(main):014:1>end
   =>nil
   irb(main):015:0>repeat "hi"
   =>"hihihihihi"
   irb(main):016:0>repeat "hi", 3
   =>"hihihi"
   irb(main):017:0>repeat 10, 3
   =>"101010"
 
注意在to_s * times前面没有return,除非你明确地告诉它返回什么值,否则Ruby中的函数总是返回最后一个赋值,因此就不需要return关键字了。

Ruby支持变量参数,如:

irb(main):018:0> def add(*values)
   irb(main):019:1>   result = 0
   irb(main):020:1>   values.each {|x| result += x}
   irb(main):021:1>   result
   irb(main):022:1> end
   => nil
   irb(main):023:0> add 1, 2, 3, 4, 5
   => 15
 
Ruby将变量参数打包成一个数组,然后你就可以访问传递来的值,并且可以将它们集合到一块儿。

函数和变量命名约定

Ruby中的函数以小写字母开头,可以包含字母,数字和下划线。改变基础对象的函数名称以一个惊叹号(!)结束,例如:upcase函数返回字符串的大写,但是还单独保留了原始字符串;相反,upcase!函数就真实地改变了基础字符串。
回答问题(返回布尔值)的函数名称以一个问号(?)结束。

类是来自新对象实例创建时的模板,例如:为了将前面的greet函数放入一个类,你可能要编写以下代码:

irb(main):001:0> class Manners
   irb(main):002:1>   def greet(name)
   irb(main):003:2>     puts "Hello, #{name}!"
   irb(main):004:2>   end
   irb(main):005:1> end
   => nil
   irb(main):006:0> m = Manners.new
   => # 前面的代码创建了一个新的类,叫做Manners,并将函数greet添加到该类中了,最后,它创建了一个Manners类的实例,使用它greet Reader。

你可能认为在Ruby中类是对象的活动模板,与.NET中的类不同,Ruby中的类是编译时定义的,你可以对其进行任意扩展,当你完成扩展后,类的现有实例也会立即得到新的反应,注意当你尝试告诉它farewell时会发生什么,如:

irb(main):008:0> m.farewell "Reader"
   NoMethodError: undefined method 'farewell' for
   #<Manners:0x404839c>
           from (irb):8
 
当你尝试调用farewell时,系统会告诉你它不知道这是什么,那么就可以对Manners类进行扩展,让它知道这么说拜拜,如:

irb(main):009:0>class Manners
   irb(main):010:1>def farewell(name)
   irb(main):011:2>puts "Goodbye, #{name}!"
   irb(main):012:2>end
   irb(main):013:1>end
   =>nil
   irb(main):014:0>m.farewell "Reader"
   Goodbye, Reader!
   =>nil
 
扩展了Manners类后,它的已有实例就会立即获得这个新的功能。

Manners类有两个函数,两个都需要你的名字,你可能需要重新编写它以便你创建它时可以传递名字给它,Ruby调用initialize函数,你传递的所有参数都传递给new,下面是更新后的Manners类:

irb(main):001:0> class Manners
   irb(main):002:1>   def initialize(name)
   irb(main):003:2>     @name = name
   irb(main):004:2>   end
   irb(main):005:1>   def greet
   irb(main):006:2>     puts "Hello, #{@name}!"
   irb(main):007:2>   end
   irb(main):008:1>   def farewell
   irb(main):009:2>     puts "Goodbye, #{@name}!"
   irb(main):010:2>   end
   irb(main):011:1> end
   => nil
   irb(main):012:0> m = Manners.new "Reader"
   => #

注意类在一个实例变量@name中存储的名字,同时注意检查实例包括所有实例变量的值。

你自己定义的类可以随意扩展,而且也可以扩展Ruby内置的类,如:

irb(main):001:0> class Array
   irb(main):002:1>   def print_tr
   irb(main):003:2>     puts "<tr>"
   irb(main):004:2>     each { |item|
   irb(main):005:3*       puts "  <td>#{item}</td>"
   irb(main):006:3>     }
   irb(main):007:2>     puts "</tr>"
   irb(main):008:2>   end
   irb(main):009:1> end
   => nil
   Irb(main):010:0> ["hello","world!"].print_tr
   <tr>
     <td>hello</td>
     <td>world!</td>
   </tr>
   => nil
 
Rails对内置类型添加了许多扩展属性,提供了非常丰富的接口,例如:你可以编写类似5.days.from_now这样的代码,返回从现在开始5天后的日期。

迄今为止,你定义的函数都已经成为实例函数,即它们仅在类的实例中有效。Ruby也有静态函数,有时也叫做类函数。实际上,你已经调用过一次静态函数了,那就是new。

你可以在现有的类上添加任何新的静态函数,如:

irb(main):001:0> def String.concat(s1, s2)
   irb(main):002:1>   s1 + ' ' + s2
   irb(main):003:1> end
   => nil
   irb(main):004:0> String.concat 'hi', 'bye'
   => "hi bye"
 
你也可以使用self语法在定义或扩展类的上下文中定义它们,如:

irb(main):001:0> class String
   irb(main):002:1>   def self.concat(s1, s2)
   irb(main):003:2>     s1 + ' ' + s2
   irb(main):004:2>   end
   irb(main):005:1> end
   => nil
   irb(main):006:0> String.concat 'hi', 'bye'
   => "hi bye"
 
反射

反射是运行时发现关于对象的信息的过程,你可以通过调用methods函数找到某个类可用的函数,Ruby中的基础类也是对象,下面是查找在Ruby中对每个对象都有效的函数的代码:

irb(main):001:0> o = Object.new
   => #<Object:0x3f8feb4>
   irb(main):002:0> o.methods
   => ["inspect", "taguri", "clone", "public_methods"
   , "taguri=", "display", "instance_variable_defined
   ?", "equal?", "freeze", "methods", "respond_to?",
   ...many more methods listed...
 
调用methods函数返回的结果是一个字符串数组,包含了那个对象上有效的每个函数的名字,你也可以认为类与散列非常相似,调用methods函数就与获取散列表的键值相似。

你若不使用函数做点事情,你会觉得它很无趣,为了调用函数,你还可以使用send函数,如下面这两条语句都是等效的:

irb(main):003:0> o.inspect
   => "#<Object:0x3f8feb4>"
   irb(main):004:0> o.send "inspect"
   => "#<Object:0x3f8feb4>"
 
通过在你的类中定义method_missing函数,Ruby让你有机会处理未知的函数,如:

irb(main):139:0> class Object
   irb(main):140:1>   def method_missing(*args)
   irb(main):142:2>     puts args
   irb(main):143:2>   end
   irb(main):144:1> end
   => nil
   irb(main):145:0> o.foobar 1, 2, 3
   foobar
   1
   2
   3
   => nil
 
正如你所看到的,传递给method_missing函数的参数包括请求的函数和所有传递给那个函数的参数,一个更好的定义如下:

def method_missing(method, *args)

元编程

即使Ruby没有属性,你也可以使用函数调用,通常不需要括弧来模拟属性,你也需要影响Ruby以“=”结束函数的特殊处理方式,让它们担当调节器的作用。

你可以象下面这样定义一个person类:

irb(main):001:0> class Person
   irb(main):002:1>   def age
   irb(main):003:2>     @age
   irb(main):004:2>   end
   irb(main):005:1>   def age=(value)
   irb(main):006:2>     @age = value
   irb(main):007:2>   end
   irb(main):008:1> end
   => nil
 
接下来就可以使用person类的实例,将age当作person类的一个属性来处理,如:

irb(main):009:0>p = Person.new
   =># 如果你想将age的默认值设为一个非零的值,那么你可以使用initialize函数来设置。

这个代码显得非常标准,如果这是一个类似c#的语言,你可能会使用类似Visual Studio中片段,甚至静态代码的产生会自动生成reader和writer的属性。
在Ruby中,你可以使用元编程做一点努力就可以创建这些事物,理想情况下,你可以编写类似下面这样的代码:

class Person
     prop :age
   end

你应该在对象上定义个类(静态)函数以便你在定义自己的类时可以使用它,你也可以使用一个你还没有看到过的函数,class_eval函数,如:

irb(main):001:0> class Object
   irb(main):002:1>   def self.prop *names
   irb(main):003:2>     names.each { |name|
   irb(main):004:3*       self.class_eval "
   irb(main):005:3"         def #{name}
   irb(main):006:3"           @#{name}
   irb(main):007:3"         end"
   irb(main):008:3>       self.class_eval "
   irb(main):009:3"         def #{name}=(value)
   irb(main):010:3"           @#{name} = value
   irb(main):011:3"         end"
   irb(main):012:3>     }
   irb(main):013:2>     nil
   irb(main):014:2>   end
   irb(main):015:1> end
   => nil
 
上面使用的class_eval函数是创建了另外一个函数结束的,它给字符串赋值,因此你可以在你的类中编写自己的函数。

每个传递给prop函数的名字向新类添加了两个函数:getter和setter。最终使用你传递给prop的名字替换掉#{name}。

接下来,你可以在你的类定义中使用prop了,如:

irb(main):016:0> class Person
   irb(main):017:1>   prop :age, :name
   irb(main):018:1>
   irb(main):019:1*   def initialize(age, name)
   irb(main):020:2>     @age = age
   irb(main):021:2>     @name = name
   irb(main):022:2>   end
   irb(main):023:1> end
   => nil
   irb(main):024:0> p = Person.new(36, "Brad")
   => # 在你的环境中有了这些便利的工具后,你可以更快速地创建更高层次的类,使用这些元编程技巧可以帮助你工作得更好,不需要依赖于编辑片段或编译时代码生成。

小结

本文只是对Ruby中便利工具做了一个皮毛介绍,今天学习好Ruby可以在当Ruby.在.NET和Silverlight中可用时帮助你,有这么强大的一个动态编程语言,你的编程工具箱也会扩宽许多,但更重要的是,它可以帮助你开始以一种新的方式思考问题和解决方案。