objective.st
Home
About
Examples
Scripting
URIs
Outlook
Download
Blog

Scripting

⇦⇨«⇦⇨⇦

Objective-Smalltalk has been carefully designed to remove barriers between scripts and programs, to the point of making the differences disappear. Scripts have direct access to the full power of the system frameworks, and methods written in Objective-Smalltalk have all the power of a scripting language.

In-App Scripting

Most of Objective-Smalltalk comes as a framework, and can therefore be added to an application by linking in the framework.

[MPWSmalltalkCompiler runScript:'a := 3+4 '];

It is also easy to add methods to classes, and there is a MethodServer that enables loading classes into a running process via HTTP.

Unix Scripting

Objective-Smalltalk comes with a Unix REPL called stsh. This simple script prints the numbers between the two numbers given on the command line:

#!/usr/local/bin/stsh
#-<void>from:<int>from to:<int>to
stdout do println:(from to: to ) each

The method declaration in the second line acts as an architectural adapter, giving stsh enough information about your script to parse and check command line arguments, in this case taking the first two parameters and binding them to the script variables to and from.

stsh also automatically prints the methods return value to stdout unless the method decares a void return.

Scripts have full access to Cocoa classes. The following script uniques the arguments passed on the command line via an NSSet:

#!/usr/local/bin/stsh
#-unique
(NSSet setWithObjects:args ) allObjects

The <ref> type can be used to indicate file references, for example the stcat script just prints out the contents of the file passed as its first parameter:

#!/usr/local/bin/stsh
#-stcat:<ref>file
file value.

Although the <ref> type defaults to files, it can actually pass arbitrary URIs, so stcat http://objective.st will retrieve this web site and stcat env:HOME will print the $HOME environment variable.

Web-Scripting

As we just saw, Objective-Smalltalk makes it easy to interact with web resources. The following example looks up a zip-code using the zipTastic web service.

#!/usr/local/bin/stsh
#-zip:zipCode
ref:http://zip.elevenbasetwo.com getWithArgs zip:zipCode

Web serving is supported using the Objective-HTTP micro framework. A trivial Hello World server looks as follows:

#!/usr/local/bin/stsh
context loadFramework:'ObjectiveHTTPD'.
scheme:site := MPWSiteMap scheme.
site:/hi := 'Hello World!'.
(scheme:site -> (MPWSchemeHttpServer serverOnPort:8081)) startHttpd.

After we load the ObjectiveHTTPD framework, we create a scheme handler that operates in memory and hook it up to the URI scheme site. We can then set our Hello World literal string directly as the value of site:/hi and then start a web-server connected to that site via the "right arrow" connector. While quite different in terms of what happens, overall code length and complexity is similar to the Ruby Sinatra micro framework's hello world example:

#!/usr/bin/ruby
require 'sinatra'

get '/hi' do
   "Hello World!"
end

The major difference is that whereas most web frameworks expect you to plug your data model into the framework's concept of web-serving, MPWSchemeHttpServer only acts as a thin bridge that serves the contents of a scheme sever (see URIs). For example, you can serve a specific directory by substituting the in-memory scheme with a directory reference (that's converted to a scheme handler implicitly):

#!/usr/local/bin/stsh
#-<void>fileserver:<ref>dir
context loadFramework:'ObjectiveHTTPD'.
(dir -> (MPWSchemeHttpServer serverOnPort:8081)) startHttpd.

Scheme handlers can manage access to objects, respond dynamically by computing values or combine other scheme handlers.

Apple-Scripting

Through use of the scripting bridge, it also becomes easy to control other applications via Apple Events, for example setting the iChat status message to the current iTunes track name.

app://com.apple.ichat/statusMessage := app://com.apple.itunes/currentTrack/name

This can be used directly from Unix scripts or application code without having to deal with script strings and try to pass arguments to those scripts via string processing or other means. If I want to prefix the current track name, I just write the code to do it:

'Listening to ',app://com.apple.itunes/currentTrack/name

(Note that the ScriptinBridge framework and corresponding schema are not loaded into the scripting environment by default, you need to add them by executing scheme:app := MPWScriptingBridgeScheme scheme.)

Copyright (c) 2012-2014 Marcel Weiher