use 语句在 AppleScript 中不起作用

use statement not working in AppleScript

我正在脚本文件中创建我的第一个 AppleScript 库,并希望使用 use 语句 (I followed these instructions) 在该文件中使用处理程序。所以我尝试了:

use script "My Library"

create_new_track(10, 2, 2)

在我的 "My Library.scpt" 文件中,有一个名为 "create_new_track" 的处理程序。 但是当我尝试在 use 语句之后调用它时,出现此错误:

error "«script» doesn’t understand the “create_new_track” message." number -1708 from «script»

通过以下代码片段,我得到了 运行 的处理程序:

tell script "My Library"
    create_new_track(10, 2, 2)
end tell

不过,我宁愿能够避免在我的脚本中使用大量的 tell 块。有人知道哪里出了问题吗?

我想我会尝试:

 use mylib : script "My Library"
 mylib's create_new_track(10, 2, 2)

如果我没记错的话,您只能像上面那样使用 use 语句,以便使用应用程序中的术语。 -但我可能听错了。

不幸的是,您假设 AppleScript 的库系统是由一位称职的工程师设计的。事实并非如此:就像当前 AppleScript 团队吐出的几乎所有东西一样,它是小丑车的软件版本:完全不可预测table,危险不安全,当你认为你终于正确地弄清楚它是如何工作的那一刻,所有的门都飞走了,然后跳出数十个疯狂的小丑,用无法形容的物质向你投掷。

无论如何,尽我所能来解释这种疯狂......

use 语句将字典定义的关键字注入您的全局命名空间。考虑到 AppleScript 已经因在语言、应用程序和脚本添加词典之间造成术语冲突而臭名昭著,这本身就是一件疯狂的事情。

但是,use 语句 不会 注入用户定义的标识符(例如您的 create_new_track 标识符)。这有点讽刺,因为用户定义的标识符比任意关键字混合使用要安全得多,而且它会使 ObjC 框架使用起来不那么烦人(我的意思是,地球上让他们认为 current application's NSWhatever... 是好的语法?!?!)。

虽然 AppleScript 确实在正确绑定静态变量名称方面存在问题,但处理程序名称始终是动态绑定的,因此用户定义的命令名称通常可以毫无问题地工作(消息只是向上传递对象委托链,直到它被处理或 "handler not found" 发生错误)。然而,use 机制不使用标准的 AppleScript 委托(并不是说它本来就是为这种用途而设计的),而是似乎依赖于对已知关键字的全局查找 table 来拦截消息使用基于关键字的名称并将这些消息重定向到最初定义该关键字的任何对象。但是由于您的 create_new_track 消息没有基于关键字的名称,因此 "redirect" 黑客完全忽略了它; AppleScript 种族隔离,如果你愿意的话。

因此,如果您想在脚本库中引用具有用户定义名称的属性和处理程序,您必须使用引用,例如create_new_track() of script "MyLibrary"。这实际上是一件好事,并且使整个混乱尽可能接近 "simple, predictable, and safe",因为它使所有脚本的命名空间保持不变,并且不会将更多可能冲突的关键字注入 AppleScript 的全局命名空间。

如果您重复使用某个库,那么编写 ...of script "MyLibrary" 确实会很乏味。虽然您可以使用 tell script "MyLibrary"...end tell 块来包装多个命令,但过度使用 tell 块是另一种容易造成完全混乱的方法,因为它们为 all[=43= 指定了默认目标] 块中的命令,而不仅仅是您实际想要发送到该对象的命令。最好的解决方案是在脚本顶部使用 property 语句将 script... 说明符绑定到一个漂亮、整洁的标识符,然后您可以在需要时在整个脚本的其余部分使用它向该库发送命令:

property mylib : script "My Library"

...

mylib's do_this()

mylib's do_that()

etc.

使用这种方法,您将避免很多痛苦。尝试成为 "clever",它几乎总是会咬你的屁股。掌握 AppleScript 语言总是与学习它的许多缺陷以及如何解决这些缺陷一样重要,就像实际学习编码一样。不幸的是,目前的 AS 团队如此专注于放纵自己病态的聪明才智,以至于年复一年地变得更难,而不是更容易。 (我希望 AS 最终会超越 C++,假设其余的 Apple 不只是先把子弹放在它身上——作为一个 15 年的 AS 老手,我越来越希望他们能在它完全扼杀用户脚本和自动化之前做到这一点。)

指出一些有用的信息……如果您选择使用 属性 的方式来定义脚本库,以便能够调用要在其他脚本中使用的处理程序和脚本对象,重要的是要保持请记住,如果对您的脚本库文件进行了任何更改……并重新编译和保存,这些更改将不会转移到您创建的脚本中,这些脚本会从您的库文件中调用脚本对象和处理程序。简而言之,您将需要打开并重新编译并保存创建的每个脚本,这些脚本调用库文件中的脚本对象和处理程序。如果您有数十个甚至数百个脚本,这可能会成为一场噩梦。

使用其他答案之一的以下示例……脚本库在编译时存储,并将保留其值,直到重新编译脚本。在重新编译并保存这些脚本之前,对原始库文件的任何更新或更改都不会反映在调用它们的脚本中

property mylib : script "My Library"

...

mylib's do_this()

mylib's do_that()

etc.

我认为更有利的选择是在 运行 时间加载脚本库。这样,任何依赖于该库文件的脚本都会在 运行... 脚本库文件被更改并保存后自动更新。

这是我在运行时间

用来加载库的代码
property myLib : missing value
property theLibrary : missing value

on loadLibraries()
    set theLibrary to (path to home folder as text) & "Library:Script Libraries:My Library.scpt"
    set myLib to load script alias theLibrary
end loadLibraries

loadLibraries()

myLib's do_this()
myLib's do_that()