domingo, 4 de septiembre de 2011

Jtalk tutorial. (Valid until the end of this week)





TL;DR
write this in a workspace, select, and click 'DoIt'. Instant reward.
Counter new appendToJQuery: 'body' asJQuery




You know Smalltalk, it is an object oriented programming language developed at Xerox PARC during the 70's by Alan Kay, Dan Ingalls and other brillant guys. It is known that Kay, and probably other members of the team, was born from the leg of Zeus. Jtalk is an implementation of Smalltalk that runs on top of JavaScript, developed by Nicolas Petton. It allows the use of Smalltalk for client side applications. Even more, Jtalk allows you to use the famous IDE from the Smalltalk world directly in your browser. It compiles to JavaScript, and follows Pharo, a fork of the Squeak Smalltalk implementation.

The canonical "Hello World" looks like this:


You create a subclass of Widget, and you implement the #renderOn: method. Jtalk will pass an HtmlCanvas instance that we call html in our code. This object provides some "brushes" allowing to "paint" into the html canvas by message passing. We created a div element by sending the div message to html. The div element has it's class and id attributes defined, and it contains a h1 element. Everything is performed by passing messages to the html object. Those familiar with the Seaside web framework will recognize the html canvas. After the HelloWorld class is
defined, you can see it in the browser by appending an instance to the page's body using JQuery:

HelloWorld new appendToJQuery: 'body' asJQuery


A JQuery object is created by passing the #asJQuery message to the string object 'body'. Then we pass the #append message to the JQuery object, with an instance of HelloWorld as argument. You can evaluate this expression in the Workspace and see it in action.

Another way to do the same is going to JQuery class, and send the #body message.

Where is the Counter?
If you know Seaside you'll want to look at the Counter example. I will reproduce the example from the Jtalk website, which you can find also with the IDE's class browser. It is a good example because it shows how you can write stateful applications in Samalltalk, by simply using its object system as you would do in any application:

As in Seaside, the button definition is beautiful. Since the object itself holds the state of the application, you simply bind a Smalltlak code block to the onclick event, and Jtalk will take it from there.

Interacting with the DOM with JQuery and JS evaluation

As you can see, there is JQuery support provided by the JQuery class. We just used it for appending a piece of html to the body element of our page. There is support for a good part of the JQuery api, as you can see by browsing the methods implemented in the JQuery class. You can do DOM insertion, css manipulation, event handling, etc. If something you like is not implemented, you can evaluate JS code by enclosing it with the "<" and ">" characters. A wrapper for ajax is also available:



Here we create an Ajax object and then we send some messages to it. As you can see, we use Samlltalk blocks as callbacks, this blocks are compiled to JavaScript anonymous functions for execution. There are other messages availables in an Ajax object, like #onCompleteDo. Dictionary like syntax is provided for passing additional settings to the Ajax object:



As test, I wrote a small HTTP service interfacing a CouchDb instance. I did it in Python using the small but cool Flask framework:



Please consider it almost pseudo code. You can note its very simple stuff. We serve the Jtalk DE at "/", and we provide access to the database in "/get/<doc_id>". Now, we could build a small wrapper for accessing this service:



We provide a single method called get:onSuccess: allowing the client code to request a document and executing a callback block on the resulting data. Smalltalk blocks are constructed using brackets, and they are like anonymous functions. Temporary named arguments are declared with the :argName, and after the bar you can write any Smalltalk statement. Our onSuccessDo callback takes the data received form the Ajax request as argument. This data comes in JSON format, so we
use an instance of the Smalltalk object to translate this to a Jtalk object, and then we pass that to the block provided by the client code, which we called "aBlock".

An experiment using Rasta.js for data persistence

Rasta.js
is a very simple key/value storage service. It provides a REST API and a client library:

<script src="http://rastajs.errorjs.com/rasta.min.js" type="text/javascript">

We can use this for looking at how can we delegate execution to a JavaScript object and also for providing some data persistence to a static website.



That was easy. The Rasta class has one instance variable, called "rasta". Instance attributes are private in Smalltalk, you have to implement methods if you want to access them from the outside. But in this case, our rasta attribute is for internal use, we don't need the stinky accessors. The Rasta.js API provides two simple JS functions:

Rasta.get('age', function(val){
/* val == '100' */
})

Rasta.set('age','100', function(){
/* */
})
Since they use an upper cased name, and in Smalltalk those are reserved for classes, we have to use a special trick. Jtalk will get confused if you try to evaluate "Rasta" directly. This not happens with lower case JS names, which are available directly in the Jtalk IDE (you can try
console log: 'fooBar' for an example in the Workspace.) So, we will use our "rasta" instance attribute for storing the JS object, we use the <jsobject> notation for getting a sort of proxy object which will delegate messages in the JS one, and we can access it under the "rasta"
name in our messages. Now we can use the Rasta.js KISS service for our data storage:
database := Rasta new.
database get: 'aKey' onSuccess: [ :data | 'div#container' asJQuery append: data ].

Ok, usualy you will want to format the data. We can wrap this into a Widget subclass and implement a #renderOn: method. At this point we can put all these features together in our mind: you get a nice programming environment which promotes good code practices like layers and concerns separation, clean and readable syntax, testing facilities, and who knows
what, with an IDE accessible directly from the browser.

On code persistence

I will just say it. If you press "F5" (or "r" if you are a hacker) you will lose your code. The IDE features a "Commit category" button, which sends a PUT request with the compiled ST in the body. But as Jtalk is focused in client side coding, it is your responsability to handle the
request and save the code into the "js/" folder, next to the Jtalk library. I will show you the "almost pseudo code" thing again, with Flask and Python:



Note that I used the secure_filename from werkzeug to sanitize the data, since I use it to build the path. You don't want to allow write to your .zshrc or similar.

Concluding

Jtalk can help you to write heavy client side applications by taking advantage of the ancient wisdom from the Smalltalk world. It still has some sharp edges but it is there for you to try it. Allows you to write stateful client code easily, and to port known and tested patterns to
the web browser, for great justice. And there is a plus. Jtalk is part of a legendary story, the Smalltalk one. After all, I have told you, these guys came from the leg of a god.

A moving target

In the couple of days that Rodrigo Bistolfi and me have been experimenting with Jtalk and writing this article (In fact he wrote most of the article), a bunch of things changed already, or are going to change shortly. For example, Capitalized Javascript objects are parsed now without problems in Jtalk. On the JQuery side, Nicolas Petton recently said that JQuery binding is going to disappear from jtalk bundle. It seems we'll be able to fetch DOM nodes directly with jtalk. So better be up to date with the jtalk git repo, because jtalk is moving fast.

Btw, there's a lot more related to Jtalk. Goran Krampe wrote jtalkc, that compiles jtalk code to js able to run in node.js. I haven't digged on that yet, but seems it also opens a shitload of possibilities... :)

Cya!

1 comentario:

Anónimo dijo...

Should it be in the example:

header := html h1 with: count asString ; yourself.

?