2012-03-24 8 views
12

I interaktive Anwendung machen will, wo es Benutzer starten und können durch Eingabe von Befehlen (eine Art von Shell)Erstellen interaktive Rubin Konsolenanwendung

Beispiel verschiedene Aufgaben tun:

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

ich aber couldn gesucht Finde keine Ruby-Edelsteine, die ich speziell für die Konsoleninteraktion verwenden könnte, also bin ich dabei, meine eigene zu machen ...

Ich schaute auf Thor, aber das ist nicht genau so wie ich wa nt, vielleicht könnte ich es verwenden, aber nicht sicher ...

es etwas aussehen könnte:

meine Frage ist
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]) 

ja, welche Edelsteine ​​kann ich verwende solche Konsole Klasse zu machen? Vielleicht hat jemand schon etwas Ähnliches gemacht? Ich plane mit HighLine für die Eingabe/Ausgabe, aber jeden anderen Vorschlag, was ich verwenden könnte?

+0

Sollte es Rubin oder Ihre eigene Syntax sein? – Reactormonk

+0

was meinen Sie mit Ruby oder eigene Syntax? : | Wenn Sie IRB verwenden, dann ist das keine Option ... – davispuh

+1

Warum nicht? Es gibt Ihnen Turing-Vollständigkeit umsonst. – Reactormonk

Antwort

17

Was Sie wollen, ist ein REPL - Read → Evaluate → Print Loop.

IRB zum Beispiel implementiert eine REPL für die Ruby-Sprache.

Hier ist eine sehr einfache Implementierung von REPL Ihrer Anwendung:

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 und \z Spiel der Anfang des Strings und das Ende des Strings sind.

+0

okay danke fürs anzeigen wie ich die konsole klassenmethode "start" implementieren könnte :) – davispuh

+0

@davispuh ich habe die prompt - update antwort mit einem vergessen verbesserte Implementierung. Ihre 'start' Methode sollte nur die Schleife enthalten. –

+2

Ich akzeptiere diese Antwort, weil sie es mir selbst empfiehlt, indem ich einen Teil der Implementierung zeige, damit ich mein eigenes CLI speziell für alle meine Bedürfnisse erstellen kann ... – davispuh

1
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 

Oder könnten Sie hebeln Befehle verwenden, aber das besiegt die Turing-Vollständigkeit. Hilfe könnte mithilfe von Befehlen implementiert werden, da ich nicht sicher bin, wie gut mein Ansatz funktioniert. Diese Methoden müssen codiert defensiv sein. Ich kann mich nicht erinnern, wie man Klassenvariablen benutzt: -

+0

es erfordert eine Menge von Änderungen/Konfiguration, damit es funktioniert, wie ich brauche ... auch würde ich es für eine Aufgabe verwenden, für die es nicht gemacht wurde, und es hat "Funktionen", die ich nicht einmal brauche ... – davispuh

+0

@davispuh, hast du 'cliqr' (oben) geschossen? Es erfordert nicht viel Konfiguration und funktioniert fast out of the Box. – nuaavee

+0

@nuaavee als ich diese Frage schrieb, existierte sie damals noch nicht, aber ja, es sieht etwas sehr ähnlich aus was ich damals nur 3 Jahre früher brauchte als es erstellt wurde: D – davispuh

4

Sie könnten auch versuchen ripl. (Aus der Dokumentation): Erstellen und eine benutzerdefinierten Shell-Start ist so einfach wie:

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

Es ist eine umfassende Liste von Plugins für RIPL sowie Liste der Konsolenanwendungen RIPL auf den Projekten Website.

+0

das sieht vielversprechender aus, muss aber noch etwas konfigurieren und wieder haben sie dieselben "features" die ich nicht brauche wie pry/irb, auch ich denke da müssen ziemlich viele änderungen/konfigurationen ... – davispuh

+2

Um ehrlich zu sein, habe ich 'ripl' bisher nicht benutzt - aber schreiben Ihre eigene Lösung von Grund auf scheint nicht die beste Idee zu sein. Berücksichtigen Sie nur die Bewegung mit der Pfeiltaste - ohne Readline-Unterstützung werden die User fluchen. –

+0

in Windows, Befehl Geschichte funktioniert (Up/Down Pfeile), ich muss nur Auto-Vervollständigung mit Tab machen, aber am Anfang könnte ich sogar ohne das leben ... – davispuh

4

ok, also habe ich diese Bibliothek zum Erstellen von Konsolenanwendungen in Ruby gemacht. Eigentlich war es vor einiger Zeit, aber nur gerade beschlossen, es zu veröffentlichen. Es unterstützt die automatische Vervollständigung, wenn es mit HighLine und Readline verwendet wird.

Als ich es schrieb, gab es keine Dokumentation noch Tests/Spezifikationen, aber jetzt habe ich einige gemacht. Immer noch nicht viel aber für den Anfang sollte ok sein.

So gem cli-console und Code ist bei GitHub, hier ist usage example

3

Werfen Sie einen Blick auf cliqr ruby ​​gem. Es sieht genau so aus, wie du es brauchst.Hier ist der GitHub Link mit einer beschreibenden Readme: https://github.com/anshulverma/cliqr

Es kann die Befehle direkt oder innerhalb einer eingebauten Shell ausführen.

Hier ist ein Testfall von seinem 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 
3

TTY ist ein wirklich gutes Juwel für diese Art von Dingen leicht zu tun. Sie haben viele Werkzeuge, die alleine oder mit dem vollen ToolKit arbeiten können. Sie können Farben, Aufforderungen, Shell-Natives ausführen, mit dem Bildschirm interagieren, Tabellen, Fortschrittsbalken und viele andere nützliche Elemente von Befehlszeilen mit der Leichtigkeit einer Goop-API drucken.

Insbesondere tty-prompt ist wirklich nützlich für die Frage nach Benutzereingaben.

Ein kurzes Beispiel für den Fall, dass Sie vorgeschlagen:

require 'tty-prompt' 
require 'pastel' 

prompt = TTY::Prompt.new 
loop do 
    cmd, parms* = prompt.ask('[email protected]$ ').split /\s/ 
    case cmd 
    when "hola" 
     puts "Hola amigo " parms 
    when "exit" 
     break if prompt.yes?('Do you really want to exit?') 
    end 
end 
+0

Danke für den Kommentar. Ich wollte das Beispiel hinzufügen. –

+0

Es ist nicht genau das, was ich gesucht habe, das ist eine Bibliothek, die verwendet werden könnte, um eine solche Konsole zu implementieren, wie Sie gezeigt haben. Übrigens, als ich diese Frage gestellt habe, gab es sie damals noch nicht: D Ich habe meine CLI-Konsole mit https://github.com/JEG2/highline implementiert, die etwas sehr ähnliches macht. – davispuh