unofficial mirror of emacs-orgmode@gnu.org
 help / color / mirror / Atom feed
* [PATCH] ob-java
@ 2020-10-05 12:35 ian martins
  2020-10-05 13:23 ` ian martins
  2020-10-24 11:58 ` Bastien
  0 siblings, 2 replies; 31+ messages in thread
From: ian martins @ 2020-10-05 12:35 UTC (permalink / raw)
  To: Org-Mode mailing list


[-- Attachment #1.1: Type: text/plain, Size: 2409 bytes --]

1 Changes
=========

  - support for functional mode (`:results value')
  - accept variables
  - don't require package, class, and main definitions
  - write source and result tempfiles to
    `org-babel-temporary-directory', but respects the `:dir' header
  - work with tramp


2 Examples
==========
Some examples follow.  See the tests for more examples.  I'll write proper
docs after review.

2.1 Example 1
~~~~~~~~~~~~~

  This outputs "hello."  If class and main definitions aren't given the
  code block will be wrapped in generic ones.

  ,----
  | System.out.print("hello");
  `----

  This is exactly equivalent:

  ,----
  | public class Main {
  |     public static void main(String[] args) {
  |         System.out.print("hello");
  |     }
  | }
  `----


2.2 Example 2
~~~~~~~~~~~~~

  This also outputs "hello."

  ,----
  | return "hello";
  `----


2.3 Example 3
~~~~~~~~~~~~~

  This generates the class "Example" in the package "org.orgmode" in the
  current directory.

  ,----
  | System.out.print("hello, org-mode");
  `----


2.4 Example 4
~~~~~~~~~~~~~

  The "Hey" class defines a static method but no main. C-c C-c on the
  "Hey" source block will write "./org/orgmode/Hey.java" and compile it.

  The "Main" class calls the "Hey" class. C-c C-c on the "Main" source
  block will write "./org/orgmode/Main.java" and compile and run it.

  ,----
  | package org.orgmode;
  |
  | public class Hey {
  |     public static String say() {
  |         return "hey";
  |     }
  | }
  `----

  ,----
  | package org.orgmode;
  |
  | public class Main {
  |     public static void main(String[] args) {
  |         System.out.print(Hey.say());
  |     }
  | }
  `----

  Instead of C-c C-c, we could have added tangle headers and written the
  source files out by tangling.


2.5 Example 5
~~~~~~~~~~~~~

  This prints the variable from the header

  ,----
  | System.out.print(msg);
  `----


2.6 Example 6
~~~~~~~~~~~~~

  This prints "hello, org-mode." The table is provided to the method as
  a list of lists.

   message  hello, org-mode

  ,----
  | System.out.print(tbl.get(0).get(1));
  `----


2.7 Example 7
~~~~~~~~~~~~~

  This example returns a list.

  Note that you're allowed to specify imports without defining the class
  or main methods.

  ,----
  | import java.util.Arrays;
  |
  | return Arrays.asList("message", "hello, org-mode");
  `----

   message  hello, org-mode

[-- Attachment #1.2: Type: text/html, Size: 3164 bytes --]

[-- Attachment #2: 0001-ob-java.el-Add-support-for-variables-return-values-t.patch --]
[-- Type: text/x-patch, Size: 39369 bytes --]

From e525a1328fee6f764c40a2158376d78e406391ae Mon Sep 17 00:00:00 2001
From: Ian Martins <ianxm@jhu.edu>
Date: Mon, 5 Oct 2020 08:07:25 -0400
Subject: [PATCH] ob-java.el: Add support for variables, return values, tramp

* lisp/ob-java.el: Add support for variables and return values.  Write
tempfiles to the org-babel-temporary-directory.  Make package, class,
and main method definitions optional.

* testing/lisp/test-ob-java.el: Add tests.
---
 lisp/ob-java.el              | 425 +++++++++++++++++++++++---
 testing/lisp/test-ob-java.el | 574 +++++++++++++++++++++++++++++++++++
 2 files changed, 958 insertions(+), 41 deletions(-)
 create mode 100644 testing/lisp/test-ob-java.el

diff --git a/lisp/ob-java.el b/lisp/ob-java.el
index fee695bb9..94c3f69cf 100644
--- a/lisp/ob-java.el
+++ b/lisp/ob-java.el
@@ -1,9 +1,8 @@
-;;; ob-java.el --- Babel Functions for Java          -*- lexical-binding: t; -*-
+;;; ob-java.el --- org-babel functions for java evaluation -*- lexical-binding: t -*-
 
 ;; Copyright (C) 2011-2020 Free Software Foundation, Inc.
 
-;; Author: Eric Schulte
-;; Maintainer: Ian Martins <ianxm@jhu.edu>
+;; Author: Ian Martins <ianxm@jhu.edu>
 ;; Keywords: literate programming, reproducible research
 ;; Homepage: https://orgmode.org
 
@@ -24,61 +23,405 @@
 
 ;;; Commentary:
 
-;; Currently this only supports the external compilation and execution
-;; of java code blocks (i.e., no session support).
+;; Org-Babel support for evaluating java source code.
 
 ;;; Code:
 (require 'ob)
 
+(defvar org-babel-temporary-directory) ; from ob-core
+
 (defvar org-babel-tangle-lang-exts)
 (add-to-list 'org-babel-tangle-lang-exts '("java" . "java"))
 
-(defcustom org-babel-java-command "java"
-  "Name of the java command.
-May be either a command in the path, like java
-or an absolute path name, like /usr/local/bin/java
-parameters may be used, like java -verbose"
+(defvar org-babel-default-header-args:java '()
+  "Default header args for java source blocks.")
+
+(defconst org-babel-header-args:java '((imports . :any))
+  "Java-specific header arguments.")
+
+(defvar org-babel-java-compiler-command "javac"
+  "Name of the command to execute the java compiler.")
+
+(defvar org-babel-java-runtime-command "java"
+  "Name of the command to run the java runtime.")
+
+(defcustom org-babel-java-hline-to "null"
+  "Replace hlines in incoming tables with this when translating to java."
   :group 'org-babel
-  :version "24.3"
+  :version "25.2"
+  :package-version '(Org . "9.3")
   :type 'string)
 
-(defcustom org-babel-java-compiler "javac"
-  "Name of the java compiler.
-May be either a command in the path, like javac
-or an absolute path name, like /usr/local/bin/javac
-parameters may be used, like javac -verbose"
+(defcustom org-babel-java-null-to 'hline
+  "Replace `null' in java tables with this before returning."
   :group 'org-babel
-  :version "24.3"
-  :type 'string)
+  :version "25.2"
+  :package-version '(Org . "9.3")
+  :type 'symbol)
 
 (defun org-babel-execute:java (body params)
-  (let* ((classname (or (cdr (assq :classname params))
-			(error
-			 "Can't compile a java block without a classname")))
-	 (packagename (file-name-directory classname))
-	 (src-file (concat classname ".java"))
+  "Execute a java source block with BODY code and PARAMS params."
+  (let* (;; if true, run from babel temp directory
+         (run-from-temp (not (assq :dir params)))
+         ;; class and package
+         (fullclassname (or (cdr (assq :classname params))
+                            (org-babel-java-find-classname body)))
+         ;; just the class name
+         (classname (car (last (split-string fullclassname "\\."))))
+         ;; just the package name
+         (packagename (if (seq-contains fullclassname ?.)
+                          (file-name-base fullclassname)))
+         ;; the base dir that contains the top level package dir
+         (basedir (file-name-as-directory (if run-from-temp
+                                              org-babel-temporary-directory
+                                            ".")))
+         ;; the dir to write the source file
+         (packagedir (if (and (not run-from-temp) packagename)
+                         (file-name-as-directory
+                          (concat basedir (replace-regexp-in-string "\\\." "/" packagename)))
+                       basedir))
+         ;; the filename of the source file
+         (src-file (concat packagedir classname ".java"))
+	 ;; compiler flags
 	 (cmpflag (or (cdr (assq :cmpflag params)) ""))
-	 (cmdline (or (cdr (assq :cmdline params)) ""))
+	 ;; runtime flags
+         (cmdline (or (cdr (assq :cmdline params)) ""))
+         ;; command line args
 	 (cmdargs (or (cdr (assq :cmdargs params)) ""))
-	 (full-body (org-babel-expand-body:generic body params)))
+         ;; the command to compile and run
+         (cmd (concat org-babel-java-compiler-command " " cmpflag " "
+                      (org-babel-process-file-name src-file 'noquote)
+                      " && " org-babel-java-runtime-command
+                      " -cp " (org-babel-process-file-name basedir 'noquote)
+		      " " cmdline " " (if run-from-temp classname fullclassname)
+		      " " cmdargs))
+         ;; header args for result processing
+         (result-type (cdr (assq :result-type params)))
+         (result-params (cdr (assq :result-params params)))
+         (result-file (and (eq result-type 'value)
+                           (org-babel-temp-file "java-")))
+         ;; the expanded body of the source block
+         (full-body (org-babel-expand-body:java body params)))
+
     ;; created package-name directories if missing
-    (unless (or (not packagename) (file-exists-p packagename))
-      (make-directory packagename 'parents))
+    (unless (or (not packagedir) (file-exists-p packagedir))
+      (make-directory packagedir 'parents))
+
+    ;; write the source file
+    (setq full-body (org-babel-java--expand-for-evaluation
+		     full-body run-from-temp result-type result-file))
     (with-temp-file src-file (insert full-body))
-    (org-babel-eval
-     (concat org-babel-java-compiler " " cmpflag " " src-file) "")
-    (let ((results (org-babel-eval (concat org-babel-java-command
-                                           " " cmdline " " classname " " cmdargs) "")))
-      (org-babel-reassemble-table
-       (org-babel-result-cond (cdr (assq :result-params params))
-	 (org-babel-read results t)
-         (let ((tmp-file (org-babel-temp-file "c-")))
-           (with-temp-file tmp-file (insert results))
-           (org-babel-import-elisp-from-file tmp-file)))
-       (org-babel-pick-name
-        (cdr (assq :colname-names params)) (cdr (assq :colnames params)))
-       (org-babel-pick-name
-        (cdr (assq :rowname-names params)) (cdr (assq :rownames params)))))))
+
+    ;; compile, run, process result
+    (org-babel-reassemble-table
+     (org-babel-java-evaluate cmd result-type result-params result-file)
+     (org-babel-pick-name
+      (cdr (assoc :colname-names params)) (cdr (assoc :colnames params)))
+     (org-babel-pick-name
+      (cdr (assoc :rowname-names params)) (cdr (assoc :rownames params))))))
+
+;; helper functions
+
+(defun org-babel-java-find-classname (body)
+  "Try to find fully qualified class name in BODY.
+Look through BODY for the package and class.  If found, put them
+together into a fully qualified class name and return.  Else just
+return class name.  If that isn't found either, default to Main."
+  (let ((package (if (string-match "package \\\([^ ]*\\\);" body)
+                     (match-string 1 body)))
+        (class (if (string-match "public class \\\([^ \n]*\\\)" body)
+                   (match-string 1 body))))
+    (or (and package class (concat package "." class))
+        (and class class)
+        (and package (concat package ".Main"))
+        "Main")))
+
+(defconst org-babel-java--package-re "^[[:space:]]*package .*;$"
+  "Regexp for the package statement.")
+(defconst org-babel-java--imports-re "^[[:space:]]*import .*;$"
+  "Regexp for import statements.")
+(defconst org-babel-java--class-re "^public class [[:alnum:]_]+[[:space:]]*\n?[[:space:]]*{"
+  "Regexp for the class declaration.")
+(defconst org-babel-java--main-re "public static void main(String\\(?:\\[]\\)? args\\(?:\\[]\\)?).*\n?[[:space:]]*{"
+  "Regexp for the main method declaration.")
+(defconst org-babel-java--any-method-re "public .*(.*).*\n?[[:space:]]*{"
+  "Regexp for any method.")
+(defconst org-babel-java--result-wrapper "\n    public static String __toString(Object val) {
+        if (val instanceof String) {
+            return \"\\\"\" + val + \"\\\"\";
+        } else if (val == null) {
+            return \"null\";
+        } else if (val.getClass().isArray()) {
+            StringBuffer sb = new StringBuffer();
+            Object[] vals = (Object[])val;
+            sb.append(\"[\");
+            for (int ii=0; ii<vals.length; ii++) {
+                sb.append(__toString(vals[ii]));
+                if (ii<vals.length-1)
+                    sb.append(\",\");
+            }
+            sb.append(\"]\");
+            return sb.toString();
+        } else if (val instanceof List) {
+            StringBuffer sb = new StringBuffer();
+            List vals = (List)val;
+            sb.append(\"[\");
+            for (int ii=0; ii<vals.size(); ii++) {
+                sb.append(__toString(vals.get(ii)));
+                if (ii<vals.size()-1)
+                    sb.append(\",\");
+            }
+            sb.append(\"]\");
+            return sb.toString();
+        } else {
+            return String.valueOf(val);
+        }
+    }
+
+    public static void main(String[] args) throws IOException {
+        BufferedWriter output = new BufferedWriter(new FileWriter(\"%s\"));
+        output.write(__toString(_main(args)));
+        output.close();
+    }"
+  "Code to inject into a class so that we can capture the value it returns.
+This implementation was inspired by ob-python, although not as
+elegant.  This modified the source block to write out the value
+it wants to return to a temporary file so that ob-java can read
+it back.  The name of the temporary file to write must be
+replaced in this string.")
+
+(defun org-babel-java--expand-for-evaluation (body suppress-package-p result-type result-file)
+  "Expand source block for evaluation.
+In order to return a value we have to add a __toString method.
+In order to prevent classes without main methods from erroring we
+add a dummy main method if one is not provided.  These
+manipulations are done outside of `org-babel--expand-body' so
+that they are hidden from tangles.
+
+BODY is the file content before instrumentation.
+
+SUPPRESS-PACKAGE-P if true, suppress the package statement.
+
+RESULT-TYPE is taken from params.
+
+RESULT-FILE is the temp file to write the result."
+  (with-temp-buffer
+    (insert body)
+
+    ;; suppress package statement
+    (goto-char (point-min))
+    (when (and suppress-package-p
+	       (re-search-forward org-babel-java--package-re nil t))
+      (replace-match ""))
+
+    ;; add a dummy main method if needed
+    (goto-char (point-min))
+    (when (not (re-search-forward org-babel-java--main-re nil t))
+      (org-babel-java--move-past org-babel-java--class-re)
+      (insert "\n    public static void main(String[] args) {
+        System.out.print(\"success\");
+}\n\n"))
+
+    ;; special handling to return value
+    (when (eq result-type 'value)
+      (goto-char (point-min))
+      (org-babel-java--move-past org-babel-java--class-re)
+      (insert (format org-babel-java--result-wrapper
+		      (org-babel-process-file-name result-file 'noquote)))
+      (search-forward "public static void main(") ; rename existing main
+      (replace-match "public static Object _main("))
+
+    ;; add imports
+    (org-babel-java--import-maybe "java.util" "List")
+    (org-babel-java--import-maybe "java.util" "Arrays")
+    (org-babel-java--import-maybe "java.io" "BufferedWriter")
+    (org-babel-java--import-maybe "java.io" "FileWriter")
+    (org-babel-java--import-maybe "java.io" "IOException")
+
+    (buffer-string)))
+
+(defun org-babel-java--move-past (re)
+  "Move point past the first occurrence of the given regexp RE."
+  (while (re-search-forward re nil t)
+    (goto-char (1+ (match-end 0)))))
+
+(defun org-babel-java--import-maybe (package class)
+  "Import from PACKAGE the given CLASS if it is used and not already imported."
+  (let (class-found import-found)
+    (goto-char (point-min))
+    (setq class-found (re-search-forward class nil t))
+    (goto-char (point-min))
+    (setq import-found (re-search-forward (concat "^import .*" package ".*" class ";") nil t))
+    (message "%s.%s: %s %s" package class class-found import-found)
+    (when (and class-found (not import-found))
+      (org-babel-java--move-past org-babel-java--package-re)
+      (insert (concat "import " package "." class ";\n")))))
+
+(defun org-babel-expand-body:java (body params)
+  "Expand BODY with PARAMS.
+BODY could be a few statements, or could include a full class
+definition specifying package, imports, and class.  Because we
+allow this flexibility in what the source block can contain, it
+is simplest to expand the code block from the inside out."
+  (let* ((fullclassname (or (cdr (assq :classname params)) ; class and package
+                            (org-babel-java-find-classname body)))
+         (classname (car (last (split-string fullclassname "\\.")))) ; just class name
+         (packagename (if (seq-contains fullclassname ?.)  ; just package name
+                          (file-name-base fullclassname)))
+         (var-lines (org-babel-variable-assignments:java params))
+         (imports-val (assq :imports params))
+         (imports (if imports-val
+                      (split-string (org-babel-read (cdr imports-val) nil) " ")
+                    nil)))
+    (with-temp-buffer
+      (insert body)
+
+      ;; wrap main.  If there are methods defined, but no main method
+      ;; and no class, wrap everything in a generic main method.
+      (goto-char (point-min))
+      (when (and (not (re-search-forward org-babel-java--class-re nil t))
+                 (not (re-search-forward org-babel-java--any-method-re nil t)))
+        (org-babel-java--move-past org-babel-java--package-re) ; if package is defined, move past it
+        (org-babel-java--move-past org-babel-java--imports-re) ; if imports are defined, move past them
+        (insert "public static void main(String[] args) {\n")
+        (indent-code-rigidly (point) (point-max) 4)
+        (goto-char (point-max))
+        (insert "\n}"))
+
+      ;; wrap class.  If there's no class, wrap everything in a
+      ;; generic class.
+      (goto-char (point-min))
+      (when (not (re-search-forward org-babel-java--class-re nil t))
+        (org-babel-java--move-past org-babel-java--package-re) ; if package is defined, move past it
+        (org-babel-java--move-past org-babel-java--imports-re) ; if imports are defined, move past them
+        (insert (concat "\npublic class " (file-name-base classname) " {\n"))
+        (indent-code-rigidly (point) (point-max) 4)
+        (goto-char (point-max))
+        (insert "\n}"))
+      (goto-char (point-min))
+
+      ;; insert variables from source block headers
+      (when var-lines
+        (goto-char (point-min))
+        (org-babel-java--move-past org-babel-java--class-re)   ; move inside class
+        (insert (mapconcat 'identity var-lines "\n"))
+        (insert "\n"))
+
+      ;; add imports from source block headers
+      (when imports
+        (goto-char (point-min))
+        (org-babel-java--move-past org-babel-java--package-re) ; if package is defined, move past it
+        (insert (mapconcat (lambda (package) (concat "import " package ";")) imports "\n") "\n"))
+
+      ;; add package at the top
+      (goto-char (point-min))
+      (when (and packagename (not (re-search-forward org-babel-java--package-re nil t)))
+        (insert (concat "package " packagename ";\n")))
+
+      ;; return expanded body
+      (buffer-string))))
+
+(defun org-babel-variable-assignments:java (params)
+  "Return a list of java statements assigning the block's variables.
+variables are contained in PARAMS."
+  (mapcar
+   (lambda (pair)
+     (let* ((type-data (org-babel-java-val-to-type (cdr pair)))
+            (basetype (car type-data))
+            (var-to-java (lambda (var) (funcall #'org-babel-java-var-to-java var basetype))))
+       (format "    static %s %s = %s;"
+               (cdr type-data)                     ; type
+               (car pair)                          ; name
+               (funcall var-to-java (cdr pair))))) ; value
+   (org-babel--get-vars params)))
+
+(defun org-babel-java-var-to-java (var basetype)
+  "Convert an elisp value to a java variable.
+Convert an elisp value, VAR, of type BASETYPE into a string of
+java source code specifying a variable of the same value."
+  (cond ((and (sequencep var) (not (stringp var)))
+         (let ((var-to-java (lambda (var) (funcall #'org-babel-java-var-to-java var basetype))))
+           (concat "Arrays.asList(" (mapconcat var-to-java var ", ") ")")))
+        ((eq var 'hline) org-babel-java-hline-to)
+        ((eq basetype 'integerp) (format "%d" var))
+        ((eq basetype 'floatp) (format "%f" var))
+        ((eq basetype 'stringp) (if (and (stringp var) (string-match-p ".\n+." var))
+                                    (error "Java does not support multiline string literals")
+                                  (format "\"%s\"" var)))))
+
+(defun org-babel-java-val-to-type (val)
+  "Determine the type of VAL.
+Return (BASETYPE . LISTTYPE), where BASETYPE is a symbol
+representing the type of the individual items in VAL, and
+LISTTYPE is a string name of the type parameter for a container
+for BASETYPE items."
+  (let* ((basetype (org-babel-java-val-to-base-type val))
+         (basetype-str (pcase basetype
+                         (`integerp "Integer")
+                         (`floatp "Double")
+                         (`stringp "String")
+                         (_ (error "Unknown type %S" basetype)))))
+    (cond
+     ((and (listp val) (listp (car val))) ; a table
+      (cons basetype (format "List<List<%s>>" basetype-str)))
+     ((or (listp val) (vectorp val))      ; a list declared in the source block header
+      (cons basetype (format "List<%s>" basetype-str)))
+     (t                                   ; return base type
+      (cons basetype basetype-str)))))
+
+(defun org-babel-java-val-to-base-type (val)
+  "Determine the base type of VAL.
+VAL may be
+`integerp' if all base values are integers
+`floatp' if all base values are either floating points or integers
+`stringp' otherwise."
+  (cond
+   ((integerp val) 'integerp)
+   ((floatp val) 'floatp)
+   ((or (listp val) (vectorp val))
+    (let ((type nil))
+      (mapc (lambda (v)
+              (pcase (org-babel-java-val-to-base-type v)
+                (`stringp (setq type 'stringp))
+                (`floatp
+                 (when (or (not type) (eq type 'integerp))
+                   (setq type 'floatp)))
+                (`integerp
+                 (unless type (setq type 'integerp)))))
+            val)
+      type))
+   (t 'stringp)))
+
+(defun org-babel-java-table-or-string (results)
+  "Convert RESULTS into an appropriate elisp value.
+If the results look like a list or vector, then convert them into an
+Emacs-lisp table, otherwise return the results as a string."
+  (let ((res (org-babel-script-escape results)))
+    (if (listp res)
+        (mapcar (lambda (el) (if (eq 'null el)
+                                 org-babel-java-null-to
+                               el))
+                res)
+      res)))
+
+(defun org-babel-java-evaluate (cmd result-type result-params result-file)
+  "Evaluate using an external java process.
+CMD the command to execute.
+
+If RESULT-TYPE equals 'output then return standard output as a
+string.  If RESULT-TYPE equals 'value then return the value
+returned by the source block, as elisp.
+
+RESULT-PARAMS input params used to format the reponse.
+
+RESULT-FILE filename of the tempfile to store the returned value in
+for 'value RESULT-TYPE.  Not used for 'output RESULT-TYPE."
+  (let ((raw (pcase result-type
+               ('output (org-babel-eval cmd ""))
+               ('value (org-babel-eval cmd "")
+                       (org-babel-eval-read-file result-file)))))
+    (org-babel-result-cond result-params raw
+      (org-babel-java-table-or-string raw))))
 
 (provide 'ob-java)
 
diff --git a/testing/lisp/test-ob-java.el b/testing/lisp/test-ob-java.el
new file mode 100644
index 000000000..4e22bd8b5
--- /dev/null
+++ b/testing/lisp/test-ob-java.el
@@ -0,0 +1,574 @@
+;;; test-ob-java.el --- tests for ob-java.el
+
+;; Copyright (c) 2020 Ian Martins
+;; Authors: Ian Martins
+
+;; This file is not part of GNU Emacs.
+
+;; This program 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 of the License, 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.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Code:
+(require 'org-test)
+
+(org-test-for-executable "java")
+(unless (featurep 'ob-java)
+  (signal 'missing-test-dependency "Support for java code blocks"))
+
+; simple tests
+
+(ert-deftest ob-java/simple ()
+  "Hello world program that writes output."
+  (org-test-with-temp-text
+      "#+begin_src java :results output silent
+System.out.print(42);
+#+end_src"
+   (should (string= "42" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/simple-with-bracket ()
+  "Hello world program that outputs an open square bracket."
+  (org-test-with-temp-text
+      "#+begin_src java :results output silent
+System.out.print(\"[42\");
+#+end_src"
+   (should (string= "[42" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/simple-with-quote ()
+  "Hello world program that writes quotes."
+  (org-test-with-temp-text
+      "#+begin_src java :results output silent
+System.out.print(\"\\\"42\\\"\");
+#+end_src"
+   (should (string= "\"42\"" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/simple-return-int ()
+  "Hello world program that returns an int value."
+  (org-test-with-temp-text
+      "#+begin_src java :results silent
+return 42;
+#+end_src"
+   (should (eq 42 (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/simple-return-float ()
+  "Hello world program that returns a float value."
+  (org-test-with-temp-text
+      "#+begin_src java :results silent
+return 42.0;
+#+end_src"
+   (should (equal 42.0 (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/simple-return-string ()
+  "Hello world program that returns a string value."
+  (org-test-with-temp-text
+      "#+begin_src java :results silent
+return \"forty two\";
+#+end_src"
+    (should (string= "forty two" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/simple-with-main ()
+  "Hello world program that defines a main function."
+  (org-test-with-temp-text
+      "#+begin_src java :results output silent
+public static void main(String[] args) {
+    System.out.print(42);
+}
+#+end_src"
+    (should (string= "42" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/simple-with-two-methods ()
+  "Hello world program with two methods and no class."
+  (org-test-with-temp-text
+      "#+begin_src java :results output silent
+public static void main(String[] args) {
+    System.out.print(foo());
+}
+public static int foo() {
+    return 42;
+}
+#+end_src"
+    (should (string= "42" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/simple-with-no-main ()
+  "Hello world program with no main method.  Babel adds a dummy one so it can run without error."
+  (org-test-with-temp-text
+      "#+begin_src java :results output silent
+public static int foo() {
+    return 42;
+}
+#+end_src"
+    (should (string= "success" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/simple-with-main-args-array ()
+  "Hello world program that defines a main function with the square brackets after `args'."
+  (org-test-with-temp-text
+      "#+begin_src java :results output silent
+public static void main(String args[]) {
+    System.out.print(42);
+}
+#+end_src"
+    (should (string= "42" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/simple-with-class ()
+  "Hello world program that defines a class."
+  (org-test-with-temp-text
+      "#+begin_src java :results output silent
+public class Simple {
+    public static void main(String[] args) {
+        System.out.print(42);
+    }
+}
+#+end_src"
+   (should (string= "42" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/simple-with-class-and-package ()
+  "Hello world program that defines a class and package."
+  (org-test-with-temp-text
+      "#+begin_src java :results output silent
+package pkg;
+public class Simple {
+    public static void main(String[] args) {
+        System.out.print(42);
+    }
+}
+#+end_src"
+    (should (string= "42" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/simple-with-class-attr ()
+  "Hello world program with class header attribute."
+  (org-test-with-temp-text
+      "#+begin_src java :results output silent :classname Simple
+public static void main(String[] args) {
+    System.out.print(42);
+}
+#+end_src"
+   (should (string= "42" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/simple-with-class-attr-with-package ()
+  "Hello world program with class attr with package."
+  (org-test-with-temp-text
+      "#+begin_src java :results output silent :classname pkg.Simple
+public static void main(String[] args) {
+    System.out.print(42);
+}
+#+end_src"
+    (should (string= "42" (org-babel-execute-src-block)))))
+
+
+(ert-deftest ob-java/one-arg ()
+  "Command line arg."
+  (org-test-with-temp-text
+      "#+begin_src java :results output silent :cmdargs \"fortytwo\"
+System.out.print(args[0]);
+#+end_src"
+    (should (string= "fortytwo" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/args-quoted-string ()
+  "Two command line args, first contains a space."
+  (org-test-with-temp-text
+      "#+begin_src java :results output silent :cmdargs \"\\\"forty two\\\" 42\"
+System.out.println(args[0]);
+System.out.println(args[1]);
+#+end_src"
+    (should (string= "forty two\n42\n" (org-babel-execute-src-block)))))
+
+;; var tests
+
+(ert-deftest ob-java/integer-var ()
+  "Read and write an integer variable."
+  (org-test-with-temp-text
+      "#+begin_src java :var a=42 :results output silent
+System.out.print(a);
+#+end_src"
+    (should (string= "42" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/var-with-main ()
+  "Read and write an integer variable, with main function provided."
+  (org-test-with-temp-text
+      "#+begin_src java :var a=42 :results output silent
+public static void main(String[] args) {
+    System.out.print(a);
+}
+#+end_src"
+    (should (string= "42" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/var-with-class ()
+  "Read and write an integer variable, with class provided."
+  (org-test-with-temp-text
+      "#+begin_src java :var a=42 :results output silent
+public class Main {
+    public static void main(String[] args) {
+        System.out.print(a);
+    }
+}
+#+end_src"
+    (should (string= "42" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/var-with-class-and-package ()
+  "Read and write an integer variable, with class and package provided."
+  (org-test-with-temp-text
+      "#+begin_src java :var a=42 :results output silent
+package pkg;
+public class Main {
+    public static void main(String[] args) {
+        System.out.print(a);
+    }
+}
+#+end_src"
+    (should (string= "42" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/var-with-class-and-hanging-curlies ()
+  "Read and write an integer variable, with class with hanging curlies."
+  (org-test-with-temp-text
+      "#+begin_src java :var a=42 :results output silent
+public class Main
+{
+    public static void main(String[] args)
+    {
+        System.out.print(a);
+    }
+}
+#+end_src"
+    (should (string= "42" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/two-vars ()
+  "Read two integer variables, combine and write them."
+  (org-test-with-temp-text
+      "#+begin_src java :var a=21 b=2 :results output silent
+System.out.print(a*b);
+#+end_src"
+    (should (string= "42" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/string-var ()
+  "Read and write a string variable."
+  (org-test-with-temp-text
+      "#+begin_src java :var a=\"forty two\" :results output silent
+System.out.print(String.format(\"%s, len=%d\", a, a.length()));
+#+end_src"
+    (should (string= "forty two, len=9" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/multiline-string-var ()
+  "Java doesn't support multiline string literals, so this errors."
+  (org-test-with-temp-text
+      "#+begin_src java :var a=\"forty\ntwo\" :results output silent
+System.out.print(String.format(\"%s, len=%d\", a, a.length()));
+#+end_src"
+    (should-error (org-babel-execute-src-block)))
+  :type 'error)
+
+;; return list
+
+(ert-deftest ob-java/return-vector-using-list ()
+  "Return a vector using a list."
+  (org-test-with-temp-text
+      "#+begin_src java :results vector silent
+import java.util.List;
+import java.util.Arrays;
+List<List<Integer>> a = Arrays.asList(Arrays.asList(4),
+                                      Arrays.asList(2));
+return a;
+#+end_src"
+    (should (equal '((4) (2))
+                   (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/return-vector-using-array ()
+  "Return a vector using an array."
+  (org-test-with-temp-text
+      "#+begin_src java :results vector silent
+Integer[][] a = {{4}, {2}};
+return a;
+#+end_src"
+    (should (equal '((4) (2))
+                   (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/read-return-list ()
+  "Read and return a list."
+  (org-test-with-temp-text
+      "#+begin_src java :var a=java_list :results silent
+import java.util.List;
+import java.util.Arrays;
+List<String> b = Arrays.asList(a.get(0).get(0),
+                               a.get(1).get(0));
+return b;
+#+end_src
+
+#+name: java_list
+- forty
+- two"
+    (should (equal '("forty" "two")
+                   (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/read-list-return-array ()
+  "Read a list and return an array."
+  (org-test-with-temp-text
+      "#+begin_src java :var a=java_list :results silent
+String[] b = {a.get(0).get(0), a.get(1).get(0)};
+return b;
+#+end_src
+
+#+name: java_list
+- forty
+- two"
+    (should (equal '("forty" "two")
+                   (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/read-return-list-with-package ()
+  "Return a vector."
+  (org-test-with-temp-text
+      "#+begin_src java :var a=java_list :results silent
+package pkg;
+import java.util.List;
+import java.util.Arrays;
+List<String> b = Arrays.asList(a.get(0).get(0),
+                               a.get(1).get(0));
+return b;
+#+end_src
+
+#+name: java_list
+- forty
+- two"
+    (should (equal '("forty" "two")
+                   (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/output-list-with-spaces ()
+  "Return a vector."
+  (org-test-with-temp-text
+      "#+begin_src java :results output list raw silent
+System.out.println(\"forty two\");
+System.out.println(\"forty two\");
+#+end_src"
+    (should (equal "forty two\nforty two\n"
+                   (org-babel-execute-src-block)))))
+
+;; list vars
+
+(ert-deftest ob-java/list-var ()
+  "Read and write a list variable."
+  (org-test-with-temp-text
+      "#+begin_src java :var a='(\"forty\" \"two\") :results silent
+import java.util.List;
+List<String> b = a;
+return b;
+#+end_src"
+    (should (equal '("forty" "two")
+                   (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/vector-var ()
+  "Read and write a vector variable."
+  (org-test-with-temp-text
+      "#+begin_src java :var a='[\"forty\" \"two\"] :results silent
+import java.util.List;
+List<String> b = a;
+return b;
+#+end_src"
+    (should (equal '("forty" "two")
+                   (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/matrix-var ()
+  "Read and write matrix variable."
+  (org-test-with-temp-text
+      "#+begin_src java :var a=java_matrix :results silent
+import java.util.List;
+import java.util.Arrays;
+List<List<Integer>> b = Arrays.asList(Arrays.asList(a.get(0).get(0), a.get(1).get(0)),
+                                      Arrays.asList(a.get(0).get(1), a.get(1).get(1)));
+return b; // transpose
+#+end_src
+
+#+name: java_matrix
+| 2 | 1 |
+| 4 | 2 |"
+    (should (equal '((2 4) (1 2))
+                   (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/matrix-var-with-header ()
+  "Read matrix variable and write it with header."
+  (org-test-with-temp-text
+      "#+begin_src java :var a=java_matrix :results value table silent
+import java.util.List;
+import java.util.Arrays;
+List<List> b = Arrays.asList(Arrays.asList(\"col1\", \"col2\"),
+                                     null,
+                                     Arrays.asList(a.get(0).get(0), a.get(1).get(0)),
+                                     Arrays.asList(a.get(0).get(1), a.get(1).get(1)));
+return b; // transpose
+#+end_src
+
+#+name: java_matrix
+| 2 | 1 |
+| 4 | 2 |"
+    (should (equal '(("col1" "col2") hline (2 4) (1 2))
+                   (org-babel-execute-src-block)))))
+
+;; output table
+
+(ert-deftest ob-java/output-table-with-header ()
+  "Write a table that includes a header."
+  (org-test-with-temp-text
+      "#+begin_src java :var a=java_matrix :results output raw table silent
+System.out.println(\"|col1|col2|\");
+System.out.println(\"|-\");
+for (int ii=0; ii<a.size(); ii++) {
+    for (int jj=0; jj<a.get(0).size(); jj++) {
+        System.out.print(\"|\" + a.get(ii).get(jj));
+    }
+    System.out.println(\"\");
+ }
+#+end_src
+
+#+name: java_matrix
+| 2 | 1 |
+| 4 | 2 |"
+    (should (equal "|col1|col2|\n|-\n|2|1\n|4|2\n"
+                   (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/inhomogeneous_table ()
+  "Read and write an inhomogeneous table."
+  (org-test-with-temp-text
+      "#+begin_src java :var a=java_table :results silent
+import java.util.List;
+import java.util.Arrays;
+List<List> b = Arrays.asList(Arrays.asList(a.get(0).get(0),
+                                           Integer.parseInt(a.get(0).get(1))*2),
+                             Arrays.asList(a.get(1).get(0),
+                                           Integer.parseInt(a.get(1).get(1))*2));
+return b;
+#+end_src
+
+#+name: java_table
+  | string | number |
+  |--------+--------|
+  | forty  |      2 |
+  | two    |      1 |"
+   (should (equal
+            '(("forty" 4) ("two" 2))
+            (org-babel-execute-src-block)))))
+
+;; imports
+
+(ert-deftest ob-java/import_library ()
+  "Import a standard java library."
+  (org-test-with-temp-text
+      "#+begin_src java :results output silent :imports java.util.Base64
+byte[] encoded = Base64.getEncoder().encode(\"42\".getBytes());
+String decoded = new String(Base64.getDecoder().decode(encoded));
+System.out.print(String.format(\"encoded=%s, decoded=%s\", new String(encoded), decoded));
+#+end_src"
+   (should (string=
+            "encoded=NDI=, decoded=42"
+            (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/import_library_inline ()
+  "Import a standard java library."
+  (org-test-with-temp-text
+      "#+begin_src java :results output silent
+import java.util.Base64;
+byte[] encoded = Base64.getEncoder().encode(\"42\".getBytes());
+String decoded = new String(Base64.getDecoder().decode(encoded));
+System.out.print(String.format(\"encoded=%s, decoded=%s\", new String(encoded), decoded));
+#+end_src"
+   (should (string=
+            "encoded=NDI=, decoded=42"
+            (org-babel-execute-src-block)))))
+
+;; tangle
+
+(ert-deftest ob-java/tangle ()
+  "Tangle a source block."
+  (org-test-with-temp-text-in-file
+      "#+begin_src java :tangle \"Tangle.java\" :results value :classname Tangle
+return \"tangled\";
+#+end_src"
+    (should
+     (string=
+      "public class Tangle {
+    public static void main(String[] args) {
+        return \"tangled\";
+    }
+}
+"
+      (unwind-protect
+          (progn (org-babel-tangle)
+                 (with-temp-buffer
+                   (insert-file-contents "Tangle.java")
+                   (buffer-string)))
+        (delete-file "Tangle.java"))))))
+
+(ert-deftest ob-java/tangle-with-package ()
+  "Tangle a source block."
+  (org-test-with-temp-text-in-file
+      "#+begin_src java :tangle \"tangle/Tangle.java\" :results value :classname tangle.Tangle
+return \"tangled\";
+#+end_src"
+    (should
+     (string=
+      "package tangle;
+
+public class Tangle {
+    public static void main(String[] args) {
+        return \"tangled\";
+    }
+}
+"
+      (unwind-protect
+          (progn
+            (make-directory "tangle")
+            (org-babel-tangle)
+            (with-temp-buffer
+              (insert-file-contents "tangle/Tangle.java")
+              (buffer-string)))
+        (delete-file "tangle/Tangle.java")
+        (delete-directory "tangle"))))))
+
+
+;; specify output dir
+
+(ert-deftest ob-java/simple-dir ()
+  "Hello world program that writes output."
+  (org-test-with-temp-text
+      (format  "#+begin_src java :results output silent :dir %s
+System.out.print(42);
+#+end_src" org-babel-temporary-directory)
+    (should (string=
+             "42"
+             (unwind-protect
+                 (org-babel-execute-src-block)
+               (delete-file (concat (file-name-as-directory org-babel-temporary-directory)
+				    "Main.java"))
+	       (delete-file (concat (file-name-as-directory org-babel-temporary-directory)
+				    "Main.class")))))))
+
+(ert-deftest ob-java/simple-dir-with-package ()
+  "Hello world program that writes output."
+  (org-test-with-temp-text
+      (format "#+begin_src java :results output silent :dir %s
+package pkg;
+
+public class Main {
+    public static void main(String[] args) {
+      System.out.print(42);
+    }
+}
+#+end_src" org-babel-temporary-directory)
+    (should (string=
+             "42"
+             (unwind-protect
+                 (org-babel-execute-src-block)
+               (delete-file (concat (file-name-as-directory org-babel-temporary-directory)
+				    "pkg/Main.java"))
+	       (delete-file (concat (file-name-as-directory org-babel-temporary-directory)
+				    "pkg/Main.class"))
+	       (delete-directory (concat (file-name-as-directory org-babel-temporary-directory)
+					 "pkg")))))))
+
+
+;;; test-ob-java.el ends here
-- 
2.25.1


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] ob-java
  2020-10-05 12:35 [PATCH] ob-java ian martins
@ 2020-10-05 13:23 ` ian martins
  2020-10-09 11:15   ` ian martins
  2020-10-24 11:58 ` Bastien
  1 sibling, 1 reply; 31+ messages in thread
From: ian martins @ 2020-10-05 13:23 UTC (permalink / raw)
  To: Org-Mode mailing list

[-- Attachment #1: Type: text/plain, Size: 5418 bytes --]

I wrote those examples in an org file so I could test as I wrote them, and
then exported it to make it more readable, but the export resulted in
source block headers being lost.  Here is the same without export:
----
* Changes

- support for functional mode (~:results value~)
- accept variables
- don't require package, class, and main definitions
- write source and result tempfiles to ~org-babel-temporary-directory~, but
respects the ~:dir~ header
- work with tramp

* Examples
** Example 1
This outputs "hello."  If class and main definitions aren't given the
code block will be wrapped in generic ones.

#+begin_src java :results output silent
  System.out.print("hello");
#+end_src

This is exactly equivalent:

#+begin_src java :results output silent
  public class Main {
      public static void main(String[] args) {
          System.out.print("hello");
      }
  }
#+end_src

** Example 2
This also outputs "hello."

#+begin_src java :results value silent
  return "hello";
#+end_src

** Example 3
This generates the class "Example" in the package "org.orgmode" in the
current directory.

#+begin_src java :results output silent :classname org.orgmode.Example :dir
.
  System.out.print("hello, org-mode");
#+end_src

** Example 4
The "Hey" class defines a static method but no main. C-c C-c on the
"Hey" source block will write "./org/orgmode/Hey.java" and compile it.

The "Main" class calls the "Hey" class. C-c C-c on the "Main" source
block will write "./org/orgmode/Main.java" and compile and run it.

#+begin_src java :results output silent :dir .
  package org.orgmode;

  public class Hey {
      public static String say() {
          return "hey";
      }
  }
#+end_src

#+begin_src java :results output silent :dir .
  package org.orgmode;

  public class Main {
      public static void main(String[] args) {
          System.out.print(Hey.say());
      }
  }
#+end_src

Instead of C-c C-c, we could have added tangle headers and written the
source files out by tangling.

** Example 5
This prints the variable from the header

#+begin_src java :var msg="hello, org-mode" :results output silent
  System.out.print(msg);
#+end_src

** Example 6
This prints "hello, org-mode." The table is provided to the method as a
list of lists.

#+name: table
| message | hello, org-mode  |

#+begin_src java :var tbl=table :results output silent
  System.out.print(tbl.get(0).get(1));
#+end_src

** Example 7
This example returns a list.

Note that you're allowed to specify imports without defining the class
or main methods.

#+begin_src java :results value :exports both
  import java.util.Arrays;

  return Arrays.asList("message", "hello, org-mode");
#+end_src

#+RESULTS:
| message | hello, org-mode |

On Mon, Oct 5, 2020 at 8:35 AM ian martins <ianxm@jhu.edu> wrote:

> 1 Changes
> =========
>
>   - support for functional mode (`:results value')
>   - accept variables
>   - don't require package, class, and main definitions
>   - write source and result tempfiles to
>     `org-babel-temporary-directory', but respects the `:dir' header
>   - work with tramp
>
>
> 2 Examples
> ==========
> Some examples follow.  See the tests for more examples.  I'll write proper
> docs after review.
>
> 2.1 Example 1
> ~~~~~~~~~~~~~
>
>   This outputs "hello."  If class and main definitions aren't given the
>   code block will be wrapped in generic ones.
>
>   ,----
>   | System.out.print("hello");
>   `----
>
>   This is exactly equivalent:
>
>   ,----
>   | public class Main {
>   |     public static void main(String[] args) {
>   |         System.out.print("hello");
>   |     }
>   | }
>   `----
>
>
> 2.2 Example 2
> ~~~~~~~~~~~~~
>
>   This also outputs "hello."
>
>   ,----
>   | return "hello";
>   `----
>
>
> 2.3 Example 3
> ~~~~~~~~~~~~~
>
>   This generates the class "Example" in the package "org.orgmode" in the
>   current directory.
>
>   ,----
>   | System.out.print("hello, org-mode");
>   `----
>
>
> 2.4 Example 4
> ~~~~~~~~~~~~~
>
>   The "Hey" class defines a static method but no main. C-c C-c on the
>   "Hey" source block will write "./org/orgmode/Hey.java" and compile it.
>
>   The "Main" class calls the "Hey" class. C-c C-c on the "Main" source
>   block will write "./org/orgmode/Main.java" and compile and run it.
>
>   ,----
>   | package org.orgmode;
>   |
>   | public class Hey {
>   |     public static String say() {
>   |         return "hey";
>   |     }
>   | }
>   `----
>
>   ,----
>   | package org.orgmode;
>   |
>   | public class Main {
>   |     public static void main(String[] args) {
>   |         System.out.print(Hey.say());
>   |     }
>   | }
>   `----
>
>   Instead of C-c C-c, we could have added tangle headers and written the
>   source files out by tangling.
>
>
> 2.5 Example 5
> ~~~~~~~~~~~~~
>
>   This prints the variable from the header
>
>   ,----
>   | System.out.print(msg);
>   `----
>
>
> 2.6 Example 6
> ~~~~~~~~~~~~~
>
>   This prints "hello, org-mode." The table is provided to the method as
>   a list of lists.
>
>    message  hello, org-mode
>
>   ,----
>   | System.out.print(tbl.get(0).get(1));
>   `----
>
>
> 2.7 Example 7
> ~~~~~~~~~~~~~
>
>   This example returns a list.
>
>   Note that you're allowed to specify imports without defining the class
>   or main methods.
>
>   ,----
>   | import java.util.Arrays;
>   |
>   | return Arrays.asList("message", "hello, org-mode");
>   `----
>
>    message  hello, org-mode
>

[-- Attachment #2: Type: text/html, Size: 6832 bytes --]

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] ob-java
  2020-10-05 13:23 ` ian martins
@ 2020-10-09 11:15   ` ian martins
  2020-10-20 18:28     ` John Herrlin
                       ` (2 more replies)
  0 siblings, 3 replies; 31+ messages in thread
From: ian martins @ 2020-10-09 11:15 UTC (permalink / raw)
  To: Org-Mode mailing list


[-- Attachment #1.1: Type: text/plain, Size: 5995 bytes --]

I noticed that the tests didn't run with "make test." This updates the
patch so that they can. I didn't add java to the list of default languages
because the java tests are slow.

On Mon, Oct 5, 2020 at 9:23 AM ian martins <ianxm@jhu.edu> wrote:

> I wrote those examples in an org file so I could test as I wrote them, and
> then exported it to make it more readable, but the export resulted in
> source block headers being lost.  Here is the same without export:
> ----
> * Changes
>
> - support for functional mode (~:results value~)
> - accept variables
> - don't require package, class, and main definitions
> - write source and result tempfiles to ~org-babel-temporary-directory~,
> but respects the ~:dir~ header
> - work with tramp
>
> * Examples
> ** Example 1
> This outputs "hello."  If class and main definitions aren't given the
> code block will be wrapped in generic ones.
>
> #+begin_src java :results output silent
>   System.out.print("hello");
> #+end_src
>
> This is exactly equivalent:
>
> #+begin_src java :results output silent
>   public class Main {
>       public static void main(String[] args) {
>           System.out.print("hello");
>       }
>   }
> #+end_src
>
> ** Example 2
> This also outputs "hello."
>
> #+begin_src java :results value silent
>   return "hello";
> #+end_src
>
> ** Example 3
> This generates the class "Example" in the package "org.orgmode" in the
> current directory.
>
> #+begin_src java :results output silent :classname org.orgmode.Example
> :dir .
>   System.out.print("hello, org-mode");
> #+end_src
>
> ** Example 4
> The "Hey" class defines a static method but no main. C-c C-c on the
> "Hey" source block will write "./org/orgmode/Hey.java" and compile it.
>
> The "Main" class calls the "Hey" class. C-c C-c on the "Main" source
> block will write "./org/orgmode/Main.java" and compile and run it.
>
> #+begin_src java :results output silent :dir .
>   package org.orgmode;
>
>   public class Hey {
>       public static String say() {
>           return "hey";
>       }
>   }
> #+end_src
>
> #+begin_src java :results output silent :dir .
>   package org.orgmode;
>
>   public class Main {
>       public static void main(String[] args) {
>           System.out.print(Hey.say());
>       }
>   }
> #+end_src
>
> Instead of C-c C-c, we could have added tangle headers and written the
> source files out by tangling.
>
> ** Example 5
> This prints the variable from the header
>
> #+begin_src java :var msg="hello, org-mode" :results output silent
>   System.out.print(msg);
> #+end_src
>
> ** Example 6
> This prints "hello, org-mode." The table is provided to the method as a
> list of lists.
>
> #+name: table
> | message | hello, org-mode  |
>
> #+begin_src java :var tbl=table :results output silent
>   System.out.print(tbl.get(0).get(1));
> #+end_src
>
> ** Example 7
> This example returns a list.
>
> Note that you're allowed to specify imports without defining the class
> or main methods.
>
> #+begin_src java :results value :exports both
>   import java.util.Arrays;
>
>   return Arrays.asList("message", "hello, org-mode");
> #+end_src
>
> #+RESULTS:
> | message | hello, org-mode |
>
> On Mon, Oct 5, 2020 at 8:35 AM ian martins <ianxm@jhu.edu> wrote:
>
>> 1 Changes
>> =========
>>
>>   - support for functional mode (`:results value')
>>   - accept variables
>>   - don't require package, class, and main definitions
>>   - write source and result tempfiles to
>>     `org-babel-temporary-directory', but respects the `:dir' header
>>   - work with tramp
>>
>>
>> 2 Examples
>> ==========
>> Some examples follow.  See the tests for more examples.  I'll write
>> proper docs after review.
>>
>> 2.1 Example 1
>> ~~~~~~~~~~~~~
>>
>>   This outputs "hello."  If class and main definitions aren't given the
>>   code block will be wrapped in generic ones.
>>
>>   ,----
>>   | System.out.print("hello");
>>   `----
>>
>>   This is exactly equivalent:
>>
>>   ,----
>>   | public class Main {
>>   |     public static void main(String[] args) {
>>   |         System.out.print("hello");
>>   |     }
>>   | }
>>   `----
>>
>>
>> 2.2 Example 2
>> ~~~~~~~~~~~~~
>>
>>   This also outputs "hello."
>>
>>   ,----
>>   | return "hello";
>>   `----
>>
>>
>> 2.3 Example 3
>> ~~~~~~~~~~~~~
>>
>>   This generates the class "Example" in the package "org.orgmode" in the
>>   current directory.
>>
>>   ,----
>>   | System.out.print("hello, org-mode");
>>   `----
>>
>>
>> 2.4 Example 4
>> ~~~~~~~~~~~~~
>>
>>   The "Hey" class defines a static method but no main. C-c C-c on the
>>   "Hey" source block will write "./org/orgmode/Hey.java" and compile it.
>>
>>   The "Main" class calls the "Hey" class. C-c C-c on the "Main" source
>>   block will write "./org/orgmode/Main.java" and compile and run it.
>>
>>   ,----
>>   | package org.orgmode;
>>   |
>>   | public class Hey {
>>   |     public static String say() {
>>   |         return "hey";
>>   |     }
>>   | }
>>   `----
>>
>>   ,----
>>   | package org.orgmode;
>>   |
>>   | public class Main {
>>   |     public static void main(String[] args) {
>>   |         System.out.print(Hey.say());
>>   |     }
>>   | }
>>   `----
>>
>>   Instead of C-c C-c, we could have added tangle headers and written the
>>   source files out by tangling.
>>
>>
>> 2.5 Example 5
>> ~~~~~~~~~~~~~
>>
>>   This prints the variable from the header
>>
>>   ,----
>>   | System.out.print(msg);
>>   `----
>>
>>
>> 2.6 Example 6
>> ~~~~~~~~~~~~~
>>
>>   This prints "hello, org-mode." The table is provided to the method as
>>   a list of lists.
>>
>>    message  hello, org-mode
>>
>>   ,----
>>   | System.out.print(tbl.get(0).get(1));
>>   `----
>>
>>
>> 2.7 Example 7
>> ~~~~~~~~~~~~~
>>
>>   This example returns a list.
>>
>>   Note that you're allowed to specify imports without defining the class
>>   or main methods.
>>
>>   ,----
>>   | import java.util.Arrays;
>>   |
>>   | return Arrays.asList("message", "hello, org-mode");
>>   `----
>>
>>    message  hello, org-mode
>>
>

[-- Attachment #1.2: Type: text/html, Size: 7390 bytes --]

[-- Attachment #2: 0001-ob-java.el-Add-support-for-variables-return-values-t.patch --]
[-- Type: text/x-patch, Size: 39756 bytes --]

From 6307c528d1d8aebc0200555dea6855f401132aa5 Mon Sep 17 00:00:00 2001
From: Ian Martins <ianxm@jhu.edu>
Date: Mon, 5 Oct 2020 08:07:25 -0400
Subject: [PATCH] ob-java.el: Add support for variables, return values, tramp

* lisp/ob-java.el: Add support for variables and return values.  Write
tempfiles to the org-babel-temporary-directory.  Make package, class,
and main method definitions optional.

* testing/lisp/test-ob-java.el: Add tests.
---
 lisp/ob-java.el              | 422 ++++++++++++++++++++++---
 testing/lisp/test-ob-java.el | 583 +++++++++++++++++++++++++++++++++++
 2 files changed, 964 insertions(+), 41 deletions(-)
 create mode 100644 testing/lisp/test-ob-java.el

diff --git a/lisp/ob-java.el b/lisp/ob-java.el
index fee695bb9..e704c5552 100644
--- a/lisp/ob-java.el
+++ b/lisp/ob-java.el
@@ -1,9 +1,8 @@
-;;; ob-java.el --- Babel Functions for Java          -*- lexical-binding: t; -*-
+;;; ob-java.el --- org-babel functions for java evaluation -*- lexical-binding: t -*-
 
 ;; Copyright (C) 2011-2020 Free Software Foundation, Inc.
 
-;; Author: Eric Schulte
-;; Maintainer: Ian Martins <ianxm@jhu.edu>
+;; Author: Ian Martins <ianxm@jhu.edu>
 ;; Keywords: literate programming, reproducible research
 ;; Homepage: https://orgmode.org
 
@@ -24,8 +23,7 @@
 
 ;;; Commentary:
 
-;; Currently this only supports the external compilation and execution
-;; of java code blocks (i.e., no session support).
+;; Org-Babel support for evaluating java source code.
 
 ;;; Code:
 (require 'ob)
@@ -33,52 +31,394 @@
 (defvar org-babel-tangle-lang-exts)
 (add-to-list 'org-babel-tangle-lang-exts '("java" . "java"))
 
-(defcustom org-babel-java-command "java"
-  "Name of the java command.
-May be either a command in the path, like java
-or an absolute path name, like /usr/local/bin/java
-parameters may be used, like java -verbose"
+(defvar org-babel-default-header-args:java '()
+  "Default header args for java source blocks.")
+
+(defconst org-babel-header-args:java '((imports . :any))
+  "Java-specific header arguments.")
+
+(defvar org-babel-java-compiler-command "javac"
+  "Name of the command to execute the java compiler.")
+
+(defvar org-babel-java-runtime-command "java"
+  "Name of the command to run the java runtime.")
+
+(defcustom org-babel-java-hline-to "null"
+  "Replace hlines in incoming tables with this when translating to java."
   :group 'org-babel
-  :version "24.3"
+  :version "25.2"
+  :package-version '(Org . "9.3")
   :type 'string)
 
-(defcustom org-babel-java-compiler "javac"
-  "Name of the java compiler.
-May be either a command in the path, like javac
-or an absolute path name, like /usr/local/bin/javac
-parameters may be used, like javac -verbose"
+(defcustom org-babel-java-null-to 'hline
+  "Replace `null' in java tables with this before returning."
   :group 'org-babel
-  :version "24.3"
-  :type 'string)
+  :version "25.2"
+  :package-version '(Org . "9.3")
+  :type 'symbol)
 
 (defun org-babel-execute:java (body params)
-  (let* ((classname (or (cdr (assq :classname params))
-			(error
-			 "Can't compile a java block without a classname")))
-	 (packagename (file-name-directory classname))
-	 (src-file (concat classname ".java"))
+  "Execute a java source block with BODY code and PARAMS params."
+  (let* (;; if true, run from babel temp directory
+         (run-from-temp (not (assq :dir params)))
+         ;; class and package
+         (fullclassname (or (cdr (assq :classname params))
+                            (org-babel-java-find-classname body)))
+         ;; just the class name
+         (classname (car (last (split-string fullclassname "\\."))))
+         ;; just the package name
+         (packagename (if (seq-contains fullclassname ?.)
+                          (file-name-base fullclassname)))
+         ;; the base dir that contains the top level package dir
+         (basedir (file-name-as-directory (if run-from-temp
+                                              org-babel-temporary-directory
+                                            ".")))
+         ;; the dir to write the source file
+         (packagedir (if (and (not run-from-temp) packagename)
+                         (file-name-as-directory
+                          (concat basedir (replace-regexp-in-string "\\\." "/" packagename)))
+                       basedir))
+         ;; the filename of the source file
+         (src-file (concat packagedir classname ".java"))
+	 ;; compiler flags
 	 (cmpflag (or (cdr (assq :cmpflag params)) ""))
-	 (cmdline (or (cdr (assq :cmdline params)) ""))
+	 ;; runtime flags
+         (cmdline (or (cdr (assq :cmdline params)) ""))
+         ;; command line args
 	 (cmdargs (or (cdr (assq :cmdargs params)) ""))
-	 (full-body (org-babel-expand-body:generic body params)))
+         ;; the command to compile and run
+         (cmd (concat org-babel-java-compiler-command " " cmpflag " "
+                      (org-babel-process-file-name src-file 'noquote)
+                      " && " org-babel-java-runtime-command
+                      " -cp " (org-babel-process-file-name basedir 'noquote)
+		      " " cmdline " " (if run-from-temp classname fullclassname)
+		      " " cmdargs))
+         ;; header args for result processing
+         (result-type (cdr (assq :result-type params)))
+         (result-params (cdr (assq :result-params params)))
+         (result-file (and (eq result-type 'value)
+                           (org-babel-temp-file "java-")))
+         ;; the expanded body of the source block
+         (full-body (org-babel-expand-body:java body params)))
+
     ;; created package-name directories if missing
-    (unless (or (not packagename) (file-exists-p packagename))
-      (make-directory packagename 'parents))
+    (unless (or (not packagedir) (file-exists-p packagedir))
+      (make-directory packagedir 'parents))
+
+    ;; write the source file
+    (setq full-body (org-babel-java--expand-for-evaluation
+		     full-body run-from-temp result-type result-file))
     (with-temp-file src-file (insert full-body))
-    (org-babel-eval
-     (concat org-babel-java-compiler " " cmpflag " " src-file) "")
-    (let ((results (org-babel-eval (concat org-babel-java-command
-                                           " " cmdline " " classname " " cmdargs) "")))
-      (org-babel-reassemble-table
-       (org-babel-result-cond (cdr (assq :result-params params))
-	 (org-babel-read results t)
-         (let ((tmp-file (org-babel-temp-file "c-")))
-           (with-temp-file tmp-file (insert results))
-           (org-babel-import-elisp-from-file tmp-file)))
-       (org-babel-pick-name
-        (cdr (assq :colname-names params)) (cdr (assq :colnames params)))
-       (org-babel-pick-name
-        (cdr (assq :rowname-names params)) (cdr (assq :rownames params)))))))
+
+    ;; compile, run, process result
+    (org-babel-reassemble-table
+     (org-babel-java-evaluate cmd result-type result-params result-file)
+     (org-babel-pick-name
+      (cdr (assoc :colname-names params)) (cdr (assoc :colnames params)))
+     (org-babel-pick-name
+      (cdr (assoc :rowname-names params)) (cdr (assoc :rownames params))))))
+
+;; helper functions
+
+(defun org-babel-java-find-classname (body)
+  "Try to find fully qualified class name in BODY.
+Look through BODY for the package and class.  If found, put them
+together into a fully qualified class name and return.  Else just
+return class name.  If that isn't found either, default to Main."
+  (let ((package (if (string-match "package \\\([^ ]*\\\);" body)
+                     (match-string 1 body)))
+        (class (if (string-match "public class \\\([^ \n]*\\\)" body)
+                   (match-string 1 body))))
+    (or (and package class (concat package "." class))
+        (and class class)
+        (and package (concat package ".Main"))
+        "Main")))
+
+(defconst org-babel-java--package-re "^[[:space:]]*package .*;$"
+  "Regexp for the package statement.")
+(defconst org-babel-java--imports-re "^[[:space:]]*import .*;$"
+  "Regexp for import statements.")
+(defconst org-babel-java--class-re "^public class [[:alnum:]_]+[[:space:]]*\n?[[:space:]]*{"
+  "Regexp for the class declaration.")
+(defconst org-babel-java--main-re "public static void main(String\\(?:\\[]\\)? args\\(?:\\[]\\)?).*\n?[[:space:]]*{"
+  "Regexp for the main method declaration.")
+(defconst org-babel-java--any-method-re "public .*(.*).*\n?[[:space:]]*{"
+  "Regexp for any method.")
+(defconst org-babel-java--result-wrapper "\n    public static String __toString(Object val) {
+        if (val instanceof String) {
+            return \"\\\"\" + val + \"\\\"\";
+        } else if (val == null) {
+            return \"null\";
+        } else if (val.getClass().isArray()) {
+            StringBuffer sb = new StringBuffer();
+            Object[] vals = (Object[])val;
+            sb.append(\"[\");
+            for (int ii=0; ii<vals.length; ii++) {
+                sb.append(__toString(vals[ii]));
+                if (ii<vals.length-1)
+                    sb.append(\",\");
+            }
+            sb.append(\"]\");
+            return sb.toString();
+        } else if (val instanceof List) {
+            StringBuffer sb = new StringBuffer();
+            List vals = (List)val;
+            sb.append(\"[\");
+            for (int ii=0; ii<vals.size(); ii++) {
+                sb.append(__toString(vals.get(ii)));
+                if (ii<vals.size()-1)
+                    sb.append(\",\");
+            }
+            sb.append(\"]\");
+            return sb.toString();
+        } else {
+            return String.valueOf(val);
+        }
+    }
+
+    public static void main(String[] args) throws IOException {
+        BufferedWriter output = new BufferedWriter(new FileWriter(\"%s\"));
+        output.write(__toString(_main(args)));
+        output.close();
+    }"
+  "Code to inject into a class so that we can capture the value it returns.
+This implementation was inspired by ob-python, although not as
+elegant.  This modified the source block to write out the value
+it wants to return to a temporary file so that ob-java can read
+it back.  The name of the temporary file to write must be
+replaced in this string.")
+
+(defun org-babel-java--expand-for-evaluation (body suppress-package-p result-type result-file)
+  "Expand source block for evaluation.
+In order to return a value we have to add a __toString method.
+In order to prevent classes without main methods from erroring we
+add a dummy main method if one is not provided.  These
+manipulations are done outside of `org-babel--expand-body' so
+that they are hidden from tangles.
+
+BODY is the file content before instrumentation.
+
+SUPPRESS-PACKAGE-P if true, suppress the package statement.
+
+RESULT-TYPE is taken from params.
+
+RESULT-FILE is the temp file to write the result."
+  (with-temp-buffer
+    (insert body)
+
+    ;; suppress package statement
+    (goto-char (point-min))
+    (when (and suppress-package-p
+	       (re-search-forward org-babel-java--package-re nil t))
+      (replace-match ""))
+
+    ;; add a dummy main method if needed
+    (goto-char (point-min))
+    (when (not (re-search-forward org-babel-java--main-re nil t))
+      (org-babel-java--move-past org-babel-java--class-re)
+      (insert "\n    public static void main(String[] args) {
+        System.out.print(\"success\");
+}\n\n"))
+
+    ;; special handling to return value
+    (when (eq result-type 'value)
+      (goto-char (point-min))
+      (org-babel-java--move-past org-babel-java--class-re)
+      (insert (format org-babel-java--result-wrapper
+		      (org-babel-process-file-name result-file 'noquote)))
+      (search-forward "public static void main(") ; rename existing main
+      (replace-match "public static Object _main("))
+
+    ;; add imports
+    (org-babel-java--import-maybe "java.util" "List")
+    (org-babel-java--import-maybe "java.util" "Arrays")
+    (org-babel-java--import-maybe "java.io" "BufferedWriter")
+    (org-babel-java--import-maybe "java.io" "FileWriter")
+    (org-babel-java--import-maybe "java.io" "IOException")
+
+    (buffer-string)))
+
+(defun org-babel-java--move-past (re)
+  "Move point past the first occurrence of the given regexp RE."
+  (while (re-search-forward re nil t)
+    (goto-char (1+ (match-end 0)))))
+
+(defun org-babel-java--import-maybe (package class)
+  "Import from PACKAGE the given CLASS if it is used and not already imported."
+  (let (class-found import-found)
+    (goto-char (point-min))
+    (setq class-found (re-search-forward class nil t))
+    (goto-char (point-min))
+    (setq import-found (re-search-forward (concat "^import .*" package ".*" class ";") nil t))
+    (when (and class-found (not import-found))
+      (org-babel-java--move-past org-babel-java--package-re)
+      (insert (concat "import " package "." class ";\n")))))
+
+(defun org-babel-expand-body:java (body params)
+  "Expand BODY with PARAMS.
+BODY could be a few statements, or could include a full class
+definition specifying package, imports, and class.  Because we
+allow this flexibility in what the source block can contain, it
+is simplest to expand the code block from the inside out."
+  (let* ((fullclassname (or (cdr (assq :classname params)) ; class and package
+                            (org-babel-java-find-classname body)))
+         (classname (car (last (split-string fullclassname "\\.")))) ; just class name
+         (packagename (if (seq-contains fullclassname ?.)  ; just package name
+                          (file-name-base fullclassname)))
+         (var-lines (org-babel-variable-assignments:java params))
+         (imports-val (assq :imports params))
+         (imports (if imports-val
+                      (split-string (org-babel-read (cdr imports-val) nil) " ")
+                    nil)))
+    (with-temp-buffer
+      (insert body)
+
+      ;; wrap main.  If there are methods defined, but no main method
+      ;; and no class, wrap everything in a generic main method.
+      (goto-char (point-min))
+      (when (and (not (re-search-forward org-babel-java--class-re nil t))
+                 (not (re-search-forward org-babel-java--any-method-re nil t)))
+        (org-babel-java--move-past org-babel-java--package-re) ; if package is defined, move past it
+        (org-babel-java--move-past org-babel-java--imports-re) ; if imports are defined, move past them
+        (insert "public static void main(String[] args) {\n")
+        (indent-code-rigidly (point) (point-max) 4)
+        (goto-char (point-max))
+        (insert "\n}"))
+
+      ;; wrap class.  If there's no class, wrap everything in a
+      ;; generic class.
+      (goto-char (point-min))
+      (when (not (re-search-forward org-babel-java--class-re nil t))
+        (org-babel-java--move-past org-babel-java--package-re) ; if package is defined, move past it
+        (org-babel-java--move-past org-babel-java--imports-re) ; if imports are defined, move past them
+        (insert (concat "\npublic class " (file-name-base classname) " {\n"))
+        (indent-code-rigidly (point) (point-max) 4)
+        (goto-char (point-max))
+        (insert "\n}"))
+      (goto-char (point-min))
+
+      ;; insert variables from source block headers
+      (when var-lines
+        (goto-char (point-min))
+        (org-babel-java--move-past org-babel-java--class-re)   ; move inside class
+        (insert (mapconcat 'identity var-lines "\n"))
+        (insert "\n"))
+
+      ;; add imports from source block headers
+      (when imports
+        (goto-char (point-min))
+        (org-babel-java--move-past org-babel-java--package-re) ; if package is defined, move past it
+        (insert (mapconcat (lambda (package) (concat "import " package ";")) imports "\n") "\n"))
+
+      ;; add package at the top
+      (goto-char (point-min))
+      (when (and packagename (not (re-search-forward org-babel-java--package-re nil t)))
+        (insert (concat "package " packagename ";\n")))
+
+      ;; return expanded body
+      (buffer-string))))
+
+(defun org-babel-variable-assignments:java (params)
+  "Return a list of java statements assigning the block's variables.
+variables are contained in PARAMS."
+  (mapcar
+   (lambda (pair)
+     (let* ((type-data (org-babel-java-val-to-type (cdr pair)))
+            (basetype (car type-data))
+            (var-to-java (lambda (var) (funcall #'org-babel-java-var-to-java var basetype))))
+       (format "    static %s %s = %s;"
+               (cdr type-data)                     ; type
+               (car pair)                          ; name
+               (funcall var-to-java (cdr pair))))) ; value
+   (org-babel--get-vars params)))
+
+(defun org-babel-java-var-to-java (var basetype)
+  "Convert an elisp value to a java variable.
+Convert an elisp value, VAR, of type BASETYPE into a string of
+java source code specifying a variable of the same value."
+  (cond ((and (sequencep var) (not (stringp var)))
+         (let ((var-to-java (lambda (var) (funcall #'org-babel-java-var-to-java var basetype))))
+           (concat "Arrays.asList(" (mapconcat var-to-java var ", ") ")")))
+        ((eq var 'hline) org-babel-java-hline-to)
+        ((eq basetype 'integerp) (format "%d" var))
+        ((eq basetype 'floatp) (format "%f" var))
+        ((eq basetype 'stringp) (if (and (stringp var) (string-match-p ".\n+." var))
+                                    (error "Java does not support multiline string literals")
+                                  (format "\"%s\"" var)))))
+
+(defun org-babel-java-val-to-type (val)
+  "Determine the type of VAL.
+Return (BASETYPE . LISTTYPE), where BASETYPE is a symbol
+representing the type of the individual items in VAL, and
+LISTTYPE is a string name of the type parameter for a container
+for BASETYPE items."
+  (let* ((basetype (org-babel-java-val-to-base-type val))
+         (basetype-str (pcase basetype
+                         (`integerp "Integer")
+                         (`floatp "Double")
+                         (`stringp "String")
+                         (_ (error "Unknown type %S" basetype)))))
+    (cond
+     ((and (listp val) (listp (car val))) ; a table
+      (cons basetype (format "List<List<%s>>" basetype-str)))
+     ((or (listp val) (vectorp val))      ; a list declared in the source block header
+      (cons basetype (format "List<%s>" basetype-str)))
+     (t                                   ; return base type
+      (cons basetype basetype-str)))))
+
+(defun org-babel-java-val-to-base-type (val)
+  "Determine the base type of VAL.
+VAL may be
+`integerp' if all base values are integers
+`floatp' if all base values are either floating points or integers
+`stringp' otherwise."
+  (cond
+   ((integerp val) 'integerp)
+   ((floatp val) 'floatp)
+   ((or (listp val) (vectorp val))
+    (let ((type nil))
+      (mapc (lambda (v)
+              (pcase (org-babel-java-val-to-base-type v)
+                (`stringp (setq type 'stringp))
+                (`floatp
+                 (when (or (not type) (eq type 'integerp))
+                   (setq type 'floatp)))
+                (`integerp
+                 (unless type (setq type 'integerp)))))
+            val)
+      type))
+   (t 'stringp)))
+
+(defun org-babel-java-table-or-string (results)
+  "Convert RESULTS into an appropriate elisp value.
+If the results look like a list or vector, then convert them into an
+Emacs-lisp table, otherwise return the results as a string."
+  (let ((res (org-babel-script-escape results)))
+    (if (listp res)
+        (mapcar (lambda (el) (if (eq 'null el)
+                                 org-babel-java-null-to
+                               el))
+                res)
+      res)))
+
+(defun org-babel-java-evaluate (cmd result-type result-params result-file)
+  "Evaluate using an external java process.
+CMD the command to execute.
+
+If RESULT-TYPE equals 'output then return standard output as a
+string.  If RESULT-TYPE equals 'value then return the value
+returned by the source block, as elisp.
+
+RESULT-PARAMS input params used to format the reponse.
+
+RESULT-FILE filename of the tempfile to store the returned value in
+for 'value RESULT-TYPE.  Not used for 'output RESULT-TYPE."
+  (let ((raw (pcase result-type
+               ('output (org-babel-eval cmd ""))
+               ('value (org-babel-eval cmd "")
+                       (org-babel-eval-read-file result-file)))))
+    (org-babel-result-cond result-params raw
+      (org-babel-java-table-or-string raw))))
 
 (provide 'ob-java)
 
diff --git a/testing/lisp/test-ob-java.el b/testing/lisp/test-ob-java.el
new file mode 100644
index 000000000..090c40084
--- /dev/null
+++ b/testing/lisp/test-ob-java.el
@@ -0,0 +1,583 @@
+;;; test-ob-java.el --- tests for ob-java.el
+
+;; Copyright (c) 2020 Ian Martins
+;; Authors: Ian Martins
+
+;; This file is not part of GNU Emacs.
+
+;; This program 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 of the License, 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.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Code:
+(require 'org-test)
+
+(require 'ob-core)
+(defvar org-babel-temporary-directory ; from ob-core
+  (if (boundp 'org-babel-temporary-directory)
+    org-babel-temporary-directory
+  (temporary-file-directory)))
+
+(org-test-for-executable "java")
+(org-test-for-executable "javac")
+(unless (featurep 'ob-java)
+  (signal 'missing-test-dependency "Support for java code blocks"))
+
+; simple tests
+
+(ert-deftest ob-java/simple ()
+  "Hello world program that writes output."
+  (org-test-with-temp-text
+      "#+begin_src java :results output silent
+System.out.print(42);
+#+end_src"
+   (should (string= "42" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/simple-with-bracket ()
+  "Hello world program that outputs an open square bracket."
+  (org-test-with-temp-text
+      "#+begin_src java :results output silent
+System.out.print(\"[42\");
+#+end_src"
+   (should (string= "[42" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/simple-with-quote ()
+  "Hello world program that writes quotes."
+  (org-test-with-temp-text
+      "#+begin_src java :results output silent
+System.out.print(\"\\\"42\\\"\");
+#+end_src"
+   (should (string= "\"42\"" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/simple-return-int ()
+  "Hello world program that returns an int value."
+  (org-test-with-temp-text
+      "#+begin_src java :results silent
+return 42;
+#+end_src"
+   (should (eq 42 (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/simple-return-float ()
+  "Hello world program that returns a float value."
+  (org-test-with-temp-text
+      "#+begin_src java :results silent
+return 42.0;
+#+end_src"
+   (should (equal 42.0 (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/simple-return-string ()
+  "Hello world program that returns a string value."
+  (org-test-with-temp-text
+      "#+begin_src java :results silent
+return \"forty two\";
+#+end_src"
+    (should (string= "forty two" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/simple-with-main ()
+  "Hello world program that defines a main function."
+  (org-test-with-temp-text
+      "#+begin_src java :results output silent
+public static void main(String[] args) {
+    System.out.print(42);
+}
+#+end_src"
+    (should (string= "42" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/simple-with-two-methods ()
+  "Hello world program with two methods and no class."
+  (org-test-with-temp-text
+      "#+begin_src java :results output silent
+public static void main(String[] args) {
+    System.out.print(foo());
+}
+public static int foo() {
+    return 42;
+}
+#+end_src"
+    (should (string= "42" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/simple-with-no-main ()
+  "Hello world program with no main method.  Babel adds a dummy one so it can run without error."
+  (org-test-with-temp-text
+      "#+begin_src java :results output silent
+public static int foo() {
+    return 42;
+}
+#+end_src"
+    (should (string= "success" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/simple-with-main-args-array ()
+  "Hello world program that defines a main function with the square brackets after `args'."
+  (org-test-with-temp-text
+      "#+begin_src java :results output silent
+public static void main(String args[]) {
+    System.out.print(42);
+}
+#+end_src"
+    (should (string= "42" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/simple-with-class ()
+  "Hello world program that defines a class."
+  (org-test-with-temp-text
+      "#+begin_src java :results output silent
+public class Simple {
+    public static void main(String[] args) {
+        System.out.print(42);
+    }
+}
+#+end_src"
+   (should (string= "42" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/simple-with-class-and-package ()
+  "Hello world program that defines a class and package."
+  (org-test-with-temp-text
+      "#+begin_src java :results output silent
+package pkg;
+public class Simple {
+    public static void main(String[] args) {
+        System.out.print(42);
+    }
+}
+#+end_src"
+    (should (string= "42" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/simple-with-class-attr ()
+  "Hello world program with class header attribute."
+  (org-test-with-temp-text
+      "#+begin_src java :results output silent :classname Simple
+public static void main(String[] args) {
+    System.out.print(42);
+}
+#+end_src"
+   (should (string= "42" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/simple-with-class-attr-with-package ()
+  "Hello world program with class attr with package."
+  (org-test-with-temp-text
+      "#+begin_src java :results output silent :classname pkg.Simple
+public static void main(String[] args) {
+    System.out.print(42);
+}
+#+end_src"
+    (should (string= "42" (org-babel-execute-src-block)))))
+
+
+(ert-deftest ob-java/one-arg ()
+  "Command line arg."
+  (org-test-with-temp-text
+      "#+begin_src java :results output silent :cmdargs \"fortytwo\"
+System.out.print(args[0]);
+#+end_src"
+    (should (string= "fortytwo" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/args-quoted-string ()
+  "Two command line args, first contains a space."
+  (org-test-with-temp-text
+      "#+begin_src java :results output silent :cmdargs \"\\\"forty two\\\" 42\"
+System.out.println(args[0]);
+System.out.println(args[1]);
+#+end_src"
+    (should (string= "forty two\n42\n" (org-babel-execute-src-block)))))
+
+;; var tests
+
+(ert-deftest ob-java/integer-var ()
+  "Read and write an integer variable."
+  (org-test-with-temp-text
+      "#+begin_src java :var a=42 :results output silent
+System.out.print(a);
+#+end_src"
+    (should (string= "42" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/var-with-main ()
+  "Read and write an integer variable, with main function provided."
+  (org-test-with-temp-text
+      "#+begin_src java :var a=42 :results output silent
+public static void main(String[] args) {
+    System.out.print(a);
+}
+#+end_src"
+    (should (string= "42" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/var-with-class ()
+  "Read and write an integer variable, with class provided."
+  (org-test-with-temp-text
+      "#+begin_src java :var a=42 :results output silent
+public class Main {
+    public static void main(String[] args) {
+        System.out.print(a);
+    }
+}
+#+end_src"
+    (should (string= "42" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/var-with-class-and-package ()
+  "Read and write an integer variable, with class and package provided."
+  (org-test-with-temp-text
+      "#+begin_src java :var a=42 :results output silent
+package pkg;
+public class Main {
+    public static void main(String[] args) {
+        System.out.print(a);
+    }
+}
+#+end_src"
+    (should (string= "42" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/var-with-class-and-hanging-curlies ()
+  "Read and write an integer variable, with class with hanging curlies."
+  (org-test-with-temp-text
+      "#+begin_src java :var a=42 :results output silent
+public class Main
+{
+    public static void main(String[] args)
+    {
+        System.out.print(a);
+    }
+}
+#+end_src"
+    (should (string= "42" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/two-vars ()
+  "Read two integer variables, combine and write them."
+  (org-test-with-temp-text
+      "#+begin_src java :var a=21 b=2 :results output silent
+System.out.print(a*b);
+#+end_src"
+    (should (string= "42" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/string-var ()
+  "Read and write a string variable."
+  (org-test-with-temp-text
+      "#+begin_src java :var a=\"forty two\" :results output silent
+System.out.print(String.format(\"%s, len=%d\", a, a.length()));
+#+end_src"
+    (should (string= "forty two, len=9" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/multiline-string-var ()
+  "Java doesn't support multiline string literals, so this errors."
+  (org-test-with-temp-text
+      "#+begin_src java :var a=\"forty\ntwo\" :results output silent
+System.out.print(String.format(\"%s, len=%d\", a, a.length()));
+#+end_src"
+    (should-error (org-babel-execute-src-block)))
+  :type 'error)
+
+;; return list
+
+(ert-deftest ob-java/return-vector-using-list ()
+  "Return a vector using a list."
+  (org-test-with-temp-text
+      "#+begin_src java :results vector silent
+import java.util.List;
+import java.util.Arrays;
+List<List<Integer>> a = Arrays.asList(Arrays.asList(4),
+                                      Arrays.asList(2));
+return a;
+#+end_src"
+    (should (equal '((4) (2))
+                   (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/return-vector-using-array ()
+  "Return a vector using an array."
+  (org-test-with-temp-text
+      "#+begin_src java :results vector silent
+Integer[][] a = {{4}, {2}};
+return a;
+#+end_src"
+    (should (equal '((4) (2))
+                   (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/read-return-list ()
+  "Read and return a list."
+  (org-test-with-temp-text
+      "#+begin_src java :var a=java_list :results silent
+import java.util.List;
+import java.util.Arrays;
+List<String> b = Arrays.asList(a.get(0).get(0),
+                               a.get(1).get(0));
+return b;
+#+end_src
+
+#+name: java_list
+- forty
+- two"
+    (should (equal '("forty" "two")
+                   (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/read-list-return-array ()
+  "Read a list and return an array."
+  (org-test-with-temp-text
+      "#+begin_src java :var a=java_list :results silent
+String[] b = {a.get(0).get(0), a.get(1).get(0)};
+return b;
+#+end_src
+
+#+name: java_list
+- forty
+- two"
+    (should (equal '("forty" "two")
+                   (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/read-return-list-with-package ()
+  "Return a vector."
+  (org-test-with-temp-text
+      "#+begin_src java :var a=java_list :results silent
+package pkg;
+import java.util.List;
+import java.util.Arrays;
+List<String> b = Arrays.asList(a.get(0).get(0),
+                               a.get(1).get(0));
+return b;
+#+end_src
+
+#+name: java_list
+- forty
+- two"
+    (should (equal '("forty" "two")
+                   (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/output-list-with-spaces ()
+  "Return a vector."
+  (org-test-with-temp-text
+      "#+begin_src java :results output list raw silent
+System.out.println(\"forty two\");
+System.out.println(\"forty two\");
+#+end_src"
+    (should (equal "forty two\nforty two\n"
+                   (org-babel-execute-src-block)))))
+
+;; list vars
+
+(ert-deftest ob-java/list-var ()
+  "Read and write a list variable."
+  (org-test-with-temp-text
+      "#+begin_src java :var a='(\"forty\" \"two\") :results silent
+import java.util.List;
+List<String> b = a;
+return b;
+#+end_src"
+    (should (equal '("forty" "two")
+                   (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/vector-var ()
+  "Read and write a vector variable."
+  (org-test-with-temp-text
+      "#+begin_src java :var a='[\"forty\" \"two\"] :results silent
+import java.util.List;
+List<String> b = a;
+return b;
+#+end_src"
+    (should (equal '("forty" "two")
+                   (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/matrix-var ()
+  "Read and write matrix variable."
+  (org-test-with-temp-text
+      "#+begin_src java :var a=java_matrix :results silent
+import java.util.List;
+import java.util.Arrays;
+List<List<Integer>> b = Arrays.asList(Arrays.asList(a.get(0).get(0), a.get(1).get(0)),
+                                      Arrays.asList(a.get(0).get(1), a.get(1).get(1)));
+return b; // transpose
+#+end_src
+
+#+name: java_matrix
+| 2 | 1 |
+| 4 | 2 |"
+    (should (equal '((2 4) (1 2))
+                   (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/matrix-var-with-header ()
+  "Read matrix variable and write it with header."
+  (org-test-with-temp-text
+      "#+begin_src java :var a=java_matrix :results value table silent
+import java.util.List;
+import java.util.Arrays;
+List<List> b = Arrays.asList(Arrays.asList(\"col1\", \"col2\"),
+                                     null,
+                                     Arrays.asList(a.get(0).get(0), a.get(1).get(0)),
+                                     Arrays.asList(a.get(0).get(1), a.get(1).get(1)));
+return b; // transpose
+#+end_src
+
+#+name: java_matrix
+| 2 | 1 |
+| 4 | 2 |"
+    (should (equal '(("col1" "col2") hline (2 4) (1 2))
+                   (org-babel-execute-src-block)))))
+
+;; output table
+
+(ert-deftest ob-java/output-table-with-header ()
+  "Write a table that includes a header."
+  (org-test-with-temp-text
+      "#+begin_src java :var a=java_matrix :results output raw table silent
+System.out.println(\"|col1|col2|\");
+System.out.println(\"|-\");
+for (int ii=0; ii<a.size(); ii++) {
+    for (int jj=0; jj<a.get(0).size(); jj++) {
+        System.out.print(\"|\" + a.get(ii).get(jj));
+    }
+    System.out.println(\"\");
+ }
+#+end_src
+
+#+name: java_matrix
+| 2 | 1 |
+| 4 | 2 |"
+    (should (equal "|col1|col2|\n|-\n|2|1\n|4|2\n"
+                   (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/inhomogeneous_table ()
+  "Read and write an inhomogeneous table."
+  (org-test-with-temp-text
+      "#+begin_src java :var a=java_table :results silent
+import java.util.List;
+import java.util.Arrays;
+List<List> b = Arrays.asList(Arrays.asList(a.get(0).get(0),
+                                           Integer.parseInt(a.get(0).get(1))*2),
+                             Arrays.asList(a.get(1).get(0),
+                                           Integer.parseInt(a.get(1).get(1))*2));
+return b;
+#+end_src
+
+#+name: java_table
+  | string | number |
+  |--------+--------|
+  | forty  |      2 |
+  | two    |      1 |"
+   (should (equal
+            '(("forty" 4) ("two" 2))
+            (org-babel-execute-src-block)))))
+
+;; imports
+
+(ert-deftest ob-java/import_library ()
+  "Import a standard java library."
+  (org-test-with-temp-text
+      "#+begin_src java :results output silent :imports java.util.Base64
+byte[] encoded = Base64.getEncoder().encode(\"42\".getBytes());
+String decoded = new String(Base64.getDecoder().decode(encoded));
+System.out.print(String.format(\"encoded=%s, decoded=%s\", new String(encoded), decoded));
+#+end_src"
+   (should (string=
+            "encoded=NDI=, decoded=42"
+            (org-babel-execute-src-block)))))
+
+(ert-deftest ob-java/import_library_inline ()
+  "Import a standard java library."
+  (org-test-with-temp-text
+      "#+begin_src java :results output silent
+import java.util.Base64;
+byte[] encoded = Base64.getEncoder().encode(\"42\".getBytes());
+String decoded = new String(Base64.getDecoder().decode(encoded));
+System.out.print(String.format(\"encoded=%s, decoded=%s\", new String(encoded), decoded));
+#+end_src"
+   (should (string=
+            "encoded=NDI=, decoded=42"
+            (org-babel-execute-src-block)))))
+
+;; tangle
+
+(ert-deftest ob-java/tangle ()
+  "Tangle a source block."
+  (org-test-with-temp-text-in-file
+      "#+begin_src java :tangle \"Tangle.java\" :results value :classname Tangle
+return \"tangled\";
+#+end_src"
+    (should
+     (string=
+      "public class Tangle {
+    public static void main(String[] args) {
+        return \"tangled\";
+    }
+}
+"
+      (unwind-protect
+          (progn (org-babel-tangle)
+                 (with-temp-buffer
+                   (insert-file-contents "Tangle.java")
+                   (untabify (point-min) (point-max))
+                   (buffer-string)))
+        (delete-file "Tangle.java"))))))
+
+(ert-deftest ob-java/tangle-with-package ()
+  "Tangle a source block."
+  (org-test-with-temp-text-in-file
+      "#+begin_src java :tangle \"tangle/Tangle.java\" :results value :classname tangle.Tangle
+return \"tangled\";
+#+end_src"
+    (should
+     (string=
+      "package tangle;
+
+public class Tangle {
+    public static void main(String[] args) {
+        return \"tangled\";
+    }
+}
+"
+      (unwind-protect
+          (progn
+            (make-directory "tangle")
+            (org-babel-tangle)
+            (with-temp-buffer
+              (insert-file-contents "tangle/Tangle.java")
+              (untabify (point-min) (point-max))
+              (buffer-string)))
+        (delete-file "tangle/Tangle.java")
+        (delete-directory "tangle"))))))
+
+
+;; specify output dir
+
+(ert-deftest ob-java/simple-dir ()
+  "Hello world program that writes output."
+  (org-test-with-temp-text
+      (format  "#+begin_src java :results output silent :dir %s
+System.out.print(42);
+#+end_src" org-babel-temporary-directory)
+    (should (string=
+             "42"
+             (unwind-protect
+                 (org-babel-execute-src-block)
+               (delete-file (concat (file-name-as-directory org-babel-temporary-directory)
+                                    "Main.java"))
+               (delete-file (concat (file-name-as-directory org-babel-temporary-directory)
+                                    "Main.class")))))))
+
+(ert-deftest ob-java/simple-dir-with-package ()
+  "Hello world program that writes output."
+  (org-test-with-temp-text
+      (format "#+begin_src java :results output silent :dir %s
+package pkg;
+
+public class Main {
+    public static void main(String[] args) {
+      System.out.print(42);
+    }
+}
+#+end_src" org-babel-temporary-directory)
+    (should (string=
+             "42"
+             (unwind-protect
+                 (org-babel-execute-src-block)
+               (delete-file (concat (file-name-as-directory org-babel-temporary-directory)
+                                    "pkg/Main.java"))
+               (delete-file (concat (file-name-as-directory org-babel-temporary-directory)
+                                    "pkg/Main.class"))
+               (delete-directory (concat (file-name-as-directory org-babel-temporary-directory)
+                                         "pkg")))))))
+
+
+;;; test-ob-java.el ends here
-- 
2.25.1


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] ob-java
  2020-10-09 11:15   ` ian martins
@ 2020-10-20 18:28     ` John Herrlin
  2020-10-20 19:17     ` John Herrlin
  2020-10-24 17:05     ` Kyle Meyer
  2 siblings, 0 replies; 31+ messages in thread
From: John Herrlin @ 2020-10-20 18:28 UTC (permalink / raw)
  To: ian martins; +Cc: emacs-orgmode


Hey Ian,

The changes list looks really nice!

But I can't get the patch to work.

The use case I have is this and it works fine in master.


   #+HEADER: :classname Main
   #+HEADER: :dir src
   #+HEADER: :cmdline -classpath ./rxjava-1.3.8.jar:.
   #+HEADER: :cmpflag -classpath ./rxjava-1.3.8.jar
   #+BEGIN_SRC java :results output code
     import rx.Observable;
     class Main {
         public static void main(String[] args) {
             Observable.range(5, 5)
                 .subscribe(System.out::println);
         }
     }
   #+END_SRC

The error message I get is the following:

   #+BEGIN_SRC text
     /home/john/git/org-files/programming/src/Main.java:5: error: class Main is already defined in package unnamed package
     class Main {
     ^
     /home/john/git/org-files/programming/src/Main.java:6: error: Illegal static declaration in inner class Main.Main
     public static void main(String[] args) {
     ^
     modifier 'static' is only allowed in constant variable declarations
     2 errors
   #+END_SRC


Best regards
John


ian martins <ianxm@jhu.edu> writes:

> I noticed that the tests didn't run with "make test." This updates the
> patch so that they can. I didn't add java to the list of default languages
> because the java tests are slow.
>
> On Mon, Oct 5, 2020 at 9:23 AM ian martins <ianxm@jhu.edu> wrote:
>
>> I wrote those examples in an org file so I could test as I wrote them, and
>> then exported it to make it more readable, but the export resulted in
>> source block headers being lost.  Here is the same without export:
>> ----
>> * Changes
>>
>> - support for functional mode (~:results value~)
>> - accept variables
>> - don't require package, class, and main definitions
>> - write source and result tempfiles to ~org-babel-temporary-directory~,
>> but respects the ~:dir~ header
>> - work with tramp
>>
>> * Examples
>> ** Example 1
>> This outputs "hello."  If class and main definitions aren't given the
>> code block will be wrapped in generic ones.
>>
>> #+begin_src java :results output silent
>>   System.out.print("hello");
>> #+end_src
>>
>> This is exactly equivalent:
>>
>> #+begin_src java :results output silent
>>   public class Main {
>>       public static void main(String[] args) {
>>           System.out.print("hello");
>>       }
>>   }
>> #+end_src
>>
>> ** Example 2
>> This also outputs "hello."
>>
>> #+begin_src java :results value silent
>>   return "hello";
>> #+end_src
>>
>> ** Example 3
>> This generates the class "Example" in the package "org.orgmode" in the
>> current directory.
>>
>> #+begin_src java :results output silent :classname org.orgmode.Example
>> :dir .
>>   System.out.print("hello, org-mode");
>> #+end_src
>>
>> ** Example 4
>> The "Hey" class defines a static method but no main. C-c C-c on the
>> "Hey" source block will write "./org/orgmode/Hey.java" and compile it.
>>
>> The "Main" class calls the "Hey" class. C-c C-c on the "Main" source
>> block will write "./org/orgmode/Main.java" and compile and run it.
>>
>> #+begin_src java :results output silent :dir .
>>   package org.orgmode;
>>
>>   public class Hey {
>>       public static String say() {
>>           return "hey";
>>       }
>>   }
>> #+end_src
>>
>> #+begin_src java :results output silent :dir .
>>   package org.orgmode;
>>
>>   public class Main {
>>       public static void main(String[] args) {
>>           System.out.print(Hey.say());
>>       }
>>   }
>> #+end_src
>>
>> Instead of C-c C-c, we could have added tangle headers and written the
>> source files out by tangling.
>>
>> ** Example 5
>> This prints the variable from the header
>>
>> #+begin_src java :var msg="hello, org-mode" :results output silent
>>   System.out.print(msg);
>> #+end_src
>>
>> ** Example 6
>> This prints "hello, org-mode." The table is provided to the method as a
>> list of lists.
>>
>> #+name: table
>> | message | hello, org-mode  |
>>
>> #+begin_src java :var tbl=table :results output silent
>>   System.out.print(tbl.get(0).get(1));
>> #+end_src
>>
>> ** Example 7
>> This example returns a list.
>>
>> Note that you're allowed to specify imports without defining the class
>> or main methods.
>>
>> #+begin_src java :results value :exports both
>>   import java.util.Arrays;
>>
>>   return Arrays.asList("message", "hello, org-mode");
>> #+end_src
>>
>> #+RESULTS:
>> | message | hello, org-mode |
>>
>> On Mon, Oct 5, 2020 at 8:35 AM ian martins <ianxm@jhu.edu> wrote:
>>
>>> 1 Changes
>>> =========
>>>
>>>   - support for functional mode (`:results value')
>>>   - accept variables
>>>   - don't require package, class, and main definitions
>>>   - write source and result tempfiles to
>>>     `org-babel-temporary-directory', but respects the `:dir' header
>>>   - work with tramp
>>>
>>>
>>> 2 Examples
>>> ==========
>>> Some examples follow.  See the tests for more examples.  I'll write
>>> proper docs after review.
>>>
>>> 2.1 Example 1
>>> ~~~~~~~~~~~~~
>>>
>>>   This outputs "hello."  If class and main definitions aren't given the
>>>   code block will be wrapped in generic ones.
>>>
>>>   ,----
>>>   | System.out.print("hello");
>>>   `----
>>>
>>>   This is exactly equivalent:
>>>
>>>   ,----
>>>   | public class Main {
>>>   |     public static void main(String[] args) {
>>>   |         System.out.print("hello");
>>>   |     }
>>>   | }
>>>   `----
>>>
>>>
>>> 2.2 Example 2
>>> ~~~~~~~~~~~~~
>>>
>>>   This also outputs "hello."
>>>
>>>   ,----
>>>   | return "hello";
>>>   `----
>>>
>>>
>>> 2.3 Example 3
>>> ~~~~~~~~~~~~~
>>>
>>>   This generates the class "Example" in the package "org.orgmode" in the
>>>   current directory.
>>>
>>>   ,----
>>>   | System.out.print("hello, org-mode");
>>>   `----
>>>
>>>
>>> 2.4 Example 4
>>> ~~~~~~~~~~~~~
>>>
>>>   The "Hey" class defines a static method but no main. C-c C-c on the
>>>   "Hey" source block will write "./org/orgmode/Hey.java" and compile it.
>>>
>>>   The "Main" class calls the "Hey" class. C-c C-c on the "Main" source
>>>   block will write "./org/orgmode/Main.java" and compile and run it.
>>>
>>>   ,----
>>>   | package org.orgmode;
>>>   |
>>>   | public class Hey {
>>>   |     public static String say() {
>>>   |         return "hey";
>>>   |     }
>>>   | }
>>>   `----
>>>
>>>   ,----
>>>   | package org.orgmode;
>>>   |
>>>   | public class Main {
>>>   |     public static void main(String[] args) {
>>>   |         System.out.print(Hey.say());
>>>   |     }
>>>   | }
>>>   `----
>>>
>>>   Instead of C-c C-c, we could have added tangle headers and written the
>>>   source files out by tangling.
>>>
>>>
>>> 2.5 Example 5
>>> ~~~~~~~~~~~~~
>>>
>>>   This prints the variable from the header
>>>
>>>   ,----
>>>   | System.out.print(msg);
>>>   `----
>>>
>>>
>>> 2.6 Example 6
>>> ~~~~~~~~~~~~~
>>>
>>>   This prints "hello, org-mode." The table is provided to the method as
>>>   a list of lists.
>>>
>>>    message  hello, org-mode
>>>
>>>   ,----
>>>   | System.out.print(tbl.get(0).get(1));
>>>   `----
>>>
>>>
>>> 2.7 Example 7
>>> ~~~~~~~~~~~~~
>>>
>>>   This example returns a list.
>>>
>>>   Note that you're allowed to specify imports without defining the class
>>>   or main methods.
>>>
>>>   ,----
>>>   | import java.util.Arrays;
>>>   |
>>>   | return Arrays.asList("message", "hello, org-mode");
>>>   `----
>>>
>>>    message  hello, org-mode
>>>
>>


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] ob-java
  2020-10-09 11:15   ` ian martins
  2020-10-20 18:28     ` John Herrlin
@ 2020-10-20 19:17     ` John Herrlin
  2020-10-21  2:37       ` ian martins
  2020-10-24 17:05     ` Kyle Meyer
  2 siblings, 1 reply; 31+ messages in thread
From: John Herrlin @ 2020-10-20 19:17 UTC (permalink / raw)
  To: ian martins; +Cc: emacs-orgmode


Hey,

Did some debugging and found out that my class didn't contained =public=
and the patch requires it to be.

This works fine:

   #+HEADER: :classname Main
   #+HEADER: :dir src
   #+HEADER: :cmdline -classpath ./rxjava-1.3.8.jar:.
   #+HEADER: :cmpflag -classpath ./rxjava-1.3.8.jar
   #+BEGIN_SRC java :results output code
     import rx.Observable;
     public class Main {
         public static void main(String[] args) {
             Observable.range(5, 5)
                 .subscribe(System.out::println);
         }
     }
   #+END_SRC




ian martins <ianxm@jhu.edu> writes:

> I noticed that the tests didn't run with "make test." This updates the
> patch so that they can. I didn't add java to the list of default languages
> because the java tests are slow.
>
> On Mon, Oct 5, 2020 at 9:23 AM ian martins <ianxm@jhu.edu> wrote:
>
>> I wrote those examples in an org file so I could test as I wrote them, and
>> then exported it to make it more readable, but the export resulted in
>> source block headers being lost.  Here is the same without export:
>> ----
>> * Changes
>>
>> - support for functional mode (~:results value~)
>> - accept variables
>> - don't require package, class, and main definitions
>> - write source and result tempfiles to ~org-babel-temporary-directory~,
>> but respects the ~:dir~ header
>> - work with tramp
>>
>> * Examples
>> ** Example 1
>> This outputs "hello."  If class and main definitions aren't given the
>> code block will be wrapped in generic ones.
>>
>> #+begin_src java :results output silent
>>   System.out.print("hello");
>> #+end_src
>>
>> This is exactly equivalent:
>>
>> #+begin_src java :results output silent
>>   public class Main {
>>       public static void main(String[] args) {
>>           System.out.print("hello");
>>       }
>>   }
>> #+end_src
>>
>> ** Example 2
>> This also outputs "hello."
>>
>> #+begin_src java :results value silent
>>   return "hello";
>> #+end_src
>>
>> ** Example 3
>> This generates the class "Example" in the package "org.orgmode" in the
>> current directory.
>>
>> #+begin_src java :results output silent :classname org.orgmode.Example
>> :dir .
>>   System.out.print("hello, org-mode");
>> #+end_src
>>
>> ** Example 4
>> The "Hey" class defines a static method but no main. C-c C-c on the
>> "Hey" source block will write "./org/orgmode/Hey.java" and compile it.
>>
>> The "Main" class calls the "Hey" class. C-c C-c on the "Main" source
>> block will write "./org/orgmode/Main.java" and compile and run it.
>>
>> #+begin_src java :results output silent :dir .
>>   package org.orgmode;
>>
>>   public class Hey {
>>       public static String say() {
>>           return "hey";
>>       }
>>   }
>> #+end_src
>>
>> #+begin_src java :results output silent :dir .
>>   package org.orgmode;
>>
>>   public class Main {
>>       public static void main(String[] args) {
>>           System.out.print(Hey.say());
>>       }
>>   }
>> #+end_src
>>
>> Instead of C-c C-c, we could have added tangle headers and written the
>> source files out by tangling.
>>
>> ** Example 5
>> This prints the variable from the header
>>
>> #+begin_src java :var msg="hello, org-mode" :results output silent
>>   System.out.print(msg);
>> #+end_src
>>
>> ** Example 6
>> This prints "hello, org-mode." The table is provided to the method as a
>> list of lists.
>>
>> #+name: table
>> | message | hello, org-mode  |
>>
>> #+begin_src java :var tbl=table :results output silent
>>   System.out.print(tbl.get(0).get(1));
>> #+end_src
>>
>> ** Example 7
>> This example returns a list.
>>
>> Note that you're allowed to specify imports without defining the class
>> or main methods.
>>
>> #+begin_src java :results value :exports both
>>   import java.util.Arrays;
>>
>>   return Arrays.asList("message", "hello, org-mode");
>> #+end_src
>>
>> #+RESULTS:
>> | message | hello, org-mode |
>>
>> On Mon, Oct 5, 2020 at 8:35 AM ian martins <ianxm@jhu.edu> wrote:
>>
>>> 1 Changes
>>> =========
>>>
>>>   - support for functional mode (`:results value')
>>>   - accept variables
>>>   - don't require package, class, and main definitions
>>>   - write source and result tempfiles to
>>>     `org-babel-temporary-directory', but respects the `:dir' header
>>>   - work with tramp
>>>
>>>
>>> 2 Examples
>>> ==========
>>> Some examples follow.  See the tests for more examples.  I'll write
>>> proper docs after review.
>>>
>>> 2.1 Example 1
>>> ~~~~~~~~~~~~~
>>>
>>>   This outputs "hello."  If class and main definitions aren't given the
>>>   code block will be wrapped in generic ones.
>>>
>>>   ,----
>>>   | System.out.print("hello");
>>>   `----
>>>
>>>   This is exactly equivalent:
>>>
>>>   ,----
>>>   | public class Main {
>>>   |     public static void main(String[] args) {
>>>   |         System.out.print("hello");
>>>   |     }
>>>   | }
>>>   `----
>>>
>>>
>>> 2.2 Example 2
>>> ~~~~~~~~~~~~~
>>>
>>>   This also outputs "hello."
>>>
>>>   ,----
>>>   | return "hello";
>>>   `----
>>>
>>>
>>> 2.3 Example 3
>>> ~~~~~~~~~~~~~
>>>
>>>   This generates the class "Example" in the package "org.orgmode" in the
>>>   current directory.
>>>
>>>   ,----
>>>   | System.out.print("hello, org-mode");
>>>   `----
>>>
>>>
>>> 2.4 Example 4
>>> ~~~~~~~~~~~~~
>>>
>>>   The "Hey" class defines a static method but no main. C-c C-c on the
>>>   "Hey" source block will write "./org/orgmode/Hey.java" and compile it.
>>>
>>>   The "Main" class calls the "Hey" class. C-c C-c on the "Main" source
>>>   block will write "./org/orgmode/Main.java" and compile and run it.
>>>
>>>   ,----
>>>   | package org.orgmode;
>>>   |
>>>   | public class Hey {
>>>   |     public static String say() {
>>>   |         return "hey";
>>>   |     }
>>>   | }
>>>   `----
>>>
>>>   ,----
>>>   | package org.orgmode;
>>>   |
>>>   | public class Main {
>>>   |     public static void main(String[] args) {
>>>   |         System.out.print(Hey.say());
>>>   |     }
>>>   | }
>>>   `----
>>>
>>>   Instead of C-c C-c, we could have added tangle headers and written the
>>>   source files out by tangling.
>>>
>>>
>>> 2.5 Example 5
>>> ~~~~~~~~~~~~~
>>>
>>>   This prints the variable from the header
>>>
>>>   ,----
>>>   | System.out.print(msg);
>>>   `----
>>>
>>>
>>> 2.6 Example 6
>>> ~~~~~~~~~~~~~
>>>
>>>   This prints "hello, org-mode." The table is provided to the method as
>>>   a list of lists.
>>>
>>>    message  hello, org-mode
>>>
>>>   ,----
>>>   | System.out.print(tbl.get(0).get(1));
>>>   `----
>>>
>>>
>>> 2.7 Example 7
>>> ~~~~~~~~~~~~~
>>>
>>>   This example returns a list.
>>>
>>>   Note that you're allowed to specify imports without defining the class
>>>   or main methods.
>>>
>>>   ,----
>>>   | import java.util.Arrays;
>>>   |
>>>   | return Arrays.asList("message", "hello, org-mode");
>>>   `----
>>>
>>>    message  hello, org-mode
>>>
>>


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] ob-java
  2020-10-20 19:17     ` John Herrlin
@ 2020-10-21  2:37       ` ian martins
  2020-10-21  5:59         ` John Herrlin
  0 siblings, 1 reply; 31+ messages in thread
From: ian martins @ 2020-10-21  2:37 UTC (permalink / raw)
  To: John Herrlin; +Cc: Org-Mode mailing list

[-- Attachment #1: Type: text/plain, Size: 7809 bytes --]

Thanks for testing, and thanks for pointing that out. I will fix it so that
`public` is optional.

btw, in your example you didn't have to specify `:classname` since you
defined the class name in the source block.

btw2, did you notice that you can C-c C-c on source blocks that don't have
main methods and it'll compile without error?

On Tue, Oct 20, 2020 at 3:17 PM John Herrlin <jherrlin@gmail.com> wrote:

>
> Hey,
>
> Did some debugging and found out that my class didn't contained =public=
> and the patch requires it to be.
>
> This works fine:
>
>    #+HEADER: :classname Main
>    #+HEADER: :dir src
>    #+HEADER: :cmdline -classpath ./rxjava-1.3.8.jar:.
>    #+HEADER: :cmpflag -classpath ./rxjava-1.3.8.jar
>    #+BEGIN_SRC java :results output code
>      import rx.Observable;
>      public class Main {
>          public static void main(String[] args) {
>              Observable.range(5, 5)
>                  .subscribe(System.out::println);
>          }
>      }
>    #+END_SRC
>
>
>
>
> ian martins <ianxm@jhu.edu> writes:
>
> > I noticed that the tests didn't run with "make test." This updates the
> > patch so that they can. I didn't add java to the list of default
> languages
> > because the java tests are slow.
> >
> > On Mon, Oct 5, 2020 at 9:23 AM ian martins <ianxm@jhu.edu> wrote:
> >
> >> I wrote those examples in an org file so I could test as I wrote them,
> and
> >> then exported it to make it more readable, but the export resulted in
> >> source block headers being lost.  Here is the same without export:
> >> ----
> >> * Changes
> >>
> >> - support for functional mode (~:results value~)
> >> - accept variables
> >> - don't require package, class, and main definitions
> >> - write source and result tempfiles to ~org-babel-temporary-directory~,
> >> but respects the ~:dir~ header
> >> - work with tramp
> >>
> >> * Examples
> >> ** Example 1
> >> This outputs "hello."  If class and main definitions aren't given the
> >> code block will be wrapped in generic ones.
> >>
> >> #+begin_src java :results output silent
> >>   System.out.print("hello");
> >> #+end_src
> >>
> >> This is exactly equivalent:
> >>
> >> #+begin_src java :results output silent
> >>   public class Main {
> >>       public static void main(String[] args) {
> >>           System.out.print("hello");
> >>       }
> >>   }
> >> #+end_src
> >>
> >> ** Example 2
> >> This also outputs "hello."
> >>
> >> #+begin_src java :results value silent
> >>   return "hello";
> >> #+end_src
> >>
> >> ** Example 3
> >> This generates the class "Example" in the package "org.orgmode" in the
> >> current directory.
> >>
> >> #+begin_src java :results output silent :classname org.orgmode.Example
> >> :dir .
> >>   System.out.print("hello, org-mode");
> >> #+end_src
> >>
> >> ** Example 4
> >> The "Hey" class defines a static method but no main. C-c C-c on the
> >> "Hey" source block will write "./org/orgmode/Hey.java" and compile it.
> >>
> >> The "Main" class calls the "Hey" class. C-c C-c on the "Main" source
> >> block will write "./org/orgmode/Main.java" and compile and run it.
> >>
> >> #+begin_src java :results output silent :dir .
> >>   package org.orgmode;
> >>
> >>   public class Hey {
> >>       public static String say() {
> >>           return "hey";
> >>       }
> >>   }
> >> #+end_src
> >>
> >> #+begin_src java :results output silent :dir .
> >>   package org.orgmode;
> >>
> >>   public class Main {
> >>       public static void main(String[] args) {
> >>           System.out.print(Hey.say());
> >>       }
> >>   }
> >> #+end_src
> >>
> >> Instead of C-c C-c, we could have added tangle headers and written the
> >> source files out by tangling.
> >>
> >> ** Example 5
> >> This prints the variable from the header
> >>
> >> #+begin_src java :var msg="hello, org-mode" :results output silent
> >>   System.out.print(msg);
> >> #+end_src
> >>
> >> ** Example 6
> >> This prints "hello, org-mode." The table is provided to the method as a
> >> list of lists.
> >>
> >> #+name: table
> >> | message | hello, org-mode  |
> >>
> >> #+begin_src java :var tbl=table :results output silent
> >>   System.out.print(tbl.get(0).get(1));
> >> #+end_src
> >>
> >> ** Example 7
> >> This example returns a list.
> >>
> >> Note that you're allowed to specify imports without defining the class
> >> or main methods.
> >>
> >> #+begin_src java :results value :exports both
> >>   import java.util.Arrays;
> >>
> >>   return Arrays.asList("message", "hello, org-mode");
> >> #+end_src
> >>
> >> #+RESULTS:
> >> | message | hello, org-mode |
> >>
> >> On Mon, Oct 5, 2020 at 8:35 AM ian martins <ianxm@jhu.edu> wrote:
> >>
> >>> 1 Changes
> >>> =========
> >>>
> >>>   - support for functional mode (`:results value')
> >>>   - accept variables
> >>>   - don't require package, class, and main definitions
> >>>   - write source and result tempfiles to
> >>>     `org-babel-temporary-directory', but respects the `:dir' header
> >>>   - work with tramp
> >>>
> >>>
> >>> 2 Examples
> >>> ==========
> >>> Some examples follow.  See the tests for more examples.  I'll write
> >>> proper docs after review.
> >>>
> >>> 2.1 Example 1
> >>> ~~~~~~~~~~~~~
> >>>
> >>>   This outputs "hello."  If class and main definitions aren't given the
> >>>   code block will be wrapped in generic ones.
> >>>
> >>>   ,----
> >>>   | System.out.print("hello");
> >>>   `----
> >>>
> >>>   This is exactly equivalent:
> >>>
> >>>   ,----
> >>>   | public class Main {
> >>>   |     public static void main(String[] args) {
> >>>   |         System.out.print("hello");
> >>>   |     }
> >>>   | }
> >>>   `----
> >>>
> >>>
> >>> 2.2 Example 2
> >>> ~~~~~~~~~~~~~
> >>>
> >>>   This also outputs "hello."
> >>>
> >>>   ,----
> >>>   | return "hello";
> >>>   `----
> >>>
> >>>
> >>> 2.3 Example 3
> >>> ~~~~~~~~~~~~~
> >>>
> >>>   This generates the class "Example" in the package "org.orgmode" in
> the
> >>>   current directory.
> >>>
> >>>   ,----
> >>>   | System.out.print("hello, org-mode");
> >>>   `----
> >>>
> >>>
> >>> 2.4 Example 4
> >>> ~~~~~~~~~~~~~
> >>>
> >>>   The "Hey" class defines a static method but no main. C-c C-c on the
> >>>   "Hey" source block will write "./org/orgmode/Hey.java" and compile
> it.
> >>>
> >>>   The "Main" class calls the "Hey" class. C-c C-c on the "Main" source
> >>>   block will write "./org/orgmode/Main.java" and compile and run it.
> >>>
> >>>   ,----
> >>>   | package org.orgmode;
> >>>   |
> >>>   | public class Hey {
> >>>   |     public static String say() {
> >>>   |         return "hey";
> >>>   |     }
> >>>   | }
> >>>   `----
> >>>
> >>>   ,----
> >>>   | package org.orgmode;
> >>>   |
> >>>   | public class Main {
> >>>   |     public static void main(String[] args) {
> >>>   |         System.out.print(Hey.say());
> >>>   |     }
> >>>   | }
> >>>   `----
> >>>
> >>>   Instead of C-c C-c, we could have added tangle headers and written
> the
> >>>   source files out by tangling.
> >>>
> >>>
> >>> 2.5 Example 5
> >>> ~~~~~~~~~~~~~
> >>>
> >>>   This prints the variable from the header
> >>>
> >>>   ,----
> >>>   | System.out.print(msg);
> >>>   `----
> >>>
> >>>
> >>> 2.6 Example 6
> >>> ~~~~~~~~~~~~~
> >>>
> >>>   This prints "hello, org-mode." The table is provided to the method as
> >>>   a list of lists.
> >>>
> >>>    message  hello, org-mode
> >>>
> >>>   ,----
> >>>   | System.out.print(tbl.get(0).get(1));
> >>>   `----
> >>>
> >>>
> >>> 2.7 Example 7
> >>> ~~~~~~~~~~~~~
> >>>
> >>>   This example returns a list.
> >>>
> >>>   Note that you're allowed to specify imports without defining the
> class
> >>>   or main methods.
> >>>
> >>>   ,----
> >>>   | import java.util.Arrays;
> >>>   |
> >>>   | return Arrays.asList("message", "hello, org-mode");
> >>>   `----
> >>>
> >>>    message  hello, org-mode
> >>>
> >>
>

[-- Attachment #2: Type: text/html, Size: 12060 bytes --]

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] ob-java
  2020-10-21  2:37       ` ian martins
@ 2020-10-21  5:59         ` John Herrlin
  2020-10-21 12:47           ` ian martins
  0 siblings, 1 reply; 31+ messages in thread
From: John Herrlin @ 2020-10-21  5:59 UTC (permalink / raw)
  To: ian martins; +Cc: Org-Mode mailing list


I did and it looks really good. The difference in this example:

    #+BEGIN_SRC java
      import rx.Observable;

      Observable.range(5, 3)
          .subscribe((Integer i) ->   { System.out.println("Got: " + i); },
                     (Throwable t) -> { t.printStackTrace();},
                     () ->            { System.out.println("Ending stream"); });
    #+END_SRC

from the ones I posted yesterday is tremendous!

I am not very experienced with Emacs lisp but I think it's pretty easy
to understand how things works and follow the code. The comments are
also of good help. I really appreciate the work you have done!


What do you think about having a configurable list where the user can
add =org-babel-java--import-maybe=? In my current use case I could then
add RxJava imports to that list and the imports could be removed from
the source code block.


NIT

Some spacing when writing =public static...=

   #+BEGIN_SRC diff
     diff --git a/lisp/ob-java.el b/lisp/ob-java.el
     index 94c3f69cf..4f3904871 100644
     --- a/lisp/ob-java.el
     +++ b/lisp/ob-java.el
     @@ -220,7 +220,7 @@ RESULT-FILE is the temp file to write the result."
            (org-babel-java--move-past org-babel-java--class-re)
            (insert "\n    public static void main(String[] args) {
              System.out.print(\"success\");
     -}\n\n"))
     +    }\n\n"))

          ;; special handling to return value
          (when (eq result-type 'value)
   #+END_SRC



ian martins <ianxm@jhu.edu> writes:

> Thanks for testing, and thanks for pointing that out. I will fix it so that
> `public` is optional.
>
> btw, in your example you didn't have to specify `:classname` since you
> defined the class name in the source block.
>
> btw2, did you notice that you can C-c C-c on source blocks that don't have
> main methods and it'll compile without error?
>
> On Tue, Oct 20, 2020 at 3:17 PM John Herrlin <jherrlin@gmail.com> wrote:
>
>>
>> Hey,
>>
>> Did some debugging and found out that my class didn't contained =public=
>> and the patch requires it to be.
>>
>> This works fine:
>>
>>    #+HEADER: :classname Main
>>    #+HEADER: :dir src
>>    #+HEADER: :cmdline -classpath ./rxjava-1.3.8.jar:.
>>    #+HEADER: :cmpflag -classpath ./rxjava-1.3.8.jar
>>    #+BEGIN_SRC java :results output code
>>      import rx.Observable;
>>      public class Main {
>>          public static void main(String[] args) {
>>              Observable.range(5, 5)
>>                  .subscribe(System.out::println);
>>          }
>>      }
>>    #+END_SRC
>>
>>
>>
>>
>> ian martins <ianxm@jhu.edu> writes:
>>
>> > I noticed that the tests didn't run with "make test." This updates the
>> > patch so that they can. I didn't add java to the list of default
>> languages
>> > because the java tests are slow.
>> >
>> > On Mon, Oct 5, 2020 at 9:23 AM ian martins <ianxm@jhu.edu> wrote:
>> >
>> >> I wrote those examples in an org file so I could test as I wrote them,
>> and
>> >> then exported it to make it more readable, but the export resulted in
>> >> source block headers being lost.  Here is the same without export:
>> >> ----
>> >> * Changes
>> >>
>> >> - support for functional mode (~:results value~)
>> >> - accept variables
>> >> - don't require package, class, and main definitions
>> >> - write source and result tempfiles to ~org-babel-temporary-directory~,
>> >> but respects the ~:dir~ header
>> >> - work with tramp
>> >>
>> >> * Examples
>> >> ** Example 1
>> >> This outputs "hello."  If class and main definitions aren't given the
>> >> code block will be wrapped in generic ones.
>> >>
>> >> #+begin_src java :results output silent
>> >>   System.out.print("hello");
>> >> #+end_src
>> >>
>> >> This is exactly equivalent:
>> >>
>> >> #+begin_src java :results output silent
>> >>   public class Main {
>> >>       public static void main(String[] args) {
>> >>           System.out.print("hello");
>> >>       }
>> >>   }
>> >> #+end_src
>> >>
>> >> ** Example 2
>> >> This also outputs "hello."
>> >>
>> >> #+begin_src java :results value silent
>> >>   return "hello";
>> >> #+end_src
>> >>
>> >> ** Example 3
>> >> This generates the class "Example" in the package "org.orgmode" in the
>> >> current directory.
>> >>
>> >> #+begin_src java :results output silent :classname org.orgmode.Example
>> >> :dir .
>> >>   System.out.print("hello, org-mode");
>> >> #+end_src
>> >>
>> >> ** Example 4
>> >> The "Hey" class defines a static method but no main. C-c C-c on the
>> >> "Hey" source block will write "./org/orgmode/Hey.java" and compile it.
>> >>
>> >> The "Main" class calls the "Hey" class. C-c C-c on the "Main" source
>> >> block will write "./org/orgmode/Main.java" and compile and run it.
>> >>
>> >> #+begin_src java :results output silent :dir .
>> >>   package org.orgmode;
>> >>
>> >>   public class Hey {
>> >>       public static String say() {
>> >>           return "hey";
>> >>       }
>> >>   }
>> >> #+end_src
>> >>
>> >> #+begin_src java :results output silent :dir .
>> >>   package org.orgmode;
>> >>
>> >>   public class Main {
>> >>       public static void main(String[] args) {
>> >>           System.out.print(Hey.say());
>> >>       }
>> >>   }
>> >> #+end_src
>> >>
>> >> Instead of C-c C-c, we could have added tangle headers and written the
>> >> source files out by tangling.
>> >>
>> >> ** Example 5
>> >> This prints the variable from the header
>> >>
>> >> #+begin_src java :var msg="hello, org-mode" :results output silent
>> >>   System.out.print(msg);
>> >> #+end_src
>> >>
>> >> ** Example 6
>> >> This prints "hello, org-mode." The table is provided to the method as a
>> >> list of lists.
>> >>
>> >> #+name: table
>> >> | message | hello, org-mode  |
>> >>
>> >> #+begin_src java :var tbl=table :results output silent
>> >>   System.out.print(tbl.get(0).get(1));
>> >> #+end_src
>> >>
>> >> ** Example 7
>> >> This example returns a list.
>> >>
>> >> Note that you're allowed to specify imports without defining the class
>> >> or main methods.
>> >>
>> >> #+begin_src java :results value :exports both
>> >>   import java.util.Arrays;
>> >>
>> >>   return Arrays.asList("message", "hello, org-mode");
>> >> #+end_src
>> >>
>> >> #+RESULTS:
>> >> | message | hello, org-mode |
>> >>
>> >> On Mon, Oct 5, 2020 at 8:35 AM ian martins <ianxm@jhu.edu> wrote:
>> >>
>> >>> 1 Changes
>> >>> =========
>> >>>
>> >>>   - support for functional mode (`:results value')
>> >>>   - accept variables
>> >>>   - don't require package, class, and main definitions
>> >>>   - write source and result tempfiles to
>> >>>     `org-babel-temporary-directory', but respects the `:dir' header
>> >>>   - work with tramp
>> >>>
>> >>>
>> >>> 2 Examples
>> >>> ==========
>> >>> Some examples follow.  See the tests for more examples.  I'll write
>> >>> proper docs after review.
>> >>>
>> >>> 2.1 Example 1
>> >>> ~~~~~~~~~~~~~
>> >>>
>> >>>   This outputs "hello."  If class and main definitions aren't given the
>> >>>   code block will be wrapped in generic ones.
>> >>>
>> >>>   ,----
>> >>>   | System.out.print("hello");
>> >>>   `----
>> >>>
>> >>>   This is exactly equivalent:
>> >>>
>> >>>   ,----
>> >>>   | public class Main {
>> >>>   |     public static void main(String[] args) {
>> >>>   |         System.out.print("hello");
>> >>>   |     }
>> >>>   | }
>> >>>   `----
>> >>>
>> >>>
>> >>> 2.2 Example 2
>> >>> ~~~~~~~~~~~~~
>> >>>
>> >>>   This also outputs "hello."
>> >>>
>> >>>   ,----
>> >>>   | return "hello";
>> >>>   `----
>> >>>
>> >>>
>> >>> 2.3 Example 3
>> >>> ~~~~~~~~~~~~~
>> >>>
>> >>>   This generates the class "Example" in the package "org.orgmode" in
>> the
>> >>>   current directory.
>> >>>
>> >>>   ,----
>> >>>   | System.out.print("hello, org-mode");
>> >>>   `----
>> >>>
>> >>>
>> >>> 2.4 Example 4
>> >>> ~~~~~~~~~~~~~
>> >>>
>> >>>   The "Hey" class defines a static method but no main. C-c C-c on the
>> >>>   "Hey" source block will write "./org/orgmode/Hey.java" and compile
>> it.
>> >>>
>> >>>   The "Main" class calls the "Hey" class. C-c C-c on the "Main" source
>> >>>   block will write "./org/orgmode/Main.java" and compile and run it.
>> >>>
>> >>>   ,----
>> >>>   | package org.orgmode;
>> >>>   |
>> >>>   | public class Hey {
>> >>>   |     public static String say() {
>> >>>   |         return "hey";
>> >>>   |     }
>> >>>   | }
>> >>>   `----
>> >>>
>> >>>   ,----
>> >>>   | package org.orgmode;
>> >>>   |
>> >>>   | public class Main {
>> >>>   |     public static void main(String[] args) {
>> >>>   |         System.out.print(Hey.say());
>> >>>   |     }
>> >>>   | }
>> >>>   `----
>> >>>
>> >>>   Instead of C-c C-c, we could have added tangle headers and written
>> the
>> >>>   source files out by tangling.
>> >>>
>> >>>
>> >>> 2.5 Example 5
>> >>> ~~~~~~~~~~~~~
>> >>>
>> >>>   This prints the variable from the header
>> >>>
>> >>>   ,----
>> >>>   | System.out.print(msg);
>> >>>   `----
>> >>>
>> >>>
>> >>> 2.6 Example 6
>> >>> ~~~~~~~~~~~~~
>> >>>
>> >>>   This prints "hello, org-mode." The table is provided to the method as
>> >>>   a list of lists.
>> >>>
>> >>>    message  hello, org-mode
>> >>>
>> >>>   ,----
>> >>>   | System.out.print(tbl.get(0).get(1));
>> >>>   `----
>> >>>
>> >>>
>> >>> 2.7 Example 7
>> >>> ~~~~~~~~~~~~~
>> >>>
>> >>>   This example returns a list.
>> >>>
>> >>>   Note that you're allowed to specify imports without defining the
>> class
>> >>>   or main methods.
>> >>>
>> >>>   ,----
>> >>>   | import java.util.Arrays;
>> >>>   |
>> >>>   | return Arrays.asList("message", "hello, org-mode");
>> >>>   `----
>> >>>
>> >>>    message  hello, org-mode
>> >>>
>> >>
>>


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] ob-java
  2020-10-21  5:59         ` John Herrlin
@ 2020-10-21 12:47           ` ian martins
  2020-10-21 13:54             ` John Herrlin
  0 siblings, 1 reply; 31+ messages in thread
From: ian martins @ 2020-10-21 12:47 UTC (permalink / raw)
  To: John Herrlin; +Cc: Org-Mode mailing list

[-- Attachment #1: Type: text/plain, Size: 11367 bytes --]

>
> What do you think about having a configurable list where the user can
> add =org-babel-java--import-maybe=? In my current use case I could then
> add RxJava imports to that list and the imports could be removed from
> the source code block.


I think this can already be done. imports can be added to the headers, and
babel allows file-wide headers, so you could add a =#+HEADER: :import
rx.Observable= line to the file and all source blocks would get it.  it's
slightly different in that =org-babel-java--import-maybe= skips imports
that it thinks aren't needed. also if there are any non-java source blocks
in the same file, these imports could be added to them which would be bad,
so when mixing multiple languages in the same file this wouldn't be an
option.

NIT
> Some spacing when writing =public static...=
>

Thanks for fixing the spacing. I don't think I can give you credit for the
patch, though, without leaving it out until ob-java is accepted.

On Wed, Oct 21, 2020 at 1:59 AM John Herrlin <jherrlin@gmail.com> wrote:

>
> I did and it looks really good. The difference in this example:
>
>     #+BEGIN_SRC java
>       import rx.Observable;
>
>       Observable.range(5, 3)
>           .subscribe((Integer i) ->   { System.out.println("Got: " + i); },
>                      (Throwable t) -> { t.printStackTrace();},
>                      () ->            { System.out.println("Ending
> stream"); });
>     #+END_SRC
>
> from the ones I posted yesterday is tremendous!
>
> I am not very experienced with Emacs lisp but I think it's pretty easy
> to understand how things works and follow the code. The comments are
> also of good help. I really appreciate the work you have done!
>
>
> What do you think about having a configurable list where the user can
> add =org-babel-java--import-maybe=? In my current use case I could then
> add RxJava imports to that list and the imports could be removed from
> the source code block.
>
>
> NIT
>
> Some spacing when writing =public static...=
>
>    #+BEGIN_SRC diff
>      diff --git a/lisp/ob-java.el b/lisp/ob-java.el
>      index 94c3f69cf..4f3904871 100644
>      --- a/lisp/ob-java.el
>      +++ b/lisp/ob-java.el
>      @@ -220,7 +220,7 @@ RESULT-FILE is the temp file to write the result."
>             (org-babel-java--move-past org-babel-java--class-re)
>             (insert "\n    public static void main(String[] args) {
>               System.out.print(\"success\");
>      -}\n\n"))
>      +    }\n\n"))
>
>           ;; special handling to return value
>           (when (eq result-type 'value)
>    #+END_SRC
>
>
>
> ian martins <ianxm@jhu.edu> writes:
>
> > Thanks for testing, and thanks for pointing that out. I will fix it so
> that
> > `public` is optional.
> >
> > btw, in your example you didn't have to specify `:classname` since you
> > defined the class name in the source block.
> >
> > btw2, did you notice that you can C-c C-c on source blocks that don't
> have
> > main methods and it'll compile without error?
> >
> > On Tue, Oct 20, 2020 at 3:17 PM John Herrlin <jherrlin@gmail.com> wrote:
> >
> >>
> >> Hey,
> >>
> >> Did some debugging and found out that my class didn't contained =public=
> >> and the patch requires it to be.
> >>
> >> This works fine:
> >>
> >>    #+HEADER: :classname Main
> >>    #+HEADER: :dir src
> >>    #+HEADER: :cmdline -classpath ./rxjava-1.3.8.jar:.
> >>    #+HEADER: :cmpflag -classpath ./rxjava-1.3.8.jar
> >>    #+BEGIN_SRC java :results output code
> >>      import rx.Observable;
> >>      public class Main {
> >>          public static void main(String[] args) {
> >>              Observable.range(5, 5)
> >>                  .subscribe(System.out::println);
> >>          }
> >>      }
> >>    #+END_SRC
> >>
> >>
> >>
> >>
> >> ian martins <ianxm@jhu.edu> writes:
> >>
> >> > I noticed that the tests didn't run with "make test." This updates the
> >> > patch so that they can. I didn't add java to the list of default
> >> languages
> >> > because the java tests are slow.
> >> >
> >> > On Mon, Oct 5, 2020 at 9:23 AM ian martins <ianxm@jhu.edu> wrote:
> >> >
> >> >> I wrote those examples in an org file so I could test as I wrote
> them,
> >> and
> >> >> then exported it to make it more readable, but the export resulted in
> >> >> source block headers being lost.  Here is the same without export:
> >> >> ----
> >> >> * Changes
> >> >>
> >> >> - support for functional mode (~:results value~)
> >> >> - accept variables
> >> >> - don't require package, class, and main definitions
> >> >> - write source and result tempfiles to
> ~org-babel-temporary-directory~,
> >> >> but respects the ~:dir~ header
> >> >> - work with tramp
> >> >>
> >> >> * Examples
> >> >> ** Example 1
> >> >> This outputs "hello."  If class and main definitions aren't given the
> >> >> code block will be wrapped in generic ones.
> >> >>
> >> >> #+begin_src java :results output silent
> >> >>   System.out.print("hello");
> >> >> #+end_src
> >> >>
> >> >> This is exactly equivalent:
> >> >>
> >> >> #+begin_src java :results output silent
> >> >>   public class Main {
> >> >>       public static void main(String[] args) {
> >> >>           System.out.print("hello");
> >> >>       }
> >> >>   }
> >> >> #+end_src
> >> >>
> >> >> ** Example 2
> >> >> This also outputs "hello."
> >> >>
> >> >> #+begin_src java :results value silent
> >> >>   return "hello";
> >> >> #+end_src
> >> >>
> >> >> ** Example 3
> >> >> This generates the class "Example" in the package "org.orgmode" in
> the
> >> >> current directory.
> >> >>
> >> >> #+begin_src java :results output silent :classname
> org.orgmode.Example
> >> >> :dir .
> >> >>   System.out.print("hello, org-mode");
> >> >> #+end_src
> >> >>
> >> >> ** Example 4
> >> >> The "Hey" class defines a static method but no main. C-c C-c on the
> >> >> "Hey" source block will write "./org/orgmode/Hey.java" and compile
> it.
> >> >>
> >> >> The "Main" class calls the "Hey" class. C-c C-c on the "Main" source
> >> >> block will write "./org/orgmode/Main.java" and compile and run it.
> >> >>
> >> >> #+begin_src java :results output silent :dir .
> >> >>   package org.orgmode;
> >> >>
> >> >>   public class Hey {
> >> >>       public static String say() {
> >> >>           return "hey";
> >> >>       }
> >> >>   }
> >> >> #+end_src
> >> >>
> >> >> #+begin_src java :results output silent :dir .
> >> >>   package org.orgmode;
> >> >>
> >> >>   public class Main {
> >> >>       public static void main(String[] args) {
> >> >>           System.out.print(Hey.say());
> >> >>       }
> >> >>   }
> >> >> #+end_src
> >> >>
> >> >> Instead of C-c C-c, we could have added tangle headers and written
> the
> >> >> source files out by tangling.
> >> >>
> >> >> ** Example 5
> >> >> This prints the variable from the header
> >> >>
> >> >> #+begin_src java :var msg="hello, org-mode" :results output silent
> >> >>   System.out.print(msg);
> >> >> #+end_src
> >> >>
> >> >> ** Example 6
> >> >> This prints "hello, org-mode." The table is provided to the method
> as a
> >> >> list of lists.
> >> >>
> >> >> #+name: table
> >> >> | message | hello, org-mode  |
> >> >>
> >> >> #+begin_src java :var tbl=table :results output silent
> >> >>   System.out.print(tbl.get(0).get(1));
> >> >> #+end_src
> >> >>
> >> >> ** Example 7
> >> >> This example returns a list.
> >> >>
> >> >> Note that you're allowed to specify imports without defining the
> class
> >> >> or main methods.
> >> >>
> >> >> #+begin_src java :results value :exports both
> >> >>   import java.util.Arrays;
> >> >>
> >> >>   return Arrays.asList("message", "hello, org-mode");
> >> >> #+end_src
> >> >>
> >> >> #+RESULTS:
> >> >> | message | hello, org-mode |
> >> >>
> >> >> On Mon, Oct 5, 2020 at 8:35 AM ian martins <ianxm@jhu.edu> wrote:
> >> >>
> >> >>> 1 Changes
> >> >>> =========
> >> >>>
> >> >>>   - support for functional mode (`:results value')
> >> >>>   - accept variables
> >> >>>   - don't require package, class, and main definitions
> >> >>>   - write source and result tempfiles to
> >> >>>     `org-babel-temporary-directory', but respects the `:dir' header
> >> >>>   - work with tramp
> >> >>>
> >> >>>
> >> >>> 2 Examples
> >> >>> ==========
> >> >>> Some examples follow.  See the tests for more examples.  I'll write
> >> >>> proper docs after review.
> >> >>>
> >> >>> 2.1 Example 1
> >> >>> ~~~~~~~~~~~~~
> >> >>>
> >> >>>   This outputs "hello."  If class and main definitions aren't given
> the
> >> >>>   code block will be wrapped in generic ones.
> >> >>>
> >> >>>   ,----
> >> >>>   | System.out.print("hello");
> >> >>>   `----
> >> >>>
> >> >>>   This is exactly equivalent:
> >> >>>
> >> >>>   ,----
> >> >>>   | public class Main {
> >> >>>   |     public static void main(String[] args) {
> >> >>>   |         System.out.print("hello");
> >> >>>   |     }
> >> >>>   | }
> >> >>>   `----
> >> >>>
> >> >>>
> >> >>> 2.2 Example 2
> >> >>> ~~~~~~~~~~~~~
> >> >>>
> >> >>>   This also outputs "hello."
> >> >>>
> >> >>>   ,----
> >> >>>   | return "hello";
> >> >>>   `----
> >> >>>
> >> >>>
> >> >>> 2.3 Example 3
> >> >>> ~~~~~~~~~~~~~
> >> >>>
> >> >>>   This generates the class "Example" in the package "org.orgmode" in
> >> the
> >> >>>   current directory.
> >> >>>
> >> >>>   ,----
> >> >>>   | System.out.print("hello, org-mode");
> >> >>>   `----
> >> >>>
> >> >>>
> >> >>> 2.4 Example 4
> >> >>> ~~~~~~~~~~~~~
> >> >>>
> >> >>>   The "Hey" class defines a static method but no main. C-c C-c on
> the
> >> >>>   "Hey" source block will write "./org/orgmode/Hey.java" and compile
> >> it.
> >> >>>
> >> >>>   The "Main" class calls the "Hey" class. C-c C-c on the "Main"
> source
> >> >>>   block will write "./org/orgmode/Main.java" and compile and run it.
> >> >>>
> >> >>>   ,----
> >> >>>   | package org.orgmode;
> >> >>>   |
> >> >>>   | public class Hey {
> >> >>>   |     public static String say() {
> >> >>>   |         return "hey";
> >> >>>   |     }
> >> >>>   | }
> >> >>>   `----
> >> >>>
> >> >>>   ,----
> >> >>>   | package org.orgmode;
> >> >>>   |
> >> >>>   | public class Main {
> >> >>>   |     public static void main(String[] args) {
> >> >>>   |         System.out.print(Hey.say());
> >> >>>   |     }
> >> >>>   | }
> >> >>>   `----
> >> >>>
> >> >>>   Instead of C-c C-c, we could have added tangle headers and written
> >> the
> >> >>>   source files out by tangling.
> >> >>>
> >> >>>
> >> >>> 2.5 Example 5
> >> >>> ~~~~~~~~~~~~~
> >> >>>
> >> >>>   This prints the variable from the header
> >> >>>
> >> >>>   ,----
> >> >>>   | System.out.print(msg);
> >> >>>   `----
> >> >>>
> >> >>>
> >> >>> 2.6 Example 6
> >> >>> ~~~~~~~~~~~~~
> >> >>>
> >> >>>   This prints "hello, org-mode." The table is provided to the
> method as
> >> >>>   a list of lists.
> >> >>>
> >> >>>    message  hello, org-mode
> >> >>>
> >> >>>   ,----
> >> >>>   | System.out.print(tbl.get(0).get(1));
> >> >>>   `----
> >> >>>
> >> >>>
> >> >>> 2.7 Example 7
> >> >>> ~~~~~~~~~~~~~
> >> >>>
> >> >>>   This example returns a list.
> >> >>>
> >> >>>   Note that you're allowed to specify imports without defining the
> >> class
> >> >>>   or main methods.
> >> >>>
> >> >>>   ,----
> >> >>>   | import java.util.Arrays;
> >> >>>   |
> >> >>>   | return Arrays.asList("message", "hello, org-mode");
> >> >>>   `----
> >> >>>
> >> >>>    message  hello, org-mode
> >> >>>
> >> >>
> >>
>

[-- Attachment #2: Type: text/html, Size: 17865 bytes --]

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] ob-java
  2020-10-21 12:47           ` ian martins
@ 2020-10-21 13:54             ` John Herrlin
  2020-10-22 12:23               ` ian martins
  0 siblings, 1 reply; 31+ messages in thread
From: John Herrlin @ 2020-10-21 13:54 UTC (permalink / raw)
  To: ian martins; +Cc: Org-Mode mailing list


ian martins <ianxm@jhu.edu> writes:

>>
>> What do you think about having a configurable list where the user can
>> add =org-babel-java--import-maybe=? In my current use case I could then
>> add RxJava imports to that list and the imports could be removed from
>> the source code block.
>
>
> I think this can already be done. imports can be added to the headers, and
> babel allows file-wide headers, so you could add a =#+HEADER: :import
> rx.Observable= line to the file and all source blocks would get it.  it's
> slightly different in that =org-babel-java--import-maybe= skips imports
> that it thinks aren't needed. also if there are any non-java source blocks
> in the same file, these imports could be added to them which would be bad,
> so when mixing multiple languages in the same file this wouldn't be an
> option.

Thanks for pointing that out! It work just fine!

>
> NIT
>> Some spacing when writing =public static...=
>>
>
> Thanks for fixing the spacing. I don't think I can give you credit for the
> patch, though, without leaving it out until ob-java is accepted.

I dont need any credits, the important part is the result!

I have made a couple of more runs and I cant find anything that doesnt
work!

>
> On Wed, Oct 21, 2020 at 1:59 AM John Herrlin <jherrlin@gmail.com> wrote:
>
>>
>> I did and it looks really good. The difference in this example:
>>
>>     #+BEGIN_SRC java
>>       import rx.Observable;
>>
>>       Observable.range(5, 3)
>>           .subscribe((Integer i) ->   { System.out.println("Got: " + i); },
>>                      (Throwable t) -> { t.printStackTrace();},
>>                      () ->            { System.out.println("Ending
>> stream"); });
>>     #+END_SRC
>>
>> from the ones I posted yesterday is tremendous!
>>
>> I am not very experienced with Emacs lisp but I think it's pretty easy
>> to understand how things works and follow the code. The comments are
>> also of good help. I really appreciate the work you have done!
>>
>>
>> What do you think about having a configurable list where the user can
>> add =org-babel-java--import-maybe=? In my current use case I could then
>> add RxJava imports to that list and the imports could be removed from
>> the source code block.
>>
>>
>> NIT
>>
>> Some spacing when writing =public static...=
>>
>>    #+BEGIN_SRC diff
>>      diff --git a/lisp/ob-java.el b/lisp/ob-java.el
>>      index 94c3f69cf..4f3904871 100644
>>      --- a/lisp/ob-java.el
>>      +++ b/lisp/ob-java.el
>>      @@ -220,7 +220,7 @@ RESULT-FILE is the temp file to write the result."
>>             (org-babel-java--move-past org-babel-java--class-re)
>>             (insert "\n    public static void main(String[] args) {
>>               System.out.print(\"success\");
>>      -}\n\n"))
>>      +    }\n\n"))
>>
>>           ;; special handling to return value
>>           (when (eq result-type 'value)
>>    #+END_SRC
>>
>>
>>
>> ian martins <ianxm@jhu.edu> writes:
>>
>> > Thanks for testing, and thanks for pointing that out. I will fix it so
>> that
>> > `public` is optional.
>> >
>> > btw, in your example you didn't have to specify `:classname` since you
>> > defined the class name in the source block.
>> >
>> > btw2, did you notice that you can C-c C-c on source blocks that don't
>> have
>> > main methods and it'll compile without error?
>> >
>> > On Tue, Oct 20, 2020 at 3:17 PM John Herrlin <jherrlin@gmail.com> wrote:
>> >
>> >>
>> >> Hey,
>> >>
>> >> Did some debugging and found out that my class didn't contained =public=
>> >> and the patch requires it to be.
>> >>
>> >> This works fine:
>> >>
>> >>    #+HEADER: :classname Main
>> >>    #+HEADER: :dir src
>> >>    #+HEADER: :cmdline -classpath ./rxjava-1.3.8.jar:.
>> >>    #+HEADER: :cmpflag -classpath ./rxjava-1.3.8.jar
>> >>    #+BEGIN_SRC java :results output code
>> >>      import rx.Observable;
>> >>      public class Main {
>> >>          public static void main(String[] args) {
>> >>              Observable.range(5, 5)
>> >>                  .subscribe(System.out::println);
>> >>          }
>> >>      }
>> >>    #+END_SRC
>> >>
>> >>
>> >>
>> >>
>> >> ian martins <ianxm@jhu.edu> writes:
>> >>
>> >> > I noticed that the tests didn't run with "make test." This updates the
>> >> > patch so that they can. I didn't add java to the list of default
>> >> languages
>> >> > because the java tests are slow.
>> >> >
>> >> > On Mon, Oct 5, 2020 at 9:23 AM ian martins <ianxm@jhu.edu> wrote:
>> >> >
>> >> >> I wrote those examples in an org file so I could test as I wrote
>> them,
>> >> and
>> >> >> then exported it to make it more readable, but the export resulted in
>> >> >> source block headers being lost.  Here is the same without export:
>> >> >> ----
>> >> >> * Changes
>> >> >>
>> >> >> - support for functional mode (~:results value~)
>> >> >> - accept variables
>> >> >> - don't require package, class, and main definitions
>> >> >> - write source and result tempfiles to
>> ~org-babel-temporary-directory~,
>> >> >> but respects the ~:dir~ header
>> >> >> - work with tramp
>> >> >>
>> >> >> * Examples
>> >> >> ** Example 1
>> >> >> This outputs "hello."  If class and main definitions aren't given the
>> >> >> code block will be wrapped in generic ones.
>> >> >>
>> >> >> #+begin_src java :results output silent
>> >> >>   System.out.print("hello");
>> >> >> #+end_src
>> >> >>
>> >> >> This is exactly equivalent:
>> >> >>
>> >> >> #+begin_src java :results output silent
>> >> >>   public class Main {
>> >> >>       public static void main(String[] args) {
>> >> >>           System.out.print("hello");
>> >> >>       }
>> >> >>   }
>> >> >> #+end_src
>> >> >>
>> >> >> ** Example 2
>> >> >> This also outputs "hello."
>> >> >>
>> >> >> #+begin_src java :results value silent
>> >> >>   return "hello";
>> >> >> #+end_src
>> >> >>
>> >> >> ** Example 3
>> >> >> This generates the class "Example" in the package "org.orgmode" in
>> the
>> >> >> current directory.
>> >> >>
>> >> >> #+begin_src java :results output silent :classname
>> org.orgmode.Example
>> >> >> :dir .
>> >> >>   System.out.print("hello, org-mode");
>> >> >> #+end_src
>> >> >>
>> >> >> ** Example 4
>> >> >> The "Hey" class defines a static method but no main. C-c C-c on the
>> >> >> "Hey" source block will write "./org/orgmode/Hey.java" and compile
>> it.
>> >> >>
>> >> >> The "Main" class calls the "Hey" class. C-c C-c on the "Main" source
>> >> >> block will write "./org/orgmode/Main.java" and compile and run it.
>> >> >>
>> >> >> #+begin_src java :results output silent :dir .
>> >> >>   package org.orgmode;
>> >> >>
>> >> >>   public class Hey {
>> >> >>       public static String say() {
>> >> >>           return "hey";
>> >> >>       }
>> >> >>   }
>> >> >> #+end_src
>> >> >>
>> >> >> #+begin_src java :results output silent :dir .
>> >> >>   package org.orgmode;
>> >> >>
>> >> >>   public class Main {
>> >> >>       public static void main(String[] args) {
>> >> >>           System.out.print(Hey.say());
>> >> >>       }
>> >> >>   }
>> >> >> #+end_src
>> >> >>
>> >> >> Instead of C-c C-c, we could have added tangle headers and written
>> the
>> >> >> source files out by tangling.
>> >> >>
>> >> >> ** Example 5
>> >> >> This prints the variable from the header
>> >> >>
>> >> >> #+begin_src java :var msg="hello, org-mode" :results output silent
>> >> >>   System.out.print(msg);
>> >> >> #+end_src
>> >> >>
>> >> >> ** Example 6
>> >> >> This prints "hello, org-mode." The table is provided to the method
>> as a
>> >> >> list of lists.
>> >> >>
>> >> >> #+name: table
>> >> >> | message | hello, org-mode  |
>> >> >>
>> >> >> #+begin_src java :var tbl=table :results output silent
>> >> >>   System.out.print(tbl.get(0).get(1));
>> >> >> #+end_src
>> >> >>
>> >> >> ** Example 7
>> >> >> This example returns a list.
>> >> >>
>> >> >> Note that you're allowed to specify imports without defining the
>> class
>> >> >> or main methods.
>> >> >>
>> >> >> #+begin_src java :results value :exports both
>> >> >>   import java.util.Arrays;
>> >> >>
>> >> >>   return Arrays.asList("message", "hello, org-mode");
>> >> >> #+end_src
>> >> >>
>> >> >> #+RESULTS:
>> >> >> | message | hello, org-mode |
>> >> >>
>> >> >> On Mon, Oct 5, 2020 at 8:35 AM ian martins <ianxm@jhu.edu> wrote:
>> >> >>
>> >> >>> 1 Changes
>> >> >>> =========
>> >> >>>
>> >> >>>   - support for functional mode (`:results value')
>> >> >>>   - accept variables
>> >> >>>   - don't require package, class, and main definitions
>> >> >>>   - write source and result tempfiles to
>> >> >>>     `org-babel-temporary-directory', but respects the `:dir' header
>> >> >>>   - work with tramp
>> >> >>>
>> >> >>>
>> >> >>> 2 Examples
>> >> >>> ==========
>> >> >>> Some examples follow.  See the tests for more examples.  I'll write
>> >> >>> proper docs after review.
>> >> >>>
>> >> >>> 2.1 Example 1
>> >> >>> ~~~~~~~~~~~~~
>> >> >>>
>> >> >>>   This outputs "hello."  If class and main definitions aren't given
>> the
>> >> >>>   code block will be wrapped in generic ones.
>> >> >>>
>> >> >>>   ,----
>> >> >>>   | System.out.print("hello");
>> >> >>>   `----
>> >> >>>
>> >> >>>   This is exactly equivalent:
>> >> >>>
>> >> >>>   ,----
>> >> >>>   | public class Main {
>> >> >>>   |     public static void main(String[] args) {
>> >> >>>   |         System.out.print("hello");
>> >> >>>   |     }
>> >> >>>   | }
>> >> >>>   `----
>> >> >>>
>> >> >>>
>> >> >>> 2.2 Example 2
>> >> >>> ~~~~~~~~~~~~~
>> >> >>>
>> >> >>>   This also outputs "hello."
>> >> >>>
>> >> >>>   ,----
>> >> >>>   | return "hello";
>> >> >>>   `----
>> >> >>>
>> >> >>>
>> >> >>> 2.3 Example 3
>> >> >>> ~~~~~~~~~~~~~
>> >> >>>
>> >> >>>   This generates the class "Example" in the package "org.orgmode" in
>> >> the
>> >> >>>   current directory.
>> >> >>>
>> >> >>>   ,----
>> >> >>>   | System.out.print("hello, org-mode");
>> >> >>>   `----
>> >> >>>
>> >> >>>
>> >> >>> 2.4 Example 4
>> >> >>> ~~~~~~~~~~~~~
>> >> >>>
>> >> >>>   The "Hey" class defines a static method but no main. C-c C-c on
>> the
>> >> >>>   "Hey" source block will write "./org/orgmode/Hey.java" and compile
>> >> it.
>> >> >>>
>> >> >>>   The "Main" class calls the "Hey" class. C-c C-c on the "Main"
>> source
>> >> >>>   block will write "./org/orgmode/Main.java" and compile and run it.
>> >> >>>
>> >> >>>   ,----
>> >> >>>   | package org.orgmode;
>> >> >>>   |
>> >> >>>   | public class Hey {
>> >> >>>   |     public static String say() {
>> >> >>>   |         return "hey";
>> >> >>>   |     }
>> >> >>>   | }
>> >> >>>   `----
>> >> >>>
>> >> >>>   ,----
>> >> >>>   | package org.orgmode;
>> >> >>>   |
>> >> >>>   | public class Main {
>> >> >>>   |     public static void main(String[] args) {
>> >> >>>   |         System.out.print(Hey.say());
>> >> >>>   |     }
>> >> >>>   | }
>> >> >>>   `----
>> >> >>>
>> >> >>>   Instead of C-c C-c, we could have added tangle headers and written
>> >> the
>> >> >>>   source files out by tangling.
>> >> >>>
>> >> >>>
>> >> >>> 2.5 Example 5
>> >> >>> ~~~~~~~~~~~~~
>> >> >>>
>> >> >>>   This prints the variable from the header
>> >> >>>
>> >> >>>   ,----
>> >> >>>   | System.out.print(msg);
>> >> >>>   `----
>> >> >>>
>> >> >>>
>> >> >>> 2.6 Example 6
>> >> >>> ~~~~~~~~~~~~~
>> >> >>>
>> >> >>>   This prints "hello, org-mode." The table is provided to the
>> method as
>> >> >>>   a list of lists.
>> >> >>>
>> >> >>>    message  hello, org-mode
>> >> >>>
>> >> >>>   ,----
>> >> >>>   | System.out.print(tbl.get(0).get(1));
>> >> >>>   `----
>> >> >>>
>> >> >>>
>> >> >>> 2.7 Example 7
>> >> >>> ~~~~~~~~~~~~~
>> >> >>>
>> >> >>>   This example returns a list.
>> >> >>>
>> >> >>>   Note that you're allowed to specify imports without defining the
>> >> class
>> >> >>>   or main methods.
>> >> >>>
>> >> >>>   ,----
>> >> >>>   | import java.util.Arrays;
>> >> >>>   |
>> >> >>>   | return Arrays.asList("message", "hello, org-mode");
>> >> >>>   `----
>> >> >>>
>> >> >>>    message  hello, org-mode
>> >> >>>
>> >> >>
>> >>
>>


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] ob-java
  2020-10-21 13:54             ` John Herrlin
@ 2020-10-22 12:23               ` ian martins
  2020-10-22 12:56                 ` John Herrlin
  0 siblings, 1 reply; 31+ messages in thread
From: ian martins @ 2020-10-22 12:23 UTC (permalink / raw)
  To: John Herrlin; +Cc: Org-Mode mailing list


[-- Attachment #1.1: Type: text/plain, Size: 13167 bytes --]

Actually I realized if I keep the commits separate and generate a patch set
instead of squashing then I can preserve authorship.

These patches, which follow patch 0001, fix the spacing and allow
non-public classes.

Thanks again for testing, debugging, and reporting.

On Wed, Oct 21, 2020 at 9:54 AM John Herrlin <jherrlin@gmail.com> wrote:

>
> ian martins <ianxm@jhu.edu> writes:
>
> >>
> >> What do you think about having a configurable list where the user can
> >> add =org-babel-java--import-maybe=? In my current use case I could then
> >> add RxJava imports to that list and the imports could be removed from
> >> the source code block.
> >
> >
> > I think this can already be done. imports can be added to the headers,
> and
> > babel allows file-wide headers, so you could add a =#+HEADER: :import
> > rx.Observable= line to the file and all source blocks would get it.  it's
> > slightly different in that =org-babel-java--import-maybe= skips imports
> > that it thinks aren't needed. also if there are any non-java source
> blocks
> > in the same file, these imports could be added to them which would be
> bad,
> > so when mixing multiple languages in the same file this wouldn't be an
> > option.
>
> Thanks for pointing that out! It work just fine!
>
> >
> > NIT
> >> Some spacing when writing =public static...=
> >>
> >
> > Thanks for fixing the spacing. I don't think I can give you credit for
> the
> > patch, though, without leaving it out until ob-java is accepted.
>
> I dont need any credits, the important part is the result!
>
> I have made a couple of more runs and I cant find anything that doesnt
> work!
>
> >
> > On Wed, Oct 21, 2020 at 1:59 AM John Herrlin <jherrlin@gmail.com> wrote:
> >
> >>
> >> I did and it looks really good. The difference in this example:
> >>
> >>     #+BEGIN_SRC java
> >>       import rx.Observable;
> >>
> >>       Observable.range(5, 3)
> >>           .subscribe((Integer i) ->   { System.out.println("Got: " +
> i); },
> >>                      (Throwable t) -> { t.printStackTrace();},
> >>                      () ->            { System.out.println("Ending
> >> stream"); });
> >>     #+END_SRC
> >>
> >> from the ones I posted yesterday is tremendous!
> >>
> >> I am not very experienced with Emacs lisp but I think it's pretty easy
> >> to understand how things works and follow the code. The comments are
> >> also of good help. I really appreciate the work you have done!
> >>
> >>
> >> What do you think about having a configurable list where the user can
> >> add =org-babel-java--import-maybe=? In my current use case I could then
> >> add RxJava imports to that list and the imports could be removed from
> >> the source code block.
> >>
> >>
> >> NIT
> >>
> >> Some spacing when writing =public static...=
> >>
> >>    #+BEGIN_SRC diff
> >>      diff --git a/lisp/ob-java.el b/lisp/ob-java.el
> >>      index 94c3f69cf..4f3904871 100644
> >>      --- a/lisp/ob-java.el
> >>      +++ b/lisp/ob-java.el
> >>      @@ -220,7 +220,7 @@ RESULT-FILE is the temp file to write the
> result."
> >>             (org-babel-java--move-past org-babel-java--class-re)
> >>             (insert "\n    public static void main(String[] args) {
> >>               System.out.print(\"success\");
> >>      -}\n\n"))
> >>      +    }\n\n"))
> >>
> >>           ;; special handling to return value
> >>           (when (eq result-type 'value)
> >>    #+END_SRC
> >>
> >>
> >>
> >> ian martins <ianxm@jhu.edu> writes:
> >>
> >> > Thanks for testing, and thanks for pointing that out. I will fix it so
> >> that
> >> > `public` is optional.
> >> >
> >> > btw, in your example you didn't have to specify `:classname` since you
> >> > defined the class name in the source block.
> >> >
> >> > btw2, did you notice that you can C-c C-c on source blocks that don't
> >> have
> >> > main methods and it'll compile without error?
> >> >
> >> > On Tue, Oct 20, 2020 at 3:17 PM John Herrlin <jherrlin@gmail.com>
> wrote:
> >> >
> >> >>
> >> >> Hey,
> >> >>
> >> >> Did some debugging and found out that my class didn't contained
> =public=
> >> >> and the patch requires it to be.
> >> >>
> >> >> This works fine:
> >> >>
> >> >>    #+HEADER: :classname Main
> >> >>    #+HEADER: :dir src
> >> >>    #+HEADER: :cmdline -classpath ./rxjava-1.3.8.jar:.
> >> >>    #+HEADER: :cmpflag -classpath ./rxjava-1.3.8.jar
> >> >>    #+BEGIN_SRC java :results output code
> >> >>      import rx.Observable;
> >> >>      public class Main {
> >> >>          public static void main(String[] args) {
> >> >>              Observable.range(5, 5)
> >> >>                  .subscribe(System.out::println);
> >> >>          }
> >> >>      }
> >> >>    #+END_SRC
> >> >>
> >> >>
> >> >>
> >> >>
> >> >> ian martins <ianxm@jhu.edu> writes:
> >> >>
> >> >> > I noticed that the tests didn't run with "make test." This updates
> the
> >> >> > patch so that they can. I didn't add java to the list of default
> >> >> languages
> >> >> > because the java tests are slow.
> >> >> >
> >> >> > On Mon, Oct 5, 2020 at 9:23 AM ian martins <ianxm@jhu.edu> wrote:
> >> >> >
> >> >> >> I wrote those examples in an org file so I could test as I wrote
> >> them,
> >> >> and
> >> >> >> then exported it to make it more readable, but the export
> resulted in
> >> >> >> source block headers being lost.  Here is the same without export:
> >> >> >> ----
> >> >> >> * Changes
> >> >> >>
> >> >> >> - support for functional mode (~:results value~)
> >> >> >> - accept variables
> >> >> >> - don't require package, class, and main definitions
> >> >> >> - write source and result tempfiles to
> >> ~org-babel-temporary-directory~,
> >> >> >> but respects the ~:dir~ header
> >> >> >> - work with tramp
> >> >> >>
> >> >> >> * Examples
> >> >> >> ** Example 1
> >> >> >> This outputs "hello."  If class and main definitions aren't given
> the
> >> >> >> code block will be wrapped in generic ones.
> >> >> >>
> >> >> >> #+begin_src java :results output silent
> >> >> >>   System.out.print("hello");
> >> >> >> #+end_src
> >> >> >>
> >> >> >> This is exactly equivalent:
> >> >> >>
> >> >> >> #+begin_src java :results output silent
> >> >> >>   public class Main {
> >> >> >>       public static void main(String[] args) {
> >> >> >>           System.out.print("hello");
> >> >> >>       }
> >> >> >>   }
> >> >> >> #+end_src
> >> >> >>
> >> >> >> ** Example 2
> >> >> >> This also outputs "hello."
> >> >> >>
> >> >> >> #+begin_src java :results value silent
> >> >> >>   return "hello";
> >> >> >> #+end_src
> >> >> >>
> >> >> >> ** Example 3
> >> >> >> This generates the class "Example" in the package "org.orgmode" in
> >> the
> >> >> >> current directory.
> >> >> >>
> >> >> >> #+begin_src java :results output silent :classname
> >> org.orgmode.Example
> >> >> >> :dir .
> >> >> >>   System.out.print("hello, org-mode");
> >> >> >> #+end_src
> >> >> >>
> >> >> >> ** Example 4
> >> >> >> The "Hey" class defines a static method but no main. C-c C-c on
> the
> >> >> >> "Hey" source block will write "./org/orgmode/Hey.java" and compile
> >> it.
> >> >> >>
> >> >> >> The "Main" class calls the "Hey" class. C-c C-c on the "Main"
> source
> >> >> >> block will write "./org/orgmode/Main.java" and compile and run it.
> >> >> >>
> >> >> >> #+begin_src java :results output silent :dir .
> >> >> >>   package org.orgmode;
> >> >> >>
> >> >> >>   public class Hey {
> >> >> >>       public static String say() {
> >> >> >>           return "hey";
> >> >> >>       }
> >> >> >>   }
> >> >> >> #+end_src
> >> >> >>
> >> >> >> #+begin_src java :results output silent :dir .
> >> >> >>   package org.orgmode;
> >> >> >>
> >> >> >>   public class Main {
> >> >> >>       public static void main(String[] args) {
> >> >> >>           System.out.print(Hey.say());
> >> >> >>       }
> >> >> >>   }
> >> >> >> #+end_src
> >> >> >>
> >> >> >> Instead of C-c C-c, we could have added tangle headers and written
> >> the
> >> >> >> source files out by tangling.
> >> >> >>
> >> >> >> ** Example 5
> >> >> >> This prints the variable from the header
> >> >> >>
> >> >> >> #+begin_src java :var msg="hello, org-mode" :results output silent
> >> >> >>   System.out.print(msg);
> >> >> >> #+end_src
> >> >> >>
> >> >> >> ** Example 6
> >> >> >> This prints "hello, org-mode." The table is provided to the method
> >> as a
> >> >> >> list of lists.
> >> >> >>
> >> >> >> #+name: table
> >> >> >> | message | hello, org-mode  |
> >> >> >>
> >> >> >> #+begin_src java :var tbl=table :results output silent
> >> >> >>   System.out.print(tbl.get(0).get(1));
> >> >> >> #+end_src
> >> >> >>
> >> >> >> ** Example 7
> >> >> >> This example returns a list.
> >> >> >>
> >> >> >> Note that you're allowed to specify imports without defining the
> >> class
> >> >> >> or main methods.
> >> >> >>
> >> >> >> #+begin_src java :results value :exports both
> >> >> >>   import java.util.Arrays;
> >> >> >>
> >> >> >>   return Arrays.asList("message", "hello, org-mode");
> >> >> >> #+end_src
> >> >> >>
> >> >> >> #+RESULTS:
> >> >> >> | message | hello, org-mode |
> >> >> >>
> >> >> >> On Mon, Oct 5, 2020 at 8:35 AM ian martins <ianxm@jhu.edu> wrote:
> >> >> >>
> >> >> >>> 1 Changes
> >> >> >>> =========
> >> >> >>>
> >> >> >>>   - support for functional mode (`:results value')
> >> >> >>>   - accept variables
> >> >> >>>   - don't require package, class, and main definitions
> >> >> >>>   - write source and result tempfiles to
> >> >> >>>     `org-babel-temporary-directory', but respects the `:dir'
> header
> >> >> >>>   - work with tramp
> >> >> >>>
> >> >> >>>
> >> >> >>> 2 Examples
> >> >> >>> ==========
> >> >> >>> Some examples follow.  See the tests for more examples.  I'll
> write
> >> >> >>> proper docs after review.
> >> >> >>>
> >> >> >>> 2.1 Example 1
> >> >> >>> ~~~~~~~~~~~~~
> >> >> >>>
> >> >> >>>   This outputs "hello."  If class and main definitions aren't
> given
> >> the
> >> >> >>>   code block will be wrapped in generic ones.
> >> >> >>>
> >> >> >>>   ,----
> >> >> >>>   | System.out.print("hello");
> >> >> >>>   `----
> >> >> >>>
> >> >> >>>   This is exactly equivalent:
> >> >> >>>
> >> >> >>>   ,----
> >> >> >>>   | public class Main {
> >> >> >>>   |     public static void main(String[] args) {
> >> >> >>>   |         System.out.print("hello");
> >> >> >>>   |     }
> >> >> >>>   | }
> >> >> >>>   `----
> >> >> >>>
> >> >> >>>
> >> >> >>> 2.2 Example 2
> >> >> >>> ~~~~~~~~~~~~~
> >> >> >>>
> >> >> >>>   This also outputs "hello."
> >> >> >>>
> >> >> >>>   ,----
> >> >> >>>   | return "hello";
> >> >> >>>   `----
> >> >> >>>
> >> >> >>>
> >> >> >>> 2.3 Example 3
> >> >> >>> ~~~~~~~~~~~~~
> >> >> >>>
> >> >> >>>   This generates the class "Example" in the package
> "org.orgmode" in
> >> >> the
> >> >> >>>   current directory.
> >> >> >>>
> >> >> >>>   ,----
> >> >> >>>   | System.out.print("hello, org-mode");
> >> >> >>>   `----
> >> >> >>>
> >> >> >>>
> >> >> >>> 2.4 Example 4
> >> >> >>> ~~~~~~~~~~~~~
> >> >> >>>
> >> >> >>>   The "Hey" class defines a static method but no main. C-c C-c on
> >> the
> >> >> >>>   "Hey" source block will write "./org/orgmode/Hey.java" and
> compile
> >> >> it.
> >> >> >>>
> >> >> >>>   The "Main" class calls the "Hey" class. C-c C-c on the "Main"
> >> source
> >> >> >>>   block will write "./org/orgmode/Main.java" and compile and run
> it.
> >> >> >>>
> >> >> >>>   ,----
> >> >> >>>   | package org.orgmode;
> >> >> >>>   |
> >> >> >>>   | public class Hey {
> >> >> >>>   |     public static String say() {
> >> >> >>>   |         return "hey";
> >> >> >>>   |     }
> >> >> >>>   | }
> >> >> >>>   `----
> >> >> >>>
> >> >> >>>   ,----
> >> >> >>>   | package org.orgmode;
> >> >> >>>   |
> >> >> >>>   | public class Main {
> >> >> >>>   |     public static void main(String[] args) {
> >> >> >>>   |         System.out.print(Hey.say());
> >> >> >>>   |     }
> >> >> >>>   | }
> >> >> >>>   `----
> >> >> >>>
> >> >> >>>   Instead of C-c C-c, we could have added tangle headers and
> written
> >> >> the
> >> >> >>>   source files out by tangling.
> >> >> >>>
> >> >> >>>
> >> >> >>> 2.5 Example 5
> >> >> >>> ~~~~~~~~~~~~~
> >> >> >>>
> >> >> >>>   This prints the variable from the header
> >> >> >>>
> >> >> >>>   ,----
> >> >> >>>   | System.out.print(msg);
> >> >> >>>   `----
> >> >> >>>
> >> >> >>>
> >> >> >>> 2.6 Example 6
> >> >> >>> ~~~~~~~~~~~~~
> >> >> >>>
> >> >> >>>   This prints "hello, org-mode." The table is provided to the
> >> method as
> >> >> >>>   a list of lists.
> >> >> >>>
> >> >> >>>    message  hello, org-mode
> >> >> >>>
> >> >> >>>   ,----
> >> >> >>>   | System.out.print(tbl.get(0).get(1));
> >> >> >>>   `----
> >> >> >>>
> >> >> >>>
> >> >> >>> 2.7 Example 7
> >> >> >>> ~~~~~~~~~~~~~
> >> >> >>>
> >> >> >>>   This example returns a list.
> >> >> >>>
> >> >> >>>   Note that you're allowed to specify imports without defining
> the
> >> >> class
> >> >> >>>   or main methods.
> >> >> >>>
> >> >> >>>   ,----
> >> >> >>>   | import java.util.Arrays;
> >> >> >>>   |
> >> >> >>>   | return Arrays.asList("message", "hello, org-mode");
> >> >> >>>   `----
> >> >> >>>
> >> >> >>>    message  hello, org-mode
> >> >> >>>
> >> >> >>
> >> >>
> >>
>

[-- Attachment #1.2: Type: text/html, Size: 21900 bytes --]

[-- Attachment #2: 0003-ob-java.el-Allow-non-public-classes.patch --]
[-- Type: text/x-patch, Size: 3253 bytes --]

From 0f754613f7b9616e6cc1c2bd3b61a6552796ea9d Mon Sep 17 00:00:00 2001
From: Ian Martins <ianxm@jhu.edu>
Date: Thu, 22 Oct 2020 06:55:59 -0400
Subject: [PATCH 3/3] ob-java.el: Allow non-public classes

* lisp/ob-java.el: Don't require class definitions to be declared
public.

* testing/lisp/test-ob-java.el: Add test with non-public class.
---
 lisp/ob-java.el              | 12 ++++++------
 testing/lisp/test-ob-java.el | 12 ++++++++++++
 2 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/lisp/ob-java.el b/lisp/ob-java.el
index 65b8c3eba..eaeb78844 100644
--- a/lisp/ob-java.el
+++ b/lisp/ob-java.el
@@ -125,22 +125,22 @@
 Look through BODY for the package and class.  If found, put them
 together into a fully qualified class name and return.  Else just
 return class name.  If that isn't found either, default to Main."
-  (let ((package (if (string-match "package \\\([^ ]*\\\);" body)
+  (let ((package (if (string-match org-babel-java--package-re body)
                      (match-string 1 body)))
-        (class (if (string-match "public class \\\([^ \n]*\\\)" body)
+        (class (if (string-match org-babel-java--class-re body)
                    (match-string 1 body))))
     (or (and package class (concat package "." class))
         (and class class)
         (and package (concat package ".Main"))
         "Main")))
 
-(defconst org-babel-java--package-re "^[[:space:]]*package .*;$"
+(defconst org-babel-java--package-re "^[[:space:]]*package[[:space:]]+\\\([[:alnum:]_\.]+\\\);$"
   "Regexp for the package statement.")
-(defconst org-babel-java--imports-re "^[[:space:]]*import .*;$"
+(defconst org-babel-java--imports-re "^[[:space:]]*import[[:space:]]+\\\([[:alnum:]_\.]+\\\);$"
   "Regexp for import statements.")
-(defconst org-babel-java--class-re "^public class [[:alnum:]_]+[[:space:]]*\n?[[:space:]]*{"
+(defconst org-babel-java--class-re "^[[:space:]]*\\\(?:public[[:space:]]+\\\)?class[[:space:]]+\\\([[:alnum:]_]+\\\)[[:space:]]*\n?[[:space:]]*{"
   "Regexp for the class declaration.")
-(defconst org-babel-java--main-re "public static void main(String\\(?:\\[]\\)? args\\(?:\\[]\\)?).*\n?[[:space:]]*{"
+(defconst org-babel-java--main-re "public static void main(String\\\(?:\\[]\\\)?[[:space:]]+[^ ]+\\\(?:\\[]\\\)?).*\n?[[:space:]]*{"
   "Regexp for the main method declaration.")
 (defconst org-babel-java--any-method-re "public .*(.*).*\n?[[:space:]]*{"
   "Regexp for any method.")
diff --git a/testing/lisp/test-ob-java.el b/testing/lisp/test-ob-java.el
index 090c40084..cb03cadac 100644
--- a/testing/lisp/test-ob-java.el
+++ b/testing/lisp/test-ob-java.el
@@ -137,6 +137,18 @@ public class Simple {
 #+end_src"
    (should (string= "42" (org-babel-execute-src-block)))))
 
+(ert-deftest ob-java/simple-with-non-public-class ()
+  "Hello world program that defines a non-public class."
+  (org-test-with-temp-text
+      "#+begin_src java :results output silent
+class Simple {
+    public static void main(String[] args) {
+        System.out.print(42);
+    }
+}
+#+end_src"
+   (should (string= "42" (org-babel-execute-src-block)))))
+
 (ert-deftest ob-java/simple-with-class-and-package ()
   "Hello world program that defines a class and package."
   (org-test-with-temp-text
-- 
2.25.1


[-- Attachment #3: 0002-ob-java.el-Fix-spacing-in-generated-main-method.patch --]
[-- Type: text/x-patch, Size: 870 bytes --]

From 2b459d59d006c190c6b7513e17378b67c8162bf9 Mon Sep 17 00:00:00 2001
From: John Herrlin <jherrlin@gmail.com>
Date: Thu, 22 Oct 2020 06:52:22 -0400
Subject: [PATCH 2/3] ob-java.el: Fix spacing in generated main method

* lisp/ob-java.el: Correct Indentation of closing curly braces when
the default main method is used.
---
 lisp/ob-java.el | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lisp/ob-java.el b/lisp/ob-java.el
index e704c5552..65b8c3eba 100644
--- a/lisp/ob-java.el
+++ b/lisp/ob-java.el
@@ -218,7 +218,7 @@ RESULT-FILE is the temp file to write the result."
       (org-babel-java--move-past org-babel-java--class-re)
       (insert "\n    public static void main(String[] args) {
         System.out.print(\"success\");
-}\n\n"))
+    }\n\n"))
 
     ;; special handling to return value
     (when (eq result-type 'value)
-- 
2.25.1


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] ob-java
  2020-10-22 12:23               ` ian martins
@ 2020-10-22 12:56                 ` John Herrlin
  0 siblings, 0 replies; 31+ messages in thread
From: John Herrlin @ 2020-10-22 12:56 UTC (permalink / raw)
  To: ian martins; +Cc: Org-Mode mailing list


ian martins <ianxm@jhu.edu> writes:

> Actually I realized if I keep the commits separate and generate a patch set
> instead of squashing then I can preserve authorship.

Thank you for taking the time! It's not necessary and not important for
me!

>
> These patches, which follow patch 0001, fix the spacing and allow
> non-public classes.
>
> Thanks again for testing, debugging, and reporting.

It's been a pleasure!

>
> On Wed, Oct 21, 2020 at 9:54 AM John Herrlin <jherrlin@gmail.com> wrote:
>
>>
>> ian martins <ianxm@jhu.edu> writes:
>>
>> >>
>> >> What do you think about having a configurable list where the user can
>> >> add =org-babel-java--import-maybe=? In my current use case I could then
>> >> add RxJava imports to that list and the imports could be removed from
>> >> the source code block.
>> >
>> >
>> > I think this can already be done. imports can be added to the headers,
>> and
>> > babel allows file-wide headers, so you could add a =#+HEADER: :import
>> > rx.Observable= line to the file and all source blocks would get it.  it's
>> > slightly different in that =org-babel-java--import-maybe= skips imports
>> > that it thinks aren't needed. also if there are any non-java source
>> blocks
>> > in the same file, these imports could be added to them which would be
>> bad,
>> > so when mixing multiple languages in the same file this wouldn't be an
>> > option.
>>
>> Thanks for pointing that out! It work just fine!
>>
>> >
>> > NIT
>> >> Some spacing when writing =public static...=
>> >>
>> >
>> > Thanks for fixing the spacing. I don't think I can give you credit for
>> the
>> > patch, though, without leaving it out until ob-java is accepted.
>>
>> I dont need any credits, the important part is the result!
>>
>> I have made a couple of more runs and I cant find anything that doesnt
>> work!
>>
>> >
>> > On Wed, Oct 21, 2020 at 1:59 AM John Herrlin <jherrlin@gmail.com> wrote:
>> >
>> >>
>> >> I did and it looks really good. The difference in this example:
>> >>
>> >>     #+BEGIN_SRC java
>> >>       import rx.Observable;
>> >>
>> >>       Observable.range(5, 3)
>> >>           .subscribe((Integer i) ->   { System.out.println("Got: " +
>> i); },
>> >>                      (Throwable t) -> { t.printStackTrace();},
>> >>                      () ->            { System.out.println("Ending
>> >> stream"); });
>> >>     #+END_SRC
>> >>
>> >> from the ones I posted yesterday is tremendous!
>> >>
>> >> I am not very experienced with Emacs lisp but I think it's pretty easy
>> >> to understand how things works and follow the code. The comments are
>> >> also of good help. I really appreciate the work you have done!
>> >>
>> >>
>> >> What do you think about having a configurable list where the user can
>> >> add =org-babel-java--import-maybe=? In my current use case I could then
>> >> add RxJava imports to that list and the imports could be removed from
>> >> the source code block.
>> >>
>> >>
>> >> NIT
>> >>
>> >> Some spacing when writing =public static...=
>> >>
>> >>    #+BEGIN_SRC diff
>> >>      diff --git a/lisp/ob-java.el b/lisp/ob-java.el
>> >>      index 94c3f69cf..4f3904871 100644
>> >>      --- a/lisp/ob-java.el
>> >>      +++ b/lisp/ob-java.el
>> >>      @@ -220,7 +220,7 @@ RESULT-FILE is the temp file to write the
>> result."
>> >>             (org-babel-java--move-past org-babel-java--class-re)
>> >>             (insert "\n    public static void main(String[] args) {
>> >>               System.out.print(\"success\");
>> >>      -}\n\n"))
>> >>      +    }\n\n"))
>> >>
>> >>           ;; special handling to return value
>> >>           (when (eq result-type 'value)
>> >>    #+END_SRC
>> >>
>> >>
>> >>
>> >> ian martins <ianxm@jhu.edu> writes:
>> >>
>> >> > Thanks for testing, and thanks for pointing that out. I will fix it so
>> >> that
>> >> > `public` is optional.
>> >> >
>> >> > btw, in your example you didn't have to specify `:classname` since you
>> >> > defined the class name in the source block.
>> >> >
>> >> > btw2, did you notice that you can C-c C-c on source blocks that don't
>> >> have
>> >> > main methods and it'll compile without error?
>> >> >
>> >> > On Tue, Oct 20, 2020 at 3:17 PM John Herrlin <jherrlin@gmail.com>
>> wrote:
>> >> >
>> >> >>
>> >> >> Hey,
>> >> >>
>> >> >> Did some debugging and found out that my class didn't contained
>> =public=
>> >> >> and the patch requires it to be.
>> >> >>
>> >> >> This works fine:
>> >> >>
>> >> >>    #+HEADER: :classname Main
>> >> >>    #+HEADER: :dir src
>> >> >>    #+HEADER: :cmdline -classpath ./rxjava-1.3.8.jar:.
>> >> >>    #+HEADER: :cmpflag -classpath ./rxjava-1.3.8.jar
>> >> >>    #+BEGIN_SRC java :results output code
>> >> >>      import rx.Observable;
>> >> >>      public class Main {
>> >> >>          public static void main(String[] args) {
>> >> >>              Observable.range(5, 5)
>> >> >>                  .subscribe(System.out::println);
>> >> >>          }
>> >> >>      }
>> >> >>    #+END_SRC
>> >> >>
>> >> >>
>> >> >>
>> >> >>
>> >> >> ian martins <ianxm@jhu.edu> writes:
>> >> >>
>> >> >> > I noticed that the tests didn't run with "make test." This updates
>> the
>> >> >> > patch so that they can. I didn't add java to the list of default
>> >> >> languages
>> >> >> > because the java tests are slow.
>> >> >> >
>> >> >> > On Mon, Oct 5, 2020 at 9:23 AM ian martins <ianxm@jhu.edu> wrote:
>> >> >> >
>> >> >> >> I wrote those examples in an org file so I could test as I wrote
>> >> them,
>> >> >> and
>> >> >> >> then exported it to make it more readable, but the export
>> resulted in
>> >> >> >> source block headers being lost.  Here is the same without export:
>> >> >> >> ----
>> >> >> >> * Changes
>> >> >> >>
>> >> >> >> - support for functional mode (~:results value~)
>> >> >> >> - accept variables
>> >> >> >> - don't require package, class, and main definitions
>> >> >> >> - write source and result tempfiles to
>> >> ~org-babel-temporary-directory~,
>> >> >> >> but respects the ~:dir~ header
>> >> >> >> - work with tramp
>> >> >> >>
>> >> >> >> * Examples
>> >> >> >> ** Example 1
>> >> >> >> This outputs "hello."  If class and main definitions aren't given
>> the
>> >> >> >> code block will be wrapped in generic ones.
>> >> >> >>
>> >> >> >> #+begin_src java :results output silent
>> >> >> >>   System.out.print("hello");
>> >> >> >> #+end_src
>> >> >> >>
>> >> >> >> This is exactly equivalent:
>> >> >> >>
>> >> >> >> #+begin_src java :results output silent
>> >> >> >>   public class Main {
>> >> >> >>       public static void main(String[] args) {
>> >> >> >>           System.out.print("hello");
>> >> >> >>       }
>> >> >> >>   }
>> >> >> >> #+end_src
>> >> >> >>
>> >> >> >> ** Example 2
>> >> >> >> This also outputs "hello."
>> >> >> >>
>> >> >> >> #+begin_src java :results value silent
>> >> >> >>   return "hello";
>> >> >> >> #+end_src
>> >> >> >>
>> >> >> >> ** Example 3
>> >> >> >> This generates the class "Example" in the package "org.orgmode" in
>> >> the
>> >> >> >> current directory.
>> >> >> >>
>> >> >> >> #+begin_src java :results output silent :classname
>> >> org.orgmode.Example
>> >> >> >> :dir .
>> >> >> >>   System.out.print("hello, org-mode");
>> >> >> >> #+end_src
>> >> >> >>
>> >> >> >> ** Example 4
>> >> >> >> The "Hey" class defines a static method but no main. C-c C-c on
>> the
>> >> >> >> "Hey" source block will write "./org/orgmode/Hey.java" and compile
>> >> it.
>> >> >> >>
>> >> >> >> The "Main" class calls the "Hey" class. C-c C-c on the "Main"
>> source
>> >> >> >> block will write "./org/orgmode/Main.java" and compile and run it.
>> >> >> >>
>> >> >> >> #+begin_src java :results output silent :dir .
>> >> >> >>   package org.orgmode;
>> >> >> >>
>> >> >> >>   public class Hey {
>> >> >> >>       public static String say() {
>> >> >> >>           return "hey";
>> >> >> >>       }
>> >> >> >>   }
>> >> >> >> #+end_src
>> >> >> >>
>> >> >> >> #+begin_src java :results output silent :dir .
>> >> >> >>   package org.orgmode;
>> >> >> >>
>> >> >> >>   public class Main {
>> >> >> >>       public static void main(String[] args) {
>> >> >> >>           System.out.print(Hey.say());
>> >> >> >>       }
>> >> >> >>   }
>> >> >> >> #+end_src
>> >> >> >>
>> >> >> >> Instead of C-c C-c, we could have added tangle headers and written
>> >> the
>> >> >> >> source files out by tangling.
>> >> >> >>
>> >> >> >> ** Example 5
>> >> >> >> This prints the variable from the header
>> >> >> >>
>> >> >> >> #+begin_src java :var msg="hello, org-mode" :results output silent
>> >> >> >>   System.out.print(msg);
>> >> >> >> #+end_src
>> >> >> >>
>> >> >> >> ** Example 6
>> >> >> >> This prints "hello, org-mode." The table is provided to the method
>> >> as a
>> >> >> >> list of lists.
>> >> >> >>
>> >> >> >> #+name: table
>> >> >> >> | message | hello, org-mode  |
>> >> >> >>
>> >> >> >> #+begin_src java :var tbl=table :results output silent
>> >> >> >>   System.out.print(tbl.get(0).get(1));
>> >> >> >> #+end_src
>> >> >> >>
>> >> >> >> ** Example 7
>> >> >> >> This example returns a list.
>> >> >> >>
>> >> >> >> Note that you're allowed to specify imports without defining the
>> >> class
>> >> >> >> or main methods.
>> >> >> >>
>> >> >> >> #+begin_src java :results value :exports both
>> >> >> >>   import java.util.Arrays;
>> >> >> >>
>> >> >> >>   return Arrays.asList("message", "hello, org-mode");
>> >> >> >> #+end_src
>> >> >> >>
>> >> >> >> #+RESULTS:
>> >> >> >> | message | hello, org-mode |
>> >> >> >>
>> >> >> >> On Mon, Oct 5, 2020 at 8:35 AM ian martins <ianxm@jhu.edu> wrote:
>> >> >> >>
>> >> >> >>> 1 Changes
>> >> >> >>> =========
>> >> >> >>>
>> >> >> >>>   - support for functional mode (`:results value')
>> >> >> >>>   - accept variables
>> >> >> >>>   - don't require package, class, and main definitions
>> >> >> >>>   - write source and result tempfiles to
>> >> >> >>>     `org-babel-temporary-directory', but respects the `:dir'
>> header
>> >> >> >>>   - work with tramp
>> >> >> >>>
>> >> >> >>>
>> >> >> >>> 2 Examples
>> >> >> >>> ==========
>> >> >> >>> Some examples follow.  See the tests for more examples.  I'll
>> write
>> >> >> >>> proper docs after review.
>> >> >> >>>
>> >> >> >>> 2.1 Example 1
>> >> >> >>> ~~~~~~~~~~~~~
>> >> >> >>>
>> >> >> >>>   This outputs "hello."  If class and main definitions aren't
>> given
>> >> the
>> >> >> >>>   code block will be wrapped in generic ones.
>> >> >> >>>
>> >> >> >>>   ,----
>> >> >> >>>   | System.out.print("hello");
>> >> >> >>>   `----
>> >> >> >>>
>> >> >> >>>   This is exactly equivalent:
>> >> >> >>>
>> >> >> >>>   ,----
>> >> >> >>>   | public class Main {
>> >> >> >>>   |     public static void main(String[] args) {
>> >> >> >>>   |         System.out.print("hello");
>> >> >> >>>   |     }
>> >> >> >>>   | }
>> >> >> >>>   `----
>> >> >> >>>
>> >> >> >>>
>> >> >> >>> 2.2 Example 2
>> >> >> >>> ~~~~~~~~~~~~~
>> >> >> >>>
>> >> >> >>>   This also outputs "hello."
>> >> >> >>>
>> >> >> >>>   ,----
>> >> >> >>>   | return "hello";
>> >> >> >>>   `----
>> >> >> >>>
>> >> >> >>>
>> >> >> >>> 2.3 Example 3
>> >> >> >>> ~~~~~~~~~~~~~
>> >> >> >>>
>> >> >> >>>   This generates the class "Example" in the package
>> "org.orgmode" in
>> >> >> the
>> >> >> >>>   current directory.
>> >> >> >>>
>> >> >> >>>   ,----
>> >> >> >>>   | System.out.print("hello, org-mode");
>> >> >> >>>   `----
>> >> >> >>>
>> >> >> >>>
>> >> >> >>> 2.4 Example 4
>> >> >> >>> ~~~~~~~~~~~~~
>> >> >> >>>
>> >> >> >>>   The "Hey" class defines a static method but no main. C-c C-c on
>> >> the
>> >> >> >>>   "Hey" source block will write "./org/orgmode/Hey.java" and
>> compile
>> >> >> it.
>> >> >> >>>
>> >> >> >>>   The "Main" class calls the "Hey" class. C-c C-c on the "Main"
>> >> source
>> >> >> >>>   block will write "./org/orgmode/Main.java" and compile and run
>> it.
>> >> >> >>>
>> >> >> >>>   ,----
>> >> >> >>>   | package org.orgmode;
>> >> >> >>>   |
>> >> >> >>>   | public class Hey {
>> >> >> >>>   |     public static String say() {
>> >> >> >>>   |         return "hey";
>> >> >> >>>   |     }
>> >> >> >>>   | }
>> >> >> >>>   `----
>> >> >> >>>
>> >> >> >>>   ,----
>> >> >> >>>   | package org.orgmode;
>> >> >> >>>   |
>> >> >> >>>   | public class Main {
>> >> >> >>>   |     public static void main(String[] args) {
>> >> >> >>>   |         System.out.print(Hey.say());
>> >> >> >>>   |     }
>> >> >> >>>   | }
>> >> >> >>>   `----
>> >> >> >>>
>> >> >> >>>   Instead of C-c C-c, we could have added tangle headers and
>> written
>> >> >> the
>> >> >> >>>   source files out by tangling.
>> >> >> >>>
>> >> >> >>>
>> >> >> >>> 2.5 Example 5
>> >> >> >>> ~~~~~~~~~~~~~
>> >> >> >>>
>> >> >> >>>   This prints the variable from the header
>> >> >> >>>
>> >> >> >>>   ,----
>> >> >> >>>   | System.out.print(msg);
>> >> >> >>>   `----
>> >> >> >>>
>> >> >> >>>
>> >> >> >>> 2.6 Example 6
>> >> >> >>> ~~~~~~~~~~~~~
>> >> >> >>>
>> >> >> >>>   This prints "hello, org-mode." The table is provided to the
>> >> method as
>> >> >> >>>   a list of lists.
>> >> >> >>>
>> >> >> >>>    message  hello, org-mode
>> >> >> >>>
>> >> >> >>>   ,----
>> >> >> >>>   | System.out.print(tbl.get(0).get(1));
>> >> >> >>>   `----
>> >> >> >>>
>> >> >> >>>
>> >> >> >>> 2.7 Example 7
>> >> >> >>> ~~~~~~~~~~~~~
>> >> >> >>>
>> >> >> >>>   This example returns a list.
>> >> >> >>>
>> >> >> >>>   Note that you're allowed to specify imports without defining
>> the
>> >> >> class
>> >> >> >>>   or main methods.
>> >> >> >>>
>> >> >> >>>   ,----
>> >> >> >>>   | import java.util.Arrays;
>> >> >> >>>   |
>> >> >> >>>   | return Arrays.asList("message", "hello, org-mode");
>> >> >> >>>   `----
>> >> >> >>>
>> >> >> >>>    message  hello, org-mode
>> >> >> >>>
>> >> >> >>
>> >> >>
>> >>
>>


--
Mvh John


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] ob-java
  2020-10-05 12:35 [PATCH] ob-java ian martins
  2020-10-05 13:23 ` ian martins
@ 2020-10-24 11:58 ` Bastien
  2020-10-25  0:30   ` ian martins
  1 sibling, 1 reply; 31+ messages in thread
From: Bastien @ 2020-10-24 11:58 UTC (permalink / raw)
  To: ian martins; +Cc: Org-Mode mailing list

Hi Ian,

feel free to install the patch when you think it's ready.

One minor nitpick:

-;; Author: Eric Schulte
-;; Maintainer: Ian Martins <ianxm@jhu.edu>
+;; Author: Ian Martins <ianxm@jhu.edu>

I suggest you leave Eric Schulte as the author while adding yourself
as the maintainer, even if the "change" is a big rewrite.

Thanks,

-- 
 Bastien


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] ob-java
  2020-10-09 11:15   ` ian martins
  2020-10-20 18:28     ` John Herrlin
  2020-10-20 19:17     ` John Herrlin
@ 2020-10-24 17:05     ` Kyle Meyer
  2020-10-25  2:10       ` ian martins
  2 siblings, 1 reply; 31+ messages in thread
From: Kyle Meyer @ 2020-10-24 17:05 UTC (permalink / raw)
  To: ian martins; +Cc: Org-Mode mailing list

Hi ian,

ian martins writes:

>> * Changes
>>
>> - support for functional mode (~:results value~)
>> - accept variables
>> - don't require package, class, and main definitions
>> - write source and result tempfiles to ~org-babel-temporary-directory~,
>> but respects the ~:dir~ header
>> - work with tramp

Thanks for all the work you've put into this.  As someone that knows
nothing about Java and hasn't touched ob-java, that sounds good :)

I see this got a "feel free to install" elsewhere in this thread, so
here are a few scattered and superficial remarks.

> Subject: [PATCH] ob-java.el: Add support for variables, return values, tramp
>
> * lisp/ob-java.el: Add support for variables and return values.  Write
> tempfiles to the org-babel-temporary-directory.  Make package, class,
> and main method definitions optional.
>
> * testing/lisp/test-ob-java.el: Add tests.

I think the changelog entry should technically have
per-function/variable entries.

More importantly from my perspective, it would be great for the message
to explain what the current state is, why it is problematic, and what
the patch's solution is.  For this patch, that'd probably be much too
large, which is a good indication that it'd be better presented as a
split up series.  But, at this point, that's not something I think you
should do for this patch, especially given there doesn't seem to be a
java/ob-java user with the bandwidth to provide a detailed review.

> -(defcustom org-babel-java-command "java"
> -  "Name of the java command.
> -May be either a command in the path, like java
> -or an absolute path name, like /usr/local/bin/java
> -parameters may be used, like java -verbose"
> +(defvar org-babel-default-header-args:java '()
> +  "Default header args for java source blocks.")
> +
> +(defconst org-babel-header-args:java '((imports . :any))
> +  "Java-specific header arguments.")
> +
> +(defvar org-babel-java-compiler-command "javac"
> +  "Name of the command to execute the java compiler.")
> +
> +(defvar org-babel-java-runtime-command "java"
> +  "Name of the command to run the java runtime.")

Rather than dropping org-babel-java-command and org-babel-java-compiler
entirely, can you make this change in a way that doesn't break for users
that have already customized org-babel-java-command?

Also, shouldn't org-babel-java-compiler-command and
org-babel-java-runtime-command be user options rather than defvars?

In general, are the changes here expected to be backwards compatible for
current ob-java users?

> +(defcustom org-babel-java-hline-to "null"
> +  "Replace hlines in incoming tables with this when translating to java."
>    :group 'org-babel
> -  :version "24.3"
> +  :version "25.2"
> +  :package-version '(Org . "9.3")
>    :type 'string)
>  
> -(defcustom org-babel-java-compiler "javac"
> -  "Name of the java compiler.
> -May be either a command in the path, like javac
> -or an absolute path name, like /usr/local/bin/javac
> -parameters may be used, like javac -verbose"
> +(defcustom org-babel-java-null-to 'hline
> +  "Replace `null' in java tables with this before returning."
>    :group 'org-babel
> -  :version "24.3"
> -  :type 'string)
> +  :version "25.2"
> +  :package-version '(Org . "9.3")
> +  :type 'symbol)

For both these options, s/9.3/9.5/.  And please drop :version, letting
it be handled by customize-package-emacs-version-alist.

>  (defun org-babel-execute:java (body params)
> -  (let* ((classname (or (cdr (assq :classname params))
> -			(error
> -			 "Can't compile a java block without a classname")))
> -	 (packagename (file-name-directory classname))
> -	 (src-file (concat classname ".java"))
> +  "Execute a java source block with BODY code and PARAMS params."
> +  (let* (;; if true, run from babel temp directory
> +         (run-from-temp (not (assq :dir params)))
> +         ;; class and package
> +         (fullclassname (or (cdr (assq :classname params))
> +                            (org-babel-java-find-classname body)))
> +         ;; just the class name
> +         (classname (car (last (split-string fullclassname "\\."))))
> +         ;; just the package name
> +         (packagename (if (seq-contains fullclassname ?.)

Please avoid seq- for compatibility with older versions of Emacs.

> +(defun org-babel-java-evaluate (cmd result-type result-params result-file)
> +  "Evaluate using an external java process.
> +CMD the command to execute.
> +
> +If RESULT-TYPE equals 'output then return standard output as a
> +string.  If RESULT-TYPE equals 'value then return the value
> +returned by the source block, as elisp.
> +
> +RESULT-PARAMS input params used to format the reponse.
> +
> +RESULT-FILE filename of the tempfile to store the returned value in
> +for 'value RESULT-TYPE.  Not used for 'output RESULT-TYPE."

Convention nit: Prefer `symbol' to 'symbol (e.g., s/'output/`output'/).
I didn't check closely if this applies to other docstrings in this
patch.

> +  (let ((raw (pcase result-type
> +               ('output (org-babel-eval cmd ""))
> +               ('value (org-babel-eval cmd "")
> +                       (org-babel-eval-read-file result-file)))))

'VAL isn't compatible with all the Emacs versions we support.  Please
use `VAL instead.


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] ob-java
  2020-10-24 11:58 ` Bastien
@ 2020-10-25  0:30   ` ian martins
  2020-10-28  9:13     ` Bastien
  0 siblings, 1 reply; 31+ messages in thread
From: ian martins @ 2020-10-25  0:30 UTC (permalink / raw)
  To: Bastien; +Cc: Org-Mode mailing list

[-- Attachment #1: Type: text/plain, Size: 1200 bytes --]

This happened because the new ob-java wasn't based on the old ob-java. I
wrote ob-haxe based on ob-C and ob-python and then derived ob-java from
ob-haxe.  I went back and forth about who should be the author of ob-haxe.
I considered listing the authors of ob-C and ob-python, but I thought it
wouldn't make sense since they may not have heard of haxe, and they may not
like my code or want their names on it. I didn't really think about the
author of the new ob-java, since it came directly from ob-haxe.

But I want to follow your conventions. I will put the authors of ob-C and
ob-python (Eric Schulte and Dan Davison) as the authors of ob-java and
ob-haxe. The implementations are nearly the same. it wouldn't make sense
for them to have different authors.

On Sat, Oct 24, 2020 at 7:58 AM Bastien <bzg@gnu.org> wrote:

> Hi Ian,
>
> feel free to install the patch when you think it's ready.
>
> One minor nitpick:
>
> -;; Author: Eric Schulte
> -;; Maintainer: Ian Martins <ianxm@jhu.edu>
> +;; Author: Ian Martins <ianxm@jhu.edu>
>
> I suggest you leave Eric Schulte as the author while adding yourself
> as the maintainer, even if the "change" is a big rewrite.
>
> Thanks,
>
> --
>  Bastien
>

[-- Attachment #2: Type: text/html, Size: 1712 bytes --]

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] ob-java
  2020-10-24 17:05     ` Kyle Meyer
@ 2020-10-25  2:10       ` ian martins
  2020-10-25  2:40         ` Kyle Meyer
  0 siblings, 1 reply; 31+ messages in thread
From: ian martins @ 2020-10-25  2:10 UTC (permalink / raw)
  To: Kyle Meyer; +Cc: Org-Mode mailing list

[-- Attachment #1: Type: text/plain, Size: 5834 bytes --]

Thanks for the feedback. In general, the changes are all intended to be
backwards compatible. Thanks for pointing out changes that weren't.

After making the changes, should I submit updated patches or is it fine to
push?

On Sat, Oct 24, 2020 at 1:05 PM Kyle Meyer <kyle@kyleam.com> wrote:

> Hi ian,
>
> ian martins writes:
>
> >> * Changes
> >>
> >> - support for functional mode (~:results value~)
> >> - accept variables
> >> - don't require package, class, and main definitions
> >> - write source and result tempfiles to ~org-babel-temporary-directory~,
> >> but respects the ~:dir~ header
> >> - work with tramp
>
> Thanks for all the work you've put into this.  As someone that knows
> nothing about Java and hasn't touched ob-java, that sounds good :)
>
> I see this got a "feel free to install" elsewhere in this thread, so
> here are a few scattered and superficial remarks.
>
> > Subject: [PATCH] ob-java.el: Add support for variables, return values,
> tramp
> >
> > * lisp/ob-java.el: Add support for variables and return values.  Write
> > tempfiles to the org-babel-temporary-directory.  Make package, class,
> > and main method definitions optional.
> >
> > * testing/lisp/test-ob-java.el: Add tests.
>
> I think the changelog entry should technically have
> per-function/variable entries.
>
> More importantly from my perspective, it would be great for the message
> to explain what the current state is, why it is problematic, and what
> the patch's solution is.  For this patch, that'd probably be much too
> large, which is a good indication that it'd be better presented as a
> split up series.  But, at this point, that's not something I think you
> should do for this patch, especially given there doesn't seem to be a
> java/ob-java user with the bandwidth to provide a detailed review.
>
> > -(defcustom org-babel-java-command "java"
> > -  "Name of the java command.
> > -May be either a command in the path, like java
> > -or an absolute path name, like /usr/local/bin/java
> > -parameters may be used, like java -verbose"
> > +(defvar org-babel-default-header-args:java '()
> > +  "Default header args for java source blocks.")
> > +
> > +(defconst org-babel-header-args:java '((imports . :any))
> > +  "Java-specific header arguments.")
> > +
> > +(defvar org-babel-java-compiler-command "javac"
> > +  "Name of the command to execute the java compiler.")
> > +
> > +(defvar org-babel-java-runtime-command "java"
> > +  "Name of the command to run the java runtime.")
>
> Rather than dropping org-babel-java-command and org-babel-java-compiler
> entirely, can you make this change in a way that doesn't break for users
> that have already customized org-babel-java-command?
>
> Also, shouldn't org-babel-java-compiler-command and
> org-babel-java-runtime-command be user options rather than defvars?
>
> In general, are the changes here expected to be backwards compatible for
> current ob-java users?
>
> > +(defcustom org-babel-java-hline-to "null"
> > +  "Replace hlines in incoming tables with this when translating to
> java."
> >    :group 'org-babel
> > -  :version "24.3"
> > +  :version "25.2"
> > +  :package-version '(Org . "9.3")
> >    :type 'string)
> >
> > -(defcustom org-babel-java-compiler "javac"
> > -  "Name of the java compiler.
> > -May be either a command in the path, like javac
> > -or an absolute path name, like /usr/local/bin/javac
> > -parameters may be used, like javac -verbose"
> > +(defcustom org-babel-java-null-to 'hline
> > +  "Replace `null' in java tables with this before returning."
> >    :group 'org-babel
> > -  :version "24.3"
> > -  :type 'string)
> > +  :version "25.2"
> > +  :package-version '(Org . "9.3")
> > +  :type 'symbol)
>
> For both these options, s/9.3/9.5/.  And please drop :version, letting
> it be handled by customize-package-emacs-version-alist.
>
> >  (defun org-babel-execute:java (body params)
> > -  (let* ((classname (or (cdr (assq :classname params))
> > -                     (error
> > -                      "Can't compile a java block without a
> classname")))
> > -      (packagename (file-name-directory classname))
> > -      (src-file (concat classname ".java"))
> > +  "Execute a java source block with BODY code and PARAMS params."
> > +  (let* (;; if true, run from babel temp directory
> > +         (run-from-temp (not (assq :dir params)))
> > +         ;; class and package
> > +         (fullclassname (or (cdr (assq :classname params))
> > +                            (org-babel-java-find-classname body)))
> > +         ;; just the class name
> > +         (classname (car (last (split-string fullclassname "\\."))))
> > +         ;; just the package name
> > +         (packagename (if (seq-contains fullclassname ?.)
>
> Please avoid seq- for compatibility with older versions of Emacs.
>
> > +(defun org-babel-java-evaluate (cmd result-type result-params
> result-file)
> > +  "Evaluate using an external java process.
> > +CMD the command to execute.
> > +
> > +If RESULT-TYPE equals 'output then return standard output as a
> > +string.  If RESULT-TYPE equals 'value then return the value
> > +returned by the source block, as elisp.
> > +
> > +RESULT-PARAMS input params used to format the reponse.
> > +
> > +RESULT-FILE filename of the tempfile to store the returned value in
> > +for 'value RESULT-TYPE.  Not used for 'output RESULT-TYPE."
>
> Convention nit: Prefer `symbol' to 'symbol (e.g., s/'output/`output'/).
> I didn't check closely if this applies to other docstrings in this
> patch.
>
> > +  (let ((raw (pcase result-type
> > +               ('output (org-babel-eval cmd ""))
> > +               ('value (org-babel-eval cmd "")
> > +                       (org-babel-eval-read-file result-file)))))
>
> 'VAL isn't compatible with all the Emacs versions we support.  Please
> use `VAL instead.
>

[-- Attachment #2: Type: text/html, Size: 7387 bytes --]

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] ob-java
  2020-10-25  2:10       ` ian martins
@ 2020-10-25  2:40         ` Kyle Meyer
  2020-10-25 19:36           ` ian martins
  0 siblings, 1 reply; 31+ messages in thread
From: Kyle Meyer @ 2020-10-25  2:40 UTC (permalink / raw)
  To: ian martins; +Cc: Org-Mode mailing list

ian martins writes:

> After making the changes, should I submit updated patches or is it fine to
> push?

Push away.  Thanks again.


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] ob-java
  2020-10-25  2:40         ` Kyle Meyer
@ 2020-10-25 19:36           ` ian martins
  2020-11-05 16:29             ` Jarmo Hurri
  0 siblings, 1 reply; 31+ messages in thread
From: ian martins @ 2020-10-25 19:36 UTC (permalink / raw)
  To: Kyle Meyer; +Cc: Org-Mode mailing list

[-- Attachment #1: Type: text/plain, Size: 298 bytes --]

I made the changes, updated the commit message for the large patch, and
pushed.

On Sat, Oct 24, 2020 at 10:40 PM Kyle Meyer <kyle@kyleam.com> wrote:

> ian martins writes:
>
> > After making the changes, should I submit updated patches or is it fine
> to
> > push?
>
> Push away.  Thanks again.
>

[-- Attachment #2: Type: text/html, Size: 600 bytes --]

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] ob-java
  2020-10-25  0:30   ` ian martins
@ 2020-10-28  9:13     ` Bastien
  2020-10-31 11:03       ` ian martins
  0 siblings, 1 reply; 31+ messages in thread
From: Bastien @ 2020-10-28  9:13 UTC (permalink / raw)
  To: ian martins; +Cc: Org-Mode mailing list

ian martins <ianxm@jhu.edu> writes:

> But I want to follow your conventions. I will put the authors of ob-C
> and ob-python (Eric Schulte and Dan Davison) as the authors of
> ob-java and ob-haxe. The implementations are nearly the same. it
> wouldn't make sense for them to have different authors.

Thanks for doing so!

-- 
 Bastien


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] ob-java
  2020-10-28  9:13     ` Bastien
@ 2020-10-31 11:03       ` ian martins
  0 siblings, 0 replies; 31+ messages in thread
From: ian martins @ 2020-10-31 11:03 UTC (permalink / raw)
  To: Bastien; +Cc: Org-Mode mailing list

[-- Attachment #1: Type: text/plain, Size: 2575 bytes --]

As I was trying to decide who is the author of the ob-java docs, I realized
it's not clear how you're defining authorship due to my confusion about
ob-java.  I can think of three ways to determine authorship:

1. the person that wrote it
2. the people who influenced the code
3. the first person to check in the filename

At first I thought I wrote ob-java by rule 1.  I didn't start from the old
ob-java, and I replaced the entire file.  The patch shows only 10 random
lines of over 400 matched the original ob-java.  If we don't count the
lines that also match ob-template.el, there are only 5.

When you said I didn't write it I thought rule 2 was the next most
reasonable, so I made the authors those that wrote the code that I
referenced.  But after thinking about it more it can't be this.  Adding
languages to babel isn't documented well enough for anyone to do it without
looking at an existing implementation, so going by rule 2 all languages
would be authored by whoever wrote the first one, and they're not.

I'm not sure but I think you'd say I wrote ob-haxe, the ob-haxe tests, the
ob-java tests, and the ob-java docs, but not ob-java.  These match up with
rule 3.  I don't think rule 3 is the one anyone would pick from the list,
but maybe most would subconsciously use it as a heuristic for rule 1, since
rule 1 is hard to establish.  I think the change in authorship is clear for
ob-java because it was replaced in one patch, usually changes are
incremental.  Each file is The Ship of Theseus.  Even if we took the
trouble to determine how much any person wrote, it is difficult to decide
for oneself let alone agree on the amount of change required to establish
new authorship.

But rule 3 doesn't work if a file is rewritten.  If Dostoevsky checks in
the text of "Crime and Punishment" as book.txt, and then Dr. Seuss replaces
the content with "The Cat in the Hat," we'd have to say Dostoevsky wrote
"The Cat in the Hat."

So I think either you didn't notice that I'd replaced the file, or you
considered the lines that matched sufficient for continuity, or you're
thinking about authorship in a way I haven't guessed.  Could you clarify?

On Wed, Oct 28, 2020 at 5:13 AM Bastien <bzg@gnu.org> wrote:

> ian martins <ianxm@jhu.edu> writes:
>
> > But I want to follow your conventions. I will put the authors of ob-C
> > and ob-python (Eric Schulte and Dan Davison) as the authors of
> > ob-java and ob-haxe. The implementations are nearly the same. it
> > wouldn't make sense for them to have different authors.
>
> Thanks for doing so!
>
> --
>  Bastien
>

[-- Attachment #2: Type: text/html, Size: 3112 bytes --]

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] ob-java
  2020-10-25 19:36           ` ian martins
@ 2020-11-05 16:29             ` Jarmo Hurri
  2020-11-05 17:10               ` ian martins
  0 siblings, 1 reply; 31+ messages in thread
From: Jarmo Hurri @ 2020-11-05 16:29 UTC (permalink / raw)
  To: emacs-orgmode


Hi there!

I noticed that a lot of work is being put into Java in Babel. Excellent.

Being a heavy user, I wonder if worg documentation page is being kept up
to date with the changes?

https://orgmode.org/worg/org-contrib/babel/languages/ob-doc-java.html

All the best, and stay safe.

Jarmo



^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] ob-java
  2020-11-05 16:29             ` Jarmo Hurri
@ 2020-11-05 17:10               ` ian martins
  2020-11-06  5:21                 ` Jarmo Hurri
  0 siblings, 1 reply; 31+ messages in thread
From: ian martins @ 2020-11-05 17:10 UTC (permalink / raw)
  To: Jarmo Hurri; +Cc: Org-Mode mailing list

[-- Attachment #1: Type: text/plain, Size: 515 bytes --]

Yes, that page is up to date. Actually, the page is new.

Are you using the latest? Were there any issues when you updated?

On Thu, Nov 5, 2020, 11:32 AM Jarmo Hurri <jarmo.hurri@iki.fi> wrote:

>
> Hi there!
>
> I noticed that a lot of work is being put into Java in Babel. Excellent.
>
> Being a heavy user, I wonder if worg documentation page is being kept up
> to date with the changes?
>
> https://orgmode.org/worg/org-contrib/babel/languages/ob-doc-java.html
>
> All the best, and stay safe.
>
> Jarmo
>
>
>

[-- Attachment #2: Type: text/html, Size: 1000 bytes --]

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] ob-java
  2020-11-05 17:10               ` ian martins
@ 2020-11-06  5:21                 ` Jarmo Hurri
  2020-11-06 23:00                   ` ian martins
  2020-11-11  7:45                   ` Bastien
  0 siblings, 2 replies; 31+ messages in thread
From: Jarmo Hurri @ 2020-11-06  5:21 UTC (permalink / raw)
  To: emacs-orgmode


Hello Ian.

ian martins <ianxm@jhu.edu> writes:

>> Being a heavy user, I wonder if worg documentation page is being kept
>> up to date with the changes?
> Yes, that page is up to date. Actually, the page is new.

Brilliant! So the only thing that was not up to date was me.

(I wonder if it would be possible to have timestamps in worg. I have
bumped into situations before where I have not known the temporal
relationship between worg documentation and current org version.)

> Are you using the latest? 

Yes.

> Were there any issues when you updated?

At some point I was using the latest at that time, and my org java stuff
broke in the middle of a presentation during class. I have not had the
time to check whether the very latest solves these issues. I will start
preparing some new material now, and will let you know if anything weird
happens.

I greatly appreciate the effort you are putting into this package.

All the best, and stay safe.

Jarmo



^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] ob-java
  2020-11-06  5:21                 ` Jarmo Hurri
@ 2020-11-06 23:00                   ` ian martins
  2020-11-09 14:06                     ` Jarmo Hurri
  2020-11-10  6:29                     ` Jarmo Hurri
  2020-11-11  7:45                   ` Bastien
  1 sibling, 2 replies; 31+ messages in thread
From: ian martins @ 2020-11-06 23:00 UTC (permalink / raw)
  To: Org-Mode mailing list

[-- Attachment #1: Type: text/plain, Size: 1277 bytes --]

I'm sorry that happened. It must have been frustrating. If you executed a
code block and no result was added to the buffer, then there's a chance it
is fixed.

Let me know how it goes.

On Fri, Nov 6, 2020 at 12:21 AM Jarmo Hurri <jarmo.hurri@iki.fi> wrote:

>
> Hello Ian.
>
> ian martins <ianxm@jhu.edu> writes:
>
> >> Being a heavy user, I wonder if worg documentation page is being kept
> >> up to date with the changes?
> > Yes, that page is up to date. Actually, the page is new.
>
> Brilliant! So the only thing that was not up to date was me.
>
> (I wonder if it would be possible to have timestamps in worg. I have
> bumped into situations before where I have not known the temporal
> relationship between worg documentation and current org version.)
>
> > Are you using the latest?
>
> Yes.
>
> > Were there any issues when you updated?
>
> At some point I was using the latest at that time, and my org java stuff
> broke in the middle of a presentation during class. I have not had the
> time to check whether the very latest solves these issues. I will start
> preparing some new material now, and will let you know if anything weird
> happens.
>
> I greatly appreciate the effort you are putting into this package.
>
> All the best, and stay safe.
>
> Jarmo
>
>
>

[-- Attachment #2: Type: text/html, Size: 1799 bytes --]

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] ob-java
  2020-11-06 23:00                   ` ian martins
@ 2020-11-09 14:06                     ` Jarmo Hurri
  2020-11-10 13:14                       ` ian martins
  2020-11-10  6:29                     ` Jarmo Hurri
  1 sibling, 1 reply; 31+ messages in thread
From: Jarmo Hurri @ 2020-11-09 14:06 UTC (permalink / raw)
  To: emacs-orgmode


Hello Ian!

ian martins <ianxm@jhu.edu> writes:

> Let me know how it goes.

The new version seems to be sensitive to whitespace:

# -------------------------------------------------
* this one works
  #+begin_src java :classname Foo :results output
    public class Foo
    {
      public static void main(String[] args)
      {
        System.out.print("hello, world");
      }
    }
  #+end_src

  #+RESULTS:
  : hello, world

* this one does not (space after word =main=)
  #+begin_src java :classname Foo2 :results output
    public class Foo2
    {
      public static void main (String[] args)
      {
        System.out.print("hello, world");
      }
    }
  #+end_src
# -------------------------------------------------

All the best,

Jarmo



^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] ob-java
  2020-11-06 23:00                   ` ian martins
  2020-11-09 14:06                     ` Jarmo Hurri
@ 2020-11-10  6:29                     ` Jarmo Hurri
  2020-11-14 11:47                       ` Jarmo Hurri
  1 sibling, 1 reply; 31+ messages in thread
From: Jarmo Hurri @ 2020-11-10  6:29 UTC (permalink / raw)
  To: emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 998 bytes --]

ian martins <ianxm@jhu.edu> writes:

> Let me know how it goes.

Hello again.

It seems that you have changed some classloader settings in the new
code. I have examples which used to work perfectly; now they still
compile, but fail to run, throwing exception

java.lang.NoClassDefFoundError

explained here:

https://stackoverflow.com/questions/17973970/how-to-solve-java-lang-noclassdeffounderror

I have attached a minimal example demontrating the problem.

1. You can see the error if you evaluate the code in the org
   file. Please observer that the submodule java file has been compiled
   to a class just fine.
   
2. If you untangle the org file, and then run

   javac LoadError.java
   java LoadError

   you should see that there is no problem with the code.

This issue is critical for me, because a lot of code I have depends on
other code (in git submodules).

Can you please tell me how this proceeds? (I may have to roll back to an
earlier org version soon.)

All the best,

Jarmo


[-- Attachment #2: load error demo --]
[-- Type: application/gzip, Size: 399 bytes --]

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] ob-java
  2020-11-09 14:06                     ` Jarmo Hurri
@ 2020-11-10 13:14                       ` ian martins
  0 siblings, 0 replies; 31+ messages in thread
From: ian martins @ 2020-11-10 13:14 UTC (permalink / raw)
  To: Org-Mode mailing list

[-- Attachment #1: Type: text/plain, Size: 941 bytes --]

That is true. I will make it less rigid.

On Mon, Nov 9, 2020 at 9:07 AM Jarmo Hurri <jarmo.hurri@iki.fi> wrote:

>
> Hello Ian!
>
> ian martins <ianxm@jhu.edu> writes:
>
> > Let me know how it goes.
>
> The new version seems to be sensitive to whitespace:
>
> # -------------------------------------------------
> * this one works
>   #+begin_src java :classname Foo :results output
>     public class Foo
>     {
>       public static void main(String[] args)
>       {
>         System.out.print("hello, world");
>       }
>     }
>   #+end_src
>
>   #+RESULTS:
>   : hello, world
>
> * this one does not (space after word =main=)
>   #+begin_src java :classname Foo2 :results output
>     public class Foo2
>     {
>       public static void main (String[] args)
>       {
>         System.out.print("hello, world");
>       }
>     }
>   #+end_src
> # -------------------------------------------------
>
> All the best,
>
> Jarmo
>
>
>

[-- Attachment #2: Type: text/html, Size: 1479 bytes --]

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] ob-java
  2020-11-06  5:21                 ` Jarmo Hurri
  2020-11-06 23:00                   ` ian martins
@ 2020-11-11  7:45                   ` Bastien
  1 sibling, 0 replies; 31+ messages in thread
From: Bastien @ 2020-11-11  7:45 UTC (permalink / raw)
  To: Jarmo Hurri; +Cc: emacs-orgmode

Hi Jarmo,

Jarmo Hurri <jarmo.hurri@iki.fi> writes:

> (I wonder if it would be possible to have timestamps in worg. I have
> bumped into situations before where I have not known the temporal
> relationship between worg documentation and current org version.)

Good point.  I think worg documentation, when related to a specific
Org feature, should mention the Org version it relates to, rather than
a timestamp.  As an additional info, the timestamp is good, but not
enough.

Let's try to follow this convention from now on.

-- 
 Bastien


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] ob-java
  2020-11-10  6:29                     ` Jarmo Hurri
@ 2020-11-14 11:47                       ` Jarmo Hurri
  2020-11-14 15:46                         ` ian martins
  0 siblings, 1 reply; 31+ messages in thread
From: Jarmo Hurri @ 2020-11-14 11:47 UTC (permalink / raw)
  To: emacs-orgmode


Hi again!

Jarmo Hurri <jarmo.hurri@iki.fi> writes:

> It seems that you have changed some classloader settings in the new
> code. I have examples which used to work perfectly; now they still
> compile, but fail to run, throwing exception
>
> java.lang.NoClassDefFoundError

I had some extra time today, so I took a look at ob-java.el. Unless
header argument dir is set, java is run in a temporary directory. So I
can get around this problem by setting header argument

:dir "."

which is nice, at least as a workaround.

I am not sure what the default behaviour should be. At the moment,
though, I do not think temporary dir is a good default, because by
default the program will then the "miss" all opened (data) files as
well. Right?

Perhaps all babel languages have a common policy here that I am not
aware of.

But in any case it looks to me that the behaviour has changed now, so if
it is changed in the stable branch (I am running master), I think it
should be documented clearly (as an incompatible change). Perhaps it
already is documented like that.

All the best, and stay safe.

Jarmo



^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] ob-java
  2020-11-14 11:47                       ` Jarmo Hurri
@ 2020-11-14 15:46                         ` ian martins
  2020-11-15  4:36                           ` Jarmo Hurri
  0 siblings, 1 reply; 31+ messages in thread
From: ian martins @ 2020-11-14 15:46 UTC (permalink / raw)
  To: Jarmo Hurri; +Cc: Org-Mode mailing list

On Sat, Nov 14, 2020 at 6:48 AM Jarmo Hurri <jarmo.hurri@iki.fi> wrote:
> Jarmo Hurri <jarmo.hurri@iki.fi> writes:
>
> > It seems that you have changed some classloader settings in the new
> > code. I have examples which used to work perfectly; now they still
> > compile, but fail to run, throwing exception
> >
> > java.lang.NoClassDefFoundError
>
> I had some extra time today, so I took a look at ob-java.el. Unless
> header argument dir is set, java is run in a temporary directory. So I
> can get around this problem by setting header argument
>
> :dir "."
>
> which is nice, at least as a workaround.

It looks like you quoted a previous email there but I never saw it.

You're right that this is a change. I will revert the default
behaviour. in the meantime you could do something like

(setq org-babel-default-header-args:java
      (cons '(:dir . ".")
            org-babel-default-header-args:java))

in your init file after loading org to fix it everywhere.

> I am not sure what the default behaviour should be. At the moment,
> though, I do not think temporary dir is a good default, because by
> default the program will then the "miss" all opened (data) files as
> well. Right?

I agree we should not change the default behavior, but I'm not sure
about data files. The run directory shouldn't change, just the place
where the files are written. when I run this block the java and
classfiles are written to my babel temp dir but it prints out the path
of the org file.

#+begin_src java :results output silent
    System.out.println( System.getProperty("user.dir"));
#+end_src

> Perhaps all babel languages have a common policy here that I am not
> aware of.

I've not seen it documented, but the other babel languages I've used
write to the temp dir. Java is the only one I'm aware of that
defaulted to writing to the current directory.

> But in any case it looks to me that the behaviour has changed now, so if
> it is changed in the stable branch (I am running master), I think it
> should be documented clearly (as an incompatible change). Perhaps it
> already is documented like that.

Yes, you're right that is a change. The current behavior is documented
in ob-doc-java [1], but it isn't called out as a change in behavior.
This is because I didn't notice it as a change, or I'd have not done
it. These changes happened in part because I wrote ob-java in a
circuitous way. I first wrote ob-haxe (for the language haxe) based on
ob-C and ob-python and then made ob-java from it. When I wrote ob-haxe
I wasn't thinking about maintaining ob-java behaviour, and it wasn't
documented, and there weren't tests, so when I had a new ob-java it
wasn't easy to see what might have changed. It is very helpful that
you tested your existing source blocks and investigated changes.
Thanks for reporting. I'll bring back the old default behavior.

[1] https://orgmode.org/worg/org-contrib/babel/languages/ob-doc-java.html#org932f876


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] ob-java
  2020-11-14 15:46                         ` ian martins
@ 2020-11-15  4:36                           ` Jarmo Hurri
  2020-11-17 12:07                             ` ian martins
  0 siblings, 1 reply; 31+ messages in thread
From: Jarmo Hurri @ 2020-11-15  4:36 UTC (permalink / raw)
  To: emacs-orgmode


ian martins <ianxm@jhu.edu> writes:

>> > It seems that you have changed some classloader settings in the new
>> > code. I have examples which used to work perfectly; now they still
>> > compile, but fail to run, throwing exception
>> >
>> > java.lang.NoClassDefFoundError
>>
>> I had some extra time today, so I took a look at ob-java.el. Unless
>> header argument dir is set, java is run in a temporary directory. So I
>> can get around this problem by setting header argument
>>
>> :dir "."
>>
>> which is nice, at least as a workaround.
>
> You're right that this is a change. I will revert the default
> behaviour. in the meantime you could do something like
>
> (setq org-babel-default-header-args:java
>       (cons '(:dir . ".")
>             org-babel-default-header-args:java))
>
> in your init file after loading org to fix it everywhere.

Thanks a bunch, will do.

All the best, and stay safe.

Jarmo



^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] ob-java
  2020-11-15  4:36                           ` Jarmo Hurri
@ 2020-11-17 12:07                             ` ian martins
  0 siblings, 0 replies; 31+ messages in thread
From: ian martins @ 2020-11-17 12:07 UTC (permalink / raw)
  To: Org-Mode mailing list

On Sat, Nov 14, 2020 at 6:48 AM Jarmo Hurri <jarmo.hurri@iki.fi> wrote:
>
> >> > It seems that you have changed some classloader settings in the new
> >> > code. I have examples which used to work perfectly; now they still
> >> > compile, but fail to run, throwing exception
> >> >
> >> > java.lang.NoClassDefFoundError
> >>

This should be fixed with 93087e0b3a. Thanks for reporting, and sorry
I missed your first email. I found it. It went to spam for some
reason.

Also I added two sections to the doc: one that explains the current
defaults and tells how to change them [1], and another that explains
where source and class files go [2].

[1] https://orgmode.org/worg/org-contrib/babel/languages/ob-doc-java.html#orgb4194fe
[2] https://orgmode.org/worg/org-contrib/babel/languages/ob-doc-java.html#org0948fdf


^ permalink raw reply	[flat|nested] 31+ messages in thread

end of thread, other threads:[~2020-11-17 12:08 UTC | newest]

Thread overview: 31+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-10-05 12:35 [PATCH] ob-java ian martins
2020-10-05 13:23 ` ian martins
2020-10-09 11:15   ` ian martins
2020-10-20 18:28     ` John Herrlin
2020-10-20 19:17     ` John Herrlin
2020-10-21  2:37       ` ian martins
2020-10-21  5:59         ` John Herrlin
2020-10-21 12:47           ` ian martins
2020-10-21 13:54             ` John Herrlin
2020-10-22 12:23               ` ian martins
2020-10-22 12:56                 ` John Herrlin
2020-10-24 17:05     ` Kyle Meyer
2020-10-25  2:10       ` ian martins
2020-10-25  2:40         ` Kyle Meyer
2020-10-25 19:36           ` ian martins
2020-11-05 16:29             ` Jarmo Hurri
2020-11-05 17:10               ` ian martins
2020-11-06  5:21                 ` Jarmo Hurri
2020-11-06 23:00                   ` ian martins
2020-11-09 14:06                     ` Jarmo Hurri
2020-11-10 13:14                       ` ian martins
2020-11-10  6:29                     ` Jarmo Hurri
2020-11-14 11:47                       ` Jarmo Hurri
2020-11-14 15:46                         ` ian martins
2020-11-15  4:36                           ` Jarmo Hurri
2020-11-17 12:07                             ` ian martins
2020-11-11  7:45                   ` Bastien
2020-10-24 11:58 ` Bastien
2020-10-25  0:30   ` ian martins
2020-10-28  9:13     ` Bastien
2020-10-31 11:03       ` ian martins

unofficial mirror of emacs-orgmode@gnu.org

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://yhetil.org/orgmode/0 orgmode/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 orgmode orgmode/ https://yhetil.org/orgmode \
		emacs-orgmode@gnu.org
	public-inbox-index orgmode

Example config snippet for mirrors.
Newsgroups are available over NNTP:
	nntp://news.yhetil.org/yhetil.emacs.orgmode
	nntp://news.gmane.io/gmane.emacs.orgmode


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git