mirror of https://github.com/Chizi123/.emacs.d.git

Chizi123
2018-11-21 e75a20334813452c6912c090d70a0de2c805f94d
commit | author | age
76bbd0 1 ;;; ob-ruby.el --- Babel Functions for Ruby          -*- lexical-binding: t; -*-
C 2
3 ;; Copyright (C) 2009-2018 Free Software Foundation, Inc.
4
5 ;; Author: Eric Schulte
6 ;; Keywords: literate programming, reproducible research
7 ;; Homepage: https://orgmode.org
8
9 ;; This file is part of GNU Emacs.
10
11 ;; GNU Emacs is free software: you can redistribute it and/or modify
12 ;; it under the terms of the GNU General Public License as published by
13 ;; the Free Software Foundation, either version 3 of the License, or
14 ;; (at your option) any later version.
15
16 ;; GNU Emacs is distributed in the hope that it will be useful,
17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 ;; GNU General Public License for more details.
20
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
23
24 ;;; Commentary:
25
26 ;; Org-Babel support for evaluating ruby source code.
27
28 ;;; Requirements:
29
30 ;; - ruby and irb executables :: http://www.ruby-lang.org/
31 ;;
32 ;; - ruby-mode :: Can be installed through ELPA, or from
33 ;;   http://github.com/eschulte/rinari/raw/master/util/ruby-mode.el
34 ;;
35 ;; - inf-ruby mode :: Can be installed through ELPA, or from
36 ;;   http://github.com/eschulte/rinari/raw/master/util/inf-ruby.el
37
38 ;;; Code:
39 (require 'ob)
40
41 (declare-function org-trim "org" (s &optional keep-lead))
42 (declare-function run-ruby "ext:inf-ruby" (&optional command name))
43 (declare-function xmp "ext:rcodetools" (&optional option))
44
45 (defvar inf-ruby-default-implementation)
46 (defvar inf-ruby-implementations)
47
48 (defvar org-babel-tangle-lang-exts)
49 (add-to-list 'org-babel-tangle-lang-exts '("ruby" . "rb"))
50
51 (defvar org-babel-default-header-args:ruby '())
52
53 (defvar org-babel-ruby-command "ruby"
54   "Name of command to use for executing ruby code.")
55
56 (defcustom org-babel-ruby-hline-to "nil"
57   "Replace hlines in incoming tables with this when translating to ruby."
58   :group 'org-babel
59   :version "24.4"
60   :package-version '(Org . "8.0")
61   :type 'string)
62
63 (defcustom org-babel-ruby-nil-to 'hline
64   "Replace nil in ruby tables with this before returning."
65   :group 'org-babel
66   :version "24.4"
67   :package-version '(Org . "8.0")
68   :type 'symbol)
69
70 (defun org-babel-execute:ruby (body params)
71   "Execute a block of Ruby code with Babel.
72 This function is called by `org-babel-execute-src-block'."
73   (let* ((session (org-babel-ruby-initiate-session
74            (cdr (assq :session params))))
75          (result-params (cdr (assq :result-params params)))
76          (result-type (cdr (assq :result-type params)))
77          (full-body (org-babel-expand-body:generic
78              body params (org-babel-variable-assignments:ruby params)))
79          (result (if (member "xmp" result-params)
80              (with-temp-buffer
81                (require 'rcodetools)
82                (insert full-body)
83                (xmp (cdr (assq :xmp-option params)))
84                (buffer-string))
85            (org-babel-ruby-evaluate
86             session full-body result-type result-params))))
87     (org-babel-reassemble-table
88      (org-babel-result-cond result-params
89        result
90        (org-babel-ruby-table-or-string result))
91      (org-babel-pick-name (cdr (assq :colname-names params))
92               (cdr (assq :colnames params)))
93      (org-babel-pick-name (cdr (assq :rowname-names params))
94               (cdr (assq :rownames params))))))
95
96 (defun org-babel-prep-session:ruby (session params)
97   "Prepare SESSION according to the header arguments specified in PARAMS."
98   ;; (message "params=%S" params) ;; debugging
99   (let* ((session (org-babel-ruby-initiate-session session))
100          (var-lines (org-babel-variable-assignments:ruby params)))
101     (org-babel-comint-in-buffer session
102       (sit-for .5) (goto-char (point-max))
103       (mapc (lambda (var)
104               (insert var) (comint-send-input nil t)
105               (org-babel-comint-wait-for-output session)
106               (sit-for .1) (goto-char (point-max))) var-lines))
107     session))
108
109 (defun org-babel-load-session:ruby (session body params)
110   "Load BODY into SESSION."
111   (save-window-excursion
112     (let ((buffer (org-babel-prep-session:ruby session params)))
113       (with-current-buffer buffer
114         (goto-char (process-mark (get-buffer-process (current-buffer))))
115         (insert (org-babel-chomp body)))
116       buffer)))
117
118 ;; helper functions
119
120 (defun org-babel-variable-assignments:ruby (params)
121   "Return list of ruby statements assigning the block's variables."
122   (mapcar
123    (lambda (pair)
124      (format "%s=%s"
125          (car pair)
126          (org-babel-ruby-var-to-ruby (cdr pair))))
127    (org-babel--get-vars params)))
128
129 (defun org-babel-ruby-var-to-ruby (var)
130   "Convert VAR into a ruby variable.
131 Convert an elisp value into a string of ruby source code
132 specifying a variable of the same value."
133   (if (listp var)
134       (concat "[" (mapconcat #'org-babel-ruby-var-to-ruby var ", ") "]")
135     (if (eq var 'hline)
136     org-babel-ruby-hline-to
137       (format "%S" var))))
138
139 (defun org-babel-ruby-table-or-string (results)
140   "Convert RESULTS into an appropriate elisp value.
141 If RESULTS look like a table, then convert them into an
142 Emacs-lisp table, otherwise return the results as a string."
143   (let ((res (org-babel-script-escape results)))
144     (if (listp res)
145         (mapcar (lambda (el) (if (not el)
146                  org-babel-ruby-nil-to el))
147                 res)
148       res)))
149
150 (defun org-babel-ruby-initiate-session (&optional session _params)
151   "Initiate a ruby session.
152 If there is not a current inferior-process-buffer in SESSION
153 then create one.  Return the initialized session."
154   (unless (string= session "none")
155     (require 'inf-ruby)
156     (let* ((cmd (cdr (assoc inf-ruby-default-implementation
157                 inf-ruby-implementations)))
158        (buffer (get-buffer (format "*%s*" session)))
159        (session-buffer (or buffer (save-window-excursion
160                     (run-ruby cmd session)
161                     (current-buffer)))))
162       (if (org-babel-comint-buffer-livep session-buffer)
163       (progn (sit-for .25) session-buffer)
164     (sit-for .5)
165     (org-babel-ruby-initiate-session session)))))
166
167 (defvar org-babel-ruby-eoe-indicator ":org_babel_ruby_eoe"
168   "String to indicate that evaluation has completed.")
169 (defvar org-babel-ruby-f-write
170   "File.open('%s','w'){|f| f.write((_.class == String) ? _ : _.inspect)}")
171 (defvar org-babel-ruby-pp-f-write
172   "File.open('%s','w'){|f| $stdout = f; pp(results); $stdout = orig_out}")
173 (defvar org-babel-ruby-wrapper-method
174   "
175 def main()
176 %s
177 end
178 results = main()
179 File.open('%s', 'w'){ |f| f.write((results.class == String) ? results : results.inspect) }
180 ")
181 (defvar org-babel-ruby-pp-wrapper-method
182   "
183 require 'pp'
184 def main()
185 %s
186 end
187 results = main()
188 File.open('%s', 'w') do |f|
189   $stdout = f
190   pp results
191 end
192 ")
193
194 (defun org-babel-ruby-evaluate
195     (buffer body &optional result-type result-params)
196   "Pass BODY to the Ruby process in BUFFER.
197 If RESULT-TYPE equals `output' then return a list of the outputs
198 of the statements in BODY, if RESULT-TYPE equals `value' then
199 return the value of the last statement in BODY, as elisp."
200   (if (not buffer)
201       ;; external process evaluation
202       (pcase result-type
203     (`output (org-babel-eval org-babel-ruby-command body))
204     (`value (let ((tmp-file (org-babel-temp-file "ruby-")))
205           (org-babel-eval
206            org-babel-ruby-command
207            (format (if (member "pp" result-params)
208                    org-babel-ruby-pp-wrapper-method
209                  org-babel-ruby-wrapper-method)
210                body (org-babel-process-file-name tmp-file 'noquote)))
211           (org-babel-eval-read-file tmp-file))))
212     ;; comint session evaluation
213     (pcase result-type
214       (`output
215        (let ((eoe-string (format "puts \"%s\"" org-babel-ruby-eoe-indicator)))
216      ;; Force the session to be ready before the actual session
217      ;; code is run.  There is some problem in comint that will
218      ;; sometimes show the prompt after the the input has already
219      ;; been inserted and that throws off the extraction of the
220      ;; result for Babel.
221      (org-babel-comint-with-output
222          (buffer org-babel-ruby-eoe-indicator t eoe-string)
223        (insert eoe-string) (comint-send-input nil t))
224      ;; Now we can start the evaluation.
225      (mapconcat
226       #'identity
227       (butlast
228        (split-string
229         (mapconcat
230          #'org-trim
231          (org-babel-comint-with-output
232          (buffer org-babel-ruby-eoe-indicator t body)
233            (mapc
234         (lambda (line)
235           (insert (org-babel-chomp line)) (comint-send-input nil t))
236         (list "conf.echo=false;_org_prompt_mode=conf.prompt_mode;conf.prompt_mode=:NULL"
237               body
238               "conf.prompt_mode=_org_prompt_mode;conf.echo=true"
239               eoe-string)))
240          "\n") "[\r\n]") 4) "\n")))
241       (`value
242        (let* ((tmp-file (org-babel-temp-file "ruby-"))
243           (ppp (or (member "code" result-params)
244                (member "pp" result-params))))
245      (org-babel-comint-with-output
246          (buffer org-babel-ruby-eoe-indicator t body)
247        (when ppp (insert "require 'pp';") (comint-send-input nil t))
248        (mapc
249         (lambda (line)
250           (insert (org-babel-chomp line)) (comint-send-input nil t))
251         (append
252          (list body)
253          (if (not ppp)
254          (list (format org-babel-ruby-f-write
255                    (org-babel-process-file-name tmp-file 'noquote)))
256            (list
257         "results=_" "require 'pp'" "orig_out = $stdout"
258         (format org-babel-ruby-pp-f-write
259             (org-babel-process-file-name tmp-file 'noquote))))
260          (list org-babel-ruby-eoe-indicator)))
261        (comint-send-input nil t))
262      (org-babel-eval-read-file tmp-file))))))
263
264 (provide 'ob-ruby)
265
266
267
268 ;;; ob-ruby.el ends here