Skip to content
This repository has been archived by the owner on Nov 26, 2021. It is now read-only.

Commit

Permalink
Add session async for ruby (#2)
Browse files Browse the repository at this point in the history
* Add session asycn for ruby

* Handle results pp

* Fix typo

* Add ruby chunk callback for better output and add unit tests

* Rename R test file

* Fix failed unit tests for R and increase timeout for ruby test

* Add missing unit tests for ruby named output

* Update author
  • Loading branch information
suonlight authored and jackkamm committed Oct 17, 2019
1 parent 540fd88 commit 578b923
Show file tree
Hide file tree
Showing 5 changed files with 209 additions and 2 deletions.
1 change: 1 addition & 0 deletions Cask
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@
:git "https://code.orgmode.org/bzg/org-mode.git"
:files ("lisp/*.el" "contrib/lisp/*.el" "testing/org-test.el"))
(depends-on "ob-async")
(depends-on "inf-ruby")
(depends-on "ess"))
115 changes: 115 additions & 0 deletions lisp/ob-session-async-ruby.el
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
;;; ob-session-async-ruby.el --- Async Babel Interaction with Ruby sessions -*- lexical-binding: t -*-

;; Copyright (C) 2019

;; Author: <minh.nh1989@gmail.com>

;; This file is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.

;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.

;; For a full copy of the GNU General Public License
;; see <http://www.gnu.org/licenses/>.


;;; Commentary:

;; Support for evaluating Ruby code asynchronously in org-babel sessions.

;;; Code:

(require 'ob-ruby)
(require 'ob-session-async)
(require 'subr-x)

(defun ob-session-async-org-babel-execute:ruby (orig-fun body params)
"Advice around `org-babel-execute:ruby' to enable asynchronous evaluation."
(let ((async (assq :async params))
(session (assq :session params)))
(if (or (not async)
(equal (cdr async) "no")
(equal (cdr session) "none"))
(funcall orig-fun body params)
(advice-add 'org-babel-ruby-evaluate
:override 'ob-session-async-org-babel-ruby-evaluate-session)
(let ((result (funcall orig-fun body params)))
(advice-remove 'org-babel-ruby-evaluate 'ob-session-async-org-babel-ruby-evaluate-session)
result))))

(advice-add 'org-babel-execute:ruby :around 'ob-session-async-org-babel-execute:ruby)

(defconst ob-session-async-ruby-indicator "puts 'ob_comint_async_ruby_%s_%s'")

(defun ob-session-async-ruby-chunk-callback (string)
(let* ((prefix-regexp "^=> nil\nirb([A-Za-z]+)[0-9:]+> ")
(suffix-regexp "\n=> true\nirb([A-Za-z]+)[0-9:]+>$")
(new-string (replace-regexp-in-string suffix-regexp ""
(replace-regexp-in-string prefix-regexp "" string))))
(org-babel-chomp new-string)))

(defun ob-session-async-org-babel-ruby-evaluate-session (buffer body &optional result-type result-params)
"Asynchronously evaluate BODY in SESSION.
Returns a placeholder string for insertion, to later be replaced
by `ob-session-async-filter'."
(ob-session-async-register
buffer (current-buffer)
"ob_comint_async_ruby_\\(.+\\)_\\(.+\\)"
'ob-session-async-ruby-chunk-callback
'ob-session-async-ruby-value-callback)
;; comint session evaluation
(pcase result-type
(`output
(let* ((uuid (md5 (number-to-string (random 100000000)))))
(with-current-buffer buffer
(mapc
(lambda (line)
(insert (org-babel-chomp line)) (comint-send-input nil t))
(list
(format ob-session-async-ruby-indicator "start" uuid)
"conf.echo=false;_org_prompt_mode=conf.prompt_mode;conf.prompt_mode=:NULL"
body
"conf.prompt_mode=_org_prompt_mode;conf.echo=true"
(format ob-session-async-ruby-indicator "end" uuid)))
(comint-send-input))
uuid))
(`value
(let* ((tmp-file (org-babel-temp-file "ruby-"))
(ppp (or (member "code" result-params)
(member "pp" result-params))))
(with-current-buffer buffer
;; (buffer org-babel-ruby-eoe-indicator t body)
(when ppp (insert "\nrequire 'pp';") (comint-send-input nil t))
(insert "\n")
(mapc
(lambda (line)
(insert (org-babel-chomp line)) (comint-send-input nil t))
(append
(list body)
(if (not ppp)
(list (format org-babel-ruby-f-write
(org-babel-process-file-name tmp-file 'noquote)))
(list
"results=_" "require 'pp'" "orig_out = $stdout"
(format org-babel-ruby-pp-f-write
(org-babel-process-file-name tmp-file 'noquote))))
(list (format ob-session-async-ruby-indicator "file" tmp-file))))
(comint-send-input nil t))
tmp-file))))

(defun ob-session-async-ruby-value-callback (params tmp-file)
"Callback for async value results.
Assigned locally to `ob-session-async-file-callback' in Ruby
comint buffers used for asynchronous Babel evaluation."
(with-temp-buffer
(insert-file-contents tmp-file)
(buffer-string)))

(provide 'ob-session-async-ruby)

;;; ob-session-async-ruby.el ends here
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
;;; ob-session-async-test.el --- Tests for ob-session-async
;;; ob-session-async-R-test.el --- Tests for ob-session-async

(require 'org-test)
(require 'ess-r-mode)
Expand All @@ -7,6 +7,7 @@
(ert-deftest ob-session-async-R-simple-session-async-value ()
(let (ess-ask-for-ess-directory
ess-history-file
(org-babel-temporary-directory "/tmp")
(org-confirm-babel-evaluate nil))
(org-test-with-temp-text
"#+begin_src R :session R :async yes\n Sys.sleep(.1)\n paste(\"Yep!\")\n#+end_src\n"
Expand All @@ -21,6 +22,7 @@
(ert-deftest ob-session-async-R-simple-session-async-output ()
(let (ess-ask-for-ess-directory
ess-history-file
(org-babel-temporary-directory "/tmp")
(org-confirm-babel-evaluate nil))
(org-test-with-temp-text
"#+begin_src R :session R :results output :async yes\n Sys.sleep(.1)\n 1:5\n#+end_src\n"
Expand All @@ -35,6 +37,7 @@
(ert-deftest ob-session-async-R-named-output ()
(let (ess-ask-for-ess-directory
ess-history-file
(org-babel-temporary-directory "/tmp")
org-confirm-babel-evaluate
(src-block "#+begin_src R :async :session R :results output\n 1:5\n#+end_src")
(results-before "\n\n#+NAME: foobar\n#+RESULTS:\n: [1] 1")
Expand All @@ -50,6 +53,7 @@
(let (ess-ask-for-ess-directory
ess-history-file
org-confirm-babel-evaluate
(org-babel-temporary-directory "/tmp")
(src-block "#+begin_src R :async :session R :results value\n paste(\"Yep!\")\n#+end_src")
(results-before "\n\n#+NAME: foobar\n#+RESULTS:\n: [1] 1")
(results-after "\n\n#+NAME: foobar\n#+RESULTS:\n: Yep!\n"))
Expand All @@ -64,6 +68,7 @@
(let (ess-ask-for-ess-directory
ess-history-file
org-confirm-babel-evaluate
(org-babel-temporary-directory "/tmp")
(src-block "#+begin_src R :async :session R :results output drawer\n 1:5\n#+end_src")
(result "\n\n#+RESULTS:\n:results:\n[1] 1 2 3 4 5\n:end:\n"))
(org-test-with-temp-text
Expand All @@ -77,6 +82,7 @@
(let (ess-ask-for-ess-directory
ess-history-file
org-confirm-babel-evaluate
(org-babel-temporary-directory "/tmp")
(src-block "#+begin_src R :async :session R :results value drawer\n 1:3\n#+end_src")
(result "\n\n#+RESULTS:\n:results:\n1\n2\n3\n:end:\n"))
(org-test-with-temp-text
Expand All @@ -86,4 +92,4 @@
(string= (concat src-block result)
(buffer-string)))))))

;;; ob-session-async-test.el ends here
;;; ob-session-async-R-test.el ends here
82 changes: 82 additions & 0 deletions test/ob-session-async-ruby-test.el
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
;;; ob-session-async-ruby-test.el --- Tests for ob-session-async

(require 'org-test)
(require 'ob-session-async-ruby)

(ert-deftest ob-session-async-ruby-simple-session-async-value ()
(let ((org-babel-temporary-directory "/tmp")
(org-confirm-babel-evaluate nil))
(org-test-with-temp-text
"#+begin_src ruby :async :session ruby :results value\n\"Yep!\"\n#+end_src\n"
(should (let ((expected "Yep!"))
(string= expected
(progn
(org-babel-execute-src-block)
(sleep-for 0 300)
(goto-char (org-babel-where-is-src-block-result))
(org-babel-read-result))))))))

(ert-deftest ob-session-async-ruby-simple-session-async-output ()
(let ((org-babel-temporary-directory "/tmp")
(org-confirm-babel-evaluate nil))
(org-test-with-temp-text
"#+begin_src ruby :async :session ruby :results output\np [1, 2, 3, 4]\n#+end_src\n"
(should (let ((expected "[1, 2, 3, 4]"))
(and (not (string= expected (org-babel-execute-src-block)))
(string-match-p expected
(progn
(sleep-for 0 400)
(goto-char (org-babel-where-is-src-block-result))
(org-babel-read-result)))))))))

(ert-deftest ob-session-async-ruby-named-output ()
(let ((org-babel-temporary-directory "/tmp")
(org-confirm-babel-evaluate nil)
(src-block "#+begin_src ruby :async :session ruby :results output\n p [1, 2, 3, 4]\n#+end_src")
(results-before "\n\n#+NAME: foobar\n#+RESULTS:\n: [1, 2, 3, 4]")
(results-after "\n\n#+NAME: foobar\n#+RESULTS:\n: [1, 2, 3, 4]\n"))
(org-test-with-temp-text
(concat src-block results-before)
(should (progn (org-babel-execute-src-block)
(sleep-for 0 400)
(string= (concat src-block results-after)
(buffer-string)))))))

(ert-deftest ob-session-async-ruby-named-value ()
(let ((org-babel-temporary-directory "/tmp")
(org-confirm-babel-evaluate nil)
(src-block "#+begin_src ruby :async :session ruby :results value\n\"Yep!\"\n#+end_src")
(results-before "\n\n#+NAME: foobar\n#+RESULTS:\n: [1] 1")
(results-after "\n\n#+NAME: foobar\n#+RESULTS:\n: Yep!\n"))
(org-test-with-temp-text
(concat src-block results-before)
(should (progn (org-babel-execute-src-block)
(sleep-for 0 400)
(string= (concat src-block results-after)
(buffer-string)))))))

(ert-deftest ob-session-async-ruby-output-drawer ()
(let ((org-babel-temporary-directory "/tmp")
(org-confirm-babel-evaluate nil)
(src-block "#+begin_src ruby :async :session ruby :results output drawer\np [1, 2, 3, 4]\n#+end_src")
(result "\n\n#+RESULTS:\n:results:\n[1, 2, 3, 4]\n:end:\n"))
(org-test-with-temp-text
src-block
(should (progn (org-babel-execute-src-block)
(sleep-for 0 400)
(string= (concat src-block result)
(buffer-string)))))))

(ert-deftest ob-session-async-ruby-value-drawer ()
(let ((org-babel-temporary-directory "/tmp")
(org-confirm-babel-evaluate nil)
(src-block "#+begin_src ruby :async :session ruby :results value drawer\n [1, 2, 3, 4]\n#+end_src")
(result "\n\n#+RESULTS:\n:results:\n[1, 2, 3, 4]\n:end:\n"))
(org-test-with-temp-text
src-block
(should (progn (org-babel-execute-src-block)
(sleep-for 0 400)
(string= (concat src-block result)
(buffer-string)))))))

;;; ob-session-async-ruby-test.el ends here
3 changes: 3 additions & 0 deletions test/test-helper.el
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
;;; test-helper.el --- Helpers for ob-session-async-test.el

(when (> emacs-major-version 26)
(defalias 'ert--print-backtrace 'backtrace-to-string))

;;; test-helper.el ends here

0 comments on commit 578b923

Please sign in to comment.