From: itsme213 Date: 2005-04-12T13:09:39+09:00 Subject: Re: [ANN] cmd 0.7.0: Library for Line-Oriented Command Interpreters (initial release) "Marcel Molina Jr." wrote > > Any plans to go towards interactive commands e.g. some commands valid only > > within scope of other commands? > > By interactive commands do you mean something like? > > > foo > # now you are in a context within 'foo' that opens you up to a whole other > # set of things Sort-of ... lousy description on my part. I can see the command interpreter as a state machine consisting of a current object + the available commands on the current object. I'll start with the latter. The available commands on the current object could change as you do things to it. Suppose each of its commands has some declared pre-condition. A command is disabled if its precondition is false. Here is one of many ways to do this. class PhoneBook < Cmd # ... define commands & docs pre :add { |pb| pb.condition_on_phonebook_add } pre :remove { |pb| pb.condition_on_phonebook_remove } end All commands whose pre is true are 'enabled', all others are 'greyed-out'. Preconditions could have a descriptive string for help purposes. Secondly the current object itself could be switched. e.g If you add some special commands to "cd", "pushd", and "popd" to any command-able object, to start working in a new command context. PBook> pushd `find Sam` - execute command "find Sam" in current context - perhaps check return (e.g. a Person) is command-able - make that the new command context, so ... Sam> first Sammy last Brown popd PBook> Plug in a Dir class and you have a command shell. And, lastly, every command has arguments. Each argument has a range of valid values that can depend on current state. If you store an array of blocks that computes the possible values for each argument given the current context object (when applicable), you can even provide completion for arguments to commands. class PhoneBook < Cmd # can only delete X if X currently in phonebook command :delete do args [ {|pb| pb.people.collect { |p| p.name }} # even better if returned objects, not strings # using to_s or some protocol to get strings for completion # command intereter keeps map of string->object # refuse to execute if no valid completion # inner code just deals with objects ] end end PBook> delete #--> Sammy Mary PBook> delete S #--> delete Sammy btw: have you considered adding a Command class to keep all info about one command?