这些天总是想要用ruby做点什么,因为喜欢ruby,也因为最近技术上缺少变化,想要主动的搞点不同的东西。想了不少的东西,但是很显然现在很忙,白天也不会有时间,只有晚上做,因此不能太大了,完整的系统就不要想了,但是找些耦合性不大的,有点意思的模块还是没有问题的,不如就做一个编号生成模块吧。
今天周六,在床上睡得七荤八素的,想到左右没有事情,或者想到些事情也不想动,不如写写这个模块,动手。
先看看需求
A. Feat:做一个编号生成模块
1. 通过类似${yyyy}-${mm}-${dd}-string-${autonum}样式来生成编码,这样生成的编号在今天就是2008-06-14-string-1,依次递增。
2. 可以配置上面的格式化字符串
3. 可以生成一个新的编号,并且不会重复,前面字符串变化后,后面的autonum可以归零再来。
B. 技术限定:用函数,不要动不动就是数据库,想都不能想;总在做数据库,早就烦了,这次至少要改变些什么,要不然太没有意思了。
C. 我要做的就是这个函数
function GenenateSerialNo(serial_format,last_serial_no,last_num)
当然需要通过下面的测试。实际上有了测试,这个函数才完整。
D. testcase :
assert_equal("2008-6-14-string-1",GenenateSerialNo("${yyyy}-${mm}-${dd}-string-${autonum}","",0))
assert_equal("2008-6-14-string-4",GenenateSerialNo("${yyyy}-${mm}-${dd}-string-${autonum}","2008-6-14-string-3",3))
assert_equal("2008-6-14-string-9",GenenateSerialNo("${yyyy}-${mm}-${dd}-string-${autonum}","2008-6-14-string-8",8))
assert_equal("2008-6-14-string-1",GenenateSerialNo("${yyyy}-${mm}-${dd}-string-${autonum}","2008-6-13-string-8",8))
如果用数据库的思路,现要考虑数据库表如何规划,上一个num和上一个格式化字符串的位置,还有这3张表的关系,耦合大了去了,又如何去重用呢?
E. Testcase换成Ruby的表达,更详细的设计
可是我不知道在ruby中如何表达单元测试?
google "ruby unit test"
找到一个例子:
少许调整,改成自己想要的东西。然后....ruby serail_test
架子成了,休息下,听音乐,音乐好啊。
F. 开始写代码 - 表意代码,但是必须替换为ruby的样子,ruby估计不会有什么now.month,也不会有replace的方法。
def GenenateSerialNo(serial_format,last_serial_no,last_num)
serial_format.replace("${yyyy}",now.year);
serial_format.replace("${mm}",now.month);
serial_format.replace("${dd}",now.day);
temp = serail.replace("${autonum},last_num")
if (temp == last_serial_no)
serial_format.replace("${autonum}",last_num+1);
else
serial_format.replace("${autonum}",1);
serial_format
end
这些代码只能算是伪代码,表达意思没有问题,但是ruby显然不是这样表达的,其中的日期函数肯定不是这样的,replace函数恐怕也没有,就算有,恐怕也不能用一个数字来替换,比如last_num,必须转成string才可以。
G. 如何表达string.replace ? 继续google "ruby string replace ",知道gsub可以干这个事情
用irb验证
"abc".gsub("ab","c)
==> cc
就是它。
H. 那么now.year 呢? google :"ruby date year",每个语言对日期的处理都不一样,不过也没有必要说那么多,都是知识性的,总之找到,然后用irb来测试。
irb(main):011:0> Time.now.day
=> 14
irb(main):012:0> Time.now.year
=> 2008
irb(main):013:0> Time.now.month
=> 6
irb(main):015:0> Time.now.month.to_s()
=> "6"
irb(main):016:0> Time.now.month.to_s
=> "6"
这样基本库函数的就比较明确了,正式编码了。
J. 废话少说,看代码,然后通过第一个测试,随后以及也就通过了,懒得在看了。
def GenenateSerialNo(serial_format,last_serial_no,last_num)
serial = serial_format
serial = serial.gsub("${yyyy}",Time.now.year.to_s)
serial = serial.gsub("${mm}",Time.now.month.to_s)
serial = serial.gsub("${dd}",Time.now.day.to_s)
temp = serial.gsub("${autonum}",last_num.to_s)
if (temp == last_serial_no)
serial = serial.gsub("${autonum}",(last_num+1).to_s);
else
serial = serial.gsub("${autonum}",1.to_s);
serial
end
end
K. 总结
一开始通过测试驱动的方式来,更加容易集中于代码,而不是考虑数据库如何,表如何.
因为和数据库,表没有关系,更加容易重用。
因为和数据库没有关系,也就有了新意,好玩,并且代码也就不多。
不要着急进入代码细节,先表意,然后用ruby翻译,当然如果ruby比较熟悉了,可以一步到位,而我现在不熟悉,就干脆从顶到下,思路更加清晰。人的头脑不适合在层次中切换,如果先考虑好上一层,然后在进入下一层,当然更加容易。
irb可以交互执行,看库函数,或者快速看结果更合适,不像ruby.exe 那么死板。可以在刚刚提到的场合多用,这个工具更加容易看到脚本比编译的灵活快速的特点。