Friday, July 27, 2012

More Clojure Datomic experiments: decoupling data building and transactions, and adding text search

I wrote two days ago and yesterday about my experiments for getting up to speed on Datomic. In the Datomic news group, Rich Hickey suggested that I keep any helper code for data-building separate from helper code for managing database access/transactions. I have reworked my code and added code to experiment with text search.

Now that I have a few days of experimenting with Datomic I think I understand how I will structure an application for a side project: write a small helper library that is application independent, much as the code snippets in this article. Write another application specific helper library that layers on top of the application independent library that encapsulates all data store functionality that I will need, and unit test this separately. Then I can write the application layer that will probably not have any Datomic application specific code. After I finish the first version of my side project this morning then I will help my customer on his Datomic project.

I removed the single core.clj functions and replaced it with two sets of functions. databuilder.clj:

(ns datomic-test.databuilder
  (:use [datomic.api :as api]))

(defn attribute [id t c doc]  ; by Michael Nygard
  {:db/id (api/tempid :db.part/db)
   :db/ident id
   :db/valueType t
   :db/cardinality c
   :db/doc doc
   :db.install/_attribute :db.part/db})

(defn string-singleton-attribute [id doc]
   (attribute id :db.type/string :db.cardinality/one doc))

(defn string-singleton-attribute-searchable [id doc]
  (assoc
    (attribute id :db.type/string :db.cardinality/one doc)
    :db/fulltext true))

(defn string-multiple-attribute [id doc]
  (attribute id :db.type/string :db.cardinality/many doc))

(defn string-multiple-attribute-searchable [id doc]
  (assoc
    (attribute id :db.type/string :db.cardinality/many doc)
    :db/fulltext true))

(defn long-singleton-attribute [id doc]
   (attribute id :db.type/long :db.cardinality/one doc))

(defn long-multiple-attribute [id doc]
  (attribute id :db.type/long :db.cardinality/many doc))
and transactions.clj:
(ns datomic-test.transactions
  (:use [datomic.api :as api]))

(defn- do-tx-helper [conn partition data-seq]
  (let [data
        (for [data data-seq]
          (assoc data :db/id (api/tempid partition)))]
    @(api/transact conn data)))

(defn do-tx-db [conn data-seq]
  (do-tx-helper conn :db.part/db data-seq))

(defn do-tx-user [conn data-seq]
  (do-tx-helper conn :db.part/user data-seq))
Finally, a little bit of test code that also includes a query using text search:
(ns datomic-test.test.core
  (:use [datomic-test.transactions])
  (:use [datomic-test.databuilder])
  (:use [clojure.test]))

(use '[datomic.api :only [q db] :as api])
(use 'clojure.pprint)

;;(def uri "datomic:free://localhost:4334//news")
(def uri "datomic:mem://news")

(api/create-database uri)
(def conn (api/connect uri))

;; create two singleton string attributes and add them
;; to the :db.part/db partition:
(do-tx-db
  conn
  [(string-singleton-attribute-searchable
     :news/title "A news story's title")
   (string-singleton-attribute
     :news/url "A news story's URL")
   (long-singleton-attribute
     :news/reader-count "Number of readers")])

;; add some data to the :db.part/user partition:
(do-tx-user conn
  [{:news/title "Rain Today"
    :news/url "http://test.com/news1"
    :news/reader-count 11}
   {:news/title "Sunshine tomorrow"
    :news/url "http://test.com/news2"
    :news/reader-count 8}])

(def results
  (q '[:find ?n :where [?n :news/title]] (db conn)))

(doseq [result results]
  (let [id (first result)
        entity (-> conn db (api/entity id))]
    (println (:news/title entity)
             (:news/reader-count entity))))

(def search-results
  (q '[:find ?e ?n
         :where [(fulltext $ :news/title "rain")
                 [[?e ?n]]]]
    (db conn)))

(doseq [result search-results]
  (let [id (first result)
        entity (-> conn db (api/entity id))]
    (println (:news/title entity)
             (:news/reader-count entity)
             (:news/url entity))))

Thursday, July 26, 2012

A little Clojure wrapper for Datomic

I wrote yesterday about getting started with Datomic in a lein based project. Probably because I am not up to speed with Datomic idioms, a lot of the data boilerplate bugs me so I wrote a little wrapper to hide all of this from my view. Starting with a some code by Michael Nygard I saw on the Datomic newsgroup I wrapped creating database attributes and adding data to the data store. I formated the following code in a funky way to make it fit on this web page:

(ns datomic-test.core
  (:use [datomic.api :as api]))

(defn attribute [id t c doc]  ; by Michael Nygard
  {:db/id (api/tempid :db.part/db)
   :db/ident id
   :db/valueType t
   :db/cardinality c
   :db/doc doc
   :db.install/_attribute :db.part/db})

(defn string-singleton-attribute [conn id doc]
  @(api/transact conn
     [(attribute id
         :db.type/string :db.cardinality/one doc)]))

(defn string-multiple-attribute [conn id doc]
  @(api/transact conn
     [(attribute id
         :db.type/string :db.cardinality/many doc)]))


(defn long-singleton-attribute [conn id doc]
  @(api/transact conn
     [(attribute id
        :db.type/long :db.cardinality/one doc)]))

(defn long-multiple-attribute [conn id doc]
  @(api/transact conn
     [(attribute id
        :db.type/long :db.cardinality/many doc)]))

(defn do-tx-user [conn data-seq]
  (let [data
        (for [data data-seq]
          (assoc data :db/id (api/tempid :db.part/user)))]
     @(api/transact conn data)))
Michael's code wraps schema attribute definitions like I showed in the file data/schema.dtm in yesterday's blog. The function do-tx-user takes a seq of maps, adds the user database partition specification to each map, and runs a transaction. With this wrapper, I don't use a separate schema input data file anymore. Here is the example I showed yesterday using the wrapper:
(ns datomic-test.test.core
  (:use [datomic-test.core])
  (:use [clojure.test]))

(use '[datomic.api :only [q db] :as api])
(use 'clojure.pprint)

;;(def uri "datomic:free://localhost:4334//news")
(def uri "datomic:mem://news")

(api/create-database uri)
(def conn (api/connect uri))

;; create two singleton string attributes and a number
;; attribute and add them to the :db.part/db partition:
(string-singleton-attribute
  conn :news/title "A news story's title")
(string-singleton-attribute
  conn :news/url "A news story's URL")
(long-singleton-attribute
  conn :news/reader-count "Number of readers")

;; add some data to the :db.part/user partition:
(do-tx-user conn
  [{:news/title "Rain Today",
    :news/url "http://test.com/news1",
    :news/reader-count 11}
   {:news/title "Sunshine tomorrow",
    :news/url "http://test.com/news2",
    :news/reader-count 8}])


(def results
  (q '[:find ?n :where [?n :news/title]] (db conn)))
(println (count results))
(doseq [result results]
  (let [id (first result)
        entity (-> conn db (api/entity id))]
    (println (:news/title entity) (:news/reader-count entity))))
Since I use many different tools, I sometimes like to figure out the subset of APIs, etc. that I need and wrap them in a form that is easier for me to remember and use. This may be a bad habit because I can end up permanently using a subset of tool functionality.

Wednesday, July 25, 2012

Using the Datomic free edition in a lein based project

Hopefully I can save a few people some time:

I flailed a bit trying to use the first released version yesterday but after updating a new version (datomic-free-0.8.3343) life is good. Download a recent release, and do a local maven install:

mvn install:install-file -DgroupId=com.datomic -DartifactId=datomic-free -Dfile=datomic-free-0.8.3343.jar -DpomFile=pom.xml
Setting a lein project.clj file for this version:
(defproject datomic-test "1.0.0-SNAPSHOT"
  :description "Datomic test"
  :dependencies [[org.clojure/clojure "1.4.0"]
                 [com.datomic/datomic-free "0.8.3343"]])
Do a lein deps and then in the datomic-free-0.8.3343 directory start up a transactor using the H2db embedded database:
cp config/samples/free-transactor-template.properties mw.propreties
bin/transactor mw.propreties
When you run the transactor it prints out the pattern for a connection URI and I used this in a modified version of the Datomic developer's Clojure startup example code:
(ns datomic-test.test.core
  (:use [datomic-test.core])
  (:use [clojure.test]))

(use '[datomic.api :only [q db] :as d])
(use 'clojure.pprint)

(def uri "datomic:free://localhost:4334//news")
(d/create-database uri)
(def conn (d/connect uri))

(def schema-tx (read-string (slurp "data/schema.dtm")))
(println "schema-tx:")
(pprint schema-tx)

@(d/transact conn schema-tx)

;; add some data:
(def data-tx [{:news/title "Rain Today", :news/url "http://test.com/news1", :db/id #db/id[:db.part/user -1000001]}])

@(d/transact conn data-tx)

(def results (q '[:find ?n :where [?n :news/title]] (db conn)))
(println (count results))
(pprint results)
(pprint (first results))

(def id (ffirst results))
(def entity (-> conn db (d/entity id)))

;; display the entity map's keys
(pprint (keys entity))

;; display the value of the entity's community name
(println (:news/title entity))
That was easy. You need to define a schema before using Datomic; here is the simple schema in data/schema.dtm that I wrote patterned on their sample schema (but much simpler!):
[
 ;; news

 {:db/id #db/id[:db.part/db]
  :db/ident :news/title
  :db/valueType :db.type/string
  :db/cardinality :db.cardinality/one
  :db/fulltext true
  :db/doc "A news story's title"
  :db.install/_attribute :db.part/db}

 {:db/id #db/id[:db.part/db]
  :db/ident :news/url
  :db/valueType :db.type/string
  :db/cardinality :db.cardinality/one
  :db/doc "A news story's url"
  :db.install/_attribute :db.part/db}

 {:db/id #db/id[:db.part/db]
  :db/ident :news/summary
  :db/valueType :db.type/string
  :db/cardinality :db.cardinality/one
  :db/doc "Automatically generated summary of a news story"
  :db.install/_attribute :db.part/db}

 {:db/id #db/id[:db.part/db]
  :db/ident :news/category
  :db/valueType :db.type/string
  :db/cardinality :db.cardinality/many
  :db/fulltext true
  :db/doc "Categories automatically set for a news story"
  :db.install/_attribute :db.part/db}

 ]

I hope this saves you some time :-)

Saturday, July 21, 2012

Using the new Bing Web Search API from Java and Clojure

I wrote a simple wrapper that is on github for calling the new API. The old API will not work starting in August 2012 so it was time to update. The README file on github has a simple example for using the JAR created by this project in a Clojure project (a pre-built JAR is also included in the github repository).

The wrapper is simple, but will save you a few minutes writing one yourself if you need to use Bing Web Search in Java, Clojure, JRuby, etc.

You get 100 free searches/day with the new API and there is a charge if you need more API calls per day.

Friday, July 20, 2012

New cellphone: Samsung Galaxy S III

My almost three year old Droid phone still works great and it was not so easy getting a new phone. What convinced me to upgrade was the Samsung Galaxy S III's screen resolution of 1280 x 720 pixels. Sure upgrading from Android 2.x to 4.x is nice, but having a high density screen makes reading email, browsing the web, reading using the Kindle app, etc. all feel very natural, even on such a small device as a cellphone.

Also: the Netflix app is fantastic: unbelievably easy to watch video at this screen resolution, even on a tiny device. I have been an enthusiastic iPad owner, but I think that the Samsung Galaxy S III will replace using the iPad about half the time. I had thought about getting a Nexus 7 tablet for occasions then the iPad was bigger (and heavier!!) than what I needed it for. At least for now, a larger cell phone with a high density screen seems to fill that niche better.

One thing that surprised me after using my old phone for almost three years: I didn't manually transfer any files from my old phone to my new phone. My old Droid automatically uploaded all the pictures I took to G+ and they were available almost instantly on my new phone. Same for my contacts, and I just about run my business on GMail and Google Calendar and those assets were immediately available - a no hassle upgrade.

My simple hack for using local JAR files in my Clojure lein projects

Maybe I shouldn't share bad habits with people but occasionally I see articles for setting up local maven repositories, etc. for using local JAR files in Clojure lein based projects. I have a kludge for doing this simply.

Now, I have to admit that I tend to use a lot of Java code and 3rd party JARs in my Clojure projects - nice if libraries are in Clojars, but if not I create a directory local_jars in a project directory, put any local JARs there, and instead of using lein deps and lein clean I use a Makefile like:

deps:
 lein deps
 cp local_jars/*.jar lib/

clean:
 rm -f -r lib/*
Really simple. A side benefit is that I use lein1 in some projects and lein2 in others. Using Makefile targets insulates me from mistakes using the incorrect version of lein.

Anyone have a better way of doing this? Please let me know.

Monday, July 16, 2012

Secrets of a polygot programmer

I often read opinions about using the best tool for the job in reference to choosing programming languages, frameworks, and libraries.

I am a polygot programmer but I am one mostly because I use languages and other software tools that my customers request. Seriously as a consultant I serve my customers' best interests and that process usually does not include trying to get their teams to pivot to use my favorite tools.

For my own side projects I am for the most part happy enough to use any of the languages that I feel most comfortable with, my favorites being Ruby and Clojure, but I also really like to use Java and Common Lisp. I usually choose languages for my own projects based on available frameworks and libraires that I can build my code on, and more rarely because of specific language features. Yes, I feel a little heretical saying that!

My secret for being comfortable with several languages is that I try to make the development experience similar across programming languages. For example, from the mid 1980s to several years ago I mostly lived inside Emacs. Certainly some language like Smalltalk carry their own IDEs around with them, but for the most part I used Emacs. Things are different now, I use various JetBrains IDEs because the editors, settings, etc. are all mostly similar:

  • Clojure - I use IntelliJ with the La Clojure and Leiningen plugins
  • Java - IntelliJ all the way
  • Ruby - I use RubyMine most of the time with some quick work done in GEdit or TextMate
  • Python - this is a tough language for me because I don't much use Python unless a customer is a Python shop. I find that PyCharm with code completion and instant syntax error hiliting really helps me a lot.
  • Common Lisp - yes, I still use Emacs
Other things that help are common tools like git, svn, crontab, PostgreSQL, MongoDB, and bash (like) shells that are fairly much constants in my work.

Saturday, July 14, 2012

I have been loving Ubuntu 12.04

12.04 was released a few months ago but I just got around to upgrading my Toshiba U505 yesterday. I must say that I don't understand some of the negative comments about Unity that I have read. Unity feels intuitive and so far has just worked for everything I have tried. A minute of google'ing found directions for seting up desktop files in .local/share/applications/. For an example, here is my .local/share/applications/rubymine.desktop file:

[Desktop Entry]
Version=1.0
Type=Application
Terminal=false
Exec=/home/rubymine/bin/rubymine.sh
Name=RubyMine
Icon=/home/rubymine/bin/RMlogo.svg
Obviously change file names and paths as required for your apps and your system. Then anytime when I need to run RubyMine I tap the ALT key and the Unity search bar appears; I start typing the first few letters of RubyMine and when the icon pops up I just click it. I also set up IntelliJ this way for Clojure and Java development. I prefer this to creating task bar icons. Very similar to using Command-space on OS X.

The only disappointment (so far) is the lack of an officially supported Evernote client for Linux. I appreciate the work the developers put into the open source client NixNote, but it lacks polish. Still, I am glad to have it!

I was very pleasantly surprised at how well the Dropbox Linux client works. Once it synchronized my files the service uses little memory and CPU time and everything is well integrated with Unity.

I have been pretty much using OS X Mountain Lion (dev preview, now the gold master) for my work this year but despite the lack of general polish in Desktop Linux there are some real wins in using Linux, at least for my workflow because I can match my development environment on my laptop with my servers, and some small time sinks of dealing with OS X go away. Since my tools like IntelliJ (for Clojure and Java), RubyMine (Ruby), Emacs, Dropbox, and lots of git repositories all work the same, it is really pretty painless for me to enjoy using Linux for a few days, alternate back to OS X, and choose the dev environment based on what I am working on.

Monday, July 09, 2012

I just released some NLP code for Pharo Smalltalk

After writing about Pharo Smalltalk the other day I started looking at some of my old projects. I created a new github repo for my Pharo code and I'll add code as I have time to re-test it and clean it up. There is not much there right now, just a part of speech (POS) tagger.

Sunday, July 08, 2012

Nice: OpenCyc version 4.0 has been released

The last release 2.0 was made available almost three years ago, so I was very happy to see that version 4 is available.

OpenCyc is a knowledge base and ontology containing about 270K terms and 2 million triples. There are now many more links to outside (or OpenCyc) knowledge resources like DBPedia, UMBEL, Wordnet, etc. Check out the new features.

I downloaded the Linux version (requires Java 6, 3 GB memory, and is only for 64 bit OSs and Java). I had no problems at all running it on 64bit Ubuntu and OS X Mountain Lion (developer preview 4) - it only took a few minutes to install and run. Just follow the instructions in the README.txt file and try the web interface at http://localhost:3602/cgi-bin/cg?cb-start Nice to see this the free version of Cyc getting support and development efforts.

I would be very interested in hearing from people who have done projects with either OpenCyc or the OpenCyc OWL/RDF data.

9-9-2012 update: Alyona Medelyan provided a link for downloading data to extend Cyc with terms from Wikipedia.

Using Dojo Mobile in Clojure Noir web apps

I made a first cut at wrapping Dojo Mobile for use in Clojure Noir web app projects. If you want to try what I wrote this morning here is the github repo. The code is really crude. For example, I just embedded Javascript to test AJAX right in a Noir Clojure view file and I don't make full use hiccup. If I have time in the future, I would like to support a wide range of Dojo control elements and perhaps even use ClojureScript. Pull requests welcomed :-)

Here is what it looks like on an iOS device:

Controls work and look different on different devices. This is part of the magic that Dojo Mobile does for us. On the Android platform a selection list behaves like an Android selection list:

Friday, July 06, 2012

A shoutout and thanks to the Pharo Smalltalk developers

Pharo is a fork from the Squeak open-source Smalltalk and provides an incredibly rich development environment. As a consultant people pay me to design and write code in Ruby, Clojure, Common Lisp, and Java. That said, for non-work related experiments, Pharo is a lot of fun to use: a modern and free Smalltalk environment. I just wanted to say thanks to the Pharo team: great work! I recently downloaded the 2.0 development build - exciting to see new features. One thing in particular that strikes me as awesome about Pharo is that it is very light weight, using little memory and CPU resources. I wrote a blog 5 years ago about deploying Squeak to Linux servers. I am a little surprised that Pharo is not more widely used for rich web applications but with so many great languages and frameworks (Rails, Sinatra, Clojure Noir, Java Play Framework, GWT, etc., etc.) there is a lot of competition for developer mindshare.

My personal interest in Smalltalk started when I got a Xerox 1108 Lisp Machine in 1982 and the Xerox SIS salesman gave me a one month license to try Smalltalk.

7-9-2012 update: I just posted some Pharo code to a new github repo.

Code examples for a Dojo Mobile one page application. Backend in Ruby/Sinatra

I wrote a few days ago that I am excited about how easy it is to make simple one page web apps using Dojo Mobile that look good and work fine on portable devices (Android and iOS) and regular web browsers. I don't do a lot of UI development for my work but when I do write web apps it is great to also be able to support mobile devices with a small amount of additional simple code. In this post I will show you hopefully useful code snippets for cookingspace.com that may save you some time if you want to write the same type of apps.

Last weekend I decided that I wanted a new mobile web interface to my old Cooking Space web site. I wanted to be able to quickly look up a recipe on my cellphone, see the ingredient list, and be able to specify how many people need to be served. I also want to see the nutrition data for the recipe. A top level requirement is that once the web page renders then everything is updated with AJAX. There are only two user interactions:

  • Enter a few search terms to locate recipes and show them in a format compatible with both small devices and a web browser on a laptop.
  • A control for changing the number of people a recipe will serve - this adjusts the amounts in the ingredients list using AJAX.
This is much simpler UI than that for the original web site but captures just what I personally want to use it for. I use the admin functionality on the old web site for adding and editing recipes which is a complex task because I use the USDA nutrition database and instead of for example adding "chicken" to a recipe I need to find out of the 200 entries for chicken in the nutrient database which entry for chicken to use. Same for all ingredients. This admin functionality is not user facing code but five years ago I implemented it in Rails with a nice AJAX enabled UI.

There is a lot of backend Ruby model code that I won't show. I'll show the controller code, the Javascript, and the HTML5 and Dojo application code I used.

The Sinatra controller code is very simple since it only has to serve up the web page and then handle AJAX calls using the model code. I reformatted the Ruby code to make it a little more verbose and easier to understand:

enable :sessions

get '/' do
  session["n"] ||= "4"
  erb :index
end

get '/getr' do  # handles AJAX calls from Javascript
  ret = "No recipes found"
  q = params['q']
  n = params['n']
  session["n"] = n.to_s   if n
  if q && q.length > 0
    ids = search q # calls model code to do search
    if ids && ids.size > 0
      num_served = session["n"].to_i
      ret = recipes_to_html num_served,ids.collect {|x| x[0]}
    end
  end
  ((!q || q.length == 0) && n) ? "*" : ret
end
The handler for the route '/getr' uses two parameters for search terms and number of people to be served. The web page has two sections: the top section contains the search input form and a control to set the number of people servered. The bottom section just contains an HTML element that receives the AJAX response. I usually put Javascript in a separate file but the Javascript code for this app is so short and simple I just included it in the HTML/ERB template file. Much of the following Dojo boilerplate comes from the excellent Dojo Mobile Documentation:
<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport"
      content="width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no"/>
    <meta name="apple-mobile-web-app-capable" content="yes"/>
    <title>CookingSpace</title>
  <script src="http://ajax.googleapis.com/ajax/libs/dojo/1.7.1/dojo/dojo.js"
         data-dojo-config="async:false"></script>
 <script>
    require(["dojox/mobile/parser",
             "dojox/mobile/deviceTheme",
             "dojox/mobile/compat",
             "dojox/mobile",
             "dojox/mobile/TextBox"],
        function(parser, deviceTheme) {
            parser.parse();
        }
     );

     function ajax_helper() {
       dojo.xhrGet({
        url: "/getr?q=" + dojo.byId("q").value +
                     "&n=" + dojo.byId("served").value,
        handleAs:"text",
        timeout: 8000, // 8 seconds
        load: function(data, args) {
          if (data != "*") {
            dojo.byId("rcontent").innerHTML = data;
          }
        },
        error: function(err, args){
          dojo.byId("rcontent").innerHTML =
           "An unexpected error occurred: " + err;
        }
     });
    }
    dojo.connect(dojo.byId("q"), 'onchange', ajax_helper);
   </script>
  </head>
  <body>
    <div id="settings"
         data-dojo-type="dojox.mobile.View"
         data-dojo-props="selected: true">
    <h3 data-dojo-type="dojox.mobile.Heading">
      CookingSpace Mobile Recipe Lookup
    </h3>
    <div data-dojo-type="dojox.mobile.RoundRect"
         data-dojo-props='shadow:true'>
    <input id="q" name="q" size="40"
           data-dojo-type="dojox.mobile.TextBox"
           placeHolder="Search for recipes" />

    Number served:
    <select name="served" id="served">
      <option value="1">1 person</option>
      <option value="2" selected="selected">2 people</option>
      <option value="3">3 people</option>
      <option value="4">4 people</option>
      <option value="5">5 people</option>
      <option value="6">6 people</option>
    </select>
   </div>

 <div id="rcontent" data-dojo-type="dojox.mobile.RoundRect">
 ...
 </div
 
Please note that I set asynchronous loading of Dojo resources to false to make sure that the Dojo parser had a chance to parse the HTML on this page marking elements with Dojo types before processing my Javascript. This simplest approach is OK for a one page web app that only gets loaded once.

This is a simple example and hopefully will give you a good start creating one page mobile HTML5 web apps using Dojo Mobile.

Wednesday, July 04, 2012

Experimenting with Dojo Mobile

In my work I specialize in Natural Language Processing (NLP), text mining, and general AI development. That said I find myself writing a lot of web apps and what I really want is an easy to use web client stack with rich controls and that facilitates writing one web app that looks and works OK in web browsers, Android phones and tablets, iPhones, and iPads.

Five years ago I wrote a very simple web app cookingspace.com that let me look up the nutrients (using the USDA nutrition database) for recipes we frequently make. I have just spent a few hours rewriting the front end using Dojo Mobile, removing a lot of features that I don't need anymore that is hosted at mobile.cookingspace.com. The new app lets me quickly check nutrients and also on portable devices I can use it while grocery shopping to make sure I get the ingredients I need for making dinner. Both apps are deployed at Heroku (thanks Heroku!).

Dojo is really a nice web client toolkit. I suggest you take a look if you haven't tried it. I have used Dojo for years with server side code written in Common Lisp, Ruby, and more recently Clojure.