macdevcenter.com
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Embedding F-Script into Cocoa Applications
Pages: 1, 2, 3

Using the asBlock Method

The asBlock method offers the simplest means of creating and executing F-Script code from Objective-C. Invoked on an NSString containing the source code for an F-Script block, it generates and returns a Block instance that can then be executed.



We can pass it parameters and retrieve the product of the execution. This technique enables us to unify the usage of blocks as, once created, they are manipulated in the same way from both F-Script and Objective-C.

Example 1: Hello World

Here's how to execute a "hello world" program written in F-Script from Objective-C:

  1. Create a string containing the F-Script code.

    NSString *fscriptCode = @"[sys log:'hello world']";

  2. Create a Block object from the string.

    Block *myBlock = [fscriptCode asBlock];

  3. Execute the block

    [myBlock value];

It's possible to combine these instructions:

[[@"[sys log:'hello world']" asBlock] value]

Note: in Objective-C, brackets (i.e. "[" and "]") denote a message send, while in F-Script they denote a block.

In the example, the character string containing the F-Script code is hard-coded, although it is possible to use a string dynamically built at runtime.

Example 2: passing parameters and retrieving the result

Let's now turn our attention to parameter passing between Objective-C and F-Script and retrieval of results. As we've already seen, with blocks everything is done in the same way as with F-Script, even though we are now manipulating them from Objective-C. In this example, we assume that we have an NSArray, called "airplanes," which is made up of objects from the Airplane class. This array will be passed-in a parameter to the F-Script code. The Airplane instances respond to the "capacity" method (which returns an int) and location method (which returns an NSString). In the array, we wish to select the planes that are currently in Chicago and whose capacity is greater than or equal to 200.

NSArray *airplanes;
...

NSArray *selectedAirplanes = [[@"[:a| a at:a location = 'CHICAGO' & (a capacity >= 200)]" asBlock] value:airplanes];

Example 3: object graph

As F-Script blocks are objects, they can be referenced by other objects. In this example, a block will be the target of an NSButton. In addition, F-Script variables, inside the block code, may reference external objects. In this example, the F-Script code will reference an NSTextField.

Let's suppose that in an Objective-C program we have an NSButton and an NSTextField. We wish to use an F-Script block to display the current date and time in the text field when the button is pressed.

Screen shot.
The mini-application we'll build.

But how do you establish a link between an F-Script variable and the external text field? All that is required is the mother block technique, which is fairly frequent with F-Script. Our block is produced by another block, which is responsible for establishing the link with the NSTextField, which it will be given as an argument, using the fact that the blocks are closures (see the Smalltalk literature for more on this).

The following is the complete program for the example.

#import <Cocoa/Cocoa.h>
#import <FScript/FScript.h>

int main(int argc, const char *argv[])
{
  NSApplication *NSApp = [NSApplication sharedApplication];
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  NSButton *button = [[[NSButton alloc] initWithFrame:NSMakeRect(100,20,100,30)] 
                    autorelease];
  NSTextField *textField  = [[[NSTextField alloc] 
   initWithFrame:NSMakeRect(50,100,200,20)] autorelease];
  NSWindow *mainWindow = [[NSWindow alloc] 
       initWithContentRect:NSMakeRect(100,100,300,160) 
             styleMask:NSClosableWindowMask | NSTitledWindowMask 
backing:NSBackingStoreBuffered defer:false];

  Block *motherBlock = [[@"[:textField| [textField setStringValue:NSDate 
    now printString]]" asBlock] retain];
  Block *printDate = [[motherBlock value:textField] retain];
  
  [[mainWindow contentView] addSubview:button];
  [[mainWindow contentView] addSubview:textField];
  [button setBezelStyle:1];
  
  [button setTarget:printDate];
  [button setAction:@selector(value:)];
  
  [mainWindow orderFront:nil];
  [pool release];
  [NSApp run];
  return 0;
}

Error Management

Previously in this series:

Scripting Cocoa with F-Script -- F-Script by Philippe Mougin is an open-source project related to Mac OS X that has caught our eye. This lightweight object-oriented scripting layer provides interactive access to Cocoa frameworks and custom objects, and we present it here as part of our ongoing exploration into Cocoa-related tools.

Browsing Cocoa with F-Script -- In his first article, Scripting Cocoa with F-Script, Philippe Mougin introduced O'Reilly readers to the joys of scripting their Cocoa projects. In this follow-up piece, he shows you a new tool, the object browser.

In the above examples, the possibility of errors is not considered, as the F-Script code is fully known here, and we know that the syntax is correct and there is no risk of F-Script generating an error on execution. In more complex cases, errors may appear on two occasions:

  • When a block is created from an NSString. The syntax of the F-Script code is checked and an error may be detected.
  • When the block is executed (for example, a division by zero will cause an error at runtime).

For managing syntax errors we prefer the asBlock:onError: method to the asBlock method (see the F-Script guide). An error during execution will cause an exception to be thrown.

The FSInterpreter API, which is the subject of the next section, offers easier error management and is therefore recommended in this type of situation.

Pages: 1, 2, 3

Next Pagearrow