数据即代码,我和小伙伴们都惊呆了!

开发 前端 开发工具
几个小伙伴在考虑下面这个各个语言都会遇到的问题:问题:设计一个命令行参数解析API

几个小伙伴在考虑下面这个各个语言都会遇到的问题:

问题:设计一个命令行参数解析API

一个好的命令行参数解析库一般涉及到这几个常见的方面:

1) 支持方便地生成帮助信息

2) 支持子命令,比如:git包含了push, pull, commit等多种子命令

3) 支持单字符选项、多字符选项、标志选项、参数选项等多种选项和位置参数

4) 支持选项默认值,比如:–port选项若未指定认为5037

5) 支持使用模式,比如:tar命令的-c和-x是互斥选项,属于不同的使用模式

经过一番考察,小伙伴们发现了这个几个有代表性的API设计:

1. getopt():

getopt()是libc的标准函数,很多语言中都能找到它的移植版本。

  1. //C 
  2. while ((c = getopt(argc, argv, "ac:d:")) != -1) { 
  3.     int this_option_optind = optind ? optind : 1; 
  4.     switch (c) { 
  5.     case 'a'
  6.         printf ("option a"); 
  7.         aopt = 1; 
  8.         break
  9.     case 'c'
  10.         printf ("option c with value '%s'", optarg); 
  11.         copt = optarg; 
  12.         break
  13.     case 'd'
  14.         printf ("option d with value '%s'", optarg); 
  15.         dopt = optarg; 
  16.         break
  17.     case '?'
  18.         break
  19.     default
  20.         printf ("?? getopt returned character code 0%o ??", c); 
  21.     } 

getopt()的核心是一个类似printf的格式字符串的命令行参数描述串,如上面的”ac:d:”定义了”a”, “c”,”d”3个命令行参数,其中,a是一个标志符不需要参数,”c”和”d”需要跟参数。getopt()功能非常弱,只支持单个字符的标志选项和参 数选项。如果按上面的5点来比对,基本上只能说是勉强支持第3点,其他几项只能靠程序自己来实现了,所以,想直接基于getopt()实现一个像git这 样复杂的命令行参数是不可能的,只有自己来做很多的解析工作。小伙伴们看过getopt()之后一致的评价是:图样图森破。

2. Google gflags

接着,小伙伴们又发现了gflags这个Google出品C++命令行参数解析库。

  1. /C++ 
  2. DEFINE_bool(memory_pool, false"If use memory pool"); 
  3. DEFINE_bool(daemon, true"If started as daemon"); 
  4. DEFINE_string(module_id, """Server module id"); 
  5. DEFINE_int32(http_port, 80, "HTTP listen port"); 
  6. DEFINE_int32(https_port, 443, "HTTPS listen port"); 
  7.   
  8. int main(int argc, char** argv) { 
  9.     ::google::ParseCommandLineFlags(&argc, &argv, true); 
  10.   
  11.     printf("Server module id: %s", FLAGS_module_id.c_str()); 
  12.   
  13.     if (FLAGS_daemon) { 
  14.       printf("Run as daemon: %d", FLAGS_daemon); 
  15.     } 
  16.     if (FLAGS_memory_pool) { 
  17.       printf("Use memory pool: %d", FLAGS_daemon); 
  18.     } 
  19.   
  20.     Server server; 
  21.   
  22.     return 0; 

小伙伴们看了后不由得感叹“真心好用啊”!的确,gflags简单地通过几个宏就定义了命令行选项,基本上很好的支持了上面提到的1,3,4这几 项,比起getopt()来强多了。对于类似cp这样的小命令,gflags应该是够用了,但要达到git这种级别就显得有些单薄了。

3. Ruby Commander

接下来小伙伴们又发现了Ruby Commander库:

  1. //Ruby 
  2. # :name is optional, otherwise uses the basename of this executable 
  3. program :name'Foo Bar' 
  4. program :version'1.0.0' 
  5. program :description'Stupid command that prints foo or bar.' 
  6. command :bar do |c| 
  7.   c.syntax = 'foobar bar [options]' 
  8.   c.description = 'Display bar with optional prefix and suffix' 
  9.   c.option '--prefix STRING'String'Adds a prefix to bar' 
  10.   c.option '--suffix STRING'String'Adds a suffix to bar' 
  11.   c.action do |args, options| 
  12.     options.default :prefix => '(':suffix => ')' 
  13.     say "#{options.prefix}bar#{options.suffix}" 
  14.   end 
  15. end 
  16. $ foobar bar 
  17. # => (bar) 
  18. $ foobar bar --suffix '}' --prefix '{' 
  19. # => {bar} 

Commander库利用Ruby酷炫的语法定义了一种描述命令行参数的内部DSL,看起来相当高端大气上档次。除了上面的第5项之外,其他几项都 有很好的支持,可以说Commander库的设计基本达到了git这种级别命令行参数解析的要求。只是,要搞懂Ruby这么炫的语法和这个库的使用方法恐 怕就不如getopt()和gflags容易了。有小伙伴当场表示想要学习Ruby,但是也有小伙伴表示再看看其他库再说。

4. Lisp cmdline库

接下来,小伙伴们发现了Lisp方言Racket的cmdline库。

  1. //Lisp 
  2. (parse-command-line "compile" (current-command-line-arguments) 
  3.   `((once-each 
  4.      [("-v" "--verbose"
  5.       ,(lambda (flag) (verbose-mode #t)) 
  6.       ("Compile with verbose messages")] 
  7.      [("-p" "--profile"
  8.       ,(lambda (flag) (profiling-on #t)) 
  9.       ("Compile with profiling")]) 
  10.     (once-any 
  11.      [("-o" "--optimize-1"
  12.       ,(lambda (flag) (optimize-level 1)) 
  13.       ("Compile with optimization level 1")] 
  14.      [("--optimize-2"
  15.       ,(lambda (flag) (optimize-level 2)) 
  16.       (("Compile with optimization level 2," 
  17.         "which implies all optimizations of level 1"))]) 
  18.     (multi 
  19.      [("-l" "--link-flags"
  20.       ,(lambda (flag lf) (link-flags (cons lf (link-flags)))) 
  21.       ("Add a flag <lf> for the linker" "lf")])) 
  22.    (lambda (flag-accum file) file) 
  23.    '("filename")) 

这是神马浮云啊?括号套括号,看起来很厉害的样子,但又不是很明白。看到这样的设计,有的小伙伴连评价都懒得评价了,但也有的小伙伴对Lisp越发崇拜,表示Lisp就是所谓的终极语言了,没有哪门语言能写出这么不明觉历的代码来!小伙伴们正准备打完收工,突然…

5. Node.js的LineParser库

发现了Node.js的LineParser库:

  1. //JavaScript 
  2. var meta = { 
  3.     program : 'adb'
  4.     name : 'Android Debug Bridge'
  5.     version : '1.0.3'
  6.     subcommands : [ 'connect''disconnect''install' ], 
  7.     options : { 
  8.     flags : [ 
  9.         [ 'h''help''print program usage' ], 
  10.         [ 'r''reinstall''reinstall package' ], 
  11.         [ 'l''localhost''localhost' ] 
  12.     ], 
  13.     parameters : [ 
  14.         [ null'host''adb server hostname or IP address'null ], 
  15.         [ 'p''port''adb server port', 5037 ] 
  16.     ] 
  17.     }, 
  18.     usages : [ 
  19.     [ 'connect', ['host''[port]'], null'connect to adb server', adb_connect ], 
  20.     [ 'connect', [ 'l' ], null'connect to the local adb server', adb_connect ], 
  21.     [ 'disconnect'nullnull'disconnect from adb server', adb_disconnect ], 
  22.     [ 'install', ['r'], ['package'], 'install package', adb_install ], 
  23.     [ null, ['h'], null'help', adb_help ], 
  24.     ] 
  25. }; 
  26.   
  27. try { 
  28.     var lineparser = require('lineparser'); 
  29.     var parser = lineparser.init(meta); 
  30.     parser.parse(['install''-r''/pkgs/bird.apk']); // adb_install will be invoked 
  31. catch (e) { 
  32.     console.error(e); 

天啊!?这是什么?我和小伙伴们彻底惊呆了!短短十几行代码就获得了上面5点的全面支持,重要的是小伙伴们居然一下子就看懂了,没有任何的遮遮掩掩 和故弄玄虚。本来以为Ruby和Lisp很酷,小伙伴们都想马上去学Ruby和Lisp了,看到这个代码之后怎么感觉前面全是在装呢?有个小伙伴居然激动 得哭着表示:我写代码多年,以为再也没有什么代码可以让我感动,没想到这段代码如此精妙,我不由得要赞叹了,实在是太漂亮了!

小伙伴们的故事讲完了,您看懂了吗?如果没有再看一遍标题吧!

原文链接:http://coolshell.cn/articles/10337.html

责任编辑:陈四芳 来源: 酷壳网
相关推荐

2013-07-22 11:06:37

2015-05-19 14:30:48

加密视频加密亿赛通

2013-12-27 09:46:40

Windows 9Windows 9桌面

2015-12-15 10:33:59

域名网络域名

2016-12-21 12:19:57

AR广告奥迪

2013-12-19 10:20:19

2013-07-30 09:49:28

联通定向流量微信定向流量移动

2023-03-27 00:06:12

2014-01-22 14:27:25

科技创业者人品

2013-08-05 14:34:46

2021-05-28 10:09:22

GC详解Java JVM

2013-08-09 14:33:34

2022-06-01 08:50:23

分布式事务模式

2014-07-10 14:48:26

无线路由器

2014-11-26 10:47:46

虚拟现实苹果

2013-09-27 13:34:09

BAT百度腾讯

2020-09-21 06:45:48

监控延迟消息队列

2020-10-31 09:06:37

C语言编程语言

2021-11-02 11:31:47

Go代码模式

2021-03-08 08:16:30

负载均衡系统流量
点赞
收藏

51CTO技术栈公众号