创建交互式ruby控制台应用程序

时间:2012-03-24 17:28:03

标签: ruby console interactive

我想在用户启动时创建交互式应用程序,并可以通过键入命令(某种shell)来执行各种任务

例如:

./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)

我搜索过但无法找到任何我可以专门用于控制台互动的红宝石宝石,所以我要自己创作...

我看了Thor,但那并不完全符合我的要求,也许我可以使用它,但不确定......

它可能看起来像:

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 个答案:

答案 0 :(得分:18)

您想要的是REPL - Read → Evaluate → Print Loop

例如,IRB为Ruby语言实现了一个REPL。

这是应用程序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分别匹配字符串的开头和字符串的结尾。

答案 1 :(得分:5)

您也可以尝试ripl。 (来自文档): 创建和启动自定义shell非常简单:

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

有一个完整的ripl插件列表以及项目网站上使用ripl的控制台应用程序列表。

答案 2 :(得分:5)

好的,所以我创建了这个库,用于在ruby中创建控制台应用程序。实际上它是在不久前,但只是决定释放它。如果与HighLine和Readline一起使用,它确实支持自动完成。

当我写它时,没有任何文档或测试/规格,但现在我做了一些。仍然不多,但开始应该没问题。

所以宝石cli-console和 代码在GitHub,这里是usage example

答案 3 :(得分:5)

TTY对于轻松做这类事情来说是一个非常好的宝石。你有很多工具可以单独使用或使用完整的toolKit。您可以使用颜色,提示,执行shell本机,与屏幕交互,打印表格,进度条以及命令行的许多其他有用元素,这些都是goop 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

答案 4 :(得分:4)

看看cliqr红宝石宝石。它看起来就像你需要的。以下是带有描述性自述文件的github链接:https://github.com/anshulverma/cliqr

它可以直接或在内置shell中执行命令。

以下是来自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

答案 5 :(得分:2)

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命令,但这会击败 图灵完备。我可以使用命令实现帮助 不确定我的方法有多好。那些方法需要 编码防御。我不记得如何使用类变量: - /