2009-08-21 62 views
16

你好同胞的Mac ruby​​ists和AppleScript的仇敌,通过Ruby避免AppleScript:rb-appscript或rubyosa?

对于那些有rubyosa和rb-appscript的经验的人,我想听听每个人的利弊,你决定坚持哪一个,以及哪一个你会推荐完全不是AppleScript精明的红宝石老前辈。另外,还有其他的选择我错过了吗?另外,任何涉及AppleScript方面的提示(例如浏览字典等)也是受欢迎的。

看到一些示例代码也有很大帮助。

+2

为什么不使用脚本桥? – Chuck 2009-08-21 04:52:17

+0

你可以扩展吗? – kch 2009-08-21 05:40:22

回答

46

答曰KCH:

这很好,但现在我很好奇 如何脚本桥比较 的AppleScript。我想我会有一些 阅读。

SB省略了AppleScript的发现了一些功能。例如,下面的脚本从桌面移动所有文件到文件夹:

tell application "Finder" 
    move every file of desktop to folder "Documents" of home 
end tell 

在SB中,SBElementArray类严重限制了你的申请一个命令到多个目标的能力,让你无论是不得不诉诸低级别的API或者获得单独的文件引用的列表和移动这些一次一个:

require 'osx/cocoa'; include OSX 
require_framework 'ScriptingBridge' 

finder = SBApplication.applicationWithBundleIdentifier('com.apple.finder') 
destination = finder.home.folders.objectWithName('Documents') 
finder.desktop.files.get.each do |f| 
    f.moveTo_replacing_positionedAt_routingSuppressed(destination, nil, nil, nil) 
end 

在RB-appscript,你会使用相同的方法的AppleScript:

require 'appscript'; include Appscript 

app("Finder").desktop.files.move(:to => app.home.folders["Documents"]) 

...

SB更重比的AppleScript的确混淆了苹果事件机制。AppleScript可能会让你头痛,使用奇怪的语法,关键字冲突的倾向等等,但除此之外,它主要是将Apple事件按原样呈现出来。 AS中唯一真正重要的魔法是当它评估一个不作为命令参数的字面引用时的“隐式get”行为。 AppleScript最大的罪孽是它的文档并没有更好地解释它的实际工作方式,但有一个very good paper by William Cook可以说明实际发生的事情。另一方面,SB会尽其最大的努力假装它是一个真正的可可风格的Cocoa API,因此层层叠加了大量的魔力。其结果是对可可开发人员表面上的吸引力,但是一旦这些抽象开始泄漏 - 就像抽象总是这样 - 你就完全了解正在发生的事情。例如,SBElementArray声称是一个数组 - 它甚至是NSMutableArray的子​​类 - 但是当你真正尝试使用它的数组方法时,其中一半工作,一半不工作。事实上,它根本不是真正的阵列;它是一个未评估的Apple事件对象说明符的包装,假装它是一个NSMutableArray。所以当它做了一些非数组类的时候,你基本上可以理解为什么。而且,正如#1所提到的,这些粗略的抽象使得难以访问下面的标准Apple事件功能。

SB最先试图成为一个好的Cocoa API而不是一个好的Apple事件API,并且最终不是很好。

Appscript顺便说一句,遵循AppleScript的主导思想,采取相反的做法:苹果事件正确,然后担心适应主机语言。这就是为什么有些人更喜欢RubyOSA而不是rb-appscript;而appscript是更强大的解决方案,如果你来自面向对象的背景,它会感觉很奇怪。这是因为Apple事件使用基于RPC加查询的范例,而任何类似的appscript可能不得不使用OOP纯粹是句法。最接近的比喻是通过XML-RPC发送XQueries,并且需要一些习惯。

...

SB往往承受着比其他的AppleScript显著多个应用程序兼容性问题。

这些问题有些是由于SB强加了自己的苹果如何事件IPC 应该就如何实际上作品的最高工作思路。例如,SB创建一组代表字典中定义的类的[伪]代理类;然后在很大程度上基于传统的面向对象行为规则的基础上,对如何与这些对象进行交互设置各种限制。

例如,下面的脚本得到的文档文件夹的所有子文件夹的名称:

tell application "Finder" 
    get name of every folder of entire contents of folder "Documents" of home 
end tell 

如果试图在SB相同的方法:

finder.home.folders.objectWithName('Documents').entireContents.folders.arrayByApplyingSelector(:name) 

它得到尽可能作为#folders方法,然后抛出一个错误,因为Finder字典中的'entire contents'属性的类型被声明为'reference'。由于在字典中没有定义'文件夹'元素的'引用'类,SB不允许你构造特定的查询(除非你想下拉到低级API并使用原始AE代码)。根据Apple的事件规则,这是完全合法的,但不符合SB规定的较窄OO中心规则集。

其他错误是由于SB对可编写脚本的应用程序如何实现某些命令和其他功能做出了假设。例如:

tell application "iTunes" 
    make new playlist with properties {name:"test 1"} 
end tell 

SB不会让你带由iTunes提供任何快捷方式的优势,但(你可以省略引用到你想要的播放列表创建的源对象,在这种情况下主“库”源使用),所以让我们写在全力为更好的比较:

tell application "iTunes" 
    make new playlist at source "Library" with properties {name:"test"} 
end tell 

在SB你会写为:

itunes = SBApplication.applicationWithBundleIdentifier('com.apple.itunes') 

playlists = itunes.sources.objectAtIndex(0).playlists() 
newplaylist = itunes.classForScriptingClass(:playlist).alloc().initWithProperties({:name => 'test'}) 
playlists.addObject(newplaylist) 

当你虽然运行它,它barfs上#addObject 。在试图将单个“make”命令变成多行练习时,SB假定'at'参数始终是形式'<元素末尾> < object>'的引用,这就是Cocoa脚本基于应用程序来做到这一点。 Carbon应用程序虽然没有用于实现Apple事件支持的单一标准框架,所以它们的要求往往会有所不同。例如,iTunes期望对容器对象的引用,在这种情况下是“源”库“',并且当SB通过源”库“的播放列表的末尾时不期望引用该容器对象。这就是许多AppleScriptable应用程序的方式,但SB在其“面向对象”的决心中忽视了这一现实。

当应用程序字典不是100%准确或详尽无遗时,会导致更多问题。 aete和sdef格式都不能让你描述应用程序的脚本接口如何以100%的细节工作;有些事情只能由用户猜测,或者在补充文档中描述 - Finder的“全部内容”属性的性质就是一个例子。其他信息,比如哪些类的对象可以是其他类对象的元素,以及每个属性的类型,AppleScript本身从未实际使用过 - 它仅作为用户文档存在。由于AppleScript不依赖这些信息,因此在测试应用程序对AppleScript的脚本支持时会漏掉任何错误,因为脚本尽管如此,仍然可以正常工作。 SB会使用这些信息,因此任何错误都会导致丢失或损坏的功能,这些功能必须通过再次下降到低级API来规避。

Appscript,BTW,也不是100%'AppleScript兼容',但它确实离得更近了。早期版本的appscript也尝试在Apple事件上实施各种面向对象的规则,比如强制实施字典定义的对象模型,但是在经历了一年的应用程序不兼容问题之后,我放弃了所有那些“聪明”的代码,并在接下来的几年尝试黑盒子反向工程AppleScript的内部机械装置,并且使得appscript尽可能地模拟它们。 “换句话说,如果你不能击败他们(你不能),那就加入他们吧。在appscript确实遇到了兼容性问题的地方,通常会有解决方法,包括翻转内部兼容性设置,将应用程序术语导出到模块,手工打补丁,然后使用它,或者下降到低级的原始AE代码蜜蜂。

...

FWIW,我也插了几个相关appscript东西。

首先,appscript网站上的ASDictionary和ASTranslate工具是您的朋友。 ASDictionary将以appscript风格的HTML格式导出应用程序字典,并启用rb-appscript中的内置#help方法;非常适合irb的互动开发。 ASTranslate将采用AppleScript命令,并且(bugs willing)会以appscript语法返回相应的命令。

其次,rb-appscript的源代码包含文档和示例脚本。如果您安装了appscript gem,请记住也要获取这些资源的zip分配。

三,Matt Neuburg has written a book about rb-appscript。如果你正在考虑使用rb-appscript,请阅读它。不管你最终决定什么,去阅读库克博士的论文。

...

反正,希望有所帮助。 (哦,并且对长度表示歉意,但本周我刚刚写了大约25000字,所以这只是一些轻松的放松。)

p.s.内德,你闪亮的美元在后。 ;)

+0

我并不清楚“每个文件”和“files.each”之间的区别 - 他们是否都将所有文件从一个位置迭代移动到另一个位置? – Chuck 2009-08-22 21:22:15

+0

区别在于谁在迭代。随着files.each,你发送一个单独的Apple事件来操纵每个元素。使用“每个文件”,您只需向应用程序发送一个单一事件,即“处理所有文件即可”。 Apple事件IPC最初是为系统7设计的,其中上下文切换非常昂贵。为了弥补,AppleScript设计师允许您为每个事件执行多个操作。尽管AE IPC在OS X上的价格要便宜得多,但它仍然是优化的,因此使用更少的事件会更有效。如果您有数百个对象需要处理,这会产生变化。 – has 2009-08-23 08:48:07

+0

这个答案应该刻在石头上,或者至少变成一篇博客文章。 – dmkc 2010-07-16 02:58:55

3

Apple通过一个名为“Scripting Bridge”的框架支持Cocoa兼容语言的脚本支持。我通过RubyCocoa/MacRuby使用它来满足我的脚本需求。它包含在盒子里,所以很方便。

require 'osx/cocoa' 
require_framework 'ScriptingBridge' 
iTunes = SBApplication.applicationWithBundleIdentifier 'com.apple.iTunes' 
puts iTunes.selection.name 

唯一的主要烦恼我发现脚本大桥是,你必须使用的包ID一样,而不是名称,但这是不是真的太大的问题,对我来说反正。它也只包含在10.5中,所以如果你需要Panther或Tiger支持,你需要其他的支持。

其他两个,RB-appscript仍积极发展,同时RubyOSA得到有效几年前冻结,所以我可能会与前走。随着Ruby 2,MacRuby和其他新实现带来语言的变化,rb-appscript更有可能在未来发挥作用。否则他们非常相似。我基本上把rb-appscript看作是RubyOSA的一个新版本,尽管它在技术上并不真实。

+0

这很好,但现在我很好奇脚本桥比较applescript。我想我会做一些阅读。 – kch 2009-08-21 21:12:55

+0

我不确定你的意思是“它如何与Applescript相比”。它以不同的语言提供相同的功能。 – Chuck 2009-08-21 21:35:23

5

我没有试过RubyOSA,但我已经对rb-appscript取得了巨大成功。它对我来说非常完美,比直接使用AppleScript更好。

你见过this thread comparing the two?它有一个很好的详细答案,注意不同之处。

+0

伟大的链接。摩尔阅读。 – kch 2009-08-21 21:13:33

+1

使用rb-appscript。 rb-appscript的开发者是AppleScript和底层OSA架构的全球专家之一。 rb-appscript建立在他多年的经验之上,包括原始的Python版本的appscript。他提供的支持非常出色。 – 2009-08-21 21:44:14

+3

请注意,**'rb-appscript'是** [**不再支持**,不建议用于新项目](http://appscript.sourceforge.net/status.html)。 – 2012-03-13 06:30:43

2

简答:rb-appscript。

因为脚本桥看起来很乱,RubyOSA已经停产。

+0

所以有rb-appscript。 (尽管如此,还是3年了。) – Trejkaz 2012-10-27 00:53:06

+0

是的,可悲的是。我爱rb-appscript。 – kch 2013-02-15 14:50:33