Anonymous functions in parenscript

140 views Asked by At

I've got some JavaScript that, along with cl-who does what I want:

      (:script :type "text/javascript"
           (cl-who:str
        "
$(document).ready(function ()
{$('#mtcars-table').DataTable({
ajax: { url: '/data?sym=mtcars&fmt=dt',
        dataSrc: 'mtcars' },
columns: [
{data: 'model', title: 'Model'},
{data: 'mpg', title: 'MPG'},
{data: 'cyl', title: 'Cylinders'},
{data: 'disp', title: 'Displacement'},
{data: 'hp', title: 'Horsepower'},
{data: 'drat', title: 'Axle Ratio'},
{data: 'wt', title: 'Weight'},
{data: 'qsec', title: 'Quarter mile time'},
{data: 'vs', title: 'V or Straight'},
{data: 'am', title: 'Transmission'},
{data: 'gear', title: '# gears'},
{data: 'carb', title: '# carbs'},
],
});
});
"))

but I'm struggling a bit with its conversion to JavaScript via ParenScript. At the moment, this seems to do most of what I need:

      (:script :type "text/javascript"
           (cl-who:str
             (ps:ps (ps:chain ($ document)
                 (ready (lambda ()
                      (foo)))))

This gets me:

"$(document).ready(function () {
    __PS_MV_REG = [];
    return foo();
});"

from ParenScript, so leave replacing foo with $(mtcars-table ....

Getting to this point though was trial, error and guesswork, and I know little about JavaScript. I'm not convinced I'm doing this the 'right way', and the documentation and tutorials on ParenScript are scarce.

Can any experts suggest a better approach for converting this JavaScript snippet?

1

There are 1 answers

0
pjstirling On

Firstly, although I mostly don't :use a package (in defpackage) I make a separate package that :use #:parenscript because it's painful otherwise.

I used a couple of helpers just to make the columns array less typing (group is in my personal util library, but I copied it just in case you need it)

(defun group (n seq)
  (if (zerop n)
      (error "0 length")
      (do ((result nil)
           (chunk nil nil))
          ((not seq) (nreverse result))
        (dotimes (i n)
          (push (car seq) chunk)
          (setf seq (cdr seq)))
        (push (nreverse chunk) result))))

(defmacro+ps temporary-columns (&body forms)
  `(array ,@ (mapcar (lambda (pair)
                       `(create data ,(first pair)
                                title ,(second pair)))
                     (group 2 forms))))

(ps
  (chain ($ document)
         (ready (lambda ()
                  (chain ($ "#mtcars-table")
                         (-data-table (create ajax (create url "/data?sym=mtcars&fmt=dt"
                                                           data-src "mtcars")
                                              columns (temporary-columns
                                                        "model" "Model"
                                                        "mpg" "MPG"
                                                        "cyl" "Cylinders"
                                                        "disp" "Displacement"
                                                        "hp" "Horsepower"
                                                        "drat" "Axle Ratio"
                                                        "wt" "Weight"
                                                        "qsec" "Quarter Mile Time"
                                                        "vs" "V or Straight"
                                                        "am" "Transmission"
                                                        "gear" "# gears"
                                                        "carb" "# carbs"))))))))

Which expands to:

$(document).ready(function () {
    __PS_MV_REG = [];
    return $('#mtcars-table').DataTable({ ajax : { url : '/data?sym=mtcars&fmt=dt', dataSrc : 'mtcars' }, columns : [{ data : 'model', title : 'Model' }, { data : 'mpg', title : 'MPG' }, { data : 'cyl', title : 'Cylinders' }, { data : 'disp', title : 'Displacement' }, { data : 'hp', title : 'Horsepower' }, { data : 'drat', title : 'Axle Ratio' }, { data : 'wt', title : 'Weight' }, { data : 'qsec', title : 'Quarter Mile Time' }, { data : 'vs', title : 'V or Straight' }, { data : 'am', title : 'Transmission' }, { data : 'gear', title : '# gears' }, { data : 'carb', title : '# carbs' }] });
});

It's an unfortunate reality that code written in parenscript doesn't end up looking that much like idiomatic common-lisp, because their data models are rather different, and you need to kowtow to js for interoperability with the js ecosystem.

I still prefer writing parenscipt though, because macros are still useful, and parenscript does paper over some of the horrible-ness of js as well.