Ruby library to read Apple Numbers documents? - ruby

There are several Ruby open-source libraries for reading Microsoft Excel files, such as roo or spreadsheet. What about Apple Numbers documents? Is there anything available?

Such a library apparently does not exist (yet?). A good workaround for now is to automate the conversion to CSV through applescript, and then read this result instead of trying to read the Numbers file directly. This might not fit everyone's needs, though, but works perfectly for me.
Here is the applescript:
# -------------------------------------------------------------------------------
# Command-line tool to convert an iWork '09 Numbers
# document to CSV.
#
# Parameters:
# - input: Numbers input file
# - output: CSV output file
#
# Attik System, Philippe Lang
#
# Creation date: 31 mai 2012
# Modification date:
# -------------------------------------------------------------------------------
on run argv
# We retreive the path of the script
set myPath to (path to me)
tell application "Finder" to set myFolder to folder of myPath
# We get the command line parameters
set input_file to item 1 of argv
set output_file to item 2 of argv
# We retreive the extension of the file
set theInfo to (info for (input_file))
set extname to name extension of (theInfo)
# Paths
set input_file_path to (myFolder as text) & input_file
set output_file_path to (myFolder as text) & output_file
if extname is equal to "numbers" then
tell application "Numbers"
open input_file_path
save document 1 as "LSDocumentTypeCSV" in output_file_path
close every window saving no
end tell
end if
end run
Use it like this:
osascript convert_to_csv.scpt input_file.numbers output_file.csv

Related

AppleScript Keynote hangup after opening a illegal pptx file

first I am a beginner AppleScript developer. and I have searched this question for a long time but no result found. I have an AppleScript to convert ppt files into pdf format. but the script will hangup after it matches a bad ppt file.
the script/keynote will popup a dialog showing "xxx.ppt can't be opened right now" "the file format is invalid".
is there any way to prevent keynote from popping up this kinds of dialog?
below is the sample code, and file is a image file but I changed extension to pptx to simulate an illegle file:
set thefile to POSIX file "/Users/dazhangluo/Downloads/brain-storming.pptx"
tell application "Keynote"
activate
try
set thedoc to open thefile
--display dialog class of thedoc
on error errMessage
--display dialog errMessage
log errorMessage
end try
end tell
There is a command-line tool called exiftool which can inspect files and get their metadata, including the 'file type' tag (using -filetype). There are a variety of ways to install it†. Unlike 'mdls', it isn't easily fooled by the file extension. If you run it on a pptx file, it will include this in its results:
File Type : PPTX
You can then grab the last word to test. This script will loop through the files in the specified folder, use exiftool to extract their file type, and then copy the alias of any matching file to a new list. It then opens each file in keynote. My version of keynote (v8) doesn't let me script anything with powerpoint documents, so you're on your own at that point.
set srcFol to (path to desktop as text) & "presentations" as alias
-- or if you prefer…
-- set srcFol to choose folder
tell application "Finder"
set fList to files of srcFol as alias list
set cleanList to {}
repeat with f in fList
set ppFile to POSIX path of f
set qfFile to quoted form of ppFile
tell me to set exifData to do shell script "/usr/local/bin/exiftool -filetype " & qfFile
if last word of exifData is "PPTX" then
set end of cleanList to contents of f
--> alias "Mac:Users:username:Desktop:presentations:powerpoint1.pptx"
end if
end repeat
end tell
tell application "Keynote"
activate
repeat with pptxFile in cleanList
open pptxFile
-- do whatever
end repeat
end tell
NB † Depending upon where exiftool is installed, you may need to change the path, which you can get with which exiftool.

Batch Convert *.numbers to *.csv AppleScript

I was looking for a script that would batch convert all *.numbers files in a given folder to *.csv files.
I found the following on GitHub and added an additional line as suggested in the comments suggestion. When I run the script, Numbers launches and opens the test file from the folder specified - but the file is not exported. Numbers just stays open and terminal errors out with:
/Users/Shared/Untitled.scpt: execution error: Numbers got an error: Invalid key form. (-10002)
The script (located in /Users/Shared) has the following permissions:
-rwxr-xr-x
#!/usr/bin/osascript
on run argv
set theFilePath to POSIX file (item 1 of argv)
set theFolder to theFilePath as alias
tell application "Finder" to set theDocs to theFolder's items
-- Avoid export privilege problem
set privilegeFile to (theFolder as text) & ".permission"
close access (open for access privilegeFile)
repeat with aDoc in theDocs
set docName to aDoc's name as text
if docName ends with ".numbers" then
set exportName to (theFolder as text) & docName
set exportName to exportName's text 1 thru -9
set exportName to (exportName & "csv")
tell application "Numbers"
open aDoc
delay 5 -- may need to adjust this higher
tell front document
export to file exportName as CSV
close
end tell
end tell
end if
end repeat
end run
Any suggestions?
Here is what I did and works for me in macOS High Sierra:
In Terminal:
touch numb2csv; open -e numb2csv; chmod +x numb2csv
• This creates an empty ASCII Text file named numb2csv.
• Opens, by default, numb2csv in TextEdit.
• Makes the numb2csv file executable.
Copy and paste the example AppleScript code, shown further below, into the opened numb2csv file.
Save and close the numb2csv file.
In Terminal executed the numb2csv executable file, e.g.:
./numb2csv "$HOME/Documents"
This created a CSV file of the same name as each Numbers document in my Documents folder, not traversing any nested folders.
Example AppleScript code:
#!/usr/bin/osascript
on run argv
set theFilePath to POSIX file (item 1 of argv)
set theFolder to theFilePath as alias
tell application "System Events" to set theDocs to theFolder's items whose name extension = "numbers"
repeat with aDoc in theDocs
set docName to aDoc's name as text
set exportName to (theFolder as text) & docName
set exportName to exportName's text 1 thru -8
set exportName to (exportName & "csv")
tell application "Numbers"
launch
open aDoc
repeat until exists document 1
delay 3
end repeat
tell front document
export to file exportName as CSV
close
end tell
end tell
end repeat
tell application "Numbers" to quit
end run
NOTE: As coded, this will overwrite an existing CSV file of the same name as each Numbers file processed, if they already exist. Additional coding required if wanting to not overwrite existing files
If you receive the Script Error:
Numbers got an error: The document “name” could not be exported as “name”. You don’t have permission.
It is my experience that the Numbers document was not fully opened prior to being exported and that increasing the value of the delay command resolves this issue. This is of course assuming that one actually has write permissions in the folder the target Numbers documents exists.
Or one can introduce an error handler within the tell front document block which, if my theory is right about the target document not being fully loaded before the export, will give additional time, e.g.:
Change:
tell front document
export to file exportName as CSV
close
end tell
To:
tell front document
try
export to file exportName as CSV
close
on error
delay 3
export to file exportName as CSV
close
end try
end tell
Note: The primary example AppleScript code is just that and does not contain any error handling as may be appropriate. The onus is upon the user to add any error handling as may be appropriate, needed or wanted. Have a look at the try statement and error statement in the AppleScript Language Guide. See also, Working with Errors. See included example directly above.
I was looking for that, unfortunately, that doesn’t work anymore.
This line
tell application "System Events" to set theDocs to theFolder's items whose name extension = "numbers"
Gets the following error:
execution error: Can’t make file "file.numbers" of application "System Events" into the expected type. (-1700)
macOs Big Sur Versio 11.01
automator version 2.10
Numbers version 10.3.5
Inspired by this thread and those articles Exporting Numbers Documents and Get full directory contents with AppleScript
The following code works:
#!/usr/bin/osascript
log "Start"
property exportFileExtension : "csv"
tell application "Finder"
activate
set sourceFolder to choose folder with prompt "Please select directory."
set fileList to name of every file of sourceFolder
end tell
set the defaultDestinationFolder to sourceFolder
repeat with documentName in fileList
log "documentName: " & documentName
set fullPath to (sourceFolder as text) & documentName
log "fullPath: " & fullPath
if documentName ends with ".numbers" then
set documentName to text 1 thru -9 of documentName
tell application "Finder"
set newExportItemName to documentName & "." & exportFileExtension
set incrementIndex to 1
repeat until not (exists document file newExportItemName of defaultDestinationFolder)
set newExportItemName to ¬
documentName & "-" & (incrementIndex as string) & "." & exportFileExtension
set incrementIndex to incrementIndex + 1
end repeat
end tell
set the targetFileHFSPath to ¬
(defaultDestinationFolder as string) & newExportItemName
tell application "Numbers"
launch
open fullPath
with timeout of 1200 seconds
export front document to file targetFileHFSPath as CSV
end timeout
close
end tell
end if
end repeat
user3439894's answer works with a few change:
exists document 1 => number of documents > 0

Applescript for batch-converting text delimited .txt to .xls

Each day, I'm delivered ~5 .txt data files delimited with "^". Manual steps taken to convert each to spreadsheet:
• Open .txt file in Excel
• Text-To-Columns
• Run through the delimiting wizard
Would love to have an applescript or applet to drop the 5 files into. A Google Sheets script would be even more magical. Thanks in advance for any guidance.
Sample data:
developer^project^lender^uuid^id^remarks^code^transfer_date
1500^1502^009^f1e97d20-b311-41cf-a40f-59db90b25ba8^73890^a10a46e8-bca8-4f0d-8938-8f2803a8bf90^9^2018-10-23 10:17:23.0
1500^1502^009^5dfc330d-0b9a-407d-a9e6-36895207b89e^74460^4a9c046a-a544-45b5-a627-f567b94f2b87^9^2018-10-23 10:17:25.0
1500^1502^009^d3295a4a-235d-4b9d-8775-5c079571193e^74901^de8f7b66-0c14-450f-8f29-c30c9a8329fa^9^2018-10-23 10:17:26.0
You'll need to change the file paths supplied at the start of the script inside the variable CSVFiles. The Excel file is saved in the same directory as the CSV file from which it sources its data, and uses the same filename, appending the extension ".xlsx" to it.
use Excel : application "Microsoft Excel"
use scripting additions
# Used to split the CSV data into columns
property text item delimiters : {"/", "^"}
# These represent the 5 CSV files you are sent on a given day
set CSVFiles to {¬
"/Users/CK/Desktop/sample.csv", ¬
"/Users/CK/Desktop/sample2.csv", ¬
"/Users/CK/Desktop/sample3.csv", ¬
"/Users/CK/Desktop/sample4.csv", ¬
"/Users/CK/Desktop/sample5.csv"}
repeat with fp in CSVFiles
try
# Make sure CSV file exists
fp as POSIX file as alias
on error
false
end try
set f to the result
if f ≠ false then
# Obtain directory and filename to use for saving Excel document
set [dirpath, filename] to [¬
text items 1 thru -2 of POSIX path of f as text, ¬
text item -1 of POSIX path of f]
# Read the CSV data into an array (list)
set CSVrows to paragraphs of (read f)
if the last item of CSVrows = "" then ¬
set CSVrows to items 1 thru -2 of CSVrows
repeat with r in CSVrows
set r's contents to text items of r
end repeat
set n to count CSVrows
set cellrange to "A1:H" & n
set colHrange to "H2:H" & n
# Create the Excel sheet
make Excel new document
set S to active sheet of window 1 of Excel
# Copy in CSV data
set value of range cellrange to CSVrows
# Format the last column to handle dates & times
set number format of range colHrange to "dd/mm/yyyy hh:mm:ss"
# Save & Close
save S in (dirpath & "/" & filename & ".xlsx")
Excel's (close front window)
end if
end repeat
If you had a dedicated folder into which you saved your newly received CSV files, then this line:
set CSVFiles to {¬
"/Users/CK/Desktop/sample.csv", ¬
"/Users/CK/Desktop/sample2.csv", ¬
"/Users/CK/Desktop/sample3.csv", ¬
"/Users/CK/Desktop/sample4.csv", ¬
"/Users/CK/Desktop/sample5.csv"}
could be replaced with this line:
tell app "System Events" to set CSVFiles to the POSIX path of ¬
every file in the folder named "/Path/To/Folder for CSV files" whose ¬
name extension = "CSV"
Then, all you'd need to do is remove yesterday's CSV files from that directory (you don't want them being processed a second time); transfer in today's CSV files; then execute the script.
Alternatively, as you stated in your question, you can create an applet onto which CSV files can be dropped and processed. This would be done via Automator.

OSX: How can check whether a file exists in current directory using applescript?

I want to make an automator app which creates an empty file in current directory.
I did some google search and found:
http://hints.macworld.com/article.php?story=20050219134457298 and http://hints.macworld.com/article.php?story=20100509134904820
However, I want to do something more powerful.
If the specified file already exists, I want to show a warning instead of overwriting the original file, which is what one of the above link does. (The other one creates a text file using textEdit. I do not want to create text file. I want an empty file like what linux/unix does)
I already figured out how to do most of the part, but
How can check whether a file exists in current directory using applescript??
How can I concatenate two variable in applescript?
Checking if a file exists (assuming thefullpath is already set as in the referenced question):
tell application "Finder"
if exists POSIX file thefullpath then
--do something here like
display alert "Warning: the file already exists"
end if
end tell
Not sure what you mean by the second part but if you want to concatenate strings stored in var1 and var2 you could simply do
var1 & var2
Something I have been using a lot of late for this sort of thing is the command /bin/test
The test test for the existence of in this case a file
if (do shell script "/bin/test -e " & quoted form of (POSIX path of theFile) & " ; echo $?") is "1" then
-- 1 is false
--do something
end if
The -e option:
-e file True if file exists (regardless of type).
The are tons of other test options shown in the /bin/test man page
The following code, adapted from your second link, is usually right, but it doesn't always work. The current directory is better specified as the directory of the document that is being opened which is most likely from the Finder's front window, but not necessarily. I like to write code that will work no matter what.
on run {input, parameters}
tell application "Finder"
set currentPath to insertion location as text
set x to POSIX path of currentPath
display dialog "currentPath: " & (x as text)
end tell
return x
end run
I wrote a whole "Run AppleScript" action to put things into context:
on run {input, parameters}
# count the number of files
set numFiles to 0
repeat with f in input
# warn the user that folders are not processed in this app
tell application "Finder"
if (kind of f is "Folder") then
display dialog "The item: " & (f as text) & " is a folder. Only files are allowed. Do you want to continue processing files or do you want to cancel?"
else
set numFiles to numFiles + 1
end if
end tell
end repeat
# require that at least one file is being opened
if numFiles < 1 then
display alert "Error: the application Test1.app cannot be run because it requires at least one file as input"
error number -128
end if
# get the current directory from the first file
set theFirstFile to (item 1 of input)
tell application "System Events" to set theFolder to (container of theFirstFile)
# ask the user for a file name
set thefilename to text returned of (display dialog "Create file named:" default answer "filename")
# create the file
tell application "System Events" to set thefullpath to (POSIX path of theFolder) & "/" & thefilename
set theCommand to "touch \"" & thefullpath & "\""
do shell script theCommand
# return the input as the output
return input
end run
The "touch" command is OK. If the file doesn't exist, it is created and if it does exist, only the modification date is changed (which isn't too bad) but it doesn't overwrite the file. If your file is being overwritten, it's not the touch command that is doing it.
I changed the default file name to remove the extension ".txt" This extension may default to being opened by TextEdit.app, but you can change this in the Finder by choosing "Get Info" for a file and changing the "Open With" property. You can change which application opens the file with that extension or you can change them all. For example, all of my ".txt" files are opened with BBEdit.app
Will you vote my answer up?
Another option that doesn't require Finder or System Events is to try to coerce a POSIX file or file object to an alias:
try
POSIX file "/tmp/test" as alias
true
on error
false
end try

Use Automator/Applescript to crop filenames after certain character?

I have a folder containing about 5000 files with names like:
Invoice 10.1 (2012) (Digital) (4-Attachments).pdf
Carbon Copy - Invoice No 02 (2010) (2 Copies) (Filed).pdf
01.Reciept #04 (Scanned-Copy).doc
I want to rename these files by removing everything from the first bracket onwards, so they look like this:
Invoice 10.1.pdf
Carbon Copy - Invoice No 02.pdf
01.Reciept #04.doc
I have found lots of scripts that will remove the last x letters, but nothing that will crop from a particular character.
Ideally I would like to use Automator, but I'm guess this might too complex for it. Any ideas?
Try:
set xxx to (choose folder)
tell application "Finder"
set yyy to every paragraph of (do shell script "ls " & POSIX path of xxx)
repeat with i from 1 to count of yyy
set theName to item i of yyy
set name of (file theName of xxx) to (do shell script "echo " & quoted form of theName & " | sed s'/ (.*)//'")
end repeat
end tell
The code posted by #adayzone will work, but there is no need to use sed for this – plain AppleScript will do, using offset:
set fullString to "Invoice 10.1 (2012) (Digital) (4-Attachments).pdf"
set trimmedString to text 1 thru ((offset of "(" in fullString) - 1) of fullString
-- trim trailing spaces
repeat while trimmedString ends with " "
set trimmedString to text 1 thru -2 of trimmedString
end repeat
this returns “Invoice 10.1". To split the file name into the name and extension, and re-add the extension, you can use System Events’ Disk-File-Folder suite, which will provide the handy name extension property you can store and re-add after trimming the name.
Assuming you use some Automator action to get the files to be processed, the full processing workflow would be to add an AppleScript action after the file selection part with the following code:
repeat with theFile in (input as list)
tell application "System Events"
set theFileAsDiskItem to disk item ((theFile as alias) as text)
set theFileExtension to name extension of theFileAsDiskItem
set fullString to name of theFileAsDiskItem
-- <insert code shown above here>
set name of theFileAsDiskItem to trimmedString & "." & theFileExtension
end tell
end repeat
If you want your Automator workflow to process the files any further, you will also have to create a list of aliases to the renamed files and return that from the AppleScript action (instead of input, which, of course, is not valid anymore).

Resources