Bluish Coder

Programming Languages, Martials Arts and Computers. The Weblog of Chris Double.


2007-01-08

JSON Web Services with Factor

There's a post on Matt Croydon's weblog about using Lua to process JSON Web Services. The resulting Lua code is very easy to read. Here's my attempt at the same code in Factor:

REQUIRES: libs/http-client libs/json ;
USING: kernel io http-client json hashtables 
       prettyprint sequences math namespaces ;

[ 
  "http://local.yahooapis.com/MapsService/V1/" %
  "trafficData?appid=YahooDemo&street=" %
  "701+First+Street&city=Sunnyvale&state=CA" %
  "&output=json" %
] "" make http-get rot 200 = [
  nip json> 
  "Result" "ResultSet" rot hash hash
  1 swap [ 
    "Result: " write 
    >r dup . 1+ r> [
      swap write ": " write .
    ] hash-each
  ] each drop
] [
  2drop
] if

I split the URL up into a 'make' block so it wouldn't wrap in this weblog post. I could have used the long string itself. It looks ok and is readable if you know Factor but not as readable as the Lua example.

In Factor the tendancy is to factor things out into small words to make things more readable and to reduce the use of stack manipulation words. Here's a refactored version:

REQUIRES: libs/http-client libs/json ;
USING: kernel io http-client json hashtables 
       prettyprint sequences math namespaces 
       errors ;

: json-get ( url -- object )
  http-get rot 200 = [ 
    nip json> 
  ] [  
    "Could not process result" throw
  ] if ;

: hash-path ( hash seq -- object )
  swap [ swap hash ] reduce ;

: counted-each ( seq quot -- )
  #! Call the quotation for each element in
  #! the sequence. The quotation receives a count
  #! of the number of times the quotation has been called
  #! and should have stack effect ( element count -- ).
  0 -rot swap [ >r >r 1+ dup r> r> -rot call ] each-with drop ; 

: print-hashtable ( hash -- )
  [ swap write ": " write . ] hash-each ;

[ 
  "http://local.yahooapis.com/MapsService/V1/" %
  "trafficData?appid=YahooDemo&street=" %
  "701+First+Street&city=Sunnyvale&state=CA" %
  "&output=json" %
] "" make json-get { "ResultSet" "Result" } hash-path [
  "Result: " write . print-hashtable
] counted-each

While longer the result is some words that are immediately reusable in other contexts. Especially 'json-get', 'hash-path' and 'counted-each'. Anyone want to contribute a different Factor version in the comments below?

Please note that I didn't do this exercise to prove that language A is better than language B, it just gave me a chance to use the JSON library in Factor and see how usable it was. In fact I found a bug in my JSON implementation while doing it so you'll need the fixes from my repository:

darcs get http://www.bluishcoder.co.nz/repos/factor
Tags: factor 

2007-01-07

ODBC Interface for Factor

I've written a simple wrapper around the ODBC API for Factor. I based it on some Forth code I wrote a few years ago.

It has only been tested in Windows but it works quite well and I plan to do some more work on it as I need features. In the meantime it's in my repository:

darcs get http://www.bluishcoder.co.nz/repos/factor

It will likely be in the standard Factor repository soon.

Currently it supports opening and closing databases given a DSN string, running queries, getting column information, and retrieving fields and rows.

Tags: factor 

2007-01-05

Erlang and Mobile Phones

Luke Gorrie has started a new weblog and he's posting about his experiences learning Squeak Smalltalk. In his first post to the weblog he mentions what he's been working on the past couple of years:

The past couple of years I've instead worked really hard with some friends to build up a happy little Erlang company with an office where we drink our coffee. We've developed and marketed a system for mobile phone companies to keep track of all the mobile phones their customers are using and to automatically send configurations for picture messaging, web browsing, and so on. We've installed these systems in over 60 countries and have more than 200 million of you puny humans represented in our Mnesia databases. We're the market leaders and have only a fraction of our competitors' staff size, but of course you guessed this when I said "Erlang". :-)

Tags: erlang 

2007-01-03

Implementing concatenative words with Pattern Matching

There's a dicussion on the concatenative mailing list about concatenative languages and macros. The discussion veered into pattern matching and Manfred Von Thun wrote about using pattern matching to implement common concatenative operations.

I wrote previously about using pattern matching in Factor to do similar, calling the word 'shuffle'. For example, 2dup, could be implemented as:

{ ?a ?b } { ?a ?b ?a ?b } shuffle

I didn't think of it at the time but Manfred's article prompted me to try doing 'cons' and similar operations that actually have to look inside data structures. Since pattern matching does this already, 'shuffle' does it as well. For example, curry could be:

: my-curry { ?a [ ?b ] } { [ ?a ?b ] } shuffle ;
"hello" [ print ] my-curry .
! => [ "hello" print ]
Tags: factor 

2007-01-01

Basic Authentication added to Factor web server

I've added a simple basic authentication mechanism to the Factor web server (called 'httpd'). Basic Authentication is built into all browsers so it makes for a simple authentication method.

It has one major downside and that is the password and username are sent from the browser to the client in clear text. You can work around this by using SSL for your web app.

Basic authentication uses usernames and passwords. These are defined to exist within a named realm. I'ved added a 'realms' symbol to httpd that holds a mapping (ie. a hashtable) from the realm name to the realm data.

The realm data can be a hashtable of usernames to passwords or a quotation with stack effect ( username password -- bool ). If it is a quotation it will be called to see if the user is valid in the given realm. If it is a hashtable the information is looked up directly. If it is anything else then the user is denied. An 'add-realm' word is provided to add (or replace) realm information:

H{ { "test1" "password1" } { "test2" "password2" } } "my-realm" add-realm
! or
[ "password" = swap "chris" = and ] "my-realm" add-realm

Realms can be set globally, per vhost or per responder in the same way as other httpd variables work.

The 'with-basic-authentication' word takes a realm name and a quotation. Before the quotation is run the http headers are checked to see if the user has been authenticated. If not a '401 Access Denied' reply is sent back to the browser with a request for basic authentication under the given realm.

The browser will then prompt the user for the username and password details and resend the request with the correct authorization headers.

If these headers exist then with-basic-authentication runs the quotation. So a simple responder is:

: my-responder ( -- )
 "my-realm" [
   "<html><body>Hello</body></html>" write
 ] with-basic-authentication ;

It can also be used with furnace, cont-responder, etc.

Another quick change I added was a 'responder-url' variable. This provides the responder portion of the URL requested. So for the default responder you'll get "/" and for other responders it will be "/responder/foo/". It always ends with a trailing slash.

This is needed for generating links and 301/307 location forwarding which require absolute url's. By using 'responder-url' you can make your responder not depend on the particular path it is installed under.

This in my repository and hopefully soon in the main factor respository. My repository is available with:

darcs get http://www.bluishcoder.co.nz/repos/factor

Oh, and Happy New Year!

Tags: factor 


This site is accessable over tor as hidden service 6vp5u25g4izec5c37wv52skvecikld6kysvsivnl6sdg6q7wy25lixad.onion, or Freenet using key:
USK@1ORdIvjL2H1bZblJcP8hu2LjjKtVB-rVzp8mLty~5N4,8hL85otZBbq0geDsSKkBK4sKESL2SrNVecFZz9NxGVQ,AQACAAE/bluishcoder/-61/


Tags

Archives
Links