9

Tôi đang cố gắng chuyển một số Bản tóm tắt cũ sang cú pháp JavaScript mới.Liệt kê tất cả các tệp trong một thư mục sử dụng JavaScript cho Tự động hóa trên Yosemite

Somethings dường như là khá thẳng về phía trước như vậy:

tell application "System Events" to keystroke "t" using command down 

trở thành:

System = Application('System Events'); 
System.keystroke("t", {using: "command down"}) 

Tuy nhiên tôi không thể cho cuộc sống của tôi làm việc ra làm thế nào để liệt kê các file tại một địa điểm cụ thể. Trong AppleScript, để trở về cho tôi một danh sách các tập tin trong thư mục /usr, bạn sẽ làm gì:

tell application "System Events" to set fileList to name of items in folder "/usr" 
-- > {"bin", "include", "lib", "libexec", "local", "sbin", "share", "standalone", "X11"} 

Tuy nhiên tôi không thể cho cuộc sống của tôi làm việc ra làm thế nào để làm điều đó trong Javascript.

System = Application('System Events') 
myPath = Path("/usr") 

fileList = System.items(myPath) 
-- > message not understood 

fileList = System.folder(myPath) 
-- > message not understood 

fileList = System.diskItems(myPath) 
-- > [] 

fileList = System.diskItems({at:myPath) 
-- > [] 

Tôi đã thử rất nhiều toàn bộ các kết hợp khác quá, nhưng không có may mắn. Bất kỳ ý tưởng?

Trả lời

13

Giống như Leopard's Scripting Bridge trước khi nó, JXA cố tình phá vỡ tất cả các loại công cụ hoạt động hoàn hảo trong AppleScript. Dưới đây là bản dịch của lệnh AppleScript ban đầu của bạn để cú pháp JXA:

//tell application "System Events" to name of items in folder "/usr" 
Application('System Events').folders.byName('/usr').items.name() 

Phiên bản AS hoạt động hoàn hảo, nhưng JXA tương đương chỉ ném một hoàn toàn vô nghĩa Error -1700: Can't convert types.

JXA dường như để làm việc nếu bạn viết diskItems thay của items:

Application('System Events').folders.byName('/usr').diskItems.name() 
// --> ["bin", "lib", "libexec", "local", "sbin", "share", "standalone", "X11", "X11R6"] 

điều này gợi ý JXA thỏa mãn trong nhiều cùng nội bộ "thông minh" gây SB để phá vỡ trên rất nhiều ứng dụng. (Lưu ý rằng tôi đã tìm thấy nhiều khiếm khuyết thiết kế như vậy trong thử nghiệm trước đó, nhưng đã từ bỏ báo cáo cho họ một khi rõ ràng AS dev chỉ quan tâm đến việc áp đặt tư tưởng và định kiến ​​cá nhân của họ lên mọi người khác, khả năng bị tê liệt và khả năng tương thích bị hỏng.)

để so sánh, đây là JavaScriptOSA (JOSA) prototype tôi nhanh chóng đặt lại với nhau để tham khảo các nhà phát triển JXA vài tháng trở lại (họ kịp thời bỏ qua nó, natch):

app('System Events').folders.named('/usr').items.name() 
// -> ["bin", "lib", "libexec", "local", "sbin", "share", "standalone", "X11", "X11R6"] 

(Mặc dù không hoàn toàn hoàn thành hoặc thử nghiệm, Josa vẫn hoạt động một chết tiệt nhìn tốt hơn JXA, được tài liệu tốt hơn, và thậm chí bao gồm một công cụ dịch tự động để chuyển đổi các lệnh AS thành cú pháp JS. Thật không may, bởi vì Apple có le gacied hoặc không chấp nhận các API Carbon AEM, CM, PM và OSA, tôi không thể khuyên dùng nó để sử dụng sản xuất; nó hoàn toàn có cho mục đích so sánh.)

Tương tự:

set myPath to POSIX file "/usr" 
tell application "System Events" to name of every disk item of folder named myPath 
--> {"bin", "lib", "libexec", "local", "sbin", "share", "standalone", "X11", "X11R6"} 

myPath = Path('/usr') 
Application('System Events').folders.byName(myPath).diskItems.name() 
// Error -1728: Can't get object. 

var myPath = Path('/usr') 
app('System Events').folders.named(myPath).diskItems.name() 
// --> ["bin", "lib", "libexec", "local", "sbin", "share", "standalone", "X11", "X11R6"] 

Bạn có thể làm việc xung quanh rằng trường hợp cụ thể bằng cách chuyển đổi các đối tượng đường dẫn đến một chuỗi, và sử dụng rằng:

myPath = Path('/usr') 
Application('System Events').folders.byName(myPath.toString()).diskItems.name() 

Mặc dù workaround rằng sẽ không nhất thiết phải giúp đỡ trong các tình huống khác; ví dụ. nó bị lỗi trong Finder vì Finder không hiểu chuỗi con đường POSIX-phong cách, và không có cách nào để có được một chuỗi đường dẫn HFS-style (mà Finder không hiểu) từ một đối tượng JXA Đường dẫn:

set myPath to POSIX file "/usr" 
tell application "Finder" to name of every item of item myPath 
--> {"X11", "X11R6", "bin", "lib", "libexec", "local", "sbin", "share", "standalone"} 

myPath = Path('/usr') 
Application('Finder').folders.byName(myPath.toString()).items.name() 
// Error -1728: Can't get object. 

Và như vậy nó đi. (Ví dụ Hãy thử kiểm tra hỗ trợ JXA cho phạm vi, lọc, tương đối, và chèn reference forms, nó đặc biệt thối.)

+0

Câu trả lời đáng kinh ngạc của Wow. Tôi đoán không có quá nhiều vấn đề trong việc thực hiện các thay đổi (items to diskItems) nếu nó làm cho mọi thứ dễ hiểu hơn (có thể cho là đúng trong trường hợp này) VÀ có tài liệu rõ ràng, rõ ràng về nó. Đó không phải là trường hợp nào cả (ít nhất là chưa, nó vẫn là một phiên bản beta - ông hy vọng). Điều đó nói rằng, nếu bạn sẽ thực hiện những thay đổi ngữ nghĩa như thế này thì chắc chắn một cái gì đó giống như Application ('Finder'). DiskItems ({atPath: path, return: "names", includeSubDirectories: true, excludeInvisibles: true) vv sẽ tạo ra rất nhiều ý nghĩa hơn, ít nhất là tôi. – dwkns

+0

JXA không thực hiện thay đổi để giúp mọi thứ dễ hiểu hơn; nó phá vỡ tính tương thích bởi vì các nhà phát triển của nó không thích và/hoặc hiểu cách IPC của Apple hoạt động. Các ứng dụng có thể đọc được [i] đã xác định tất cả các hành vi [/ i]. Là một khách hàng [i] của những ứng dụng đó, trách nhiệm của JXA là hỗ trợ những hành vi đó một cách đầy đủ và chính xác, không ném một sự phù hợp hissy chỉ vì nó xúc phạm niềm tin cá nhân của các nhà phát triển JXA. Đó là lái xe hậu trường bệnh lý, không có gì khác. – foo

+0

OK. Vì vậy, có cách nào để tìm ra phương pháp/thuộc tính nào thực sự áp dụng tại bất kỳ thời điểm nào. Tài liệu này không giúp ích gì nhiều cho vấn đề này. Tôi có thể tìm thấy trong ứng dụng tài liệu ('Sự kiện hệ thống'). Thư mục nhưng không có tham chiếu đến byName(). Và bạn dường như không thể xây dựng các lệnh một chút tại một thời điểm. Folders.byName ('/ usr') không trả lại bất cứ điều gì, vậy làm sao bạn biết để áp dụng .diskItems.name() cho nó? Bạn chỉ cần biết công cụ này? Hoặc làm thế nào để bạn làm việc nó ra? – dwkns

2

tôi có thể lấy nó như

foldersList = foldersList = System.folders.byName("usr").folders.name() 

này -> [ "bin", "lib", "libexec", "sbin", "chia sẻ", "độc lập", "X11"]

Và thậm chí làm việc này:

foldersList = System.folders.byName("/Users/USERName/Documents/").folders.name() 

nhưng tôi cho đến nay không thể có được lệnh Đường dẫn để làm việc trên bất cứ điều gì nhưng 'mở'

+0

@dwkns Đã làm một bản cập nhật nhỏ – markhunte

7

Cách tiếp cận "System Events" chắc chắn không có công đức của sự đơn giản, nhưng nó quay ra rằng việc sử dụng $.NSFileManager (nay là trực tiếp có sẵn cho kịch bản) cho hiệu năng nhanh hơn đáng kể.

Trên hệ thống của tôi, bắt đầu để so sánh với

var strPath = '/usr'; 

var appSys = Application('System Events'), 
lstHarvest = appSys.folders.byName(strPath).diskItems.name(); 

Một test nhanh với một vài ngàn lần lặp gợi ý rằng chúng ta luôn có thể tăng tốc độ nó lên bằng một khiêm tốn 40% với cách tiếp cận hơi baroque này:

var strPath = '/usr'; 
var fm = $.NSFileManager.defaultManager, 
    oURL = $.NSURL.fileURLWithPathIsDirectory(strPath, true), 
    lstFiles = ObjC.unwrap(
     fm.contentsOfDirectoryAtURLIncludingPropertiesForKeysOptionsError(
      oURL, [], 1 << 2, null 
     ) 
    ), 
    lstHarvest = []; 

lstFiles.forEach(function (oItem) { 
    lstHarvest.push(
     ObjC.unwrap(oItem.path) 
    ); 
}); 

và tốt hơn 300% với sự thay đơn giản:

var strPath = '/usr'; 
var fm = $.NSFileManager.defaultManager, 
    lstFiles = ObjC.unwrap(
     fm.contentsOfDirectoryAtPathError(strPath, null) 
    ), 
    lstHarvest = []; 

lstFiles.forEach(function (oItem) { 
    lstHarvest.push(
     ObjC.unwrap(oItem) 
    ); 
}); 
Các vấn đề liên quan