02 Jun 2020

feedPlanet Lisp

Alexander Artemenko: cl-cron

This is a small system which allows you to organize a scheduled function execution in a Cron-like manner.

POFTHEDAY> (cl-cron:make-cron-job
            (lambda ()
              (format t "[~A] Cron works!~%"
                      (local-time:now))))
#:|cron743|

POFTHEDAY> (cl-cron:start-cron)
#<SB-THREAD:THREAD "Anonymous thread" RUNNING {1004D8CB93}>

[2020-06-02T22:29:00.328017+03:00] Cron works!
[2020-06-02T22:30:00.321083+03:00] Cron works!

POFTHEDAY> (cl-cron:stop-cron)
NIL

POFTHEDAY> (defun list-cron-jobs ()
             (loop for key being the hash-key
                     of cl-cron::*cron-jobs-hash*
                   collect key))

POFTHEDAY> (list-cron-jobs)
(#:|cron743|)

POFTHEDAY> (cl-cron:delete-cron-job (first *))
T

POFTHEDAY> (list-cron-jobs)
NIL

Having unnamed cron jobs is not convenient because it is to remove them, you need to get its name using list-cron-jobs function.

But you can provide a hash-key argument to the make-cron-job function:

POFTHEDAY> (cl-cron:make-cron-job
            (lambda ()
              (format t "[~A] Cron works!~%"
                      (local-time:now)))
            :hash-key :print-every-minute)
:PRINT-EVERY-MINUTE

POFTHEDAY> (list-cron-jobs)
(:PRINT-EVERY-MINUTE)

POFTHEDAY> (cl-cron:delete-cron-job
            :print-every-minute)
T

POFTHEDAY> (list-cron-jobs)
NIL

To make a task which runs not every minute but at the specified time, you can pass keyword arguments to the make-cron-job.

For example, this will add a callback to run at 10:00 of every Sunday:

POFTHEDAY> (cl-cron:make-cron-job
            (lambda ()
              (format t "Wake Up!~%"))

            ;; Days of week are numbered from 0,
            ;; where 0 is Monday.
            ;; Run every Sunday:
            :day-of-week 6
            :hour 10
            :minute 0
            :hash-key :sunday-alarm)
:SUNDAY-ALARM

I use cl-cron in the Ultralisp.org, to schedule different tasks. And another useful trick I do is redefining cl-cron:log-cron-message.

By default it writes lines to the ./cron.log, but using this definition you can redirect all messages to the log4cl:

;; Here we are patching this function because
;; original tries to write into a file cl-cron.log
(defun cl-cron:log-cron-message (message &optional (type "error"))
  (if (string-equal type "error")
      (log:error message)
      (log:info message)))

Probably, I'll make a pull-request with these fixes soon. But seems the author of this library is not very active neither at BitBucket nor at the GitHub.

02 Jun 2020 8:15pm GMT

Alexander Artemenko: plump

Yesterday @Shinmera mentioned Plump in the @XH004's thread about performance optimization of it's new HTML parser. And I decided to review it.

Plump is able to parse, modify and serialize an HTML back.

Let's write a crawler to grab @shinmera's posts from Twitter!

POFTHEDAY> (defvar *raw-html*
              (dex:get "https://twitter.com/shinmera"))

POFTHEDAY> (defvar *html* (plump:parse *raw-html*))

;; We need all divs with class "tweet-text"
POFTHEDAY> (defvar *posts*
             (remove-if-not (lambda (div)
                              (str:containsp "tweet-text"
                                             (plump:attribute div "class")))
                            (plump:get-elements-by-tag-name *html* "p")))

POFTHEDAY> (loop for post in (rutils:take 5 *posts*)
                 for full-text = (plump:render-text post)
                 for short-text = (str:shorten 40 full-text)
                 do (format t "- ~A~2%" short-text))
- 1478 Lighting sketch #onesies https:/...

- Trust Level: Swiss A fridge with cool...

- The arch.pic.twitter.com/gMamJfZ1r4

- らくがきばかりアップしていたやつ、今度は動きます。週末にプロクリエイトで描...

- Shit's broken. Will be back in a few ...

This library has more utils for HTML parsing. Read the documentation to learn more.

If you are going to write crawlers in Common lisp, I recommend you to use Plump together with another @shimera's library - clss but we'll play with it tomorrow :)

02 Jun 2020 4:15am GMT

01 Jun 2020

feedPlanet Lisp

Alexander Artemenko: pythonic-string-reader

This is a small package which adds a new syntax for writing multiline string as you do in Python.

I already reviewed the "heredoc" library providing a similar functionality:

http://40ants.com/lisp-project-of-the-day/2020/05/0055-cl-heredoc.html

Here is how pythonic-string-reader can be used:

;; Enable the syntax:
POFTHEDAY> (named-readtables:in-readtable
            pythonic-string-reader:pythonic-string-syntax)

;; Using it from the REPL:
POFTHEDAY> """
Hello "Lisp World!"
"""
"
Hello \"Lisp World!\"
"

;; Using it for function's docstring:
POFTHEDAY> (defun foo (x)
             """ This is a function
                 which multiplies "x"
                 to itself.
             """
             (* x x))
FOO
POFTHEDAY> (documentation 'FOO
                          'function)
" This is a function
                 which multiplies \"x\"
                 to itself.
             "

Whereas cl-heredoc package allowed you to choose a string which will denote the end of the string literal, pythonic-string-reader supports only 3 or 4 double-quotes.

4 double-quotes might be useful if you want to use 3 double quotes in the text:

POFTHEDAY> (defun foo ()
             """"
             You also might enter text with 3 double quotes:

             """
             Just use 4 double quotes when starting such string
             literal.
             """
"""")

POFTHEDAY> (foo)
"
             You also might enter text with 3 double quotes:

             \"\"\"
             Just use 4 double quotes when starting such string
             literal.
             \"\"\"
"

01 Jun 2020 8:15pm GMT