【问题标题】:Creating interactive ruby console application创建交互式 ruby​​ 控制台应用程序
【发布时间】:2012-04-08 21:04:18
【问题描述】:

我想制作交互式应用程序,用户可以在其中启动它并可以通过键入命令(某种 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)

我搜索了但找不到任何可以专门用于控制台交互的 ruby​​ gem,所以我将自己制作...

我查看了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 进行输入/输出,但我还能使用什么其他建议?

【问题讨论】:

  • 应该是ruby还是你自己的语法?
  • 你所说的 ruby​​ 或自己的语法是什么意思? :|如果您的意思是使用 IRB,那么这不是一个选项...
  • 为什么不呢?它免费为您提供图灵完备性。
  • 因为它执行 ruby​​ 代码,但在我的情况下,只允许一些特定的“命令”,键入不正确的语法不应引发异常,也不应该有重新定义或覆盖这些命令的方法...
  • 是安全问题吗?您可以连接到pry 以查找语法错误。重新定义应该不是问题,因为您需要知道它是如何工作的。当您希望您的用户在当前敏感的东西时代使用命令行而不是 GUI 时,我会相信他们有一点权力。但这是你的选择,重新实现很多东西而不是在对象上调用 pry 会很有趣。您还可以免费获得一个 API。

标签: ruby console interactive


【解决方案1】:

你想要的是REPLRead → 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 分别匹配字符串的开头和结尾。

【讨论】:

  • 好的,感谢您展示了我如何实现控制台类方法“start”的一种方法:)
  • @davispuh 我忘记了提示 - 通过改进的实施更新了答案。您的 start 方法应该只包含循环。
  • 我接受了这个答案,因为它建议自己通过展示部分实现来制作它,所以我将制作自​​己的 CLI,特别是满足我的所有需求......
  • Console 是 Ruby 自带的类吗?如果是这样,我需要什么才能获得它?
  • @LironYahdav 不,该类是我为这个答案编写的 API 的一部分。想象一下,Console 包含与终端仿真器接口相关的所有应用程序代码,prompt 是一个读取器方法,它返回 REPL 的配置提示。
【解决方案2】:

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

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

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

【讨论】:

  • 这看起来更有希望,但仍然需要进行一些配置,并且它具有与 pry/irb 相同的“功能”,我不需要,我认为还需要很多更改/配置.. .
  • 说实话,到目前为止我还没有使用ripl - 但是从头开始编写自己的解决方案似乎不是最好的主意。只需考虑使用箭头键移动 - 没有 readline 支持,用户会发誓。
  • 在 Windows 中,命令历史记录正在运行(向上/向下箭头),我只需要使用选项卡自动完成,但一开始我什至可能没有那个...
  • @davispuh 这不仅仅是关于历史和完成。 Readline 在 shell 中为您提供了类似 emacs/vi 的绑定,许多用户非常习惯并认为这是理所当然的,因为它们默认在 Bash/Zsh 中可用。
【解决方案3】:

好的,所以我制作了这个库,用于在 ruby​​ 中创建控制台应用程序。其实是很久以前的事了,只是刚刚决定发布。如果与 HighLine 和 Readline 一起使用,它确实支持自动完成。

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

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

【讨论】:

    【解决方案4】:

    TTY 是一个非常好的宝石,可以轻松完成此类事情。您有很多可以单独使用或与完整工具包一起使用的工具。您可以使用颜色、提示、执行 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
    

    【讨论】:

    • 感谢您的评论。我正要添加示例。
    • 这不是我想要的,这是一个库,可以用来实现你展示的这样的控制台。顺便说一句,当我问这个问题时,它还不存在:D 我使用 github.com/JEG2/highline 实现了我的 CLI-Console,它做了非常相似的事情。
    【解决方案5】:

    看看cliqr ruby​​ gem。它看起来正是您所需要的。这是带有描述性自述文件的 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
    

    【讨论】:

      【解决方案6】:
      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 命令,但这会破坏 图灵完备性。可以使用命令来实现帮助,就像我一样 不确定我的方法效果如何。这些方法需要 编码防御。我不记得如何使用类变量了:-/

      【讨论】:

      • 它需要进行大量更改/配置才能使其按我的需要工作......而且我会将它用于它不是为它设计的任务并且它具有我不具备的“功能”甚至不需要...
      • @davispuh,你给cliqr(上图)打了一针吗?它不需要太多配置,而且几乎可以开箱即用。
      • @nuaavee 当我写这个问题时它还不存在,但是是的,它看起来与我需要的东西非常相似,然后只比它创建早了 3 年:D
      猜你喜欢
      • 1970-01-01
      • 2013-07-28
      • 2020-07-01
      • 2016-04-30
      • 1970-01-01
      • 2016-06-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多