TweetFollow Us on Twitter

An Editor to Create DropScript Droplets

Volume Number: 19 (2003)
Issue Number: 5
Column Tag: Programming

An Editor to Create DropScript Droplets

Making the DropScript experience more like the MacPerl experience

by Larry Taylor

A Problem

I love MacPerl. I even wrote an article for MacTech extolling its virtues (Sept. 2000). MacPerl is a Mac port of Perl, initially a UNIX scripting language. Being UNIX based, OS X comes with a Perl implementation and there have been many excellent MacTech articles recently touting its uses. Rich Morin has a whole series (Aug. & Sept. 2002, Jan. 2003); Jeff Clites (April 2000), Paul Ammann (June 2002) and Joe Zobkiw (Sept. 2002) have articles as well. By the time this appears, there will undoubtedly be more. The basic idea is simple. Write a Perl script to do something useful, make the file executable, set it to be opened by the Terminal application and you're ready to go. Double click on the file and the Perl script runs, just like simple droplets in MacPerl.

However many scripts process files or folders. The great thing about a MacPerl droplet is that you can drag the files/folders onto it and get the path names of the dropped collection in the @ARGV array. My article depended on this behavior and I really miss it in OS X.

Then Wilfredo Sanchez wrote a program called DropScript to make droplets. He wrote a nice MacTech article (Aug. 2001) about it. Additional information can be found in the README file in the examples folder that comes with the DropScript distribution. DropScript can make droplets to run Bourne shell scripts, the case Sanchez concentrates on, or Perl scripts, tcl scripts, Python scripts ... . Just set the shebang line correctly and you're off.

My main gripe with DropScript comes from my bad habit of coding quickly. Every time I changed the code I had to re-run the file through DropScript and, if I forgot to delete the old droplet, I was merely informed that the droplet existed and I had to go back, delete the old droplet and run my file through DropScript yet again. Not an appealing scenario! Using MacPerl you just opened the droplet in MacPerl, typed in your new code, saved it and the behavior of the droplet reflected your changes immediately.

A second issue is the end-of-line problem. DropScript expects the scripts dropped on it to have UNIX end-of-lines, \n, whereas it is notoriously easy to be using a file with Mac end-of-lines, \r. TextEdit or BBEdit will save files as 'TEXT' with UNIX eol's once you have such a file and BBEdit will even convert an old Mac file for you, so the issue is not serious as long as you remember to do the switch.

A Solution

Reading Sanchez's article more carefully I realized that these droplets were applications and applications are folders under OS X. You can see the folder by option-clicking the app and selecting Show Package Contents from the contextual menu. Your application opens as a folder which contains a single folder called Contents, and DropScript copies the script to the file /Contents/Resources/script. Experimentation showed that I could edit this file directly and run the new code without going through DropScript again and the eol-problem took care of itself.

Eventually it occurred to me that I could write a droplet-Perl-script to avoid the option-click process, hence Droplet Editor, the focus of this article. Drop a droplet onto Droplet Editor and the script file is opened. Droplet Editor also supports making a new droplet.

First Steps

Since Droplet Editor itself is a droplet, we are going to begin with a minimal version of the code and then use it to finish the whole project. Step one is to acquire DropScript from

www.apple.com/downloads/macosx/unix_open_source/dropscript.html

and put the application somewhere - it needs no installer. I put mine in a folder DropScript inside my Applications folder, but it doesn't have to go there. Make a copy of the program, rename it Droplet Editor and put it anywhere you have read/write permissions. Now option-click Droplet Editor and select Show Package Contents from the contextual menu. Open the Contents folder and then the Resources folder. Open the file script in BBEdit or TextEdit by dragging it to the dock onto one of these apps.

Delete the code currently in the file and enter the following code.

#!/usr/bin/perl
use strict;
#############  Fixed paths #############
my($editor_path)="/Applications/BBEdit/BBEdit.app";
my($emulator_path)="/Contents/Resources/script";
my($aa);
foreach $aa (@ARGV){
  if( $aa=~m/\.app$/ && -f $aa.$emulator_path) {
    my($app)=substr($aa,rindex($aa,"/")+1);
    print"Opening the script for \"$app\".\n";
    $aa=$aa.$emulator_path;
    system("open -a \"$editor_path\" \"$aa\"");
    }
  }

If your editor of choice is located elsewhere, change the $editor_path. Save your text and close the file. Add Droplet Editor to the dock. Track down and open the Console program, usually in /Applications/Utilities/, since messages from droplets show up here. Now drag the Droplet Editor application onto its icon in the dock and your file will pop open in BBEdit or to whatever word processor your $editor_path points. If you drop any other droplet onto Droplet Editor the script for that droplet opens. If you have errors in this initial Droplet Editor script, the error messages show up in the Console window. Reopen the script the hard way and fix the errors. Repeat as needed until the script opens.

Completing the Project

The rest of the project involves adding bells and whistles to this basic code, especially the mechanism to create new droplets. We do this by treating the drop of anything that is not a droplet as a request to make a new droplet, named after the dropped object. If you drop a file or a folder named foo which is not a droplet, you get a new droplet, Dropfoo, in the same folder as the file or inside the folder. This bit of the project is handled by a subroutine make_basic_droplet which takes two arguments, the folder in which to put the new droplet and its name. You can set the extension of the dropped object to specify what sort of script you want as indicated below.

First add the path to your copy of DropScript to the "Fixed paths" list.

my($dropscript_path)="/Applications/DropScript/DropScript.app";
At the bottom of the foreach-loop add the following two elsif's:
  elsif( -d $aa) {
    my($name)=substr($aa,rindex($aa,"/")+1);
    make_basic_droplet($aa,$name);
    }
  elsif( -f $aa) { 
    my($dir)=substr($aa,0,rindex($aa,"/"));
    my($name)=substr($aa,rindex($aa,"/")+1);
    make_basic_droplet($dir,$name);
    }

This finishes the project except for writing the code for the subroutine. Begin with three lines.

sub make_basic_droplet{
my($dir)=shift(@_);
my($name)=shift(@_);

Next we determine the type of script being requested. The next four lines extract the extension of the dropped object and do some checking. If the eventual name of the script would start with a period, which would make the resulting droplet invisible, we bail.

my($script_type);
if( $name=~s/(\.[^\.]*)$//) {$script_type=$1;} 
else {$script_type='.default';}
if($name eq "") {return;}

Next we want to determine if we recognize the extension. We begin by building a list of extensions we recognize. Return to the top of the file and just after the "Fixed paths" add some lines

################# Script types #################
my(%script_type);
$script_type{'.default'}="#!/usr/bin/perl";
$script_type{'.perl'}="#!/usr/bin/perl";
$script_type{'.py'}="#!/usr/bin/python";
$script_type{'.sh'}="#!/bin/sh";
$script_type{'.tcl'}="#!/usr/bin/tclsh";
##################################

The first line is required; the rest are optional. I mostly write Perl scripts so my ".default" script_type is the Perl shebang line, but I have included extensions for Bourne shell scripts, ".sh", Python scripts, ".py" and tcl scripts, ".tcl". If the dropped file/folder has a recognized extension, the shebang line in the new script will be the corresponding %script_type. A non-recognized extension, including no extension, defaults to ".default". You are of course free to add/delete/modify these entries to suit your needs. As an example, if you always use the -w flag in Perl you might want to change the '.perl' entry to $script_type{'.perl'}="#!/usr/bin/perl -w";

Now return to the bottom of the file and add the line

if( !exists($script_type{$script_type})) {$script_type='.default';}

which sets the variable $script_type to either ".default" or the dropped object's extension if we recognize it. Then add ten more lines which construct the droplet name and check that the name isn't in use. If it is we just keep adding a number to the name until we get a name with no conflicts. This prevents accidental destruction of files, but if you never make such mistakes, skip the nine lines beginning "if( -d ...".

my($aa)=$dir."/Drop".$name.".app";
if( -d $aa) {
  print"\n\nThere already is a droplet \"Drop",$name,"\".\n\n";
  my($nextname)=1;
  my($Name)=$name;
  while( -d $aa) {
    $name=$Name.$nextname;
    $aa=$dir."/Drop".$name.".app";$nextname++;
    }
  }

DropScript is expecting a file to copy into the new droplet, so next we produce the required file. If there already is a script file then we read it into the @script array and change any Mac eol's to UNIX ones, avoiding any eol-problems. If there is not already a script file we just set @script to put in a couple of UNIX eol's. Then we write a file, $outfile, which DropScript will copy into the droplet. If you already had a script with a shebang line, you now start with two. We do this because Apple does not always put programs like Perl in their standard places so if you are porting a Perl script, its shebang line is probably wrong. However, it may have flags you will need to copy so it's nice to see what the old one was.

my($outfile)=$dir."/".$name.$script_type;
my(@script);
if( -f $outfile) {
  open(IN,$outfile) or die($!);
  @script=<IN>;
  close(IN);
  my($xx);
  foreach $xx (@script) {$xx=~s/\r/\n/g;}
  }
else {push(@script,"\n\n");}
$outfile=$dir."/".$name.".default";
open(OUT,">$outfile") or die($!);
print OUT $script_type{$script_type},"\n";
print OUT @script;
close(OUT);
undef(@script);

The next step tells DropScript to make the droplet and announces the birth.

system("open -a \"$dropscript_path\"  \"$outfile\"");
print"\n\nCreating new droplet: \"Drop",$name,"\".\n\n";

The final bit of code is designed to overcome a threading problem. DropScript requests that the file $outfile be copied to the file $AA, but the copy may not take place immediately. We want to delete the file $outfile from which we are copying, but we shouldn't do this until after the copy is finished. The empty while-loops just wait until various files/folders are created and the $AA file has non-zero length. Then we wait some more until $AA and $outfile are the same, which we check using the UNIX diff command. The >/dev/null bit is UNIX for "throw away the output of the diff command" (which is a list of the differences). Finally we delete $outfile.

while( ! -d "$aa") {;}
my($AA)=$aa.$emulator_path;
while( ! -f "$AA") { ;}
my($BB)=$aa."/Contents/Info.plist";
while( ! -f "$BB") { ;}
while( -z "$AA") { ;}
while (system("diff \"$AA\" \"$outfile\" > /dev/null")/256 !=0) {;}
unlink($outfile);

We end by opening the script of our new droplet and closing the brace for our subroutine.

system("open -a \"$editor_path\" \"$AA\"");
}

Some Final Remarks

DropScript-droplets have two annoying features. One bit of annoyance is that print commands go to the Console program which may be hidden or may not even be open, so you'll think there was no output. To fix this, add the line

system("open \"/Applications/Utilities/Console.app\"");

up near the start of your scripts. Other programs are also writing to this window so your output may get sandwiched between other output which is why I have the \n\n's around my text to make it easier to find.

The other annoyance is that the working directory of your droplet is root, whereas MacPerl sets it to the folder containing the droplet. If your code has path names beginning with "./" these droplets probably will not work. Other scripts may try to write files to the root directory which often fails and is never where you are looking for them anyway. Calling pwd in your code probably means it will break as well. The solution is to get the folder containing the droplet, and then you can do a chdir. The Perl variable $0 contains the path to the code file, but under OS X this file is several folders deep inside the droplet, which is a folder. The following code snippet yields the folder containing the droplet (without the final "/").

my($app)=$0; 
$app=substr($app,0,rindex($app,"/Contents")); $app=substr($app,0,rindex($app,"/"));

Initially I ended this article with a list of features enjoyed by MacPerl droplets that I would like to see in DropScript droplets. An anonymous editor saw this version and pointed out that many of these features had been carbonized in recent releases of MacPerl. A bit of experimentation revealed that if you have chased down and installed both a version of Perl newer than the Apple-included version, and the carbonized MacPerl modules, then you can have many of the MacPerl features such as Ask, Answer, Pick, etc. in your new droplets. These installations are not for the faint-of-heart, but if you google around you can dig up the necessary files and lots of chit-chat on problems/solutions.

Happy scripting!


Larry Taylor is a research mathematician and professor who spends too much time fooling around with this sort of thing. More stuff at <www.nd.edu/~taylor>.

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

ExpanDrive 6.1.8 - Access cloud storage...
ExpanDrive builds cloud storage in every application, acts just like a USB drive plugged into your Mac. With ExpanDrive, you can securely access any remote file server directly from the Finder or... Read more
DiskCatalogMaker 7.2.7 - Catalog your di...
DiskCatalogMaker is a simple disk management tool which catalogs disks. Simple, light-weight, and fast Finder-like intuitive look and feel Super-fast search algorithm Can compress catalog data for... Read more
DiskCatalogMaker 7.2.7 - Catalog your di...
DiskCatalogMaker is a simple disk management tool which catalogs disks. Simple, light-weight, and fast Finder-like intuitive look and feel Super-fast search algorithm Can compress catalog data for... Read more
Iridient Developer 3.2.1 - Powerful imag...
Iridient Developer (was RAW Developer) is a powerful image-conversion application designed specifically for OS X. Iridient Developer gives advanced photographers total control over every aspect of... Read more
BusyContacts 1.2.7 - Fast, efficient con...
BusyContacts is a contact manager for OS X that makes creating, finding, and managing contacts faster and more efficient. It brings to contact management the same power, flexibility, and sharing... Read more
MegaSeg 6.0.5 - Professional DJ and radi...
MegaSeg is a complete solution for pro audio/video DJ mixing, radio automation, and music scheduling with rock-solid performance and an easy-to-use design. Mix with visual waveforms and Magic... Read more
BusyContacts 1.2.7 - Fast, efficient con...
BusyContacts is a contact manager for OS X that makes creating, finding, and managing contacts faster and more efficient. It brings to contact management the same power, flexibility, and sharing... Read more
MegaSeg 6.0.5 - Professional DJ and radi...
MegaSeg is a complete solution for pro audio/video DJ mixing, radio automation, and music scheduling with rock-solid performance and an easy-to-use design. Mix with visual waveforms and Magic... Read more
Iridient Developer 3.2.1 - Powerful imag...
Iridient Developer (was RAW Developer) is a powerful image-conversion application designed specifically for OS X. Iridient Developer gives advanced photographers total control over every aspect of... Read more
iFFmpeg 6.6.1 - Convert multimedia files...
iFFmpeg is a comprehensive media tool to convert movie, audio and media files between formats. The FFmpeg command line instructions can be very hard to master/understand, so iFFmpeg does all the hard... Read more

Latest Forum Discussions

See All

The best deals on the App Store this wee...
A new week means new discounts on the App Store. This week's deals run the gamut of action-adventure titles, puzzle games, and one of the best narrative adventure series out there. If you're looking to fill out your mobile gaming library on a... | Read more »
What you need to know about Animal Cross...
We hope you've been hard at work on collecting all of those holiday items in Animal Crossing: Pocket Camp, because you're about to get a whole new list of fun things to do as the game receives its first big update sometime soon. There are a lot of... | Read more »
Reigns: Her Majesty guide - how to use e...
Ruling a kingdom isn't easy--doubly so for a queen whose every decision is questioned by the other factions seeking a slice of power. Reigns: Her Majesty builds on the original game's swipey tactics, adding items that you can use to move the story... | Read more »
The best new games we played this week -...
Friday has crept up on us once again, so it's time to honor the best new games we've played over the past few days. This past week was a pretty exciting one, with the debut of lots of beautiful new indies and some familiar faces returning to the... | Read more »
Portal Knights guide- beginner tips and...
Portal Knights is finally making the jump to iOS and Android, and it's already climbing the ranks to become the next big MMO experience on mobile. This sprawling sandbox game will let you pursue any adventure you wish, whether you want to sling... | Read more »
Reigns: Her Majesty guide - how to swipe...
Reigns: Her Majesty is storming the App Store this week, bringing more tinder-esque kingdom building to eager players everywhere. If you've played the original Reigns, you'll know that leading a kingdom is never easy. It's a careful balancing act... | Read more »
Getting Over It (Games)
Getting Over It 1.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0 (iTunes) Description: A game I madeFor a certain kind of person To hurt them. • Climb up an enormous mountain with nothing but a hammer and a pot.•... | Read more »
Reigns: Her Majesty (Games)
Reigns: Her Majesty 1.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0 (iTunes) Description: | Read more »
Pocket Legends Adventures guide - how to...
Pocket Legends Adventures is a fun action adventure RPG that takes control when you want it to, but also opens itself for player input, too, if you're looking to tkae a more active role in combat. Regardless of play style, the game can be quite... | Read more »
Portal Knights (Games)
Portal Knights 1.2.4 Device: iOS Universal Category: Games Price: $4.99, Version: 1.2.4 (iTunes) Description: Craft your adventure. Forge your hero. Become the ultimate Portal Knight! | Read more »

Price Scanner via MacPrices.net

Green Monday deal: 15″ 2.8GHz MacBook Pro on...
B&H Photo has the 15″ 2.8GHz Space Gray MacBook Pro on sale for $250 off MSRP for today only as part of their Green Monday/Holiday sale. Shipping is free, and B&H charges sales tax for NY... Read more
Green Monday sale: B&H offers 12″ Apple i...
B&H Photo has 12″ iPad Pros on sale for up to $150 off MSRP as part of their Green Monday/Holiday sale. Shipping is free, and B&H charges sales tax in NY & NJ only: – 12″ 64GB WiFi iPad... Read more
Holiday deal: 21″ and 27″ Apple iMacs on sale...
MacMall has 2017 21″ and 27″ Apple iMacs on sale for up to $200 off MSRP. Shipping is free: – 21″ 2.3GHz iMac: $999 $100 off MSRP – 21″ 3.0GHz iMac: $1199 $100 off MSRP – 21″ 3.4GHz iMac: $1379 $120... Read more
Holiday deal: Apple Mac minis for up to $150...
MacMall has Mac minis on sale for up to $100 off MSRP, each including free shipping: – 1.4GHz Mac mini: $399 $100 off MSRP – 2.6GHz Mac mini: $599 $100 off MSRP – 2.8GHz Mac mini: $949 $50 off MSRP... Read more
Beats by Dr. Dre – BeatsX Earphones on sale f...
Best Buy has BeatsX Earphones on sale for $109, $40 off, on their online store. Sale price for online orders only. Choose free store pickup, if available, or choose free shipping. Read more
10″ 64GB WiFi Apple iPad Pros on sale for $59...
MacMall has 10.5″ 64GB Apple iPad Pros on sale for $599 including free shipping. That’s $50 off MSRP and among the lowest prices available for these iPads from any Apple reseller. Read more
15″ 2.2GHz MacBook Pros on sale for $200-$300...
B&H Photo has the 15″ 2.2GHz MacBook Pro available for $200 off MSRP including free shipping plus NY & NJ sales tax only: – 15″ 2.2GHz MacBook Pro (MJLQ2LL/A): $1799 $200 off MSRP Apple has... Read more
Holiday sale: 15″ MacBook Pros for $200-$420...
MacMall has 15″ MacBook Pros on sale for $220-$300 off MSRP, each including free shipping: – 15″ 2.8GHz MacBook Pro Space Gray (MPTR2LL/A): $2179, $220 off MSRP – 15″ 2.8GHz MacBook Pro Silver (... Read more
Holiday sale: 13″ MacBook Airs for up to $150...
B&H Photo has 13″ MacBook Airs on sale for $100 off MSRP as part of their Holiday sale. Shipping is free, and B&H charges sales tax for NY & NJ residents only: – 13″ 1.8GHz/128GB MacBook... Read more
The best Holiday sale prices on 13″ MacBook P...
B&H Photo has 13″ MacBook Pros on sale this weekend, with models available for $100-$150 off MSRP. Shipping is free, and B&H charges sales tax for NY & NJ residents only: – 13-inch 2.3GHz... Read more

Jobs Board

*Apple* Retail - Multiple Positions - Apple,...
Job Description:SalesSpecialist - Retail Customer Service and SalesTransform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*Apple* Retail - Multiple Positions - Apple,...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*Apple* Retail - Multiple Positions - Apple,...
Job Description:SalesSpecialist - Retail Customer Service and SalesTransform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*Apple* Information Security - Security Data...
# Apple Information Security - Security Data Analyst Job Number: 113119545 Austin, Texas, United States Posted: 10-Nov-2017 Weekly Hours: 40.00 **Job Summary** This Read more
*Apple* Retail - Multiple Positions - Apple,...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.