1. 你会感觉你就是管理员
用过Mac或着Linux的朋友应该就有这样的感觉,如果你是root你就是上帝(God)
。你可以对系统进行任何操作,包括直接删除系统的根目录。这种上帝的感觉真好。不过好归好,能力越大责任越大
。如果你不幸
得到了公司产品线机器的root权限,你就得对它的运行负责。
扯远了,相似的如果你要用Ruby这门语言你将拥有近似于root的权限。你可以修改这门语言的任何东西。甚至内置对象
。这听起来可能会很不可思议。Python这些语言就会有一定的保护机制,我们原则上无法轻易破坏他们的内置函数。但是Ruby就不一样了。你可以随时随地地修改Ruby的内置函数,类等等。所以很多人都觉得Ruby这门语言十分适合那些禁得起折腾,又有一定的安全意识和编程经验的人--Hacker。Ruby究竟有多猛?破坏一个类究竟有多难?我们往下看。
2. 修改String类
这里只是举例来说明,不限于String类
class String
def become
return "good"
end
end
p "lanzhiheng".become
结果:
good
上面这个例子很简单其他语言也可以做到类似的事情。但是注意了,这里我们定义的实例方法是属于String
类的。它是Ruby里面的内置类,理论
上应该是不允许修改的。但是,我们却可以很容易地修改它的值。当然还不仅仅是如此。
[7] pry(main)> String.instance_methods.grep /cat/
=> [:concat]
上面看到String
类的一个实例方法是 concat
。我们试试这个脚本。
p "Hello".concat " World!!"
class String
def concat(x)
self + ", I'm a bug"
end
end
p "Hello".concat " Good!!"
结果
"Hello World!!"
"Hello, I'm a bug"
我们甚至还可以修改原有的内置方法的定义。如果我们这个脚本先于其他脚本加载,而其他脚本如果都运用到这个concat
方法的话,那就乱套了。这种修改类的方式我们业界给了专业术语叫做打开类。 另外,有些人不喜欢这种能够修改类本身内置对象的行为,所以给它取了个名字叫做猴子补丁
。
这样对于一些喜欢折腾的人固然是很好,而很多的程序员都能够驾驭这种能力。然而,肯定还是有人不满意。我们的Ruby社区是考虑地如此周到。从Ruby2.0开始加入了细化(refine)的功能,能够在一定程度上较少这种影响的范围。
module StringExtensions
refine String do
def concat(x)
self + ", I'm a bug"
end
end
end
module StringStuff
using StringExtensions
p "Hello".concat " Good!!"
end
p "Hello".concat " Good!!"
现在的结果是
"Hello, I'm a bug"
"Hello Good!!"
只有在module中通过using引入细化过的类,才会影响原来实例方法的行为。而不会影响其他地方同名实例方法的行为。
3.修改字符串本身
注意这里是修改字符串本身
,我们都知道Ruby的实例方法是可以带特殊符号的。有一特殊符号为!
(感叹号)。如果方法后面带上它标示强制修改。我们看看下面这个例子
# 不加感叹号,则返回修改后的值a本身并没有变
[4] pry(main)> a = "be good at "
=> "be good at "
[5] pry(main)> b = a.strip
=> "be good at"
[6] pry(main)> b
=> "be good at"
[7] pry(main)> a
=> "be good at "
# 加上感叹号,则返回修改后的值的同时,修改a本身
[8] pry(main)> a = "be good at "
=> "be good at "
[9] pry(main)> b = a.strip!
=> "be good at"
[10] pry(main)> b
=> "be good at"
[11] pry(main)> a
=> "be good at"
刚开始接触的时候我也觉得不可思议,因为目前我学过的语言只有C是有这种功能的。没想到Ruby居然支持这种行为。这也给一些有洁癖的,喜欢折腾的程序员带来了福音。反正我是觉得这个很酷。不知道你怎么想了-!!!
4.写在最后
总之,在用Ruby的时候我们是拥有那么高的权限。甚至有作者说
如果你心情不好去修改常量String,就能够把系统弄崩溃。
这么任性我喜欢。
我们也知道常量是赋值之后就不建议修改了。如果修改的话会有警告,但是并不会妨碍我们修改。所以当我们去修改String常量的时候:
[12] pry(main)> String = 12
(pry):12: warning: already initialized constant String
=>
(pry) output error: #<TypeError: can't define singleton>
[13] pry(main)> 2
SystemStackError: stack level too deep
....
错误栈能延伸到系统那层了。几乎整个系统都会用到String这个类,所以现在我的pry环境就不能用了,只能重新启动。希望你会喜欢上今天提到的Ruby特性。
今天就到这里。哦,不对,晚点应该还会有其他文章。