Как перейти в repl из приложения командной строки Clojure?

Я пишу приложение Clojure CLI, и я хотел бы разрешить ему дать команду, которая перебросит людей в REPL clojure.main.

Кто-нибудь знает, как я могу это сделать? Мои усилия не увенчались успехом.

РЕДАКТИРОВАТЬ:

Моя проблема усугубляется тем фактом, что мой интерфейс командной строки принимает входные данные по конвейеру. Вот пример того, что я хотел бы работать:

(ns playground.core
  (:gen-class))

(defn -main
  [& args]
  (with-open [r (io/reader *in*)]
    (doseq [line (line-seq r)]
      (println line)))
;; Drop in repl after having read the input and printed its content)

Затем я называю это так:

cat ./somefile.txt | lein trampoline run

person Didier A.    schedule 07.11.2018    source источник
comment
Я не думаю, что это дубликат, потому что этот вопрос не затрагивает идею о том, что repl не обязательно должен быть первым потребителем ввода в программу и его не нужно запускать при запуске программы.   -  person Arthur Ulfeldt    schedule 08.11.2018
comment
Да, мой вопрос конкретно пытается получить ответ там, где REPL не стоит начинать в первую очередь. Программа сначала запускается, принимает входные данные от in, выполняет другие действия, а затем ей нужно перейти в REPL.   -  person Didier A.    schedule 11.11.2018
comment
CLI REPL работает через stdin и stdout, как и конвейер. Может быть, вам следует использовать nREPL/сокет REPL с pREPL и подключаться удаленно? Это сохраняет ваш стандартный ввод открытым для вашего файлового канала, но позволяет удаленно подключать REPL. В качестве альтернативы вы можете прочитать stdin затем запустить REPL, как указано в других ответах.   -  person Olical    schedule 14.11.2018
comment
@Olical Я мог бы пойти по этому пути, но дело в том, что я закончил со стандартным вводом к тому времени, когда я добавляю repl. Но кажется, что что-то в стандартном вводе вызывает закрытие REPL сразу после его запуска.   -  person Didier A.    schedule 14.11.2018


Ответы (2)


Может быть, вам подойдет запуск безголового REPL и два отдельных шага?

Шаг 1

Запустите безголовый REPL, подождите, пока он запустится

$ lein repl :headless :host 0.0.0.0 :port 9000
nREPL server started on port 9000 on host 0.0.0.0 - nrepl://0.0.0.0:9000

Шаг 2

В другой оболочке отправьте команды в REPL с помощью вашей команды:

$ cat test.txt 
(def hello "Hello world!")

$ cat test.txt | lein repl :connect 0.0.0.0:9000
Connecting to nREPL at 0.0.0.0:9000
REPL-y 0.3.7, nREPL 0.2.12
Clojure 1.8.0
OpenJDK 64-Bit Server VM 1.8.0_181-8u181-b13-1ubuntu0.18.04.1-b13
    Docs: (doc function-name-here)
          (find-doc "part-of-name-here")
  Source: (source function-name-here)
 Javadoc: (javadoc java-object-or-class-here)
    Exit: Control+D or (exit) or (quit)
 Results: Stored in vars *1, *2, *3, an exception in *e

pipetest.core=> (def hello "Hello world!")
#'pipetest.core/hello
pipetest.core=> Bye for now!

Шаг 3

Вы можете подключиться к REPL, продолжить после того, как состояние изменится с предыдущего шага, но теперь вы можете использовать его для взаимодействия.

$ lein repl :connect 0.0.0.0:9000
Connecting to nREPL at 0.0.0.0:9000
REPL-y 0.3.7, nREPL 0.2.12
Clojure 1.8.0
OpenJDK 64-Bit Server VM 1.8.0_181-8u181-b13-1ubuntu0.18.04.1-b13
    Docs: (doc function-name-here)
          (find-doc "part-of-name-here")
  Source: (source function-name-here)
 Javadoc: (javadoc java-object-or-class-here)
    Exit: Control+D or (exit) or (quit)
 Results: Stored in vars *1, *2, *3, an exception in *e

pipetest.core=> (str hello "!!!")
"Hello world!!!!"
person Denis Fuenzalida    schedule 17.11.2018

Вы можете просто вызвать clojure.main/repl из своей программы, и она начнет слушать стандартный ввод и «отвечать на него» ;-) в этот момент начнется repl

user> (clojure.main/repl)

затем я ввожу в терминал (+ 1 2 3)

user=> 6
user=> 

поэтому у меня был repl в repl, имитирующий случай, когда человек, использующий вашу программу, вводит команду start repl.

проект rebl-readline для удобной работы с репликами значительно расширяет возможности вызов clojure.main/repl:

(rebel-readline.core/with-line-reader
  (rebel-readline.clojure.line-reader/create
    (rebel-readline.clojure.service.local/create))
  (clojure.main/repl
     :prompt (fn []) ;; prompt is handled by line-reader
     :read (rebel-readline.clojure.main/create-repl-read)))


Поскольку ваша программа состоит из двух фаз,

  1. читать вещи со стандартного ввода навсегда или до тех пор, пока стандартный ввод не будет окончательно закрыт.
  2. как только программа мертва или стандартный ввод больше не доступен, в зависимости от того, что произойдет раньше, читайте больше из стандартного ввода.

Вы можете захотеть (или, возможно, у вас уже есть) вещь, которая вырывается из with-open после отправки какой-то специальной строки. как только это будет получено, полностью выйдите из line-seq и with-open. затем запустите repl, чтобы он мог получить дескриптор входного файла.


как только вы заставите программу получить входные данные для repl, ваша проблема с конвейером может быть решена с помощью прилагаемой команды оболочки. cat принимает специальный аргумент - (просто тире и ничего больше с пробелами с обеих сторон), который говорит: «остановитесь здесь и читайте с клавиатуры, пока не будет нажата Crtl-d»

~ » cat a-file - | cat
hello im a line from a file
hello
hello

в этом примере он прочитал строку из файла, передал ее команде cat (замените на вашу программу), затем он прочитал слово hello с клавиатуры и также напечатал его (так что вы видите его дважды на экране)

person Arthur Ulfeldt    schedule 08.11.2018
comment
Я передаю ввод в мой CLI Clojure. Например, cat somefile.txt | lein trampoline run. В этом случае ни вызов clojure.main/repl, ни использование _readline_readline не работают. Если я не передаю ввод и просто запускаю lein trampoline run, это работает. Любая идея, как я могу зайти в repl, учитывая, что я ввожу ввод? - person Didier A.; 09.11.2018
comment
@ДидьерА. добавлено немного о том, как обойти конвейерный ввод, и некоторые мнения о том, как вывести его из строки чтения - person Arthur Ulfeldt; 15.11.2018