Main

September 27, 2009

filing a bug with DTS on DTS:

Radar # 7256673:

DTS needs to provide code-level support for AppleScriptObjC developers. Also on Open Radar.

If you want DTS to support AppleScriptObjC, go and file many, many duplicates.

Categories:     Applescript, Mac Matters
Posted by John C. Welch at 13:51 | Permalink



Comments

Warning for Notes users: The commenting system uses HTML.
I know this will be scary for some of you, especially Notes fans. However, open standards, rah-rah.
If you want to use less-than or greater-than signs, or other similar charachters that HTML reserves,
you'll simply have to learn to do it the HTML way. Luckily, HTML is kind of popular, no matter what
your re-educators have told you, and you can easily find help on the intertubes.

September 19, 2009

A look at AppleScriptObjC

What AppleScript Programmers have been waiting for, even if they didn't know it: AppleScriptObjC

As some of you might know, AppleScript Studio, (Studio for short), never impressed me. To be blunt, I thought that it was a nice try that quickly showed itself to have gone down a bad path. The problem was that to do anything but a really narrow range of tasks (for Cocoa anyway), you had to use the "call method" command with a gob of 'real' Cocoa code, and if you're going to do that, why bother with Studio? The debugger was essentially unusable, and much of the time, just rebuilding a project with no code changes whatsoever would fail.

I have a real limit as to how much work I'll do to make up for a bad tool, and that's what Studio was...a bad tool with good intentions. Especially because I'd been spoiled by really good AppleScript tools like Script Debugger. Compared to Script Debugger, Studio lived down to its unfortunate acronym.

However, while no one was looking, Apple was listening. With Mac OS X 10.6, they released AppleScriptObjC, which is finally the product that Studio never could be: A real, first-class way to use AppleScript to create Cocoa applications. No more half-baked implementations or "oh, you need call method to do THAT" nonsense. Access to all the frameworks now, and in the future, the same way that Cocoa developers using Objective-C, Ruby, or Python get them...for free.

I'm not going to do a tutorial on AppleScriptObjC, because I'm still wrapping my head around it. If you want a tutorial, there's a good one at MacScripter. What I am going to do is do a light comparison between an AppleScriptObjC application, and the Objective-C version, then one between an AppleScriptObjC application and the Studio version. As you'll see, AppleScriptObjC is a win.

One of the things that AppleScriptObjC does is use AppleScript in a more "Cocoa-y" fashion. That is, Apple made the decision that for AppleScriptObjC, the way you use AppleScript should match the way you'd use other languages. There are obviously going to be significant differences between Objective-C, Ruby, Python, and AppleScript, but in general, Apple tried to make using AppleScriptObjC 'feel' as close to using any other language as possible. (There are more details on this in the AppleScriptObjC release notes I linked to.)

DotView

DotView is a simple application that draws a solid circle, or dot, in a window. You can move the dot around with the mouse, there's a slider to change the dot size, and a color control to change the dot's color. It's a simple application, and so is a good way to show the similarities between Objective-C in Cocoa and AppleScript in AppleScriptObjC.

DotView window

DotView

Looking at the Objective-C version, there's not a lot of code. There's two .m files, DotView.m and main.m, and two header files, DotView.h and Preview.h. We'll focus on just the DotView.* files here, starting with the Objective-C version of DotView.h

<#import Cocoa/Cocoa.h>

@interface DotView : NSView {
     NSPoint center;
     NSColor *color;
     CGFloat radius;
}

// Standard view create/free methods
- (id)initWithFrame:(NSRect)frame;
- (void)dealloc;

// Drawing
- (void)drawRect:(NSRect)rect;
- (BOOL)isOpaque;

// Event handling
- (void)mouseUp:(NSEvent *)event;

// Custom methods for actions this view implements
- (IBAction)setRadius:(id)sender;
- (IBAction)setColor:(id)sender;

@end

Not much really, about 14 lines of code that does the setup for things like setting the center, color, and radius of the dot, the functions for drawing the dot, and the functions for resizing and changing the color of the dot.

As far as the AppleScriptObjC version goes, there isn't one. AppleScript is a higher level language, and doesn't use header files. The AppleScriptObjC version still has to deal with the items that are in the Objective-C header file, but it will do so differently. (note that in this usage, "higher" is not a sign of superiority or inferiority. Instead, it denotes how "far from the hardware" a language lives. So AppleScript is a higher level language than Objective-C which is a higher level language than Assembly.)

What about the 'real' code? Well, here's the Objective-C DotView.m contents:

#import <Cocoa/Cocoa.h>
#import "DotView.h"

@implementation DotView


- (id)initWithFrame:(NSRect)frame {
     [super initWithFrame:frame];
     center.x = 50.0;
     center.y = 50.0;
     radius = 10.0;
     color = [[NSColor redColor] retain];
     return self;
}

- (void)dealloc {
     [color release];
     [super dealloc];
}
// drawRect: should be overridden in subclassers of NSView to do necessary
// drawing in order to recreate the the look of the view. It will be called
// to draw the whole view or parts of it (pay attention the rect argument);
// it will also be called during printing if your app is set up to print.
// In DotView we first clear the view to white, then draw the dot at its
// current location and size.

- (void)drawRect:(NSRect)rect {
     NSRect dotRect;

     [[NSColor whiteColor] set];
     NSRectFill([self bounds]);
// Equiv to [[NSBezierPath bezierPathWithRect:[self bounds]] fill]

     dotRect.origin.x = center.x - radius;
     dotRect.origin.y = center.y - radius;
     dotRect.size.width = 2 * radius;
     dotRect.size.height = 2 * radius;

     [color set];
     [[NSBezierPath bezierPathWithOvalInRect:dotRect] fill];
}

- (BOOL)isOpaque {
     return YES;
}

// Recommended way to handle events is to override NSResponder (superclass
// of NSView) methods in the NSView subclass. One such method is mouseUp:.
// These methods get the event as the argument. The event has the mouse
// location in window coordinates; use convertPoint:fromView: (with "nil"
// as the view argument) to convert this point to local view coordinates.
//
// Note that once we get the new center, we call setNeedsDisplay:YES to
// mark that the view needs to be redisplayed (which is done automatically
// by the AppKit).

- (void)mouseUp:(NSEvent *)event {
     NSPoint eventLocation = [event locationInWindow];
     center = [self convertPoint:eventLocation fromView:nil];
     [self setNeedsDisplay:YES];
}

// setRadius: is an action method which lets you change the radius of the dot.
// We assume the sender is a control capable of returning a floating point
// number; so we ask for it's value, and mark the view as needing to be
// redisplayed. A possible optimization is to check to see if the old and
// new value is the same, and not do anything if so.

- (void)setRadius:(id)sender {
     radius = [sender doubleValue];
     [self setNeedsDisplay:YES];
}

// setColor: is an action method which lets you change the color of the dot.
// We assume the sender is a control capable of returning a color (NSColorWell
// can do this). We get the value, release the previous color, and mark the
// view as needing to be redisplayed. A possible optimization is to check to
// see if the old and new value is the same, and not do anything if so.

- (void)setColor:(id)sender {
     [color autorelease];
     color = [[sender color] retain];
     [self setNeedsDisplay:YES];
}

@end

I left some of the functional comments in, so it's easier to see what the different parts of DotView.m are doing, but if you remove the comments and blank lines, the entire 'main' part of the application is only 47 lines of code. Admittedly, it doesn't do a lot, but still, that's not a lot. What about the AppleScriptObjC version? Here:

property NSColor : class "NSColor"
property NSBezierPath : class "NSBezierPath"

script DotView
     property parent : class "NSView"

     property |center| : {x:0.0, y:0.0}
     property radius : 0.0
     property |color| : missing value

     on initWithFrame_(frame)
          continue initWithFrame_(frame)
          set my |center|'s x to 50.0
          set my |center|'s y to 50.0
          set my radius to 10.0
          set my |color| to NSColor's redColor()
          return me
     end initWithFrame_

     on drawRect_(rect)
          NSColor's whiteColor()'s |set|()
          tell NSBezierPath's bezierPathWithRect_(my |bounds|()) to fill()

          set origin to {(my |center|'s x) - (my radius), (my |center|'s y) - (my radius)}
          set |size| to {2 * (my radius), 2 * (my radius)}

          my |color|'s |set|()
          tell NSBezierPath's bezierPathWithOvalInRect_({origin, |size|}) to fill()
     end drawRect_

     on isOpaque()
          return true
     end isOpaque

     on mouseUp_(|event|)
          set eventLocation to |event|'s locationInWindow()
          set my |center| to my convertPoint_fromView_(eventLocation, missing value)
          tell me to setNeedsDisplay_(true)
     end mouseUp_

     on setRadius_(sender)
          set radius to sender's doubleValue()
          tell me to setNeedsDisplay_(true)
     end setRadius_

     on setColor_(sender)
          set my |color| to sender's |color|()
          tell me to setNeedsDisplay_(true)
     end setColor_

end script

This does the same thing as the Objective-C version, but in about 40 lines of code. If that doesn't make any sense, this is where AppleScript being a higher level language has its advantages. Because the AppleScript runtime, (the component that executes all AppleScript code), handles things like memory management for you, you don't have to write code to deal with de-allocating memory you allocated earlier. However, there's a price to be paid for this convenience, and that's usually in size, (all things being equal, an application written in an interpreted language like AppleScript tends to be larger, and need more memory than an application written in a compiled language like Objective-C), and speed, (interpreted languages tend to be slower than compiled ones). But, for code that really doesn't care about either, the difference is a wash, and is up to programmer preferences/job requirements.

The thing I wanted you to initially see, is that unlike Studio, which as we'll see, has a syntax implementation that "verbose" doesn't even begin to cover, AppleScriptObjC lets you get work done without having to bang out gobs of code for even simple things. The next thing we want to look at is the way that AppleScriptObjC and Objective-C have similar structure, even though the languages themselves are quite different. For example, let's look at setting up the variables for drawing the dot. To draw a solid colored circle, you need three basic bits of information:

In the Objective-C version, this is done in the header, (.h) file with this code:

@interface DotView : NSView {
     NSPoint center;
     NSColor *color;
     CGFloat radius;
}

The code is using features of the NSView class to create three things:

Those will be used in the DotView main code to tell the application what the center, color, and radius of the circle should be so it can be drawn correctly. Now, the AppleScriptObjC version:

property parent : class "NSView"

property |center| : {x:0.0, y:0.0}
property radius : 0.0
property |color| : missing value

The syntax is different, but still similar. We tell the script to use the features of NSView to create the same three variables: center, radius, and color. With AppleScriptObjC, we also have to set the initial values for the variables, whereas we didn't in Objective-C, but that's a syntax difference. The reason that AppleScriptObjC's center and radius variable names have vertical bars around them is because those particular words are normally reserved by AppleScript. The vertical bars tell the AppleScript runtime "Hey, for this application, use these variables the way I'm defining them here, not the way you normally would use them." In talking with some of the AppleScript team at Apple, they told me that the bars themselves are harmless. If you accidentally put them in where they aren't needed, no harm no foul, it shouldn't affect anything adversely. The reason that color is defined to be a missing variable is because its value will be set by a UI control, and so this is how AppleScriptObjC lets you reserve variables that you're going to "hook up" to the UI in your application.

The important point is, if you were to have never coded in anything but Objective-C in your life, and suddenly had to look at the AppleScriptObjC version of some Objective-C code, you'd have a far easier time of correctly interpreting what the code was doing than you'd ever have with Studio. Here, let's look at one more example. This time, we'll look at the code that creates the initial dot on application launch. First, the Objective-C code:

- (id)initWithFrame:(NSRect)frame {
     [super initWithFrame:frame];
     center.x = 50.0;
     center.y = 50.0;
     radius = 10.0;
     color = [[NSColor redColor] retain];
     return self;
}

Now the AppleScriptObjC code:

on initWithFrame_(frame)
     continue initWithFrame_(frame)
     set my |center|'s x to 50.0
     set my |center|'s y to 50.0
     set my radius to 10.0
     set my |color| to NSColor's redColor()
     return me
end initWithFrame_

The AppleScriptObjC code's a bit more verbose, but still, the similarities are undeniable. Thanks to the work the AppleScript team did to make AppleScript syntax work the way 'normal' Cocoa application syntax works, it is much, much easier to move between Objective-C and AppleScriptObjC's 'flavor' of AppleScript than it ever was to move between Objective-C and Studio's 'flavor' of AppleScript.

The advantages to this aren't just in more efficient code, or fewer lines. One big advantage to this similarity is that an AppleScriptObjC programmer can read the 'normal' Cocoa documentation far easier than a Studio programmer can, because the way you use the language now follows the 'correct' Cocoa methods more closely. So rather than having to recreate the entire Cocoa documentation set for AppleScriptObjC, the AppleScript team can create a smaller set of core AppleScriptObjC documentation to help you get started, and then you can use the normal Cocoa docs for everything else. That's a huge advantage.

But what about AppleScriptObjC and Studio? How does AppleScriptObjC compare to Studio? Quite favorably as it turns out. By 'quite favorably' I mean "leaves Studio in the dust, choking and wondering why those durn kids knocked its walker over". First, with Studio, you only had access to the parts of Cocoa that Studio explicitly knew about. If Apple introduced a new framework, you couldn't just use that in Studio, you had to wait for the Studio team to implement it. With AppleScriptObjC, there's none of that. AppleScriptObjC is able to use new frameworks and features as soon as they show up in the OS. Now, you could work around that limitation in Studio via the infamous "call method" which let you shell out to 'real' Cocoa code in the Studio application. It turns out, you did that a lot in a Studio application, to where a lot of people just gave in and learned Objective-C.

Task List

So from a feature standpoint, it's not even close. AppleScriptObjC wins easily over Studio. What about a code comparison? Unfortunately, I couldn't find a Studio version of DotView, but I did find another simple application that has both Studio and AppleScriptObjC versions: Task List. Task List is just what it sounds like: a simple application that lets you create and manage a list of tasks/to-dos

Task list

Task List

A nice simple application, so the comparison, as with DotView, will be simple. So, first, the AppleScriptObjC version:

script Task_ListAppDelegate
     property tableData : {}
     property removedTableData : {}
     property tableDataController : missing value
     property CalCalendarStore : class "CalCalendarStore"
     property NSMutableArray : class "NSMutableArray"
     property CalTaskClass : class "CalTask"

     on awakeFromNib()
          set removedTableData to NSMutableArray's array()
          set tableData to NSMutableArray's array()
          syncTaskList()
     end awakeFromNib

     on applicationWillTerminate_(application)
          syncTaskList()
     end applicationWillTerminate_

     on applicationWillResignActive_(application)
          syncTaskList()
     end applicationWillResignActive_

     on applicationWillBecomeActive_(application)
          syncTaskList()
     end applicationWillBecomeActive_

     on addTask_(sender)
          tableDataController's addObject_({priority:"3", task:"", status:"Not Started", calTask:missing value})
     end addTask_

     on removeTask_(sender)
          set deleted_objects to tableDataController's selectedObjects
          set deleted_object to item 1 of deleted_objects
          removedTableData's addObject_(deleted_object)
          tableDataController's remove_(missing value)
     end removeTask_

     on syncTaskList()
          set calendarStore to CalCalendarStore's defaultCalendarStore
          set theCalendars to calendarStore's calendars
          set todoPredicate to CalCalendarStore's taskPredicateWithCalendars_(theCalendars)
          set tasksInCalStore to CalCalendarStore's defaultCalendarStore's tasksWithPredicate_(todoPredicate)
          set tasksInTable to tableData's valueForKey_("calTask")
          set tasksToDelete to removedTableData's valueForKey_("calTask")

          set tasksAdded to NSMutableArray's array()

          -- Get tasks from iCal that aren't in the table, and delete tasks from iCal that we've been asked to kill
          repeat with aTask in tasksInCalStore
          if not (tasksInTable's containsObject_(aTask) as boolean) and not (tasksToDelete's containsObject_(aTask) as boolean) then
               -- Add a new task if it's not in the list of showing or deleted taks
               set priority to aTask's priority as string
               set |title| to aTask's |title| as string
               tableDataController's addObject_({priority:priority, task:|title|, |status|:"Not started", calTask:aTask})
               tell tasksAdded to addObject_(aTask)
          else if tasksToDelete's containsObject_(aTask) as boolean then
               -- Delete task we were asked to kill
               set returnValue to calendarStore's removeTask_error_(aTask, reference)
               if not item 1 of returnValue then
                    set err to item 2 of returnValue
                    error (err's localizedDescription())
               end if
          end if
     end repeat

     -- Update and create new calTasks based on table data
     repeat with tableDataItem in tableData
          set calTable to tableDataItem as record
          try
               set aCalTask to calTable's calTask
          on error
               set aCalTask to missing value
          end try

          if aCalTask is not equal to missing value and not (tasksInCalStore's containsObject_(aCalTask) as boolean) and not tasksAdded's containsObject_(aCalTask) as boolean then
               -- Delete this task, which was deleted in iCal
               tell tableDataController to removeObject_(tableDataItem)
               exit repeat
          else if aCalTask is equal to missing value then
               -- Create new CalTask for a newly created table row
               set aCalTask to CalTaskClass's task()
               set aCalTask's calendar to (get first item of calendarStore's calendars)
               set the calTask of tableDataItem to aCalTask
          end if

          -- Save out both the existing tasks and freshly created tasks
          if aCalTask is not equal to missing value then
               set the |title| of aCalTask to tableDataItem's task
               set the priority of aCalTask to (tableDataItem's priority's integerValue)
               set returnValue to calendarStore's saveTask_error_(aCalTask, missing value)
               end if
          end repeat
     end syncTaskList
end script

That's not bad, about 73 lines of code, if you remove non-code lines. What about the Studio version? I'm not pasting it in here, because it's about 185 lines of code or so to do the same thing. Well, less, as we'll see in a bit. So let's look at some common code here, the "awake from nib" function, which is analogous to the application launch. The AppleScriptObjC version:

on awakeFromNib()
     set removedTableData to NSMutableArray's array()
     set tableData to NSMutableArray's array()
     syncTaskList()
end awakeFromNib


That's pretty simple. Set a couple variables to arrays, and run something called syncTaskList. The Studio version:

on awake from nib theObject
     if name of theObject is "tasks" then
          -- Create the data source for our "tasks" table view
          set theDataSource to make new data source at end of data sources with properties {name:"tasks"}

          -- Create the data columns, "priority", "task" and "status". We also set the sort properties of each of the data columns, including the sort order, the type of data in each column and what type of sensitivity to use.
          make new data column at end of data columns of theDataSource with properties {name:"priority", sort order:ascending, sort type:numerical, sort case sensitivity:case sensitive}
          make new data column at end of data columns of theDataSource with properties {name:"task", sort order:ascending, sort type:alphabetical, sort case sensitivity:case sensitive}
          make new data column at end of data columns of theDataSource with properties {name:"status", sort order:ascending, sort type:alphabetical, sort case sensitivity:case sensitive}

          -- Set the data source as sorted
          set sorted of theDataSource to true

          -- Set the "priority" data column as the sort column
          set sort column of theDataSource to data column "priority" of theDataSource

          -- Finally, assign the data source of the table view to our data source
          set data source of theObject to theDataSource
     end if
end awake from nib

Oof. Even if I were to take the comments out, we can still see that the Studio version is a lot bigger, and seems to require you to do a lot more work for the initial application setup. That's because it does require more work for initial application setup. Even though you use Interface Builder to build the UI elements for both AppleScriptObjC and Studio, AppleScriptObjC is able to use things the way a 'real' Cocoa application does. So unlike Studio which makes you create manually create the AppleScript implementation of the data columns that will be used by the UI, and set all the properties of those data columns, AppleScriptObjC is able to use the information that you already put into Interface Builder, and that Interface Builder provides for free. The idea behind this is trick called "bindings". I'm not going to even try to explain bindings here, but they're what allow AppleScriptObjC to not have to need all the code that Studio needs. It's not that the UI in Studio doesn't have all the bindings info available to it, it's that bindings are invisible to Studio, and so with Studio, you're stuck using the older Data Source API. So, in a sense, even though you've built the UI in Interface Builder, you have to do a lot of redundant work in Studio to manually define what the UI elements in Task List are doing, work you don't have to do in AppleScriptObjC.

That's kind of the idea with Interface Builder, by the way. You create the UI elements, set them up, and then the code is able to just use them.

While Studio's use of AppleScript is more 'traditional', it's also far kludgier. This is repeated over and over throughout the code. Stuff that AppleScriptObjC can do in a few lines, Studio takes a book. Stuff that AppleScriptObjC doesn't even need code for, Studio needs lines and lines and lines.

Oh, and the syntax is so far removed from 'normal' Cocoa syntax, even allowing for specific language differences that there's almost no way to apply standard Cocoa documentation and sample code to Studio. The gulf between them is just too wide.

However, I do feel that I should come clean about something. When I said that AppleScriptObjC took about 73 lines of code to do the same thing that Studio needs almost 200 lines of code to do, I was lying. Blatantly lying. It really only needed 24 lines of code to do what Studio did. The other 49 or so lines of code let you integrate Task List into the iCal store, so you can see your iCal tasks in Task List, and have the tasks you add to Task List show up in iCal. I don't even want to think about what it would take to do that with Studio, assuming you even could without having to use "call method" and shell out to 'real' Cocoa code. However, AppleScriptObjC does lose to Studio in one important way: AppleScriptObjC and AppleScriptObjC applications will only run on Mac OS X 10.6 or later. If you want to create applications using AppleScript for Mac OS X 10.5 or earlier, you cannot use AppleScriptObjC.

AppleScriptObjC is a huge change, and it does bring with it a lot of new things you'll need to learn, and unlearn, especially if you are using Studio. But, it is also a huge leap forward in capability and features for AppleScript. It also shows, better than any amount of platitudes could, that AppleScript is not going away anytime soon. I just cannot see Apple doing this much work, and creating such a monstrously huge improvement to AppleScript just to knife it.

Categories:     AppleScriptObjC, Applescript, Mac OS X Scripts
Posted by John C. Welch at 00:58 | Permalink



Comments

Warning for Notes users: The commenting system uses HTML.
I know this will be scary for some of you, especially Notes fans. However, open standards, rah-rah.
If you want to use less-than or greater-than signs, or other similar charachters that HTML reserves,
you'll simply have to learn to do it the HTML way. Luckily, HTML is kind of popular, no matter what
your re-educators have told you, and you can easily find help on the intertubes.

September 14, 2009

It's still not the language's fault.

From the new Acorn 2.0 release notes:

I actually came up with JSTalk specifically for Acorn. I was looking at adding AppleScript support to Acorn, since scriptibility was a big feature request, but I've always found AppleScript to be too cumbersome. And I hate writing examples in AppleScript, so JSTalk it is.

That sound was my interest in the product fading away. Not because I hate Javascript, even though I do. Because sometimes, JS is the best tool for the job, and you use it anyway. But because Apple does make creating an language-neutral scripting interface doable, (dude, it's a 10.6 only application, so screw legacy support, there is none, and besides, in 10.6, AppleScriptObjC really does put AppleScript on the same level as Ruby and Python), and there are hundreds of people who if you ask, and maybe throw in a license or two of Acorn and a thank you, will write your examples for you.

Secondly, if you're going to rag on AppleScript because it's "too cumbersome", then don't have shit like this on your jstalk sample page:

Give me an example Here's an AppleScript example, for adding a new rectangle object to a sketch document:

tell application "Sketch"
tell document 1
set o to make new box
set width of o to 100
set height of o to 100
set stroke thickness of o to 10
end tell
end tell

And here's how you do it with JSTalk, using a doctored version of Sketch (6 lines of code, + the JSTalk framework):

var sketch = [JSTalk application:"Sketch"];
var doc = [sketch orderedDocuments][0]
var rectangle = [doc makeNewBox];

[rectangle setWidth:100];
[rectangle setHeight:100];

[rectangle setXPosition:100];
[rectangle setYPosition:100];

If you aren't a fan of the optional bracket syntax, you can also write the script this way:

var sketch = JSTalk.application_("Sketch");
var doc = sketch.orderedDocuments()[0]
var rectangle = doc.makeNewBox();

rectangle.setWidth_(100);
rectangle.setHeight_(100);
rectangle.setXPosition_(100);
rectangle.setYPosition_(100);

if there's some fucking magic here that makes "set o to make new box" less cumbersome than "var rectangle = doc.makeNewBox();" or "var rectangle = doc.makeNewBox();", I'm totally missing it.

Note that the example AppleScript Gus shows is actually more cumbersome than it needs to be, because the way to do this is to make width, height, stroke, xPos, and yPos properties of box, so you could do it as:

set o to make new box with properties {height:100, width:100, xPos:100, yPos:100, stroke:10}

Yep, that's so cumbersome.

But like computers, programming languages all suck anyway. The ones you like? They suck. The ones I like? They suck too. If however, they suck the right way, and you can wrap your head around them, then you can use them. But they still suck.

As to Gus disliking AppleScript, he must really dislike it. There's nary a post on either AppleScript-Implementors or AppleScript users asking either for tips in implementing a dictionary, or help with examples. Kind of hard to get help when you never ask for any. Funny how that works.

As well, Gus seems to either miss, or not care that he's kind of cutting Acorn off from the larger Mac OS scripting community. Because by writing a language-specific scripting implementation, now, if you want to have scripts that say, shove data into or get data out of Acorn, you have to either do all the bridge work to JSTalk yourself, or, you have to start writing Objective C code:

But no apps out there currently support JSTalk! Applications can also be scripted using Cocoa's Script Bridge class, SBApplication. Here's an example:

[[SBApplication application:"iChat"] setStatusMessage:"Happy (funball)"];

Although this is great to have, it's not the same as an application natively support JSTalk over DO. Anything more than simple tasks using SBApplication tends to be a little more than difficult.

No kidding. Again, let's see how cumbersome this would be in AppleScript:

tell application "iChat" to set status message to "not that hard after all"

Wow. That's pretty cumbersome. Thank God we have a way to avoid such onerous syntax.

Yes, I know, the snark is cranked, but too bad. If Gus felt that writing his own language-specific scripting implementations was the best way to go, fine, then say that. See, it's easy:

"For Acorn, none of the existing scripting implementations did what I wanted, so I rolled my own." See? Easy, and you're standing on your own two feet. But don't hide behind some bullshit like "I hate writing AppleScript sample code" when as near as I can tell, (based on searching for Acorn, Gus, Mueller, or Gus Mueller), you never even bloody looked into it because of your feelings towards AppleScript. Given the way you write AppleScript examples, I don't see a lot of experience with the language.

That's not AppleScript's fault, that's your goddamned decision all on its own, so put your fucking big boy pants on and stop letting others be your fall guy.

Categories:     Applescript, Mac Matters, Other
Posted by John C. Welch at 21:33 | Permalink



Comments

Warning for Notes users: The commenting system uses HTML.
I know this will be scary for some of you, especially Notes fans. However, open standards, rah-rah.
If you want to use less-than or greater-than signs, or other similar charachters that HTML reserves,
you'll simply have to learn to do it the HTML way. Luckily, HTML is kind of popular, no matter what
your re-educators have told you, and you can easily find help on the intertubes.

August 27, 2009

Stupid Service Tricks

Since Apple is publishing all kinds of cool information about the new Services changes in Snow Leopard, I figured I'd throw a link to some of the AppleScripts I've converted to Services.

Obviously, you need 10.6 for them to work. If you try them in 10.5, they won't work.

The files are here. Read the code, they're all pretty basic things. For the ones that need certain apps, like Pages, Numbers, Keynote, Entourage, etc., if you don't have those apps, again, they won't work.

But they should give you a bit of a start.

Categories:     Applescript, Entourage X Scripts, Mac OS X Scripts
Posted by John C. Welch at 18:40 | Permalink



Comments

Warning for Notes users: The commenting system uses HTML.
I know this will be scary for some of you, especially Notes fans. However, open standards, rah-rah.
If you want to use less-than or greater-than signs, or other similar charachters that HTML reserves,
you'll simply have to learn to do it the HTML way. Luckily, HTML is kind of popular, no matter what
your re-educators have told you, and you can easily find help on the intertubes.

April 13, 2009

Under the "I think this will create a vortex" heading...

Actual AppleScript command from iWeb's Dictionary:

add page if there are no pages

add page if there are no pages (verb)adds a new page if there are no pages (from the iWeb suite)

Is it just me, or are Apple's application teams leading the charge for really shitty scripting dictionaries lately. Hey guys, how about, before you release a dictionary with stupid-assed Klein Bottle syntax like that, you MAYBE, just MAYBE go walk over and talk to the fucking core scripting folks?

this is just fucking stupid.

Categories:     Applescript, Mac Matters, Mac OS X Scripts
Posted by John C. Welch at 16:12 | Permalink



Comments

Warning for Notes users: The commenting system uses HTML.
I know this will be scary for some of you, especially Notes fans. However, open standards, rah-rah.
If you want to use less-than or greater-than signs, or other similar charachters that HTML reserves,
you'll simply have to learn to do it the HTML way. Luckily, HTML is kind of popular, no matter what
your re-educators have told you, and you can easily find help on the intertubes.

January 15, 2009

Minor script update

Since Numbers '09 is scriptable, and its "Send to Mail" function only works with Mail.app, I figured I'd do the script to send Numbers files as an email attachment via Entourage 2008. It's in a zipfile along with my original "Send via email" Pages and Keynote scripts.

The original article has the code, and since the only difference between the Numbers and Keynote scripts is two words, I'm not going to detail that code here.

Some items:


Technorati Tags:
, ,


Categories:     Applescript, Mac OS X Scripts
Posted by John C. Welch at 12:39 | Permalink



Comments

Warning for Notes users: The commenting system uses HTML.
I know this will be scary for some of you, especially Notes fans. However, open standards, rah-rah.
If you want to use less-than or greater-than signs, or other similar charachters that HTML reserves,
you'll simply have to learn to do it the HTML way. Luckily, HTML is kind of popular, no matter what
your re-educators have told you, and you can easily find help on the intertubes.
digital.forest Where Internet solutions grow

There, a PayPal Button.

 
Use this code for your Macworld tickets!
Family
The Artwork of Melissa Findley
Diane Francis @ the National Post Eric Francis @ the Calgary Sun

Apple Amazon Links
Apple Mac OS X Server 10.5 [Unlimited]

Apple Mac OS X Server 10.5 [10-Client]

Apple Mac OS X 10.5 Leopard

Apple Mac OS X 10.5 Leopard [5-User Family Pack]

Amazon Book Links
Legacy of Ashes: The History of the CIA

The Donnas: Bitchin'

Wizards at War (The Young Wizards, Book 8)

The Demon's Sermon on the Martial Arts

The Collected Stories of Arthur C. Clarke

JavaScript and Ajax for the Web, Sixth Edition

Awakening Warrior: Revolution in the Ethics of Warfare

FOB Links

Mac Web Writers

Techie Links

Review Victims