REPL

Цель

Научиться реализовывать консольные приложения на основе REPL.

Начальные требования

Базовые знания Javascript.

Введение

Модуль обеспечивает имплементацию Read-Eval-Print-Loop (REPL). Он может использоваться как отдельная программа, либо же может включаться в другие приложения. Он может быть доступен с использованием:

const repl = require('repl');

Устрйство и возможности

Модуль repl module экспортирует класс repl.REPLServer. При исполнении экземпляры repl.REPLServer получит индивидуальный строки пользовательского вввода, вычислит их согласно определенным пользователем функциям вычислени, и затем выведет результат. Ввод и вывод могут быть из stdin и stdout соответственно, либо же могут быть подключены к любому потоку Node.js (stream).

Экземпляры repl.REPLServer поддерживают автозавершение ввода, упрощенное редактирование строк в стиле Emacs, многострочные ввводы, ввод в стиле ANSI, сохранение и восстановление текущего состояния сессии REPL, восстановление после ошибок и настраевыемы функции вычисления.

Команды и специальные символы.

Следующие специальные команды поддерживаются всеми экземплярами REPL:

  • .break - Когда в процессе ввода многосрочного выражения вводится команда .break (или нажимается сочетание клавиш <ctrl>-C), она прервет дальнейший ввод или обработку этого выражения.
  • .clear - Сбрасывает контекст REPL до пустого объекта и очищает любое многострочное выражение, которое вводится в данный момент
  • .exit - Закрывает все потоки ввода/вывода что приводит к выходу из REPL.
  • .help - Показывает данный список специальных команд.
  • .save - Сохраняет текущую сессию REPL в файл `> .save ./file/to/save.js `
  • .load - Загружает файл в текущую сессию REPL > .load ./file/to/load.js
  • .editor - Вход в режим редактора (<ctrl>-D чтобы закончить, <ctrl>-C чтобы прервать)
> .editor
// Entering editor mode (^D to finish, ^C to cancel)
function welcome(name) {
  return `Hello ${name}!`;
}

welcome('Node.js User');

// ^D
'Hello Node.js User!'
>

Следующие сочитаниния клавиш в REPL имеют специальный эффект:

  • <ctrl>-C - Если нажато единожды, имеет тот же эффект, что и команда .break. Если нажата дважды в пустой строке, имеет тот же эффект что и команда .exit.
  • <ctrl>-D - Имеет тот же эффект что и команда.exit.
  • <tab> - Если нажата в пустой строке, отображает глобальные и локальные переменные. Если нажато во время какого-либо ввода, отображает опции автозавершения.

Вычисление по умолчанию

По умолчанию все экземпляры repl.REPLServer используют функцию вычисления, которая вычисляет выражения JavaScript и обеспечивают доступ к встроенным модулям Node.js. Это поведение по умолчанию может быть переопределено путем передачи альтернативных функций вычисления в момет создания экземпляраrepl.REPLServer instance.

Выражения JavaScript

Функция вычисления по умолчанию поддерживает прямое вычисление выражений JavaScript:

> 1 + 1
2
> const m = 2
undefined
> m + 1
3

Переменные определенные явно с помощью const, let, or varсуществуют в глобальной области видимости, если их область видимости не определена иначе с помощью функций или блоков.

Глобальная и локальная область видимости

Функция вычисления по умолчанию обеспечивает доступ к любым переменным, которые существую в глобальной области видимости. Есть возможность сделать переменную видимой для REPL явно, путем назначения ее в объекте context, связанном с каждым REPLServer. Например:

const repl = require('repl');
const msg = 'message';

repl.start('> ').context.m = msg;

Свойства в объектеcontexto ппоявляются как локальные внутри REPL:

$ node repl_test.js
> m
'message'

Важно отметит что свойства контекста не ограничены только для чтения по умолчанию. Чтобы объявить глобальные значения только для чтени, свойства контекста должны быть определены с испольованиемObject.defineProperty():

const repl = require('repl');
const msg = 'message';

const r = repl.start('> ');
Object.defineProperty(r.context, 'm', {
  configurable: false,
  enumerable: true,
  value: msg
});

Доступ к встроенным модулям Node.js

Функция вычисления по умолчанию автоматически загружает встроенные модули Node.js в окружение REPL при ее вызове. Например, если нет других объявлений глобальных или локальных переменных, введенное слово fs будет эквивалентно global.fs = require('fs').

> fs.createReadStream('./some/file');

Присвоение переменной _ (underscore)

Функция вычисления по умолчанию будет присваивать результат самых последних вычислений выражений специальной переменной _ (underscore). Явное присвоение _ какой либо переменной отменит это поведение.

> [ 'a', 'b', 'c' ]
[ 'a', 'b', 'c' ]
> _.length
3
> _ += 1
Expression assignment to _ now disabled.
4
> 1 + 1
2
> _
4

Функция вычисления определенная пользователем

Во время создания нового экземпляра repl.REPLServer is reated, можно определить новую функцию вычисления. Это может быть использвано, например, для разработки полностью настроенного пользователем приложения REPL.

Ниже приведен гипотетический пример REPL который выполняет перевод текста с одного языка на другой:

const repl = require('repl');
const { Translator } = require('translator');

const myTranslator = new Translator('en', 'fr');

function myEval(cmd, context, filename, callback) {
  callback(null, myTranslator.translate(cmd));
}

repl.start({ prompt: '> ', eval: myEval });

Исправляемые ошибки

В то время как пользователь осуществляет ввод в приглашении REPL, нажатие клавиши <enter> пошлет текущую строку функции eval. Для поддержки многострочного ввода эта функция может вернуть экземпляр repl.Recoverable предоставленной колбэк функции:

function myEval(cmd, context, filename, callback) {
  let result;
  try {
    result = vm.runInThisContext(cmd);
  } catch (e) {
    if (isRecoverableError(e)) {
      return callback(new repl.Recoverable(e));
    }
  }
  callback(null, result);
}

function isRecoverableError(error) {
  if (error.name === 'SyntaxError') {
    return /^(Unexpected end of input|Unexpected token)/.test(error.message);
  }
  return false;
}

Настройка вывода REPL

По умолчанию экземпляры repl.REPLServer форматируют вывод с использованием util.inspect() перед тем как послать его на предоставленный поток для записи (по умолчанию process.stdout). Булевская опция useColors может быть назначена во время конструирования экземпляра чтобы заставить функцию записи использовать коды ANSI для раскраски вывода из метода util.inspect().

Существует возможность полностью настроит вывод экземпляра repl.REPLServer instance путем передачи новой функции в опцию writer при конструировании экземпляра. Приведенный ниже пример просто преобразует весь вывод в верхний регистр.

const repl = require('repl');

const r = repl.start({ prompt: '> ', eval: myEval, writer: myWriter });

function myEval(cmd, context, filename, callback) {
  callback(null, cmd);
}

function myWriter(output) {
  return output.toUpperCase();

Класс REPLServer

Класс repl.REPLServer наследуется от класса readline.Interface. Экземпляры repl.REPLServer создаются с помощью метода repl.start() и не должны создаваться напрямую с помощью ключевого слова new. Описание класса, его свойств и методов см. в документации.

Практическое задание

  1. Написать приложение, которое переводит введенный пользователем цвет с английского на русский (достаточно трех цветов).
  2. Сделать так, чтобы выводимый перевод подкрашивался соответствующим цветом.

results matching ""

    No results matching ""