2009-08-21 5 views
16

Rubyistas Hola compañeros de Mac y enemigos AppleScript,Evitar AppleScript a través de Ruby: rb-appscript o rubyosa?

Para aquellos de ustedes que tienen experiencia con ambos rubyosa y rb-appscript, me gustaría oír a los pros y los contras de cada uno, que las que decidió seguir con, y cuál recomendarías para un veterano de rubí que no sea AppleScript. Además, ¿hay alguna otra opción que me haya perdido?

Como nota aparte, cualquier consejo que trate sobre el lado AppleScript de la ecuación (por ejemplo, diccionarios de navegación, etc.) también es bienvenido.

Ver algunos ejemplos de código también ayuda mucho.

+2

¿Por qué no Scripting Bridge? – Chuck

+0

¿puedes ampliar eso? – kch

Respuesta

46

Quoth kch:

eso es bueno, pero ahora tengo curiosidad por saber cómo puente de secuencias de comandos se compara con applescript. Supongo que tendré algunas lecturas de que hacer.

SB omite algunas funcionalidades que se encuentran en AppleScript. Por ejemplo, el siguiente script mueve todos los archivos desde el escritorio a la carpeta Documentos:

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

En SB, la clase SBElementArray restringe severamente su capacidad de aplicar un único comando a varios objetos, por lo que o bien tienen que recurrir a la API de bajo nivel o bien obtener una lista de referencias de archivos individuales y que se muevan uno a la vez:

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 

en rb-appscript, tendrá que utilizar el mismo enfoque que AppleScript:

require 'appscript'; include Appscript 

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

...

SB ofusca el mecanismo de evento de Apple mucho más que AppleScript.AppleScript puede ser difícil de entender, con la sintaxis extraña, la tendencia a conflictos de palabras clave y cosas por el estilo, pero más allá de eso, presenta en gran medida los eventos de Apple tal como están. La única pieza de magia realmente importante en AS es su comportamiento de "obtención implícita" cuando evalúa una referencia literal que no aparece como un parámetro de un comando. El mayor pecado de AppleScript es que su documentación no explica mejor cómo funciona en realidad, pero hay un very good paper by William Cook que arroja mucha luz sobre lo que realmente está sucediendo.

SB, por otro lado, hace todo lo posible para pretender que es un Cocoa API genuino con un comportamiento de estilo Cocoa, por lo que las capas en una gran cantidad de magia. El resultado es algo superficialmente atractivo para los desarrolladores de Cocoa, pero tan pronto como esas abstracciones comiencen a filtrarse, como invariablemente suceden las abstracciones, estás completamente en el mar en términos de entender lo que está sucediendo. Por ejemplo, SBElementArray pretende ser una matriz, incluso subclases NSMutableArray, pero cuando realmente intenta utilizar sus métodos de matriz, la mitad de ellos funcionan y la mitad no. De hecho, no es una matriz real en absoluto; es un contenedor alrededor de un especificador de objeto de evento Apple no evaluado, simulado para pretender que es un NSMutableArray. Entonces, cuando hace algo parecido a un array, estás en gran medida relleno para entender por qué. Y, como se menciona en el n. ° 1, algunas de estas abstracciones espesas dificultan el acceso a la funcionalidad de eventos estándar de Apple debajo.

SB firstmost intenta ser una buena API de Cocoa en lugar de una API de evento de Apple, y termina siendo muy bueno en ninguno.

Appscript, por cierto, sigue el ejemplo de AppleScript y toma el enfoque opuesto: hacer los eventos de Apple correctos, y luego preocuparse por acomodar el idioma del host. Es por eso que algunas personas prefieren RubyOSA sobre rb-appscript; mientras que Appscript es la solución más capaz, si proviene de un entorno orientado a objetos, se sentirá muy extraño. Esto se debe a que los eventos de Apple usan un paradigma basado en RPC-plus-query, y cualquier semejanza que pueda tener APPDA con OOP es puramente sintáctico. La analogía más cercana sería enviar XQueries a través de XML-RPC, y lleva algo de tiempo acostumbrarse.

...

SB tiende a sufrir significativamente más problemas de compatibilidad de aplicaciones que AppleScript.

Algunos de estos problemas se deben a SB imponer sus propias ideas de cómo evento de Apple IPC debería trabajar en la parte superior de la forma en que realmente obras. Por ejemplo, SB crea un conjunto de clases proxy [pseudo] que representan las clases definidas en el diccionario; luego impone varias restricciones sobre cómo puede interactuar con esos objetos basándose principalmente en las reglas de comportamiento orientadas a objetos clásicos.

Por ejemplo, el siguiente script obtiene los nombres de todas las subcarpetas de la carpeta Documentos:

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

Si intenta el mismo enfoque en SB:

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

se pone en la medida de como el método #folders, arroja un error porque el tipo de la propiedad 'todo el contenido' en el diccionario del Finder se declara como 'referencia'. Como no hay una clase de "referencia" con elementos de "carpeta" definidos en el diccionario, SB no le permite construir esa consulta en particular (a menos que desee bajar a las API de bajo nivel y usar códigos AE sin formato). Es perfectamente legal de acuerdo con las reglas de eventos de Apple, pero no encaja dentro del conjunto de reglas más estrecho centrado en OO impuesto por SB.

Otros errores se deben a SB que hace suposiciones sobre cómo las aplicaciones de secuencias de comandos implementarán ciertos comandos y otras características.Por ejemplo:

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

SB no le permite tomar ventaja de todos los accesos directos proporcionados por iTunes, aunque (se puede omitir la referencia al objeto de origen desea que la lista de reproducción creada en, en cuyo caso el principal 'Biblioteca' se utiliza la fuente), por lo que vamos a escribir en su totalidad para una mejor comparación:

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

en SB que iba a escribir esto como:

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

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

Cuando se ejecuta, sin embargo, que vomita en #addObject . En su intento de convertir un único comando 'hacer' en un ejercicio multilínea, SB asume que el parámetro 'at' siempre será una referencia del formulario 'end of < elements> of < object>', que es cómo Cocoa Scripting aplicaciones basadas en lo hacen. Sin embargo, las aplicaciones de carbono no tienen un marco estándar único para implementar el soporte de eventos de Apple, por lo que tienden a variar un poco más en sus requisitos. iTunes, por ejemplo, espera una referencia al objeto contenedor, en este caso 'fuente' Biblioteca "', y no le gusta cuando SB pasa' al final de las listas de reproducción de la fuente 'Biblioteca' '. Así es como muchas aplicaciones de AppleScriptable, pero SB ignora esa realidad en su determinación de estar "orientada a objetos".

Sin embargo, se producen más problemas cuando un diccionario de aplicación no es 100% preciso o exhaustivo en detalle. Ni los formatos aete ni sdef le permiten describir cómo funciona la interfaz de scripting de una aplicación en un 100% de detalle; algunas cosas solo tienen que ser adivinadas por los usuarios, o se describen en documentación adicional; la naturaleza de la propiedad de "contenidos enteros" de Finder es un ejemplo. Otra información, como qué clases de objetos pueden ser elementos de qué otras clases de objetos, y qué tipo de cada propiedad es, en realidad nunca es utilizada por AppleScript en sí misma, solo está allí como documentación del usuario. Dado que AppleScript no confía en esta información, se perderán los errores al probar el soporte de scripting de la aplicación en AppleScript, ya que los scripts funcionan bien a pesar de ello. SB no utiliza esa información, por lo que cualquier error tipográfico dará como resultado características faltantes o rotas que tienen que sortearse al volver a bajar a las API de bajo nivel.

Appscript, BTW, tampoco es 100% 'compatible con AppleScript', pero sí mucho más cerca. Las primeras versiones de appscript también intentaron imponer varias reglas de OO en los eventos de Apple, como aplicar el modelo de objeto definido por el diccionario, pero después de un año de encontrarse con incompatibilidades de aplicaciones gané todo ese código "inteligente" y pasé los siguientes años intentando Black-Box hace ingeniería inversa en las maquinaciones internas de AppleScript y hace que Appscript las emule lo más cerca posible. "Si no puedes vencerlos (que no puedes), únete a ellos", en otras palabras. Y donde Appscript resuelve un problema de compatibilidad, generalmente hay formas de eludirlo, como voltear la configuración de compatibilidad interna, exportar la terminología de la aplicación a un módulo, parchearla a mano y usarla en su lugar, o bajar a su código AE de bajo nivel APIs

...

Fwiw, también debe conectar un par de golosinas appscript relacionados.

Primero, las herramientas ASDictionary y ASTranslate en el sitio de appscript son tus amigos. ASDictionary exportará diccionarios de aplicaciones en formato HTML de estilo appscript y también habilitará el método #help incorporado en rb-appscript; ideal para el desarrollo interactivo en irb. ASTranslate tomará un comando de AppleScript y (los bugs están dispuestos) devolverán el comando equivalente en la sintaxis de appscript.

En segundo lugar, la distribución fuente de rb-appscript contiene documentación y scripts de muestra. Si instala la gema de appscript, recuerde tomar la distribución zip para esos recursos también.

En tercer lugar, Matt Neuburg has written a book about rb-appscript. Ve a leerlo si estás pensando en usar rb-appscript. Y lea el documento del Dr. Cook, independientemente de lo que decida.

...

De todos modos, espero que ayude. (Ah, y disculpas por la duración, pero acabo de escribir unas 25000 palabras esta semana, así que esto es solo un poco de relajación ligera)

p.s. Ned, tu dólar brillante está en la publicación. ;)

+0

No tengo clara la diferencia entre "cada archivo" y "files.each": ¿no mueven de manera iterativa todos los archivos de una ubicación a otra? – Chuck

+0

La diferencia es quién realiza la iteración. Con files.each, está enviando un evento de Apple por separado para manipular cada elemento. Con 'cada archivo', está enviando un único evento a la aplicación que dice "procesar todos los archivos en su extremo". Apple event IPC se diseñó originalmente para System 7, donde los conmutadores de contexto eran caros. Para compensar, los diseñadores de AppleScript le permitieron realizar múltiples acciones por evento. Mientras que AE IPC es mucho más barato en OS X, aún está optimizado, por lo que es más eficiente usar menos eventos que hagan más. Si tiene que procesar cientos de objetos, esto hace la diferencia. – has

+0

Esta respuesta debe ser tallada en piedra, o al menos convertida en una publicación de blog. – dmkc

3

Apple incluye compatibilidad con scripts para los idiomas compatibles con Cocoa a través de un marco denominado "Scripting Bridge". Lo uso a través de RubyCocoa/MacRuby para mis necesidades de scripting. Está incluido en la caja, así que es bastante conveniente.

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

La única molestia importante que he encontrado para el puente de secuencias de comandos es que usted tiene que utilizar los identificadores de paquete como el que en lugar de nombres, pero eso no es realmente un gran problema para mí de todos modos. También solo está incluido en 10.5, por lo que si necesita el soporte de Panther o Tiger, necesitará uno de los otros.

De los otros dos, rb-appscript aún se desarrolla activamente, mientras que RubyOSA se congeló efectivamente hace un par de años, así que probablemente vaya con el anterior. Como Ruby 2, MacRuby y otras implementaciones nuevas provocan cambios en el lenguaje, es más probable que rb-appscript funcione en el futuro. De lo contrario, son bastante similares. En esencia trato a rb-appscript como una nueva revisión de RubyOSA, aunque técnicamente no es verdad.

+0

Eso está bien, pero ahora tengo curiosidad acerca de cómo se compara scripting bridge con applescript. Creo que tendré algo que leer. – kch

+0

No estoy seguro de qué quiere decir con "cómo se compara con Applescript". Proporciona la misma funcionalidad en un idioma diferente. – Chuck

5

No he probado RubyOSA, pero he tenido un gran éxito con rb-appscript. Me ha funcionado perfectamente y es mucho mejor que trabajar directamente con AppleScript.

¿Has visto this thread comparing the two? Tiene una bonita respuesta detallada que señala las diferencias.

+0

Gran enlace. Lectura de Moar – kch

+1

Vaya con rb-appscript. El desarrollador de rb-appscript es uno de los expertos mundiales en AppleScript y la arquitectura OSA subyacente. rb-appscript se basa en sus años de experiencia, incluida la versión original de Python de appscript. Y el apoyo que brinda es sobresaliente. –

+3

Tenga en cuenta que ** 'rb-appscript' es ** [** ya no es compatible con **, y no se recomienda para nuevos proyectos] (http://appscript.sourceforge.net/status.html). –

2

Respuesta corta: rb-appscript.

Porque Scripting Bridge parece ser un desastre y se ha suspendido RubyOSA.

+0

También lo tiene rb-appscript. (3 años en la pista). – Trejkaz

+0

Sí, por desgracia. Me encanta rb-appscript. – kch

Cuestiones relacionadas