如何設計出漂亮的 Ruby APIs

Python014

如何設計出漂亮的 Ruby APIs,第1张

1.Argument Processing

Ruby 使用了 Symbols 和 Hash 来达到虚拟关键字参数(Pseudo-Keyword Arguments)。这种技巧被广泛应用在 Ruby 的函式库和 Rails 中,增加了阅读性,也很容易使用。

def blah(options)

puts options[:foo]

puts options[:bar]

end

blah(:foo =>"test", :bar =>"test")

Ruby 也可以将参数列当成阵列使用:

def sum(*args)

puts args[0]

puts args[1]

puts args[2]

puts args[3]

end

sum(1,2,3)

如此就可以设计出不固定参数列、十分弹性的 API。类似於 C++ 的 function overloading。在 Rails 中也十分常见这样的 API 设计,例如 link_to 就支援了两种用法:

# USAGE-1 without block

<% link_to 'Posts list', posts_path, :class =>'posts' %>

# USAGE-2 with block

<% link_to posts_path, :class =>'posts' do %>

Posts list

<% end %>

搭配虚拟关键字参数使用的话,可以参考 ActiveSupport#extract_options! 这个小技巧取出 Hash 值。

2. Code Blocks

程式区块(Block)是 Ruby 最重要的特色,除了拿来做迭代(Iteration)之外,也可以包装前後置处理(pre- and Post-processing),一个最基本的例子就是开档了,一般程序式的写法如下:

f = File.open("myfile.txt", 'w')

f.write("Lorem ipsum dolor sit amet")

f.write("Lorem ipsum dolor sit amet")

f.close

使用 Block 之後,我们可以将 f.close 包装起来,不需要明确呼叫。只要程式区块结束,Ruby 就会自动关档。程式一来因为缩排变得有结构,二来也确定档案一定会关闭(不然就语法错误了)

# using block

File.open("myfile.txt", 'w') do |f|

f.write("Lorem ipsum dolor sit amet")

f.write("Lorem ipsum dolor sit amet")

end

另一个程式区块的技法,是用来当做回呼(Dynamic Callbacks)。在 Ruby 中,程式区块也是物件,於是我们可以将程式区块如透过”注册”的方式先储存下来,之後再依照需求找出来执行。例如在 Sinatra 程式中:

get '/posts' do

#.. show something ..

end

post '/posts' do

#.. create something ..

end

我们”注册”了两个回呼:一是当浏览器送出 GET ‘/posts’ 时,会执行 show something 的程式区块,二是 POST ‘/posts’ 时。

3. Module

模组(Module)是 Ruby 用来解决多重继承问题的设计。其中有一招 Dual interface 值得一提:

module Logger

extend self

def log(message)

$stdout.puts "#{message} at #{Time.now}"

end

end

Logger.log("test") # as Logger’s class method

class MyClass

include Logger

end

MyClass.new.log("test") # as MyClass’s instance method

Ruby 的 extend 作用是将模组混入(mix-in)进单件类别(singleton class),於是 log 这个方法除了可以像一般的模组被混入 MyClass 中使用,也可以直接用 Logger.log 呼叫。

要将 Ruby 模组的混入成类别方法(class method),也有一些常见的 pattern 模式,可以将模组设计可以同时混入实例方法(instance method)和类别方法,请参阅投影片范例。这在撰写 Rails plugin 时非常常用。

4. method_missing?

Ruby 的 Missing 方法是当你呼叫一个不存在的方法时,Ruby 仍然有办法处理。它会改呼叫 method_missing 这个方法,并把这个不存在的方法名称传进去当做参数。这个技巧在 Rails 的 ActiveRecord 中拿来使用:

class Person <ActiveRecord::Base

end

p1 = Person.find_by_name("ihower")

p2 = Person.find_by_name_and_email("ihower", "[email protected]")

其中 find_by_name 和 find_by_email 就是这样的方法。不过这个技巧不是万能丹,它的执行效率并不好,所以只适合用在你没办法预先知道方法名称的情况下。不过也不是没有补救之道,如果同样的方法还会继续呼叫到,你可以在 method_missing 之中用 define_method 或 class_eval 动态定义此方法,那麼下次呼叫就不会进来 method_missing,进而获得效能的改善。事实上,ActiveRecord::Base 的 method_missing 就是这麼做的。(感谢 BigCat 留言提醒我有此补救之道)

另一个 Missing 方法的绝妙 API 设计,是拿来构建 XML 文件:

builder = Builder::XmlMarkup.new(:target=>STDOUT, :indent=>2)

builder.person do |b|

b.name("Jim")

b.phone("555-1234")

b.address("Taipei, Taiwan")

end

# <person>

# <name>Jim</name>

# <phone>555-1234</phone>

# <address>Taipei, Taiwan</address>

# </person>

搭配了区块功能,就能用 Ruby 语法来写 XML,非常厉害。

5. const_missing

除了 method_missing,Ruby 也有 const_missing。顾名思义就是找不到此常数时,会呼叫一个叫做 const_missing 的方法。现实中的例子有 Rails 的 ActiveSupport::Dependencies,它帮助我们不需要先载入所有类别档案,而是当 Rails 碰到一个还不认识的常数时,它会自动根据惯例,找到该档案载入。

我们也可以利用这个技巧,针对特定的常数规则来处理。例如以下的程式会自动将 U 开头的常数,自动转译成 Unicode 码:

class Module

original_c_m = instance_method(:const_missing)

define_method(:const_missing) do |name|

if name.to_s =~ /^U([0-9a-fA-F]{4})$/

[$1.to_i(16)].pack("U*")

else

original_c_m.bind(self).call(name)

end

end

end

puts U0123 # ģ

puts U9999 # 香

6. Methods chaining

方法串接是一个很常见的 API 设计,透过将方法的回传值设成 self,我们就可以串接起来。例如:

[1,1,2,3,3,4,5].uniq!.reject!{ |i| i%2 == 0 }.reverse

# 5,3,1

7. Core extension

Ruby 的类别是开放的,可以随时打开它新增一点程式或是修改。即使是核心类别如 Fixnum 或是 Object(这是所有类别的父类别) 都一样。例如 Rails 就定义了一些时间方法在 Fixnum 里:

class Fixnum

def hours

self * 3600 # 一小时有多少秒

end

alias hour hours

end

Time.now + 14.hours

Ruby 的物件模型与元编程(Meta-programming)

在 Ruby 中,所有东西都是物件。甚至包括类别(class)本身也是物件。这个类别物件(class object)是一个叫做 Class 的类别所实例出来的物件。而所有的物件(当然也包括类别物件),都有一个 metaclass (又叫做 singleton, eigenclass, ghost class, virtual class 等名字)。定义在 metaclass 里的方法,只有该物件能够使用,也就是 singleton method (单件方法),只有该物件才有的方法。

了解什麼是 metaclass 是 Ruby 元编程的一个重要前提知识。Ruby 元编程最常用的用途,就是因应需求可以动态地定义方法,例如在 Rails ActiveRecord 中常见的 Class Macro 应用。

要能随心所欲动态定义方法的关键重点,就是 variable scope (变数的作用域) 了。例如以下我们透过 class_eval 和 define_method 帮 String 定义了一个 say 方法,注意到整个 variable scope 都是通透的,没有建立新的 scope:

name = "say"

var = "it’s awesome"

String.class_eval do

define_method(name) do

puts var

end

end

"ihower".say # it’s awesome

class_eval 可以让我们改变 method definition 区域(又叫做 current class)。除了本投影片,建议可以阅读 Metaprogramming in Ruby: It’s Allhe Self 和 Three implicit contexts in Ruby 这两篇文章深入了解 self 和 current class。

8. Class Macro (Ruby’s declarative style)

Class Macro 是 Ruby Meta-programming 非常重要的一个应用,例如在 Rails ActiveRecord 中:

class User <ActiveRecord::Base

validates_presence_of :login

validates_length_of :login,:within =>3..40

validates_presence_of :email

belongs_to :group

has_many :posts

end

ASP

ASP(Active Server Pages)动态网页,是微软公司推出的一种用以取代CGI(Common Gateway Interface)通用网关接口的技术。我们可以通过ASP结合HTML语言、ASP指令和ActiveX元件以及数据库等方面知识,使用自己的 Web 服务器创建并运行动态的交互式 Web 站点。ASP的主要优点大概可以归纳如下:

1、您可以用 VBScript 或JScript创建脚本,同时结合HTML语言就能够非常方便地完成网站的应用程序。对于 VBScript和JScript,使用哪种语言并不重要,Web 服务器等同地处理这两种语言,并向用户的浏览器发送 HTML 格式化结果。

2、因为ASP采用Script语言(VBScript和JScript)就可以轻松编写程序,因此这就大节省了网络设计人员又得重新学习一种新语言的时间。而且编写ASP无须手工compile编译或链接程序,可在服务器端直接执行,这无疑是更加方便了我们的编写过程。

3、使用普通的使用记事本之类的文本编辑器,即可进行编辑设计,如:Windows的记事本。建议不要用FontPage98或DreamWeaver2.0等主页制作软件修改,因为他们会破坏源代码的。在这里我建议使用CuteFTP携带的CuteHTML编辑器进行编辑设计。

4、ASP是运行在服务器端,所以我们无须担心浏览器是否支持ASP所使用的编程语言,用户端只要使用可执行HTML码的浏览器,即可浏览Active Server Pages所设计的网页内容。ASP在服务器端运行,当程序执行完毕后,服务器仅将执行的结果返回给客户浏览器,这样也就减轻了客户端浏览器的负担,大大提高了交互的速度。

5、ASP能与任何ActiveX scripting语言相容。除了可用VBScript或JScript语言来设计外,还通过plug-in的方式,使用由第三方所提供的其他脚本语言,譬如Perl、Tcl等。脚本引擎是处理脚本程序的COM(Component Object Model)组件。

6、Active Server Pages的程序代码隐藏,在客户端上仅可以看到由ASP输出的动态HTML文件。因而可以避免所写的源程序被他人剽窃,也提高了程序的安全性。

7、可使用服务器端的脚本来产生客户端的脚本。

8、面向对象(Object oriented),并可扩展ActiveX Server组件功能。

9、ActiveX Server Components(ActiveX服务器组件)具有无限可扩充性。你可以使用任何编程语言来编写你所需要的ActiveX Server 组件。

10、可以通过ADO(ActiveX Data Objects,微软的一种新的数据访问模型,是一种可以提供WEB页面开发者轻松存取Internet的数据库,并可以在用户端实现网上立即、即时更新显示的最新WEB页面数据库技术。)非常方便地访问数据库,从而使存取数据库变得轻松容易。

JSP

JSP(Java Server Pages)是由Sun Microsystems公司倡导、许多公司参与一起建立的一种动态网页技术标准,本文简单介绍JSP及其优点。

JSP(Java Server Pages)是由Sun Microsystems公司倡导、许多公司参与一起建立的一种动态网页技术标准。 JSP技术是用JAVA语言作为脚本语言的,JSP网页为整个服务器端的JAVA库单元提供了一个接口来服务于HTTP的应用程序。

在传统的网页HTML文件(*.htm,*.html)中加入Java程序片段(Scriptlet)和JSP标记(tag),就构成了JSP网页(*.jsp)。Web服务器在遇到访问JSP网页的请求时,首先执行其中的程序片段,然后将执行结果以HTML格式返回给客户。程序片段可以操作数据库、重新定向网页以及发送 email 等等,这就是建立动态网站所需要的功能。所有程序操作都在服务器端执行,网络上传送给客户端的仅是得到的结果,对客户浏览器的要求最低,可以实现无Plugin,无ActiveX,无Java Applet,甚至无Frame。

JSP的优点:

·对于用户界面的更新,其实就是由 Web Server进行的,所以给人的感觉更新很快。

·所有的应用都是基于服务器的,所以它们可以时刻保持最新版本。

·客户端的接口不是很繁琐,对于各种应用易于部署、维护和修改。

Python

首先就以语法而论,python完全没有perl的灵活紧凑。只能说是中庸,感觉和basic,pascal,java差不多。一个简单的问题,如果没有相应的类库,也要写上一段臃肿的代码。唯一的好处是代码臃肿却直白,容易看懂--和basic一样。

类库-比perl真的是大大不如,只能覆盖很小的范围,更不用说java了,很多需要的工作都要自己来做。

快速开发--说实话,我觉得用python和用C++效率差不多。谁能告诉我python效率比C++高在哪里吗?对于perl我则可以毫不犹豫的说,是它语法的灵活,对于字符处理能力的强大。

很多人说python适合大型工程,但更多的人说,他们用python不过是作为一种原型语言来使用。。这本身不就有点矛盾吗?呵呵 而且对于脚本来完成大型工程,我本身就持怀疑态度。

觉得python唯一的优点在于嵌入C++使用时体现出来的:支持OO,语法容易看懂,有一个boost.python

不是想引起论战,只是不吐不快

Ruby

Ruby是面向对象的编程语言,她追求的是“简便快捷的面向对象编程”。Ruby是解释型语言,因此不需编译即可快捷地编程。同时Ruby具有类似Perl的强大的文本处理功能,她可并不只是个玩具,您可以用她来进行实用的编程。此外,您还可以很方便地使用C语言来扩展Ruby的功能,因此可以把她当作各种库的前端来使用。

若您曾经“想要一种简单的面向对象的语言”,或者认为“Perl的功能虽然好用,但它的语法真让人受不了”,又或者觉得“lisp系列语言的思想不错,但到处都是括号真让人讨厌,最起码算式应该按照通常的样式书写”。那么,Ruby或许能让您满意。

归纳以来,Ruby有以下优点。

解释器

Ruby是解释型语言,其程序无需编译即可轻松执行。

变量无类型

Ruby的变量没有类型,因此不必为静态的类型匹配而烦恼。相应地,错误检查功能也变弱了。

不需要变量声明

所有变量均无需声明即可立即使用。另外,从变量名即可判断出是何种变量(局部变量,全局变量,实例变量)。

语法简单

语法比较简单,类似Algol系语法。

不需要内存管理

具有垃圾回收(Garbage Collect,GC)功能,能自动回收不再使用的对象。

一切都是对象

Ruby从一开始就被设计成纯粹的面向对象语言,因此以整数等基本数据类型为首的所有东西都是对象,它们都有发送信息的统一接口。

类,继承,方法

Ruby当然具有面向对象语言的基本功能。

特殊方法

可向某对象添加方法。例如,可以把GUI按钮被按下时的动作作为方法记述下来,还可以用它来进行原型库(prototypebase)的面向对象编程(有人这么干吧)。

用模块进行混合插入(Mixin)

Ruby故意舍弃了多重继承,但拥有混合插入功能。使用模块来超越类的界限来共享数据和方法等。

迭代器

该功能可以将循环抽象化。

闭包

可以将某过程片段对象化。对象化后的该过程片段就称作闭包。

功能强大的字符串操作/正则表达式

以Perl为样板创造出了功能强大的字符串操作和正则表达式检索功能。

拥有超长整数

添加超长整数功能后,可以计算非常大的整数。例如计算400的阶乘也轻而易举。

具有错误处理功能

错误处理功能可以使您编写代码处理出错情况。

可以直接访问OS

Ruby可以使用(UNIX的)绝大部分的系统调用。单独使用Ruby也可以进行系统编程。

动态加载

若OS支持的话,可以在运行时读入对象文件。

但Ruby也有下列缺点。

Ruby On Rails,优点是不像Struts那样需要大量的配置文件,一切都采取默认的配置,包括访问路径,uri等,而这也是它的缺点,不能灵活的配置。

见笑,小弟看了几天,一点见解。

RERL

第一. Perl强大的正则表示式(regular expression)比对以及字符串操作使这个工作变得简单而没有其它语言能相比。Perl 非常擅长于切割,扭转,绞,弄平,总结,以及其它的操作文字文件。生物资料大部分是文字文件:物种名称,种属关系,基因或序列的注解,评住,目录查阅, 甚至DNA序列也是类文字的。现在互相交换以以文字文件的形式存在的但是具有不兼容的资料格式生物信息资料是一个很头疼的问题,perl的这个方面的优点,可以在这一方面解决不少问题.

第二. Perl 能容错。生物资料通常是不完全的,错误或者说误差从数据的产生时候可能就产生了.另外生物数据的某项值栏位可以被忽略 ,可能是空着的,或是某个栏位也就是某个值,被预期要出现好几次(举例来说,一个实验可能被重复的操作),或是资料以手动输入所以有错误。Perl并不介意某个值是空的或是有奇怪的字符。正规表示式能够被写成取出并且更正错误的一般错误。当然这种弹性也可能是各坏处。

还有,Perl 是组件导向的。Perl 鼓励人们将他们的软件写成小模组,不论是用 Perl 函式库模组或是正统的 Unix 工具导向的方式。外部程序能够轻易的被整合进 Perl 程序,靠着管道(pipe),系统呼叫,或是插座(socket)。Perl5 引进的动态载入器允许人们使用 C 的函式,或者让整个编程过的函式库,被使用在 Perl 直译器中。最近的成果是世界各地的智能结晶都会收录在一组模组里面,称为”bioPerl”(请参考 Perl Journal)

Perl 很容易去写并且能很快开发完。直译器让你不需要宣告你所有的函数型式以及资料型态,当未定义的函式被呼叫时只会引起一个错误,除错器也能与Emacs很好的合作并且让你能用令人舒服的交谈式的开发模式。

Perl 是良好的原型语言。因为它快而且脏(quick and dirty),用 Perl 建构新演算的原型比直接写成一个快的需要编程过的语言来的有意义。有时候发现结果是Perl已经够快了,所以程序变不需要移植更多情形是某人可以用C写一个小的核心程序,编程成动态载入的模组或是外部的可执行程序,然后其它的部分用Perl来完成。这部分的例子可以参考 http://waldo.wi.mit.edu/ftp/distribution/software/rhmapper/)。

有一点要强调的是, Perl 在写作网页 CGI 方面非常优秀,而且重要性随着各实验将资料发表在网络上之后更是增加。我在基因中心环境下使用 Perl 的经验从头到尾都是值得称赞的。然而我发现 Perl 也有它的问题。它的松散的程序风格导致许多错误,这些在其它严格的语言都会被抓到。举例来说,Perl 让你在一个变数在被指定值之前就能使用,这是个很有用的特性当你需要的时候,但是却是一个灾难当你单纯的打错了辨识名称。同样的,很容易忘记要宣告一个函式里面的区域变数,导致不小心地改到了全域变数。

最后,Perl 的不足之处在于建立图形化的使用者接口。虽然 Unix忠实信徒所有事情都能在命令模式下完成,大多数的终端使用者却不同意。视窗,选单,弹跳的图案已经变成了必要的时尚。

直到最近,直到最近,Perl 的使用者界面(GUI)发展仍是不成熟的。然而 Nick Ing-Simmons的努力使得 perlTK(pTK) 的整合使得以 Perl 驱动的使用者接口在 X-window上面成为可能。我的伙伴和我曾经在 MIT 基因中心写过几个 pTK 为基础的应用程序供互连网使用者,而且从头到尾都是一个令人满意的经验。其它的基因中心则更大规模的使用 pTK,在某些地方已经成为主要的生产力。

你的问题是不是“ruby 语言的特点”吧??哈哈~~还是我自做多情啦~~~~

Ruby特点

一般认为,他有如下特点:

简单

解释型语言,所以不必事先编译,直接运行,开发周期短,调试方便。

变量没有类型的区分,变量不需要定义,而且是弱类型,即可以改变类型。

irb(main):004:0>a=1

=>1

irb(main):005:0>a.class

=>Fixnum

irb(main):006:0>a*3

=>3

irb(main):007:0>a="str"

=>"str"

irb(main):008:0>a.class

=>String

irb(main):009:0>a*3

=>"strstrstr"

irb(main):010:0>

简单的语法,多从Eiffel继承而来,容易学习。

不需要内存管理,系统提供GC处理机制。其实自从学习JAVA之后,几乎就很少想起指针和内存分配了。

它是纯的面向对象的语言

一切都是对象,像整数等类型从开始就被设计为对象来处理。

有类,实例,模块,继承,方法重载等。

module和Mixin ,实现多重继承。

比Python,Java,C++等更OO。

脚本语言

解释执行

很强的文字处理能力和正则表达式

直接访问OS,用ruby编写系统程序也是可能的。

其他

支持多种长整数,如果内存允许,可以进行很大数的计算操作。

具备异常处理能力,类似java的异常处理功能。

动态载入。可以在运行时候重定义自己,类也可以在运行时继承/取消继承。

线程支持。

反射(Reflection)。Ruby可以看到程序的内部,比如一个模块是否含一个特定方法,一个对象是哪个class等等。类似java的反射功能。

扩展性。使用C API可以轻松的建立国更多的应用库,比如Ruby Mysql模块就是用C语言编写以供Ruby调用Mysql数据库用的。

迭代器和闭包。一个在闭包开始时定义的资源在闭包结束后会被释放,适合于socket,数据库连接,文件句柄等。而迭代器则是非常方便的工具。

跨平台,支持Linux,Unix,Windows,Mac等更重操作系统。

发行许可证。基于Ruby Artistic License (BSD样式的)和GPL。

像其它开源软件一样,有活跃的社区,大量面向Ruby的软件越来越多。