Ruby和微软的Windows

优质
小牛编辑
131浏览
2023-12-01
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并不知道这些方法(比如visiblegohome),它会把这些向它调用的方法传到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 theType property in theexcelchart 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 useeach 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 chart

excel['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
end

excelchart2 = 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