Создание интерактивного консольного приложения ruby - PullRequest
14 голосов
/ 24 марта 2012

Я хочу создать интерактивное приложение, где пользователь запускает его и может выполнять различные задачи, набирая команды (какая-то оболочка)

пример:

./myapp.rb  
App says Hi  
Commands:   
  help - display help about command
  open - open task
  do - do action
Start>help open
  open <TaskName>
  opens specified task
Start>open Something  
Something>do SomeAction
  Success!
Something> (blinking cursor here)

Я искал, но не смогЯ не нашел рубиновых самоцветов, которые мог бы использовать специально для взаимодействия с консолью, так что я собираюсь сделать свой собственный ...

Я посмотрел на Тор , но это не совсем такЯ хочу, может быть, я мог бы использовать это, но не уверен ...

это может выглядеть примерно так:

class Tasks
  attr_reader :opened_task

  desc "open <TaskName>", "opens specified task"
  def open(params)
  end

  desc "do <ActionName>", "do specified action"
  def do(params)
  end
end

tasks = Tasks.new
# theoretical Console class
console = Console.new
console.addCommand("open",tasks.method(:open),"open task")
console.addCommand("do",tasks.method(:do),"do action")
console.start("%s>",[*tasks.opened_task])

поэтому мой вопрос, какие драгоценные камни я мог бы использовать, чтобы сделать такую ​​консольучебный класс?может кто-то уже сделал что-то подобное?Я планирую использовать HighLine для ввода / вывода, но какие-либо другие предложения, которые я мог бы использовать?

Ответы [ 6 ]

18 голосов
/ 24 марта 2012

То, что вы хотите, это REPL - Read → Evaluate → Print Loop.

IRB, например, реализует REPL для языка Ruby.

Вот очень простая реализация REPL вашего приложения:

loop do
  Application::Console.prompt.display
  input = gets.chomp
  command, *params = input.split /\s/

  case command
  when /\Ahelp\z/i
    puts Application::Console.help_text
  when /\Aopen\z/i
    Application::Task.open params.first
  when /\Ado\z/i
    Application::Action.perform *params
  else puts 'Invalid command'
  end
end

\A и \z соответствуют началу строки и концу строки соответственно.

5 голосов
/ 25 сентября 2017

TTY - действительно хороший драгоценный камень для того, чтобы легко делать такие вещи. У вас есть много инструментов, которые могут работать в одиночку или с полным набором инструментов. Вы можете использовать цвета, подсказки, выполнять встроенные функции оболочки, взаимодействовать с экраном, печатать таблицы, индикаторы выполнения и многие другие полезные элементы командных строк с помощью простого API-интерфейса.

Особенно tty-prompt действительно полезен для запроса ввода данных пользователем.

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

require 'tty-prompt'
require 'pastel'

prompt = TTY::Prompt.new
loop do
  cmd, parms* = prompt.ask('user@machine$ ').split /\s/
  case cmd
    when "hola"
      puts "Hola amigo " parms
    when "exit"
      break if prompt.yes?('Do you really want to exit?')
  end
end
5 голосов
/ 03 марта 2013

хорошо, поэтому я сделал эту библиотеку для создания консольных приложений в ruby. На самом деле это было некоторое время назад, но только решил выпустить его. Он поддерживает автозаполнение, если используется с HighLine и Readline.

Когда я писал это, не было ни документации, ни тестов / спецификаций, но теперь я сделал некоторые. Еще немного, но для начала все должно быть в порядке.

So gem cli-console и код на GitHub, вот пример использования

5 голосов
/ 26 марта 2012

Вы также можете попробовать ripl .(из документации): Создание и запуск пользовательской оболочки так же просто, как:

require 'ripl'
# Define plugins, load files, etc...
Ripl.start

На веб-сайте проектов есть полный список плагинов для ripl, а также список консольных приложений, использующих ripl.

4 голосов
/ 16 июня 2015

Взгляните на cliqr рубиновый камень. Похоже, именно то, что вам нужно. Вот ссылка на GitHub с описательным readme: https://github.com/anshulverma/cliqr

Может выполнять команды напрямую или внутри встроенной оболочки.

Вот тестовый пример из его git repo:

    it 'can execute a sub action from shell' do
      cli = Cliqr.interface do
        name 'my-command'
        handler do
          puts 'base command executed'
        end

        action :foo do
          handler do
            puts 'foo executed'
          end

          action :bar do
            handler do
              puts 'bar executed'
            end
          end
        end
      end

      with_input(['', 'my-command', 'foo', 'foo bar', 'foo bar help']) do
        result = cli.execute %w(my-command shell), output: :buffer
        expect(result[:stdout]).to eq <<-EOS
Starting shell for command "my-command"
my-command > .
base command executed
my-command > my-command.
base command executed
my-command > foo.
foo executed
my-command > foo bar.
bar executed
my-command > foo bar help.
my-command foo bar

USAGE:
    my-command foo bar [actions] [options] [arguments]

Available options:

    --help, -h  :  Get helpful information for action "my-command foo bar" along with its usage information.

Available actions:
[ Type "my-command foo bar help [action-name]" to get more information about that action ]

    help -- The help action for command "my-command foo bar" which provides details and usage information on how to use the command.
my-command > exit.
shell exited with code 0
        EOS
      end
    end
2 голосов
/ 25 марта 2012
class MyAPI
  def self.__is__(text)
    @__is__ = text
  end

  def self.method_added(method)
    @__help__ ||= {}
    @__help__[method.to_s] = @__is__
    @__is__ = nil
  end

  def self.help(of)
    @__help__[of]
  end

  __is__ "open file <file>"
  def open(file)
    #...
  end

  __is__ "do X"
  def do(*params)
    #...
  end

  __is__ "calls help, use help <command>"
  def help(*args, &block)
    self.class.help(*args, &block)
  end
end

MyAPI.new(...).pry

Или вы можете использовать команды pry, но это нарушает полноту тьюринга.Помощь может быть реализована с помощью команд, так как я не уверен, насколько хорошо мой подход работает.Эти методы должны быть закодированы как защитные.Я не могу вспомнить, как использовать переменные класса: - /

...