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
并不知道这些方法(比如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的图表。然后,
Type
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