Pass Multiple Applescript Variables to Ruby - ruby

I'm working on a Ruby script that requires some variables from Applescript. Right now I'm having success grabbing them one at a time, but it seems inelegant and possibly slow. For example:
note = %x{ osascript <<APPLESCRIPT
tell application "Evernote"
if selection is not {} then
set the_selection to selection
if notebook of item 1 of the_selection is (notebook named "Writing") then
return HTML content of item 1 of the_selection
end if
else
return ""
end if
end tell
APPLESCRIPT}
title = %x{ osascript <<APPLESCRIPT
tell application "Evernote"
if selection is not {} then
set the_selection to selection
if notebook of item 1 of the_selection is (notebook named "Writing") then
return title of item 1 of the_selection
end if
else
return ""
end if
end tell
APPLESCRIPT}
I know I'm probably overlooking something obvious, but is there an easy way I can do this with just a single snippet of Applescript that returns both variables into Ruby (note, title)?

Getting multiple values out of AppleScript is the easy part. Instead of returning a single value, return a list:
result = %x{ osascript <<APPLESCRIPT
tell application "Evernote"
if selection is not {} then
set the_selection to selection
if notebook of item 1 of the_selection is (notebook named "Writing") then
set title to title of item 1 of the_selection
set html to HTML content of item 1 of the_selection
return { title, html }
end if
else
return ""
end if
end tell
APPLESCRIPT}
The hard part is parsing the output. Supposing your title is This is a note and html is <h1>Hello World</h1>, osascript will return this:
This is a note, <h1>Hello World</h1>
You could split it on the , but if title happens to contain a comma, you've got a problem. You can also pass the -ss option to osascript, which makes it return formatted AppleScript objects, but you don't want to have to write your own AppleScript parser in Ruby.
An alternative, if you know title will never contain a line break, is to put a line break after the title:
result = %x{ osascript <<APPLESCRIPT
...
if notebook of item 1 of the_selection is (notebook named "Writing") then
set title to title of item 1 of the_selection
set html to HTML content of item 1 of the_selection
return title & "\n" & html
end if
...
APPLESCRIPT}.chomp
Now the output (result) will look like this:
This is a note
<h1>Hello World</h1>
...and you can get the title and HTML like this:
title, html = result.split("\n", 2)
puts title
# => This is a note
puts html
# => <h1>Hello World</h1>
Now, if you have line breaks in any of your titles (I can't remember if Evernote allows that or not), or if you want to return more than two values, this will be problematic as well. The next simplest solution would be to choose some kind of delimiter that's unlikely to appear in any part of the output, for example %!%:
DELIMITER = '%!%'
result = %x{ osascript <<APPLESCRIPT
...
if notebook of item 1 of the_selection is (notebook named "Writing") then
set title to title of item 1 of the_selection
set html to HTML content of item 1 of the_selection
return title & "#{DELIMITER}" & html
end if
...
APPLESCRIPT}.chomp
# =>This is a note%!%<h1>Hello World</h1>
title, html = result.split(DELIMITER, 2)
If all else fails, you could use an addon to make osascript output a known format that Ruby knows how to parse. Just now I found this free JSON Helper that looks pretty handy.

Related

AppleScript read data every few minutes

I run a screen which display some data on the menu bar
the variables are taken from "~/Desktop/_MyData.plist"
everything work fine, however when the data change on _MyData.plist
How, can I make the script getting the new data ? I guess we can't expect AppleScript to detect file change and then run the script but is there a way to get the plist data on idle maybe and keeping running the whole script.
Here is the part that only getting the data :
property theAccountNumberFromPlist : ""
property SNNumber : ""
property appName : ""
property devicesID : ""
property domainEMAIL : ""
property fullEmail : ""
property purchaseDate : ""
property thename : ""
property theList : ""
set the plistfile_path to "~/Desktop/_MyData.plist.plist"
tell application "System Events"
set p_list to property list file (plistfile_path)
-- read the plist data
set theAccountNumberFromPlist to value of property list item "AccountNumber" of p_list as text
set SNNumber to value of property list item "SNNUMBER" of p_list as text
set appName to value of property list item "appName" of p_list as text
set devicesID to value of property list item "devicesID" of p_list as text
set domainEMAIL to value of property list item "domainEMAIL" of p_list as text
set fullEmail to value of property list item "fullEmail" of p_list as text
set purchaseDate to value of property list item "purchaseDate" of p_list as text
set thename to value of property list item "thename" of p_list as text
end tell
Here is the whole script :
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
property StatusItem : missing value
property selectedMenu : ""
property theDisplay : ""
property defaults : class "NSUserDefaults"
property internalMenuItem : class "NSMenuItem"
property externalMenuItem : class "NSMenuItem"
property newMenu : class "NSMenu"
property theAccountNumberFromPlist : ""
property SNNumber : ""
property appName : ""
property devicesID : ""
property domainEMAIL : ""
property fullEmail : ""
property purchaseDate : ""
property thename : ""
property theList : ""
set the plistfile_path to "~/Desktop/_MyData.plist.plist"
tell application "System Events"
set p_list to property list file (plistfile_path)
-- read the plist data
set theAccountNumberFromPlist to value of property list item "AccountNumber" of p_list as text
set SNNumber to value of property list item "SNNUMBER" of p_list as text
set appName to value of property list item "appName" of p_list as text
set devicesID to value of property list item "devicesID" of p_list as text
set domainEMAIL to value of property list item "domainEMAIL" of p_list as text
set fullEmail to value of property list item "fullEmail" of p_list as text
set purchaseDate to value of property list item "purchaseDate" of p_list as text
set thename to value of property list item "thename" of p_list as text
end tell
if not (current application's NSThread's isMainThread()) as boolean then
display alert "This script must be run from the main thread." buttons {"Cancel"} as critical
error number -128
end if
on menuNeedsUpdate:(menu)
my makeMenus()
end menuNeedsUpdate:
on makeMenus()
newMenu's removeAllItems()
repeat with i from 1 to number of items in someListInstances
set this_item to item i of someListInstances
set thisMenuItem to (current application's NSMenuItem's alloc()'s initWithTitle:this_item action:"someAction:" keyEquivalent:"")
(newMenu's addItem:thisMenuItem)
(thisMenuItem's setTarget:me) -- required for enabling the menu item
if i is equal to 3 then
(newMenu's addItem:(current application's NSMenuItem's separatorItem)) -- add a seperator
end if
end repeat
end makeMenus
on someAction:sender
--MenuItem
end someAction:
-- create an NSStatusBar
on makeStatusBar()
set bar to current application's NSStatusBar's systemStatusBar
set StatusItem to bar's statusItemWithLength:-1.0
-- set up the initial NSStatusBars title
StatusItem's setTitle:(theAccountNumberFromPlist & " " & thename & " " & fullEmail & " " & SNNumber & " " & appName)
-- set up the initial NSMenu of the statusbar
set newMenu to current application's NSMenu's alloc()'s initWithTitle:"Custom"
newMenu's setDelegate:me (*
*)
StatusItem's setMenu:newMenu
end makeStatusBar
my makeStatusBar()
Make use of an idle handler.
on idle
-- do your stuff
return 5 -- idle handler will be executed again in 5 seconds.
end
Therefore you need to save your script as application. Here's the essential part from apples docs:
idle and quit Handlers for Stay-Open Applications
By default, a script application that receives a run or open command
handles that single command and then quits. In contrast, a stay-open
script application (one saved as Stay Open in Script Editor) stays
open after it is launched.
A stay-open script application can be useful for several reasons:
Stay-open script applications can receive and handle other commands in
addition to run and open. This allows you to use a script application
as a script server that, when it is running, provides a collection of
handlers that can be invoked by any other script.
Stay-open script applications can perform periodic actions, even in
the background, as long as the script application is running.
Two particular handlers that stay-open script applications often
provide are an idle handler and a quit handler.
idle Handlers
If a stay-open script application includes an idle handler,
AppleScript sends the script application periodic idle commands—by
default, every 30 seconds—allowing it to perform background tasks when
it is not performing other actions.
If an idle handler returns a positive number, that number becomes the
rate (in seconds) at which the handler is called. If the handler
returns a non-numeric value, the rate is not changed. You can return 0
to maintain the default delay of 30 seconds.
For example, when saved as a stay-open application, the following
script beeps every 5 seconds:
on idle
    beep
    return 5
end idle
The result returned from a handler is just the result of the last statement, even if it doesn’t include the word return explicitly.

Logic not working with List items in Applescript

This is a very strange problem I could not understand it, the code is very clear as you can see, I don't know if I am tired or could not see something... please tell me why I am getting False as a result, while it should be True, I have a list with one item and it is the exact one in the variable
thanks
property forbidenFolders : {"/Volumes/USERS/"}
set ff to "/Volumes/USERS/" as text
my isForbidenFolder(ff)
on isForbidenFolder(SelectedFolder)
repeat with i in forbidenFolders
log "forbiden folders: " & i
log "actual folder : " & SelectedFolder
if i = SelectedFolder then
log "this folder is forbiden"
return true
end if
end repeat
log "NOT forbiden"
return false
end isForbidenFolder
result here
That's the reference trap.
The syntax repeat with item in list iterates thru the list with references e.g. a reference to item 1 of list, a reference to item 2 of list etc. rather than the item itself.
To be able to check for equality you have to dereference the item using contents of
if contents of i = SelectedFolder then
When i is set to the item of a list in a repeat loop, you are getting a reference to the item. You need to coerce it into a string for your comparison.
if (i as string) = SelectedFolder

Applescript and empty mail signature / input in value list

I have two questions with my applescript. The script is supposed to send a dropped file as attachment by email and asking the object of the mail from a list.
The content of the message MUST be empty.
1) How to set an "empty" email signature because the content of my mail should be empty. I receive an error code "error in mail impossible to solve signature..."
2) I wish that the user can modify the value list {"00111111111111-number1, "0011111111111-number2"...} and add more numbers. What is the best approach to do this ?
Thanks very much in advance for your suggestions.
property theSubject : "subject"
property theNumber : ""
property theContent : ""
property theSignature : "none"
property onRun : ""
on run
tell application "Finder"
set sel to (get selection)
end tell
set onRun to 1
new_mail(sel)
end run
on open droppedFiles
new_mail(droppedFiles)
end open
on new_mail(theFiles)
set chosen to choose from list {"0011111111111-number1", "0011111111111-number2"} with prompt "Thanks to select"
if chosen is false then return "" -- in case of 'Cancel' return empty string
set theNumber to text 1 thru 13 of (item 1 of chosen) -- as chosen returns a list by default it must be flattened
tell application "Mail"
set newMessage to make new outgoing message with properties {visible:true, subject:theNumber}
tell newMessage
make new to recipient with properties {address:faxboxEmail}
if onRun < 1 then
make new attachment with properties {file name:theFiles as alias} at after last paragraph
end if
set the content to theContent
set message signature of newMessage to signature theSignature
end tell
activate
if onRun < 1 then
send
end if
end tell
end new_mail
to add new item in the list, may be this could help you ?
set BaseList to {"0011111111111-number1", "0011111111111-number2"}
set CList to BaseList & {"Add new item"}
set chosen to choose from list CList with prompt "Thanks to select"
if chosen is false then return "" -- in case of 'Cancel' return empty string
if "Add new item" is in chosen then
set OKNew to false
repeat until OKNew
set NewItem to display dialog "Enter new value :" default answer ""
set OKNew to (button returned of NewItem is "OK") and (text returned of NewItem is not "")
set theNumber to text returned of NewItem
set BaseList to baseList & {theNumber} -- to add the new item in the BaseList
end repeat
else
set theNumber to text 1 thru 13 of (item 1 of chosen) -- as chosen returns a list by default it must be flattened
end if
I also experienced some issues with the signature and the attachement together. if you remove the line "make new attachment..." the signature line is working. Also if you move the signature line before the attachement line, and make a break before the attachement, the signature will be OK. bug ?
Then, based on my tests, if you do not want signature at all, just delete the line "set message signature..." by default, no signature will be set.
My last comment is to reduce your script by adding the content directly in property list of the "make new outgoing message..."
tell application "Mail"
set newMessage to make new outgoing message with properties {visible:true, subject:TheNumber, content:TheContent}
tell newMessage
make new to recipient with properties {address:faxboxmail}
if onRun > 1 then
make new attachment with properties {file name:theFile as alias} at after last paragraph
end if
end tell
activate
end tell
I tried it, and it is creates mail with no content and no signature as expected (Mail 8.2)

List directory with custom name applescript

I am looking for a way to display this list with a few custom tags.
Could anybody help me out? I only found this script and is very useful to me if I could alter a few parameters. However I have zero applescript experience.
I would like to have img, description and title as extra variable.
So the output would look like this: ( I will fill in title & description in later ofc. )
{
"title": "",
"gallery": [
{
"img": "101.jpg",
"title": "",
"description": ""
},
{
"img": "102.jpg",
"title": "",
"description": ""
}
]
}
etc for all images in that folder
Please find the script that outputs me my content of a chosen folder as an array. which outputs now as {"P1000443.JPG", "P1000444.JPG"}
tell application "Finder"
set file_list to name of every file of entire contents of (choose folder with prompt "Please select directory.")
end tell
Thanks!
What you're asking is complicated so let me get you started. Run this script, choose a file, and look at the results.
set aFile to choose file
tell application "Finder" to return properties of aFile
You will see all of the properties you can get from a file. Right now in your code you are asking only for the "name" property so you'll have to figure out what properties you want and ask for them in a similar manner as you have asked for the name. Then you'll have to convert all of that information into a nice organized list as you request... that's the difficult part. If you want something that you can't find in the properties then you'll have to figure out how to get that information in another way, for example "description".
EDIT: Based on your comment, I suggest you just use a repeat loop and create a string any way you want. Here's one example. You can use this technique to create the output in any format you want.
set file_list to {"P1000443.JPG", "P1000444.JPG"}
set outputString to ""
repeat with i from 1 to count of file_list
set outputString to outputString & "img: " & item i of file_list & return & "title: " & return & "description: " & return & return
end repeat
return outputString
The output based on the way I formatted it will look like this...
img: P1000443.JPG
title:
description:
img: P1000444.JPG
title:
description:
Good luck.

Why does this throw up an error?

tell application "VoodooPad"
tell document 1
repeat with thisPage from 1 to number of items in pages
set theName to display name of page thisPage
set creationDate to created of page thisPage
set theText to text of page thisPage
tell application "Evernote"
create note with text theText title theName notebook "VoodooPad Imported Notes" tags "imported_from_VoodooPad" created creationDate
end tell
end repeat
end tell
end tell
This produces the following error:
error "VoodooPad got an error: every item of every page of document 1 doesn’t understand the count message." number -1708 from every item of every page of document 1
Any Idea on how to get the script to run?
Try this:
set allPages to pages as list // now you have items in a list
repeat with thisPage from 1 to number of items in allPages
...

Resources