如何写一个简单的console?

June 03, 2015 12:34


前话

刚开始没头绪时,想着确定是比较麻烦,怎么写呢?

不过理一上思路,清楚之后,要做一个简单的控制台还是非常简单的

分析

一个自己的CLI无非是接受输入,然后输出结果。

这就是一个循环一直在做【接受输入】 => 【输出结果】这件事了

接收的输入需要解析命令及参数,简单的就可以使用空格来分割,第一个字符串为命令,后面的是参数

结构

基本上流程就是 接受输入 => 解析输入 => 执行 => 输出结果

在代码中如何可以非常简单的去定义一个命令对应的操作呢?第一反应是就是:

  define_command :cmd do |argv|
    puts argv
  end

定义一个cmd命令,带有一个参数,操作就是直接打印这个参数,通过cmd my_name就可以直接调用了

可以定义一个Console 模块,支持定义command,解析输入,调用定义好的command

实现

Console

使用

定义一个自己的控制台:

#! /usr/bin/env ruby

require 'console'

class MyConsole
  include Console

  define_cmd(:rand, "puts random number") do |max = 100|
    puts rand(max.to_i)
  end

  define_cmd(:incr, "increment number") do |incrby = 1|
    @number ||= 0
    puts @number += incrby.to_i
  end
end

MyConsole.new.start("my-console > ", "Use 'help' show all commands")

运行

$ ruby my_console.rb
Use 'help' show all commands
my-console > help
  help: show all commands
  exit: exit console
  rand: puts random number
  incr: increment number
my-console > rand
23
my-console > rand 10
4
my-console > rand 10100
2492
my-console > incr
1
my-console > incr 3
4
my-console > incr
5
my-console > exit
$ 

可以改为可执行文件,直接运行

$ mv my_console.rb my_console
$ chmod a+x my_console
$ ./my_console

# or
$ mv my_console ~/bin/
$ my_console

元编程知识点

proc = Proc.new { self }
obj = Object.new
proc.call # => main

如何让一个proc在一个object的环境中执行?

obj.instance_eval(&proc)
# => obj

但这样确是无法传递参数给proc的,如何传递自定的参数?

Object.send(:define_method, :_my_method, &proc)
m = Object.instance_method(:_my_method)
bm = m.bind(obj)
bm.call # => obj

如上,在call的时候可以传递任意参数,而且执行的context是在obj上(self == obj), 虽然这种方式比较麻烦,然后会污染obj的class。不过在某些时候还是非常方便有用的。

将一个method 转换为一个proc

bm.to_proc.call # => obj

嗯,这是最简单的了。。

Comments: