I have:
- existing object oriented native code API (non GUI)
- GUI application that works with this API
现有的面向对象的本机代码API(非GUI)
适用于此API的GUI应用程序
The goal: To create an additional console application that lets user do some set of workflows (similar to ones of the above GUI app) by typing commands. This app should be "stateful" - available commands and their results would depend on the previously issued commands.
目标:创建一个额外的控制台应用程序,通过键入命令,用户可以执行一些工作流程(类似于上面的GUI应用程序)。此应用程序应为“有状态” - 可用命令及其结果将取决于先前发出的命令。
The problem: I do not want to "reinvent the wheel". Are there existing patterns for both building the app and defining the "vocabulary"? Currently, it seems to me the best option would be to write a set of helpers and command parser "from scratch".
问题是:我不想“重新发明*”。是否存在构建应用程序和定义“词汇表”的模式?目前,在我看来,最好的选择是“从头开始”编写一组帮助程序和命令解析器。
P.S. If my API would be in .Net, I would look into PowerShell direction, but the API is large and wrapping it into .Net is very time consuming.
附:如果我的API将在.Net中,我会考虑PowerShell方向,但API很大并且将其包装到.Net中非常耗时。
6 个解决方案
#1
To get started on the command line, first don't reinvent the wheel. There are a lot of options out there to parse commands.
要开始使用命令行,首先不要重新发明*。有很多选项来解析命令。
In Java there is Commons CLI which provides you everything you need. There is a .NET CLI port as well.
在Java中,有Commons CLI,它为您提供所需的一切。还有一个.NET CLI端口。
InfiniteRed has a good writeup of how to do this in Ruby.
InfiniteRed在Ruby中有很好的写作方式。
As far as implementation goes, you have the right idea. But don't reinvent the wheel here, either. Encapsulate work in Command
objects and look at using the Chain of Responsibility pattern; Commons Chain works well. There is also a .NET Chain port.
就实施而言,你有正确的想法。但也不要在这里重新发明*。封装Command对象中的工作并查看使用Chain of Responsibility模式; Commons Chain效果很好。还有一个.NET链端口。
If using these frameworks isn't an option, take a look at how they're implemented. Also if you've got a problem doing interop with some of these options, Ruby is really a nice swiss-army knife for doing this type of thing. It's relatively portable and the code can end up being really clean and easy to maintain.
如果不能使用这些框架,请查看它们是如何实现的。另外,如果你在使用其中一些选项进行互操作时遇到问题,那么Ruby对于做这类事情来说真是一把不错的瑞士军刀。它相对便携,代码最终可以非常干净,易于维护。
UPDATE: JCommander also looks interesting.
更新:JCommander看起来也很有趣。
#2
The pattern of use you are describing sounds like a Read-Eval-Print loop (REPL), the common mode of interaction for interpreted languages.
您描述的使用模式听起来像是Read-Eval-Print循环(REPL),这是解释语言的常见交互模式。
In point of fact, you seem to be describing a command language and interpreter, so I would suggest examining that domain for patterns matching your existing binding for the API.
事实上,您似乎在描述命令语言和解释器,因此我建议检查该域是否与您现有的API绑定模式匹配。
#3
Do you have any COM interfaces? PowerShell can seamlessly script COM, WMI or .NET; you could even do runtime p/invoke calls with pure script; a lot less time consuming to prototype. Once you solidify the design, you can optionally wrap as native Cmdlets later for speed.
你有COM接口吗? PowerShell可以无缝编写COM,WMI或.NET脚本;你甚至可以使用纯脚本进行运行时p / invoke调用;原型制造的时间要少得多。一旦巩固了设计,您可以选择在以后包装为本机Cmdlet以提高速度。
-Oisin
#4
If you do end up using .net, perhaps you could take a look @ the Mono.Options library: http://tirania.org/blog/archive/2008/Oct-14.html
如果你最终使用.net,也许你可以看看@ Mono.Options库:http://tirania.org/blog/archive/2008/Oct-14.html
"Mono.Options is a beautiful command line parsing library. It is small, succinct, a joy to use, easy and powerful, all in one."
“Mono.Options是一个漂亮的命令行解析库。它小巧,简洁,使用快乐,简单而强大,一体化。”
#5
Wrap your API using automatic tools like SIP or SWIG, import them as a python module into an ipython session, do stuff with your objects from the command line. Job done.
使用SIP或SWIG等自动工具包装API,将它们作为python模块导入ipython会话,从命令行执行对象操作。任务完成。
If this fails, it'll be because either:
如果失败,那将是因为:
- Your objects/API aren't suitable for automatic wrapping (but the process of getting them into a wrappable state generally means improving them).
- Python isn't really what you had in mind for a command line (even with the ipython enhancements).
您的对象/ API不适合自动换行(但是将它们置于可换行状态的过程通常意味着改进它们)。
Python并不是你想要的命令行(即使使用ipython增强功能)。
#6
I strongly agree with xOn's answer, but to maintain state between calls, just make it a single instance com object, then write a "login" function to call AddRef and a "logoff" function to call Release. That way the object will stick around between calls. The only risk will be multiple runs on the same box with multiple logins... so you will want to trap for that.
我非常同意xOn的答案,但是为了维持调用之间的状态,只需将它设为单个实例com对象,然后编写一个“登录”函数来调用AddRef和一个“注销”函数来调用Release。这样,对象将在调用之间保持不变。唯一的风险是在多个登录的同一个盒子上多次运行......所以你会想要陷阱。
Depending on the state you require, if its not much and can be streamed easily to a disk file or database, then a multi-instance com object would behave better, and wouldn't require the addref or release calls.
根据您需要的状态,如果它不多并且可以轻松地流式传输到磁盘文件或数据库,那么多实例com对象会表现得更好,并且不需要addref或release调用。
#1
To get started on the command line, first don't reinvent the wheel. There are a lot of options out there to parse commands.
要开始使用命令行,首先不要重新发明*。有很多选项来解析命令。
In Java there is Commons CLI which provides you everything you need. There is a .NET CLI port as well.
在Java中,有Commons CLI,它为您提供所需的一切。还有一个.NET CLI端口。
InfiniteRed has a good writeup of how to do this in Ruby.
InfiniteRed在Ruby中有很好的写作方式。
As far as implementation goes, you have the right idea. But don't reinvent the wheel here, either. Encapsulate work in Command
objects and look at using the Chain of Responsibility pattern; Commons Chain works well. There is also a .NET Chain port.
就实施而言,你有正确的想法。但也不要在这里重新发明*。封装Command对象中的工作并查看使用Chain of Responsibility模式; Commons Chain效果很好。还有一个.NET链端口。
If using these frameworks isn't an option, take a look at how they're implemented. Also if you've got a problem doing interop with some of these options, Ruby is really a nice swiss-army knife for doing this type of thing. It's relatively portable and the code can end up being really clean and easy to maintain.
如果不能使用这些框架,请查看它们是如何实现的。另外,如果你在使用其中一些选项进行互操作时遇到问题,那么Ruby对于做这类事情来说真是一把不错的瑞士军刀。它相对便携,代码最终可以非常干净,易于维护。
UPDATE: JCommander also looks interesting.
更新:JCommander看起来也很有趣。
#2
The pattern of use you are describing sounds like a Read-Eval-Print loop (REPL), the common mode of interaction for interpreted languages.
您描述的使用模式听起来像是Read-Eval-Print循环(REPL),这是解释语言的常见交互模式。
In point of fact, you seem to be describing a command language and interpreter, so I would suggest examining that domain for patterns matching your existing binding for the API.
事实上,您似乎在描述命令语言和解释器,因此我建议检查该域是否与您现有的API绑定模式匹配。
#3
Do you have any COM interfaces? PowerShell can seamlessly script COM, WMI or .NET; you could even do runtime p/invoke calls with pure script; a lot less time consuming to prototype. Once you solidify the design, you can optionally wrap as native Cmdlets later for speed.
你有COM接口吗? PowerShell可以无缝编写COM,WMI或.NET脚本;你甚至可以使用纯脚本进行运行时p / invoke调用;原型制造的时间要少得多。一旦巩固了设计,您可以选择在以后包装为本机Cmdlet以提高速度。
-Oisin
#4
If you do end up using .net, perhaps you could take a look @ the Mono.Options library: http://tirania.org/blog/archive/2008/Oct-14.html
如果你最终使用.net,也许你可以看看@ Mono.Options库:http://tirania.org/blog/archive/2008/Oct-14.html
"Mono.Options is a beautiful command line parsing library. It is small, succinct, a joy to use, easy and powerful, all in one."
“Mono.Options是一个漂亮的命令行解析库。它小巧,简洁,使用快乐,简单而强大,一体化。”
#5
Wrap your API using automatic tools like SIP or SWIG, import them as a python module into an ipython session, do stuff with your objects from the command line. Job done.
使用SIP或SWIG等自动工具包装API,将它们作为python模块导入ipython会话,从命令行执行对象操作。任务完成。
If this fails, it'll be because either:
如果失败,那将是因为:
- Your objects/API aren't suitable for automatic wrapping (but the process of getting them into a wrappable state generally means improving them).
- Python isn't really what you had in mind for a command line (even with the ipython enhancements).
您的对象/ API不适合自动换行(但是将它们置于可换行状态的过程通常意味着改进它们)。
Python并不是你想要的命令行(即使使用ipython增强功能)。
#6
I strongly agree with xOn's answer, but to maintain state between calls, just make it a single instance com object, then write a "login" function to call AddRef and a "logoff" function to call Release. That way the object will stick around between calls. The only risk will be multiple runs on the same box with multiple logins... so you will want to trap for that.
我非常同意xOn的答案,但是为了维持调用之间的状态,只需将它设为单个实例com对象,然后编写一个“登录”函数来调用AddRef和一个“注销”函数来调用Release。这样,对象将在调用之间保持不变。唯一的风险是在多个登录的同一个盒子上多次运行......所以你会想要陷阱。
Depending on the state you require, if its not much and can be streamed easily to a disk file or database, then a multi-instance com object would behave better, and wouldn't require the addref or release calls.
根据您需要的状态,如果它不多并且可以轻松地流式传输到磁盘文件或数据库,那么多实例com对象会表现得更好,并且不需要addref或release调用。