Ruby和微软的Windows
Ruby 的实现是基于 POSIX环境的,也就是说它可以利用unix程序员熟悉的所有的系统调用和系统库。
同时,系统设计的时候扩展了对windows的支持,这章,我们将看看这方面的特性,并展示一些在windows下高效使用ruby的秘诀。
Ruby Ports
Windows does not provide a POSIX environment by itself, so some sort of emulation library is required in order to provide the necessary functions. There are several ports of Ruby for Windows: the most commonly used one relies on the GNU Win32 environment, and is called the ``cygwin32'' port. The cygwin32 port works well with extension libraries, and is available on the Web as a precompiled binary. Another port, ``mswin32,'' does not rely on cygwin. It is currently available as source code only. The remainder of this chapter will refer to the cygwin32 port.
在 Windows下运行Ruby
cygwin32版本的ruby发布包括两个可执行文件:ruby.exe
,rubyw.exe
ruby.exe
用在命令提示符下(dos shell),就像unix版本中的一样。对于需要从标准输入输出进行读写操作的应用来说比较适合,但是这样的话我们运行什么程序都需要额外多开了一个窗口,而不管我们需不需要这个窗口,有时候这样就显得不合适了,比如我们双击一个ruby脚本运行一个图形接口(比如Tk),或者作为后台程序运行,或者在别的程序中被调用。
在这种情况下,我们可以用
rubyw.exe
,他和
ruby.exe
一样,但是不提供标准输入和标准输出,或者标准错误,并且不会打开一个dos shell的窗口。
可以对ruby脚本(.rb结尾的文件)设定文件关联[在用菜单 查看/选项/文件类型
],然后双击这个文件就可以调用rubyw.exe
来执行这个程序了。
Win32API
如果你的ruby程序打算直接访问win32api,或者用一些DLL的入口点,你将会用到
Win32API
扩展。
你可以用要访问的DLL名字创建一个
Win32API
对象,表示对一个指定的DLL的入口点的调用,DLL的名字包括函数,函数签名(参数和返回值),建立的win32api对象就可以用来对指定的dll进行调用。
DLL的很多参数都是一定形式的二进制结构,
Win32API
用ruby的字符串对象处理这些参数,进行来回的传递。你需要对这些字符串进行打包和解包(pack and unpack)
Windows Automation
如果你对使用低层次的windows API调用不感兴趣,你可以使用windows utomation,ruby可以当成Windows Automation 的客户。感谢 Masaki Suketa写的 win32OLE扩展。下面例子是WIN32OLE发布包中提供的。
Windows 自动化允许自动化控制器(客户端)向自动化服务器(Excel, Word, PowerPoint等)发送一个命令或者进行查询。
你可以向
WIN32OLE
发送一个命令,从而可以执行自动化服务器上具有相同名字的方法。例如,你可以创建一个
WIN32OLE
客户,创建几个全新的IE浏览器,并且显示ie设置的主页:
ie = WIN32OLE.new('InternetExplorer.Application') ie.visible = true ie.gohome |
WIN32OLE
并不知道这些方法(比如visible
和gohome
),它会把这些向它调用的方法传到WIN32OLE#invoke
,在这个方法里向自动化服务器发送正确的命令。
读、写自动化服务器的属性
你可以用通常的哈希表示方法从自动化服务器读写服务器的属性。比如,可以如下面一样设定一个Excel chart的
Rotation
的值:
excel = WIN32OLE.new("excel.application") excelchart = excel.Charts.Add() ... excelchart['Rotation'] = 45 puts excelchart['Rotation'] |
OLE对象的参数自动都会被设成属性,也就是说你可以你可以通过给一个属性赋值而设定一个参数。
excelchart.rotation = 45 r = excelchart.rotation |
因为这些属性是常规的ruby访问方法,而属性名不能以大写字母开头,所以你要用
rotation
而不是
Rotation
。
命名参数(Named Arguments)
其他的能实现自动化客户端的语言,比如VB,有一种叫做命名参数(named arguments)的概念,假设我们有这样的一个VB方法:
Song(artist, title, length): rem Visual Basic |
要想调用这个方法,除了按顺序写全这三个参数来调用之外,我们可以用命名参数的方法:
Song title := 'Get It On': rem Visual Basic |
这等同于
调用 Song(nil, 'Get It On', nil)
。
在Ruby中,可以在调用的时候用哈希结构来指定参数名和它的值,比如:
Song.new( 'title' => 'Get It On' ) |
for each方法
VB有一个方法 ``for each''语句,可以在服务端对一个集合进行迭代,
WIN32OLE
对象也有一个方法完成相同的作用。
一个例子
下面这个例子,用到了微软的Excel,覆盖了上面说的很多概念。首先,我们创建了一个新的基于Excel的WIN32OLE
对象,并增加了一些单元格,并给这些单元格赋值。然后,我们选中了一个区域,并创建了图表(chart),我们通过给这个图表的type属性赋值,使它成为一个3D的图表。然后,
The following example, using Microsoft Excel, illustrates most of these concepts. First, we create a new object attached to Excel and set some cell values. Next we select a range of cells and create a . We set the
Type
property in the
excelchart
object to make it a 3D chart. Next we'll loop through and change the chart rotation, 10?at a time. We'll add a few charts, and we'll use
each
to step through and print them out. Finally, we'll close down the Excel application and exit.
require 'win32ole'# -4100 is the value for the Excel constant xl3DColumn. ChartTypeVal = -4100;# Creates OLE object to Excel excel = WIN32OLE.new("excel.application")# Create and rotate the chartexcel['Visible'] = TRUE; workbook = excel.Workbooks.Add(); excel.Range("a1")['Value'] = 3; excel.Range("a2")['Value'] = 2; excel.Range("a3")['Value'] = 1; excel.Range("a1:a3").Select(); excelchart = workbook.Charts.Add(); excelchart['Type'] = ChartTypeVal;30.step(180, 10) do |rot| excelchart['Rotation'] = rot endexcelchart2 = workbook.Charts.Add(); excelchart3 = workbook.Charts.Add();charts = workbook.Charts charts.each { |i| puts i }excel.ActiveWorkbook.Close(0); excel.Quit(); |
优化
As with most (if not all) high-level languages, it can be all too easy to churn out code that is unbearably slow, but that can be easily fixed with a little thought.
对
WIN32OLE
来说, 我们要避免不必要的动态查找(dynamic lookups)。如果可能,尽量把
WIN32OLE
对象 赋给一个变量,然后引用这个变量的元素,而不要使用一大串的"." 构成的表达式。
比如,我们不应该写出这样的代码:
workbook.Worksheets(1).Range("A1").value = 1 workbook.Worksheets(1).Range("A2").value = 2 workbook.Worksheets(1).Range("A3").value = 4 workbook.Worksheets(1).Range("A4").value = 8 |
我们可以通过把这些语句的前面部分放到一个临时变量里,而使用临时变量来执行方法。
worksheet = workbook.Worksheets(1)worksheet.Range("A1").value = 1 worksheet.Range("A2").value = 2 worksheet.Range("A3").value = 4 worksheet.Range("A4").value = 8 |
Extracted from the book "Programming Ruby - The Pragmatic Programmer's Guide"
Copyright © 2001 by Addison Wesley Longman, Inc. This material may be distributed only subject to the terms and conditions set forth in the Open Publication License, v1.0 or later (the latest version is presently available at http://www.opencontent.org/openpub/)).Distribution of substantively modified versions of this document is prohibited without the explicit permission of the copyright holder.Distribution of the work or derivative of the work in any standard (paper) book form is prohibited unless prior permission is obtained from the copyright holder.