Hopwatch – a debugging tool for Go

Hopwatch is an experimental tool that can help debugging Go programs. Unlike most debuggers, hopwatch requires you to insert function calls at points of interest in your program. At these program locations, you can tell Hopwatch to display variable values and suspend the program (or goroutine). Hopwatch uses Websockets to exchange commands between your program and the debugger running in a HTML5 page.

Using Hopwatch

Basically, there are two functions Display and Break. Calling Display will print the variable,value pairs in the debugger page. Calling Break will suspend the program until you tell the debugger to Resume. The Display function takes one or more pairs of (variable name,value). The Break function takes one or more boolean values to be conditionally. Below is a test example.

package main

import "github.com/emicklei/hopwatch"

func main() {
	for i := 0; i < 6; i++ {
		hopwatch.Display("i",i)
		j := i * i
		hopwatch.Display("i",i, "j", j ).Break(j > 10)
		hopwatch.Break()
	}
}

Starting your Go program that includes a Hopwatch function call waits for a connection to the debugger page.
You can disable Hopwatch by passing the command line parameters -hopwatch false.

2012/12/14 17:24:47 [hopwatch] open http://localhost:23456/hopwatch.html ...
2012/12/14 17:24:47 [hopwatch] no browser connection, wait for it ...

Once the debugger is connected, it can receive Display and Break command requests from your Go program. You can look at the stack trace, resume a suspended program or disconnect from your program.

Hopwatch debugger page

I made a short movie (1.5Mb .mov) that demonstrates using hopwatch in a multiple goroutines program. This example is included in the tests folder of the hopwatch package.

What’s next?

Creating this tool has been fun and educative. Hopwatch uses two channels to communicate between the sendLoop and receiveLoop goroutines and uses the go.net Websocket package to talk to Javascript in a browser. As a tool Hopwatch may be useful (perhaps for remote debugging?) but ofcourse it lacks the important features of a real debugger (GDB) such as setting breakpoints at runtime (and therefore without source modification).
If you have suggestions then please leave a comment on the announcement in the go-nuts discussion group.

The project is located at github ; documentation can also be found on godoc.org

Posted in Go | Tagged , , , | Comments Off

Methods as objects in Go

In an earlier post, I discussed an example of using plain functions as objects. Today, I investigated solutions for using Methods as objects. As I understand it, Go methods are functions that are “bound” to a named type that is not a pointer or an interface.

package main

import "fmt"

type T struct {
	S string
}

func (t T) GetS1() string {
	return t.S
}

func (t *T) GetS2() string {
	return t.S
}

func main() {
	t := T{"hello"}
	f := (*T).GetS1
	g := (T).GetS1
	h := (*T).GetS2
	// i := (T).GetS2   // invalid method expression T.GetS2 (needs pointer receiver: (*T).GetS2)
	fmt.Printf("%v, %v %v, who is there?", f(&t) ,g(t), h(&t))
}

Run it yourself.

In the example, I defined a type T and the value method GetS1 and pointer method GetS2 both returning the value of field S. In the main() function, I create a T and three variables (f,g and h) to hold references to the methods GetS1 and GetS2. The statement for the variable i is commented ; this is an illegal construction. Finally, in the printing statement, I put the expressions to call the functions using the t parameter ; either using its address, or as a value.

Posted in Go, Open source | Tagged | Comments Off

go-restful first working example

In a previous post, I discussed the design of go-restful which is a package for building REST-style WebServices using the Google Go programming language.

Today, I completed the implementation of that package which provides the basics:

  • Creating a WebService with Routes (mapping between Http Request and a Go function)
  • Each Route requires information about the Http method (GET,POST,…), URL Path (/users..), Mime-types and the function it binds to
  • Functions get passed in a Request and a Response
  • The Request is used to access Path and Query parameters , Headers and request content (XML, JSON,…)
  • The Response is used to set Status, Headers, and response content
  • Both Request and Response can Unmarshal and Marshal objects to and from XML,JSON using the standard packages

All of this can best be illustrated with a small example ; a Webservice for CRUD operations on User objects.
We start by creating the file userservice.go inside its own folder userservice.

package userservice

import (
	"github.com/emicklei/go-restful"
	"log"
)

type User struct {
	Id, Name string
}

Type User represents our domain object.

Next section in this file is the API specification of the WebService. The API is a collection of Route objects which specify how an incoming Http Request is mapped to a function.

func New() *restful.WebService {
	service := new(restful.WebService)
	service.
		Path("/users").
		Consumes(restful.MIME_XML, restful.MIME_JSON).
		Produces(restful.MIME_XML, restful.MIME_JSON)

	service.Route(service.GET("/{user-id}").To(FindUser))
	service.Route(service.POST("").To(UpdateUser))
	service.Route(service.PUT("/{user-id}").To(CreateUser))
	service.Route(service.DELETE("/{user-id}").To(RemoveUser))

	return service
}

First, the service is initialized with a root URL path for all routes, the MIME-types each route can receive (Consumes) and the MIME-types it can respond (Produces). It is possible to specify this for each individual Route. Next, the service specifies what Routes it can provide. The function call GET(“/{user-id}”) is just a shortcut for Method(“GET”).Path(“/{user-id}”) and creates a RouteBuilder object. Using the RouteBuilder we specify that the route with method GET will be handled by the function FindUser.

Next section in this file will be the function definitions for each Route.

func FindUser(request *restful.Request, response *restful.Response) {
	id := request.PathParameter("user-id")
	// here you would fetch user from some persistence system
	usr := &User{Id: id, Name: "John Doe"}
	response.WriteEntity(usr)
}

The signature for functions that are used in Routes are all the same and contain a restful Request,Response pair. Request is a wrapper for a http Request that provides convenience methods. Response is a wrapper on the actual http ResponseWriter. This design gives you as a developer complete access to the underlying http structures and access to common restful functions such as WriteEntity. The WriteEntity function will inspect the Accept header of the request to determine the Content-Type of the response and how to Marshal the object (in this case the User).

The remainder of the userservice.go file will contain the other function definitions.

func UpdateUser(request *restful.Request, response *restful.Response) {
	usr := new(User)
	err := request.ReadEntity(&usr)
	// here you would update the user with some persistence system
	if err == nil {
		response.WriteEntity(usr)
	} else {
		response.WriteError(http.StatusInternalServerError,err)
	}
}

func CreateUser(request *restful.Request, response *restful.Response) {
	usr := User{Id: request.PathParameter("user-id")}
	err := request.ReadEntity(&usr)
	// here you would create the user with some persistence system
	if err == nil {
		response.WriteEntity(usr)
	} else {
		response.WriteError(http.StatusInternalServerError,err)
	}
}

func RemoveUser(request *restful.Request, response *restful.Response) {
	// here you would delete the user from some persistence system
}

Now,we have completed the specification and implementation of the UserService. The next snippet shows an example how to use this service in an application.

package main

import (
	"github.com/emicklei/go-restful"
	"log"
	"net/http"
	"userservice"
)

func main() {
	restful.Add(userservice.New())
	log.Fatal(http.ListenAndServe(":8080", nil))
}

The go-restful project source can be found on github and is documented on go.pkgdoc.org

Posted in Go, Open source | Tagged | Comments Off

First class functions in Go

Today, I played with functions as objects in the Go programming language. If functions are first class citizens in Go then it must be possible to store them in fields of a struct, pass them as arguments to other functions and use them as return values of other functions.

So I visited play.golang.org for putting together a simple program that demonstrates this.

package main

import "fmt"

func CallWith(f func(string), who string) {
	f(who)
}

type FunctionHolder struct {
	Function func(string)
}

func main() {
	holder := FunctionHolder{ func(who string) { fmt.Println("Hello,", who) }}
	CallWith(holder.Function,"ernest")
}
  • The CallWith function takes a one string parameter function f and a string parameter who. The body of the CallWith function evaluates the function parameter with the string parameter.
  • The FunctionHolder is a struct type with a field called Function which must be a function with a string parameter.
  • In the main function, a FunctionHolder is created initializing the Function field with a function that prints an Hello message.
  • Next in the main function, the CallWith function is called with the Function value of the holder and a string value.

On play.golang.org can run this program yourself

Posted in coding4fun, Go | Tagged | Comments Off

go-restful api design

I have been using JAX-RS for many REST-based service implementations in Java.
As part of my journey into the Google Go programming language, I am exploring designs for such REST support using the standard net/http package in Go.

JAX-RS provides a set of Annotation classes which can be used to add meta-data to classes, methods and method arguments. In JAX-RS these annotation are used to specify the mapping between a Http Request to a Java method and its arguments.

With the exception of tags (string) for struct fields, there is no such concept in Go (AFAIK). So, I tried several approaches to specify this mapping information when defining a REST Resource. For that I wrote a simple example that defines a UserResource which has the REST versions of the CRUD operations on a domain type “User”.

Iteration 1: ResourceMethod and ResourceMethodContainer

The first part below shows the implementation of a UserResource with functions for each GET,PUT,POST and DELETE. The second part shows the Go code to specify the mappings for each function.

type UserResource struct {
	restful.ResourceMethodContainer
}
func (self UserResource) GetUser(userid restful.PathParam) restful.Response {
	response := restful.Response{Status: http.StatusOK}
	// someUser := fetch by userid
	// response.SetEntity(someUser)
	response.AddHeader(restful.HeaderLastModified, time.Now().Add(time.Duration(1000)))
	return response
}
func (self UserResource) UpdateUser(userid restful.PathParam, who User) restful.Response {
	// update User with id = userid
	return restful.Response{Status: http.StatusOK}
}
func (self UserResource) CreateUser(userid restful.PathParam, who User) restful.Response {
	// new User with id = userid
	return restful.Response{Status: http.StatusCreated}
}
func (self UserResource) DeleteUser(userid restful.PathParam) restful.Response {
	// delete User where id = userid
	return restful.Response{Status: http.StatusOK}
}

The functions in UserResource all return a restful.Response which is used to specifiy the status, the response body (bytes) and optional Http headers.

A mapping is specified with a ResourceMethod struct ; its Function field must match to a function defined in the UserResource package. That is the reason why the UserResource has an anonymous field ResourceMethodContainer.

// Create a new UserResource and register all mappings between HTTP requests and UserResource functions
func New() UserResource {
	res := UserResource{restful.ResourceMethodContainer{Root: "/"}}
	userPath := "/users/{user-id}"
	res.Register(restful.ResourceMethod{
        Method:   restful.GET,
        Path:     userPath,
        Produces: restful.XML,
        Function: "GetUser"})

    res.Register(restful.ResourceMethod{
        Method:   restful.POST,
        Path:     userPath,
        Consumes: restful.XML,
        Function: "UpdateUser"})

    res.Register(restful.ResourceMethod{
        Method:   restful.PUT,
        Path:     userPath,
        Consumes: restful.XML,
        Function: "CreateUser"})
    res.Register(restful.ResourceMethod{
        Method:   restful.DELETE,
        Path:     userPath,
        Function: "DeleteUser"})
	return res
}

Iteration 2: Apply Builder pattern to reduce clutter

The idea here is to use a ResourceMethodBuilder to build ResourceMethod structs using a fluent api. The builder is initialized with defaults and has methods to change its state in order to build a ResourceMethod. For example, the call GET(“GetUser”) tells the builder to change the current Http method to “GET” and that it is mapped to the function “GetUser”.

func New() *UserResource {
	res := new(UserResource)
	res.Path("/users")

	builder := restful.ResourceMethodBuilder {
	   Produces: restful.XML,
	   Consumes: restful.XML }
	builder.Path("/{user-id}")

	res.Add(builder.GET("GetUser").Build())
	res.Add(builder.POST("UpdateUser").Build())
	res.Add(builder.PUT("CreateUser").Build())
	res.Add(builder.DELETE("DeleteUser").Build())

	res.Add(builder.GET("FindUsersByName").Path("/").QueryParam("name").Build())

	return res
}

Below, the restful.Response is replaced by a function parameter of type restful.ResponseBuilder. It has convenience build functions to compose the response. Its implementation will use the http.ResponseWriter for actually writing the response content including the marshalled entity.

func (self UserResource) FindUsersByName(response restful.ResponseBuilder, name restful.QueryParam) {
    users := []User{} // select from User where name  = ?
    response.StatusOK()
    response.AddHeader(restful.HeaderLastModified, time.Now().Add(time.Duration(1000)))
    response.Entity(users)
}

Iteration 3: Introduce defaults on the Resource and override per method if needed

func New() *UserResource {
    resource := new(UserResource)
    // set the root path and defaults for accept and contentType
    resource.Path("/users").Accept(restful.XML).ContentType(restful.XML)

    // create a builder for Resource Methods
    builder := resource.NewMethodBuilder().Path("/{user-id}")

    // add methods using current path, contentType and accept
    resource.Add(builder.GET("GetUser"))
    resource.Add(builder.POST("UpdateUser"))
    resource.Add(builder.PUT("CreateUser"))
    resource.Add(builder.DELETE("DeleteUser"))

    // change current contentType and path for function FindUsersByName
    builder.ContentType(restful.JSON).Path("/")
    resource.Add(builder.GET("FindUsersByName").QueryParam("name"))

    return resource
}

Iteration 4:  Binding Routes to Functions

In this iteration, I decided to change the name of ResourceMethodContainer to WebService. The combination “restful.WebService” is clear about what its functionality will provide.

The next (and biggest) change is to use Functions as first class citizens. Instead of storing the function name in the Resource and resolving this to a function at runtime, I introduced Route structs that are initialized with a reference to the function. In the example below, a Route is created that binds a GET on “/users/{user-id}” to the function GetUser.

Finally, I simplified the signature for functions that are used for mapping (Routes) from Http requests. A restful.Request is used to access Path,Query,URI and Header information. A restful.Response is used to write back the response composed of Status,Header and Body (bytes). In previous api designs, I tried to use an explicit argument mapping strategy i.e. the parameter value “{user-id}” could have been mapped to the “userid PathParam”. This complicates the implementation of go-restful but also causes challenges for functions that need more information from the Request or need to add more information to the Response.

type UserService struct {
	restful.WebService
}
func New() *UserService {
	service := new(UserService)
	service.Path("/users").Accept("application/xml").ContentType("application/xml")

	service.Route(service.Method("GET").Path("/{user-id}").To(GetUser))
	return service
}

func GetUser(request *restful.Request, response *restful.Response) {
	id := request.PathParameter("user-id")
	wantsDetails := request.QueryParameter("details")
	x := request.Header.Get("X-Something")
	// ... fetching the user
	response.StatusOK()
	response.AddHeader("Last-Modified", time.Now().Add(time.Duration(1000)).String())
	response.Entity(user)
}

Iteration 5 (2012-12-04): Document the API

To allow for a more detailed auto-generated API document, the RouteBuilder (and therefore Route) is extended to include comment Doc(string), the request payload type Reads(…) and the response payload type Write(…).

	service.Route(service.GET("?from={from}&to={to}&type={type}&center={center}").
		Doc(`Get all (filtered) connections for all applications and the given scope`).
		To(getFilteredConnections).
		Writes(model.Connection{}))

	service.Route(service.PUT("/from/{from}/to/{to}/type/{type}?allowCreate={true|false}").
		Doc(`Create a new connection using the from,to,type values`).
		PathParam("from", "comma separated list of application ids").
		PathParam("to", "comma separated list of application ids").
		PathParam("type", "comma separated list of application ids").
		QueryParam("allowCreate", "if true then create any missing applications").
		To(putConnection).
		Reads(model.Connection{}))

Update 1: Others designs (and implementations) are rest2go and gorest

Update 2: go-restful is now work-in-progress

Posted in design, Go, Open source, Open source projects | Tagged | Comments Off

renderShark – lean application server for renderSnake

I started working on this “yet-another-web-server” project for one of the most important reasons: because its fun. I got inspired for doing this after reading about the Netty framework and all the positive reviews that people write.

My requirements for this server are

  • provide a minimal MVC framework that uses renderSnake to render HTML pages
  • (distributed) Http session management using JBOSS Infinispan, a modern caching solution
  • use Netty , a well-designed fast server framework which I will use for its HTTP support
  • components are wired together using Guice, a lean dependency injection library
  • support for a minimal feature set to run Web applications
    • GET, POST
    • Redirects,Forwards
    • Sessions, Cookies
    • Error Handling (404,500,…)
  • Logging using SLF4j
  • Basic static content serving

To “eat my own dogfood”, I re-implemented the renderSnake website (which is just a Java application) using the renderShark engine.

The project is hosted on googlecode.  Have a look at the example project that demonstrates all the features.

Posted in Java, Open source | Tagged , , | Comments Off

6hoek.com, a showcase for renderSnake

For the past month, I have been working on a new iPad Web application that recently was launched at 6hoek.com. This application provides easy access to the complete product catalog of the Dutch online webshop bol.com.

Because it is targeted to owners of tablet devices such as the Apple iPad, I decided to embrace the upcoming JQuery Mobile framework (JQM), an open-source Javascript library that provides an unified UI to various mobile devices. For producing the HTML markup, I (obviously) choose renderSnake, an open-source HTML component library that promotes writing UI components in Java instead of templates.

6hoek.com on the iPad

6hoek.com on the iPad

Looking back at the development process with respect to these frameworks, I see that:

  • Even though JQM is still beta, it is mature enough to start depending on it
  • Most issues with JQM were easily resolved by reading the excellent JQ forum discussions
  • Writing Java component classes instead of JSP/templates turned out to be very productive
    • Small reusable components that encapsulate complex HTML and Javascript constructions
    • Debugging and refactoring (rename,extract) support from the IDE
    • Presentation logic in plain Java
  • CSS is still a magic beast to tame
  • Javascript debugging (I use Google Chrome) is a big time saver

Of course by creating a real application using these frameworks, one better realizes what features are missing or need to be changed. The upcoming 1.2 release of renderSnake will include all of them.

Posted in Java | Tagged | Comments Off

Getting from HTML design to renderSnake components

RenderSnake is a Java library for creating components and pages that produce HTML using only Java. Its purpose is to support the creation of Web applications that are better maintainable, allows for easier reuse, have testable UI components and produces compact HTML in an efficient way.

This blog post explains how to start from a carefully designed rich HTML page and create new or use the components available in the library.

Web development

The tasks of developing web applications include implementing the application domain logic, database access for persistence and the presentation layer for user-interaction handling and page rendering. For most development teams, members have different roles in the process. Typically, web and interaction designers have the responsibility to create the page flow and construct initial versions of the HTML pages needed. These mockup pages need to be translated into a form that can be served by a web application, make them interactive and present dynamic information.

When using renderSnake to implement the HTML pages, you need to think about how to map the designs to components and how to integrate them with other assets such as Javascript, images and stylesheets.

Layout

The master design of a Web application typically has a small number of layouts. Popular HTML compositions include a Heading, Menu, Search and Footer section. Each of these sections can be defined by its own Renderable component. The composition can defined by creating a subclass of RenderableWrapper. Wrappers can be used in places where you see a standard decoration of dynamic information. Examples are contacts in a list view, search results and product galleries.

Unit

Given the set of HTML mockup pages, the developer has to decide what functional or decoration parts will be translated into Renderable components. Components that render too much HTML are likely to change more frequently over time. Components that are too small require more work, produce more code to maintain and therefore makes development less productive and hard to keep an overview.

Because all components are defined in Java, as a developer you can use all the available language features. Parameterising components translate to adding fields to components classes. Specializing components translate to using class inheritance and composition. Decorations such as layouts translate to Wrapper subclasses. And finally, as a Java developer you have powerful IDE tools with refactoring and debugging support. Changing your component designs is therefore much easier to do and contributes to a more agile development process.

Examples of renderSnake components can be browsed from the renderSnake site itself. Use the HTML Translator tool to convert (parts of) your design to Java code.

Static content

Larger content that is not managed by some CMS system can be maintained by external resource files. These resources are encapsulated (and cached) by instances of StringResource that know how to render them. The separation of static content in files makes maintenance easier ; no Java skills are required for such changes. The classes StringResource and StringTemplate can be used to externalize plain text, embedded Javascript and even HTML fragments.

Javascripts

With the exception of external Javascript libraries such as JQuery and Prototype, most rich Web applications require script elements that implement part of the user-interaction. These Javascript functions are dependent on the structure of the page via element identifiers and CSS classes. For those Javascript functions that cannot be part of an externally hosted resource file, you can use a StringResource to encapsulate each of them. Again, the separation of Javascripts into separate files allows for faster (you know where to look) and easier maintenance.

Examples of resources managed by StringResource objects can be browsed from the renderSnake site itself.

Posted in Java, Open source | Tagged , , | Comments Off

Using renderSnake to build the presentation layer in Spring-MVC

renderSnake is a open-source library for creating components that produce HTML using only Java. By defining Java classes for HTML components and pages you can exploit all the language features (e.g. inheritance, composition, type-checking) and IDE tooling (e.g. refactoring, unit-testing, references search, debugging,…). In addition, renderSnake is designed to produce compact HTML in an memory efficient way.

The “V” in MVC

Basically, renderSnake is responsible for the presentation layer of a Web application. It has no dependencies with an application framework but it does provide classes to integrate with other technologies such as JavaServer Pages and Spring-MVC. Spring-MVC is a popular implementation of the MVC architecture. This pattern isolates “domain logic” (the application logic for the user) from the user interface (input and presentation), permitting independent development, testing and maintenance of each (separation of concerns).

Example

Below is an example of a Spring-MVC based setup of components. ProductListController is a component that is responsible to handling incoming requests. That execution starts by retrieving the Product objects (Model) through a Product Data Access Object. Then a ProductListPage object is created and asked to render itself. Each UI component that is part of the ProductListPage is asked to do the same. The response will have the resulting HTML content.

Spring-MVC and renderSnake

Controller

The method below is part of the ProductListController and is called with a prepared HtmlCanvas object that captures the request,response and output writer. Before rendering the page using the HtmlCanvas, all required domain objects are retrieved and made available to the PageContext (Map) of the HtmlCanvas object. Now the HtmlCanvas has all the information needed to perform the rendering phase.

@RequestMapping("/productlist.html")
@ResponseBody
public void showProductListPage(HtmlCanvas html) throws IOException {

        html.getPageContext().set("products", this.productListDao.getBestSellersProductList());
        html.render(new WebshopLayoutWrapper(new ProductListPage())));
}

View

Using renderSnake, the View layer is implemented by a collection of small, potentially reusable, UI component classes that are composed into Page objects that represent HTML content.

Class Head is an example UI component responsible for rendering the head section of every HTML page. It implements the Renderable interface and uses the HtmlCanvas parameter object for rendering. The HtmlCanvas object has methods of all elements (tags) in order to write HTML content. Using the HtmlAttributesFactory, you can specify the attributes for each HTML tag. By convention, the method source has a format that uses indentation to see the nesting of tags. This is not required but improves its readability.

import static org.rendersnake.HtmlAttributesFactory.*;

public class Head implements Renderable {

    @Override
    public void renderOn(HtmlCanvas canvas) throws IOException {//@formatter:off
       canvas
           .head()
               .meta(
                   http_equiv("Content-Type")
                   .content("text/html; charset=utf-8"))
               .title().write("Welcom to the Webshop")._title()
               .link(
                   rel("stylesheet")
                   .href("../../css/main.css")
                   .type("text/css")
                   .media("all"))
               .meta(
                   name("format-detection")
                   .content("telephone=no"))
               .meta(
                   name("viewport")
                   .content("width=device-width, user-scalable=no"))
           ._head();
    }
}

The class ProductUI is created and initialized with a product from the list of products. While rendering the HTML tags, it can access the attributes of the product in order to show the information on the resulting HTML page.

public class ProductUI implements Renderable {

    public Product product;

    @Override
    public void renderOn(HtmlCanvas canvas) throws IOException {

        canvas
            .li()
                .div(class_("productInfo"))
                    .img(src(product.image).alt(product.title))
                    .h3().write(product.title)._h3()
                    .p().write(product.author)
                        .span(class_("extraInfo")).write(product.extraInfo)._span()
                    ._p()
                ._div()
                .div(class_("orderButton"))
                    .p().span(class_("price")).write("€ ",false).write(product.price)._span()._p()
                    .a(href("paypal?bookid="+product.id))
                        .img(src("../../images/bt_order.gif").alt("Order now").width("103").height("37"))
                    ._a()
                ._div()
                .div(class_("clearer"))._div()
            ._li();
    }

Presentation and logic

Using the Spring-MVC framework is it possible to build applications that clearly separate the responsibilities for handling user interaction and presenting that user with information. Using available Spring extensions, it is possible to integrate the renderSnake library with this framework. By collecting all information (models) in the controller handler method, presentation components can simply access the available information from the page context.

renderSnake project hosting
renderSnake documentation site

    (uses renderSnake)
Posted in design, Java, Open source | Tagged , , , , | Comments Off

Soek.goodies.st improved

The site soek.goodies.st gives access to the sources of open-source Smalltalk libraries and frameworks. A big advantage to developers is that they can explore Smalltalk classes without having to successfully load them into one of the Smalltalk dialect platforms. Recently, I have changed much of the Smalltalk generator and HTML/Javascript generated code.

Formerly, all Smalltalk source was highlighted using a client-side Javascript library. This resulted in long page loading times because it had to iterate through all DOM elements and replace the HTML content by a post-processing (using regex) result. Current version of Soek uses a highlighter written in Smalltalk that can pre-process all class source files.

Soek.goodies.st is now a complete static site and each project has its own stylesheet and javascript additions. This results in faster load times and better flexibility in adding new features to new exported versions of Smalltalk libraries.

Because the Soek project is implemented in VisualWorks, the first projects were exports of loaded bundles and packages from the Public Store. With the help of the Monticello VW package, it is now possible to add projects from any Monticello repository out there. The process of adding a new library is almost completely automated and uses Cloudfork for storing metadata in Amazon SimpleDB and uploading the site contributions to Amazon S3.

In the next weeks, I would like to update the existing projects listed at soek.goodies.st to newer versions. As stated on the site, I welcome suggestions to add other projects (or versions).

Recent additions:

Posted in coding4fun, Open source, s3, Smalltalk | Tagged , , , , , | 3 Comments