Saturday, October 19, 2019

#1 2019-03-13 12:40:42 am

ScriptLover
Member
Registered: 2018-09-04
Posts: 7

Script Doesn’t Work When Target App is Referenced by Variable

Hello,

I’m trying to write a script it takes a bunch of either xlsx, docx or pptx files, and converts each to a PDF using the appropriate iWork app (Numbers, Pages and Keynote, respectively). Here’s how it goes:

1. Files are dropped on to the script, or sent to it by Finder selection.
2. Each file is put in a JSON-like record, with the designated target app as a property.
3. Records are sorted (thanks, Nigel!) by the target app property, to make conversions more streamlined and to be able to close the target app once it’s done.
4. Everything works well, except for this very specific segment:

Applescript:


       export doc_id ¬
       to file ((source_parent & source_name & ".pdf") as text) ¬
       as PDF

It doesn’t even let me compile the script. If I put this block in and if-else clause, and based on the extension, explicitly refer to the app to handle the export, the script works well, e.g.:

Applescript:


if source_ext = "xlsx" or source_ext = "xls" then
    tell app "Numbers" to export doc_id --...

It has been driving me crazy! Help would be extremely appreciated.

Thanks!

Here’s the full script:

Applescript:



tell application "Finder"
   set thePaths to selection as alias list
end tell

set docs_to_process to {}
repeat with thePath in thePaths
   tell application "Finder"
       set source_parent to folder of thePath as text
       set source_path to thePath
       set source_ext to name extension of thePath
       set source_name to (name of thePath as text)
   end tell
   if source_ext = "xlsx" or source_ext = "xls" then
       set target_app to "Numbers"
   else if source_ext = "ppt" or source_ext = "pptx" then
       set target_app to "Keynote"
   else if source_ext = "docx" or source_ext = "doc" then
       set target_app to "Pages"
   end if
   set docs_to_process to docs_to_process & [{source_path:source_path, source_parent:source_parent, target_app:target_app, source_name:source_name}]
end repeat

customBubbleSort(docs_to_process, byTargetApp)

repeat with the_doc in docs_to_process
   if application target_app is running then
       set quitApp to false
   else
       set quitApp to true
   end if
   
   tell application target_app
       set doc_id to open thePath -- gives the the opened doc a 'document id'
       tell application "Finder"
           if (exists file (source_parent & source_name & ".pdf")) then
               set n to 1
               repeat while (exists file (source_parent & source_name & ".pdf"))
                   set source_name to source_name & space & n
                   set n to n + 1
               end repeat
           end if
       end tell
       --export doc_id ¬
       --to file ((source_parent & source_name & ".pdf") as text) ¬
       --as PDF
       close doc_id
       if quitApp is true then
           quit
       end if
   end tell
end repeat

on customBubbleSort(thelist, compObj)
   script o
       property lst : thelist
   end script
   
   repeat with i from (count thelist) to 2 by -1
       set a to beginning of o's lst
       repeat with j from 2 to i
           set b to item j of o's lst
           if (compObj's isGreater(a, b)) then
               set item (j - 1) of o's lst to b
               set item j of o's lst to a
           else
               set a to b
           end if
       end repeat
   end repeat
end customBubbleSort

script byTargetApp
   on isGreater(a, b)
       (a's target_app > b's target_app)
   end isGreater
end script


Filed under: Iwork

Offline

 

#2 2019-03-13 04:22:00 am

Nigel Garvey
Moderator
From:: Warwickshire, England
Registered: 2002-11-20
Posts: 5068

Re: Script Doesn’t Work When Target App is Referenced by Variable

ScriptLover wrote:

4. Everything works well, except for this very specific segment:

Applescript:


       export doc_id ¬
       to file ((source_parent & source_name & ".pdf") as text) ¬
       as PDF

It doesn’t even let me compile the script.


Hi.

The compiler needs to be able to identify the application in order to read its dictionary and find out how to compile 'export'. It can't do this if it's instead given a variable which won't be set until the script's run.

I think that Numbers, Keynote, and Pages use the same token for 'export', and their dictionary entries for it appear to be identical, so this may work for all three:

Applescript:

using terms from application "Numbers" -- also covers Keynote and Pages for 'export'.
   tell application target_app to export doc_id ¬
       to file ((source_parent & source_name & ".pdf") as text) ¬
       as PDF
end using terms from

'running', 'open', 'close', and 'quit' are common to all apps, which is why the compiler has no problem with them.

It's a good idea not to nest 'tell' blocks to different applications if this can be avoided, so your second repeat may be better arranged like this:

Applescript:

repeat with the_doc in docs_to_process
   set quitApp to (application target_app is not running)
   
   tell application "Finder"
       if (exists file (source_parent & source_name & ".pdf")) then
           set n to 1
           repeat while (exists file (source_parent & source_name & ".pdf"))
               set source_name to source_name & space & n
               set n to n + 1
           end repeat
       end if
   end tell
   
   using terms from application "Numbers" -- also covers Keynote and Pages for 'export'.
       tell application target_app
           set doc_id to (open thePath) -- gives the opened doc a 'document id'
           export doc_id ¬
               to file ((source_parent & source_name & ".pdf") as text) ¬
               as PDF            
           close doc_id
           if (quitApp) then
               quit
           end if
       end tell
   end using terms from
end repeat

Last edited by Nigel Garvey (2019-03-13 04:56:58 am)


NG

Offline

 

#3 2019-03-14 12:32:09 pm

ScriptLover
Member
Registered: 2018-09-04
Posts: 7

Re: Script Doesn’t Work When Target App is Referenced by Variable

Thanks for the quick reply, Nigel, but sadly your suggestion doesn’t work. Even with the ‘using terms from’ statement, the target app still has to be specified explicitly. Thanks also for the other suggestion, I’ve implemented that as well.

P. S. — Apparently the script was defective on a whole other level, in the last tell block, I forgot to refer specifically to the document’s (the one in the current iteration) properties (i.e. “the_doc’s source_path” instead of just “source_path”).

Offline

 

#4 2019-03-14 01:56:20 pm

Yvan Koenig
Member
Registered: 2006-09-14
Posts: 3596

Re: Script Doesn’t Work When Target App is Referenced by Variable

see below

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) jeudi 14 mars 2019 20:55:54

Last edited by Yvan Koenig (2019-03-15 05:18:01 am)

Online

 

#5 2019-03-15 02:37:11 am

Yvan Koenig
Member
Registered: 2006-09-14
Posts: 3596

Re: Script Doesn’t Work When Target App is Referenced by Variable

I'm not surprised that Using terms from doesn't solve the problem.
In raw format, the export instruction is coded :
«event Knstexpo» doc_id given «class kfil»:pathToPDF, «class exft»:«constant KnefKpdf» in Keynote terms,
«event Nmstexpo» doc_id given «class pfil»:pathToPDF, «class exft»:«constant NmefNpdf» in Numbers terms
«event Pgstexpo» doc_id given «class pfil»:pathToPDF, «class exft»:«constant PgefPpdf» in Pages terms.

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) vendredi 15 mars 2019 09:36:50

Online

 

#6 2019-03-15 03:16:25 am

Nigel Garvey
Moderator
From:: Warwickshire, England
Registered: 2002-11-20
Posts: 5068

Re: Script Doesn’t Work When Target App is Referenced by Variable

Yvan Koenig wrote:

In raw format, the export instruction is coded :


Ah. Thanks, Yvan. And now I look more closely at the applications' dictionaries, 'export' is in the individual suite for each of them, not in their iWork Suites.

Sorry for the bad guess, ScriptLover.  sad


NG

Offline

 

#7 2019-03-15 05:31:49 am

Yvan Koenig
Member
Registered: 2006-09-14
Posts: 3596

Re: Script Doesn’t Work When Target App is Referenced by Variable

When I tested I missed some points.
(1) On each test I passed a single file so I missed that the script missed to treat different files.
This required the addition of four instructions:

Applescript:

set thePath to the_doc's source_path # ADDED
set source_parent to the_doc's source_parent # ADDED
set target_app to the_doc's target_app # ADDED
set source_name to the_doc's source_name # ADDED

(2) When it tried to open the 2nd file, the instructions:
tell application target_app
    set doc_id to open thePath -- gives the the opened doc a 'document id'
end tell

were executed as :
tell application "Script Editor"
    open alias "SSD 500:Users:**********:Desktop:Address List to Merge.xls"
    open alias "SSD 500:Users:**********:Desktop:Address List to Merge.xls"
--> error "Erreur dans Numbers : L’application n’est pas ouverte." number -600

So I moved the open instruction in the piece of code dedicated to each application.

(3) The use of quitApp failed.
It appeared that the instruction defining quitApp must be in the code dedicated to each application too.

The resulting code is :

Applescript:

(*

https://macscripter.net/viewtopic.php?id=46774

*)


property theList : {{"pptx", "Keynote"}, {"ppt", "Keynote"}, {"xlsx", "Numbers"}, {"xls", "Numbers"}, {"docx", "Pages"}, {"doc", "Pages"}}

tell application "Finder"
   set thePaths to selection as alias list
end tell

set docs_to_process to {}
repeat with thePath in thePaths
   set source_path to contents of thePath
   tell application "Finder"
       set source_parent to folder of source_path as text
       set source_ext to name extension of source_path
   end tell
   repeat with i from 1 to count theList
       if source_ext = item 1 of my theList's item i then
           set target_app to item 2 of my theList's item i
           exit repeat
       end if
   end repeat
   
   copy {source_path:source_path, source_parent:source_parent, target_app:target_app} to end of docs_to_process
end repeat

customBubbleSort(docs_to_process, byTargetApp)

repeat with the_doc in docs_to_process
   
   set source_path to the_doc's source_path
   set source_parent to the_doc's source_parent
   set target_app to the_doc's target_app
   
   tell application "Finder"
       # Extract the filename here so there is no need to insert it in the list of records!
       set source_name to name of source_path
       if (exists file (source_parent & source_name & ".pdf")) then
           set n to 2
           repeat while (exists file (source_parent & source_name & space & n & ".pdf"))
               set n to n + 1
           end repeat
           set source_name to source_name & space & n
       end if
   end tell -- Finder
   
   set pathToPDF to (source_parent & source_name & ".pdf") as «class furl»
   
   if target_app = "Keynote" then
       set quitApp to not (application "Keynote" is running)
       tell application "Keynote"
           set doc_id to open source_path -- gives the the opened doc a 'document id'
           export doc_id to pathToPDF as PDF
           close doc_id
           if quitApp then
               quit
               delay 0.1
           end if
       end tell # "Keynote"
   else if target_app = "Numbers" then
       set quitApp to not (application "Numbers" is running)
       tell application "Numbers"
           set doc_id to open source_path -- gives the the opened doc a 'document id'
           export doc_id to pathToPDF as PDF
           close doc_id
           if quitApp then
               quit
               delay 0.1
           end if
       end tell # "Numbers"
   else if target_app = "Pages" then
       set quitApp to not (application "Pages" is running)
       tell application "Pages"
       if quitApp then activate # ADDED
           set doc_id to open source_path -- gives the the opened doc a 'document id'
           export doc_id to pathToPDF as PDF
           close doc_id
           if quitApp then
               quit
               delay 0.1
           end if
       end tell # "Pages"
   end if
end repeat

#=====

on customBubbleSort(theList, compObj)
   script o
       property lst : theList
   end script
   
   repeat with i from (count theList) to 2 by -1
       set a to beginning of o's lst
       repeat with j from 2 to i
           set b to item j of o's lst
           if (compObj's isGreater(a, b)) then
               set item (j - 1) of o's lst to b
               set item j of o's lst to a
           else
               set a to b
           end if
       end repeat
   end repeat
   --return thelist # Matter of taste, for my own use, I would activate this instruction
end customBubbleSort

script byTargetApp
   on isGreater(a, b)
       (a's target_app > b's target_app)
   end isGreater
end script

I tested with a selection containing : a .doc, a .docx, a .xls, a xlsx files
I have no .ppt files on my machine.

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) vendredi 15 mars 2019 12:31:11

Last edited by Yvan Koenig (2019-03-15 11:25:16 am)

Online

 

#8 2019-03-15 11:24:21 am

Yvan Koenig
Member
Registered: 2006-09-14
Posts: 3596

Re: Script Doesn’t Work When Target App is Referenced by Variable

Hello

I just discovered a curious behavior.
When the script quit once Pages, for the other documents using Pages, the open process is reported as :
tell application "Script Editor"
    open alias "SSD 500:Users:**********:Desktop:Demande Mr KOENIG Yvan.docx"
end tell
tell application "Pages"
    open alias "SSD 500:Users:**********:Desktop:Demande Mr KOENIG Yvan.docx"
        --> document id "532A0C67-491B-43E7-A95C-508C5630C113"
    export document id "532A0C67-491B-43E7-A95C-508C5630C113" to file "SSD 500:Users:**********:Desktop:Demande Mr KOENIG Yvan.docx 3.pdf" as PDF
    close document id "532A0C67-491B-43E7-A95C-508C5630C113"
    quit
end tell

The only way to get rid of that was to activate Pages before opening the document.
I edited the script above accordingly.

No need to do that with Numbers.
I don't know if it is needed for Keynote.
I will appreciate feedback about this point.

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) vendredi 15 mars 2019 18:24:11

Online

 

#9 2019-03-16 04:50:12 am

Yvan Koenig
Member
Registered: 2006-09-14
Posts: 3596

Re: Script Doesn’t Work When Target App is Referenced by Variable

I was bored by the fact that the script had to quit - restart the used app repeatedly so I decided to design an alternate scheme which finally appears to be neater.

Applescript:

(*

https://macscripter.net/viewtopic.php?id=46774

*)


tell application "Finder"
   set thePaths to selection as alias list
end tell

set docsForKeynote to {}
set docsForNumbers to {}
set docsForPages to {}

repeat with thePath in thePaths
   set source_path to contents of thePath
   tell application "Finder"
       set source_ext to name extension of source_path
   end tell
   
   if source_ext is in {"pptx", "ppt"} then
       copy source_path to end of docsForKeynote # Build a list of doc to treat with Keynote
   else if source_ext is in {"xlsx", "xls"} then
       copy source_path to end of docsForNumbers # Build a list of doc to treat with Numbers
   else if source_ext is in {"docx", "doc"} then
       copy source_path to end of docsForPages # Build a list of doc to treat with Pages
   end if
end repeat

set quitKeynote to not (application "Keynote" is running)
repeat with the_doc in docsForKeynote # Treat every pptx or ppt documents
   set pathToPDF to my buildPathToPDF(the_doc)
   tell application "Keynote"
       set doc_id to open the_doc -- gives the the opened doc a 'document id'
       export doc_id to pathToPDF as PDF
       close doc_id
   end tell # "Keynote"
end repeat
if quitKeynote then quit application "Keynote" # Quit only once if it's needed.
# If Keynote wasn't running on entry, now it's not running.

set quitNumbers to not (application "Numbers" is running)
repeat with the_doc in docsForNumbers # Treat every xlsx or xls documents
   set pathToPDF to my buildPathToPDF(the_doc)
   tell application "Numbers"
       set doc_id to open the_doc -- gives the the opened doc a 'document id'
       export doc_id to pathToPDF as PDF
       close doc_id
   end tell # "Numbers"
end repeat
if quitNumbers then quit application "Numbers" # Quit only once if it's needed.
# If Numbers wasn't running on entry, now it's not running.

set quitPages to not (application "Pages" is running)
repeat with the_doc in docsForPages # Treat every docx or doc documents
   set pathToPDF to my buildPathToPDF(the_doc)
   tell application "Pages"
       set doc_id to open the_doc -- gives the the opened doc a 'document id'
       export doc_id to pathToPDF as PDF
       close doc_id
   end tell # "Pages"
end repeat
if quitPages then quit application "Pages" # Quit only once if it's needed.
# If Pages wasn't running on entry, now it's not running.

#=====

on buildPathToPDF(source_path)
   local source_parent, source_name, n
   tell application "Finder"
       set source_parent to folder of source_path as text
       set source_name to name of source_path
       
       if exists file (source_parent & source_name & ".pdf") then
           set n to 2
           repeat while (exists file (source_parent & source_name & space & n & ".pdf"))
               set n to n + 1
           end repeat
           set source_name to source_name & space & n
       end if
   end tell -- Finder
   
   return (source_parent & source_name & ".pdf") as «class furl»
end buildPathToPDF

#=====

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) samedi 16 mars 2019 11:48:53

Last edited by Yvan Koenig (2019-03-16 06:22:12 am)

Online

 

#10 2019-03-19 12:26:51 am

ScriptLover
Member
Registered: 2018-09-04
Posts: 7

Re: Script Doesn’t Work When Target App is Referenced by Variable

Thanks Ivan, this indeed works and a similar version to what you’ve offered is what I’ve been using so far, but I’ve opened this discussion in hopes of finding a shorter, more elegant script. Guess there’s no way to avoid the final if-else clause.

Thanks!

Offline

 

Board footer

Powered by FluxBB

RSS (new topics) RSS (active topics)