Monday, November 20, 2017
  • Index
  •  » unScripted
  •  » Converting an AppleScript to Ruby using RB-Appscript

#1 2008-08-21 02:52:00 pm

Craig Williams
Administrator
From:: Ft. Smith, AR
Registered: 2006-12-07
Posts: 888

Converting an AppleScript to Ruby using RB-Appscript

Converting an AppleScript to Ruby using RB-Appscript

Edit: A few modification were made to clean up the code thanks to suggestions by has!

In this tutorial we will take one of my commonly used AppleScripts and re-write it in Ruby using rb-appscript.

For those who do not know, rb-appscript is a bridge to communicate with scriptable applications through Apple Events using Ruby. It was written by Hamish Sanderson who has also written bridges for Obj-C and Python. Appscript website

A few things before we get started.
1. rb-appscript does not come pre-installed on your mac.

Refer to this excellent article by Matt Neuburg. It spells out how to install rb-appscript and gives more detail about how rb-appscript works.
Installing rb-appscript


2. You will need an editor to write Ruby code.

A popular free editor is  TextWrangler by Barebones. My personal choice is TextMate by MacroMates. The snippets alone make this well worth the money. It is absolutely amazing what you can do with this program.


3. Get Ruby Beautifer for TextMate (if you are using TM)

You can read all about it at Ruby Beautifer website and for your convenience you can download it here.


.
   

Download the Ruby source file from this article
The Ruby source file is available  here.

self.everything_is_setup == 'OK' ? self.proceed.on : self.go_and_setup_rbappscript


The AppleScript to be transformed.
This is the AppleScript that we will transform into Ruby.

Applescript:


tell application "Finder"
   try
       set theSelection to the selection as alias list
   on error
       display dialog "You must have something selected." buttons {"OK"} default button 1
       error number -128
   end try
   set thePath to theSelection as alias
   set theChosenPath to button returned of (display dialog "HFS or POSIX." buttons {"POSIX", "HFS"} default button 2)
   if theChosenPath = "POSIX" then
       set the clipboard to "\"" & POSIX path of thePath & "\""
   else
       set the clipboard to "\"" & thePath & "\""
   end if
end tell

A short version of the Ruby code
The Ruby code is going to be much longer than the AppleScript equivalent above so some of you may be thinking, "Why would I write all that Ruby code when the AppleScript version is so much less!!" For this reason the next bit of Ruby code will produce the same results as above and it is written in a procedural way just as the AppleScript. For this article though we will be writing a class with methods and lots of comments. smile

require 'appscript'; include Appscript
require 'osax'; include OSAX
finder = app("Finder")

finder.activate
file_selection = finder.selection.get(:result_type => :alias)
if file_selection.size < 1 then osax.display_dialog("No item selected.", :buttons => ['OK']); exit end
hfs_posix = osax.display_dialog("What type of file path would you like?", :buttons => ['Cancel ', 'HFS', 'POSIX'], :default_button => 2)
exit if hfs_posix[:button_returned] == 'Cancel '
path_for_user = hfs_posix[:button_returned] == 'HFS' ? file_selection[0].hfs_path : file_selection
osax.set_the_clipboard_to("\"#{path_for_user}\"")


On to the code!
When writing Ruby code we need to include a few libraries and a 'SheBang' line.

#!/usr/bin/env ruby -w

require 'appscript'; include Appscript
require 'osax'; include OSAX


The first line, also known as a 'SheBang' line declares that this is a Ruby file and should be interpreted as such. It also gives the location where the system should look for Ruby. The two 'require' statements are loading in the appscript and osax libraries.

Class anyone?
We will wrap our Ruby script in a class. All of our code will go inside this class. This is very handy when you want to include this code in another application, script or share with the community.

class RetrieveFilePath
end


Initializer
The first bit of code we will add to the class is an initializer. I love initializers!
When the class gets called the first thing it does is process everything inside the initializer method.
This is where we set things up for our class.
When defining a method or handler in Ruby we use 'def' just like we would use 'on' or 'to' in AppleScript.

class RetrieveFilePath

    def initialize
      # Declare an instance variable @finder to hold a
      # reference to the Finder application.
      # An instance variable is available to all the
      # methods of this class.
      @finder = app("Finder")
    end

end


Method One => "Finder Selection"

# determine what if anything is selected in the Finder
# if so, get it's path. if not, exit.
def current_finder_selection()
  # Instead of saying "tell application "Finder" to activate"
  @finder.activate
  # Here we create an instance variable called @file_selection
  # It will hold an array of all the selected files. If only one
  # file is selected then it will hold an array of one.
  # Since it is an instance variable it will also be available
  # to our entire class without explicitly handing it to each method.
@file_selection = @finder.selection.get(:result_type => :alias)
  if @file_selection.size < 1 then
    osax.display_dialog("No item selected.", :buttons => ['OK'])
    exit
  else

    # Now that we know there is an item selected
    # ask the user what type of file path they want.
    # Below the 'self' prefixing the method call is optional
    # but imho it is clearer what the code is doing
    file_type = self.hfs_posix_dialog()
    path_for_user = self.return_file_type(file_type)
    osax.set_the_clipboard_to("\"#{path_for_user}\"")
  end
end


Method Two => "File Type Dialog"

# Ask user which file path type to return
# One thing to note here is the 'Cancel ' button
# It has an extra space after the name. Without this
# space you will get an error when the button is clicked.
def hfs_posix_dialog()
  hfs_posix = osax.display_dialog("What type of file path would you like?",
  :buttons => ['Cancel ', 'HFS', 'POSIX'],
  :default_button => 2)
  exit if hfs_posix[:button_returned] == 'Cancel '
  return hfs_posix[:button_returned]
end


Method Three => "Return File Type"

# Return to the user the type of path requested
# Here we are using a ternary expression which is
# just a compact 'if else' statement which reads
# if hfs_posix is equal to 'HFS' then create the hfs type and if not return the posix type
def return_file_type(hfs_posix)
  return hfs_posix == 'HFS' ? @file_selection[0].hfs_path : @file_selection
end


The last step
The last thing we need to do to be able to run this script is add the following
to the bottom of the file after the end of the class declaration.

# This says that if this script is being executed then do the following.
# We create a new instance of the RetrieveFilePath class by calling 'new' method.
# If we were including this code in another script it would not execute this code.
if __FILE__ == $0
  # Create an instance of our class and execute the current_finder_selection() method
  file_path = RetrieveFilePath.new
  file_path.current_finder_selection()
end


Here is the full code without comments

#!/usr/bin/env ruby -w

require 'appscript'; include Appscript
require 'osax'; include OSAX

class RetrieveFilePath

  def initialize
    @finder = app("Finder")
  end

  def current_finder_selection()
    @finder.activate
    @file_selection = @finder.selection.get(:result_type => :alias)
    if @file_selection.size < 1 then
      osax.display_dialog("No item selected.", :buttons => ['OK'])
      exit
    else
      file_type = self.hfs_posix_dialog()
      path_for_user = self.return_file_type(file_type)
      osax.set_the_clipboard_to("\"#{path_for_user}\"")
    end
  end

  def hfs_posix_dialog()
    hfs_posix = osax.display_dialog("What type of file path would you like?",
    :buttons => ['Cancel ', 'HFS', 'POSIX'],
    :default_button => 2)
    if hfs_posix[:button_returned] == 'Cancel ' then exit end
    return hfs_posix[:button_returned]
  end

  def return_file_type(hfs_posix)
    return hfs_posix == 'HFS' ? @file_selection[0].hfs_path : @file_selection
  end
 
end # end class


if __FILE__ == $0
  file_path = RetrieveFilePath.new
  file_path.current_finder_selection()
end


Some exciting things about Ruby
Just to name a few and in no particular order.

1. Regular expressions
2. Arrays
3. Hashes
4. Case statements
5. Html, Xml libraries
6. MySql, Sqlite libraries
7. And soooo much more!


Wrap up
If you have been hesitant to try out Ruby and rb-appscript then I hope this will
encourage you to take it for a spin!

Until next time. Happy coding!

Offline

 
  • Index
  •  » unScripted
  •  » Converting an AppleScript to Ruby using RB-Appscript

Board footer

Powered by FluxBB

RSS (new topics) RSS (active topics)