diff options
| -rw-r--r-- | src/bot/method-macros.lisp | 16 | ||||
| -rw-r--r-- | src/bot/methods.lisp | 18 | ||||
| -rw-r--r-- | src/strings.lisp | 26 |
3 files changed, 45 insertions, 15 deletions
diff --git a/src/bot/method-macros.lisp b/src/bot/method-macros.lisp index 0500de9..d4f04ad 100644 --- a/src/bot/method-macros.lisp +++ b/src/bot/method-macros.lisp | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | (defpackage :ukkoclot/bot/method-macros | 3 | (defpackage :ukkoclot/bot/method-macros |
| 4 | (:use :c2cl :iterate) | 4 | (:use :c2cl :iterate) |
| 5 | (:import-from :ukkoclot/state :bot) | 5 | (:import-from :ukkoclot/state :bot) |
| 6 | (:import-from :ukkoclot/strings :ends-with :lisp->camel-case) | ||
| 6 | (:import-from :ukkoclot/transport :do-call) | 7 | (:import-from :ukkoclot/transport :do-call) |
| 7 | (:export :define-tg-method)) | 8 | (:export :define-tg-method)) |
| 8 | (in-package :ukkoclot/bot/method-macros) | 9 | (in-package :ukkoclot/bot/method-macros) |
| @@ -25,6 +26,12 @@ | |||
| 25 | (iter (for param-spec in param-specs) | 26 | (iter (for param-spec in param-specs) |
| 26 | (collect (apply #'make-param param-spec)))) | 27 | (collect (apply #'make-param param-spec)))) |
| 27 | 28 | ||
| 29 | (defun path-from-name (name) | ||
| 30 | (let ((str (lisp->camel-case (symbol-name name)))) | ||
| 31 | (if (ends-with str "%") | ||
| 32 | (subseq str 0 (- (length str) 1)) | ||
| 33 | str))) | ||
| 34 | |||
| 28 | (defun emit-append-to-args (param args) | 35 | (defun emit-append-to-args (param args) |
| 29 | `(setf ,args (acons ',(param-name param) ,(param-name param) ,args))) | 36 | `(setf ,args (acons ',(param-name param) ,(param-name param) ,args))) |
| 30 | 37 | ||
| @@ -35,7 +42,7 @@ | |||
| 35 | (defun emit-defun-arg (param) | 42 | (defun emit-defun-arg (param) |
| 36 | `(,(param-name param) ,(param-default param))) | 43 | `(,(param-name param) ,(param-default param))) |
| 37 | 44 | ||
| 38 | (defun emit-defun (name return-type params method path) | 45 | (defun emit-defun (name return-type params method) |
| 39 | (let ((revparams (reverse params)) | 46 | (let ((revparams (reverse params)) |
| 40 | (args (gensym "ARGS")) | 47 | (args (gensym "ARGS")) |
| 41 | (bot (gensym "BOT"))) | 48 | (bot (gensym "BOT"))) |
| @@ -48,7 +55,7 @@ | |||
| 48 | ,(param-default param)) | 55 | ,(param-default param)) |
| 49 | ,(emit-append-to-args param args)) | 56 | ,(emit-append-to-args param args)) |
| 50 | (emit-append-to-args param args)))) | 57 | (emit-append-to-args param args)))) |
| 51 | (do-call ,bot ,method ,path ',return-type ,args))))) | 58 | (do-call ,bot ,method ,(path-from-name name) ',return-type ,args))))) |
| 52 | 59 | ||
| 53 | (defun emit-ftype (name return-type params) | 60 | (defun emit-ftype (name return-type params) |
| 54 | `(declaim (ftype (function (bot &key ,@(iter (for param in params) | 61 | `(declaim (ftype (function (bot &key ,@(iter (for param in params) |
| @@ -56,11 +63,10 @@ | |||
| 56 | ,return-type) | 63 | ,return-type) |
| 57 | ,name)))) | 64 | ,name)))) |
| 58 | 65 | ||
| 59 | ;; TODO: Automatically derive path from name | ||
| 60 | (defmacro define-tg-method ( | 66 | (defmacro define-tg-method ( |
| 61 | (name type path &optional (method :POST)) | 67 | (name type &optional (method :POST)) |
| 62 | &body param-specs) | 68 | &body param-specs) |
| 63 | (let ((params (parse-param-specs param-specs))) | 69 | (let ((params (parse-param-specs param-specs))) |
| 64 | `(progn | 70 | `(progn |
| 65 | ,(emit-ftype name type params) | 71 | ,(emit-ftype name type params) |
| 66 | ,(emit-defun name type params method path)))) | 72 | ,(emit-defun name type params method)))) |
diff --git a/src/bot/methods.lisp b/src/bot/methods.lisp index 2daea6f..6f01cae 100644 --- a/src/bot/methods.lisp +++ b/src/bot/methods.lisp | |||
| @@ -6,19 +6,19 @@ | |||
| 6 | (:export :answer-callback-query :delete-message :send-animation :edit-message-text :get-me :get-updates :send-message :set-my-name)) | 6 | (:export :answer-callback-query :delete-message :send-animation :edit-message-text :get-me :get-updates :send-message :set-my-name)) |
| 7 | (in-package :ukkoclot/bot/methods) | 7 | (in-package :ukkoclot/bot/methods) |
| 8 | 8 | ||
| 9 | (define-tg-method (answer-callback-query boolean "answerCallbackQuery") | 9 | (define-tg-method (answer-callback-query boolean) |
| 10 | (callback-query-id string) | 10 | (callback-query-id string) |
| 11 | (text (or string null) nil) | 11 | (text (or string null) nil) |
| 12 | (show-alert boolean nil) | 12 | (show-alert boolean nil) |
| 13 | (url (or string null) nil) | 13 | (url (or string null) nil) |
| 14 | (cache-time (or integer null) nil)) | 14 | (cache-time (or integer null) nil)) |
| 15 | 15 | ||
| 16 | (define-tg-method (delete-message boolean "deleteMessage") | 16 | (define-tg-method (delete-message boolean) |
| 17 | (chat-id (or integer string)) | 17 | (chat-id (or integer string)) |
| 18 | (message-id integer)) | 18 | (message-id integer)) |
| 19 | 19 | ||
| 20 | ;; TODO: Add a way to simply specify :message msg :) | 20 | ;; TODO: Add a way to simply specify :message msg :) |
| 21 | (define-tg-method (edit-message-text message "editMessageText") | 21 | (define-tg-method (edit-message-text message) |
| 22 | (business-connection-id (or string null) nil) | 22 | (business-connection-id (or string null) nil) |
| 23 | (chat-id (or integer string null) nil) | 23 | (chat-id (or integer string null) nil) |
| 24 | (message-id (or integer null) nil) | 24 | (message-id (or integer null) nil) |
| @@ -29,7 +29,7 @@ | |||
| 29 | (link-preview-options (or link-preview-options null) nil) | 29 | (link-preview-options (or link-preview-options null) nil) |
| 30 | (reply-markup (or inline-keyboard-markup null) nil)) | 30 | (reply-markup (or inline-keyboard-markup null) nil)) |
| 31 | 31 | ||
| 32 | (define-tg-method (get-me% user "getMe" :GET)) | 32 | (define-tg-method (get-me% user :GET)) |
| 33 | 33 | ||
| 34 | (defun get-me (bot) | 34 | (defun get-me (bot) |
| 35 | (let ((res (get-me% bot))) | 35 | (let ((res (get-me% bot))) |
| @@ -37,16 +37,16 @@ | |||
| 37 | (setf (bot-username% bot) (user-username res)) | 37 | (setf (bot-username% bot) (user-username res)) |
| 38 | res)) | 38 | res)) |
| 39 | 39 | ||
| 40 | (define-tg-method (get-my-name bot-name "getMyName" :GET) | 40 | (define-tg-method (get-my-name bot-name :GET) |
| 41 | (language-code (or string null) nil)) | 41 | (language-code (or string null) nil)) |
| 42 | 42 | ||
| 43 | (define-tg-method (get-updates (array update) "getUpdates") | 43 | (define-tg-method (get-updates (array update)) |
| 44 | (offset (or integer null) nil) | 44 | (offset (or integer null) nil) |
| 45 | (limit (or integer null) nil) | 45 | (limit (or integer null) nil) |
| 46 | (timeout (or integer null) nil) | 46 | (timeout (or integer null) nil) |
| 47 | (allowed-updates (or string null) nil)) | 47 | (allowed-updates (or string null) nil)) |
| 48 | 48 | ||
| 49 | (define-tg-method (send-animation message "sendAnimation") | 49 | (define-tg-method (send-animation message) |
| 50 | (business-connection-id (or string null) nil) | 50 | (business-connection-id (or string null) nil) |
| 51 | (chat-id (or integer string)) | 51 | (chat-id (or integer string)) |
| 52 | (message-thread-id (or integer null) nil) | 52 | (message-thread-id (or integer null) nil) |
| @@ -69,7 +69,7 @@ | |||
| 69 | (reply-parameters (or reply-parameters null) nil) | 69 | (reply-parameters (or reply-parameters null) nil) |
| 70 | (reply-markup (or inline-keyboard-markup reply-keyboard-markup reply-keyboard-remove force-reply null) nil)) | 70 | (reply-markup (or inline-keyboard-markup reply-keyboard-markup reply-keyboard-remove force-reply null) nil)) |
| 71 | 71 | ||
| 72 | (define-tg-method (send-message message "sendMessage") | 72 | (define-tg-method (send-message message) |
| 73 | (business-connection-id (or string null) nil) | 73 | (business-connection-id (or string null) nil) |
| 74 | (chat-id (or integer string)) | 74 | (chat-id (or integer string)) |
| 75 | (message-thread-id (or integer null) nil) | 75 | (message-thread-id (or integer null) nil) |
| @@ -83,7 +83,7 @@ | |||
| 83 | (reply-parameters (or reply-parameters null) nil) | 83 | (reply-parameters (or reply-parameters null) nil) |
| 84 | (reply-markup (or inline-keyboard-markup reply-keyboard-markup reply-keyboard-remove force-reply null) nil)) | 84 | (reply-markup (or inline-keyboard-markup reply-keyboard-markup reply-keyboard-remove force-reply null) nil)) |
| 85 | 85 | ||
| 86 | (define-tg-method (set-my-name% boolean "setMyName") | 86 | (define-tg-method (set-my-name% boolean) |
| 87 | (name (or string null) nil) | 87 | (name (or string null) nil) |
| 88 | (language-code (or string null) nil)) | 88 | (language-code (or string null) nil)) |
| 89 | 89 | ||
diff --git a/src/strings.lisp b/src/strings.lisp index 68289aa..b11c31c 100644 --- a/src/strings.lisp +++ b/src/strings.lisp | |||
| @@ -3,11 +3,23 @@ | |||
| 3 | (defpackage :ukkoclot/strings | 3 | (defpackage :ukkoclot/strings |
| 4 | (:use :c2cl :iterate) | 4 | (:use :c2cl :iterate) |
| 5 | (:import-from :cl-unicode :general-category) | 5 | (:import-from :cl-unicode :general-category) |
| 6 | (:export :escape-xml :is-tg-whitespace-str :lisp->snake-case :snake->lisp-case :starts-with :starts-with-ignore-case)) | 6 | (:export |
| 7 | :ends-with | ||
| 8 | :escape-xml | ||
| 9 | :is-tg-whitespace-str | ||
| 10 | :lisp->camel-case | ||
| 11 | :lisp->snake-case | ||
| 12 | :snake->lisp-case | ||
| 13 | :starts-with | ||
| 14 | :starts-with-ignore-case)) | ||
| 7 | (in-package :ukkoclot/strings) | 15 | (in-package :ukkoclot/strings) |
| 8 | 16 | ||
| 9 | ;; These are very inefficient but I don't care until I profile | 17 | ;; These are very inefficient but I don't care until I profile |
| 10 | 18 | ||
| 19 | (defun ends-with (str suffix) | ||
| 20 | (and (> (length str) (length suffix)) | ||
| 21 | (string= str suffix :start1 (- (length str) (length suffix))))) | ||
| 22 | |||
| 11 | (defun escape-xml (str &optional out) | 23 | (defun escape-xml (str &optional out) |
| 12 | (if out | 24 | (if out |
| 13 | (escape-xml% str out) | 25 | (escape-xml% str out) |
| @@ -36,6 +48,18 @@ | |||
| 36 | (iter (for ch in-string str) | 48 | (iter (for ch in-string str) |
| 37 | (always (is-tg-whitespace ch)))) | 49 | (always (is-tg-whitespace ch)))) |
| 38 | 50 | ||
| 51 | (defun lisp->camel-case (str) | ||
| 52 | (with-output-to-string (out) | ||
| 53 | (let ((should-caps nil)) | ||
| 54 | (iter (for ch in-string str) | ||
| 55 | (cond ((char= ch #\-) | ||
| 56 | (setf should-caps t)) | ||
| 57 | (should-caps | ||
| 58 | (write-char (char-upcase ch) out) | ||
| 59 | (setf should-caps nil)) | ||
| 60 | (t | ||
| 61 | (write-char (char-downcase ch) out))))))) | ||
| 62 | |||
| 39 | (defun lisp->snake-case (str) | 63 | (defun lisp->snake-case (str) |
| 40 | (with-output-to-string (out) | 64 | (with-output-to-string (out) |
| 41 | (loop for ch across str do | 65 | (loop for ch across str do |