Ruby学习之元编程
Kernel#evel()方法
和Object#instance_evel()、Module#class_evel()方法类似,evel()方法也是一个内核方法,Object#instance_evel()方法可以使调用对象为self,当前类为#self(当前对象的eigenclass),并且传递一个代码块访问self;Module#class_evel()方法则可以使调用者成为当前类,并在当前类中执行传入的块(self此时是一个class的实例对象),从而修改当前类的方法和属性。Kernel#evel()方法则是调用一串代码字符串,并且执行这个字符串中的代码。
*evel()方法都可以传入一个Binding类,Binding类是一个只包含作用域的对象,通过传入Binding类,可以使*evel()方法在Binding类所携带的作用域中执行代码。
Binding类可以通过Kernel#binding()方法创建:
class MyClass
def my_method
@a = 1
binding
end
end
当执行 b = MyClass.new.my_method时, b就代表了一个作用域,通过 eval “puts @a” ,b 传入该绑定,获得@a。
使用evel方法可以很方便地实现一些功能,如计算器应用的编写等,但是在能力越大的同时,也有更大的危险。Kernel#evel方法执行时不会检查字符串代码的语法,并且会带来一些安全问题:代码注入。当evel方法面向很多其他用户的时候,就可以通过传入一些命令来获得你的私有信息,所以用evel方法时必须非常谨慎,Ruby中,也会有一些安全措施:
Ruby会把不安全的对象标记为被污染的(尤其是从外部传入的对象),通过tainted?()方法可以判断该字符串是否被污染,为了避免检查每个对象的污染情况,Ruby内置了安全级别来默认处理这些危险操作。通过$SAFE全局变量可以改变当前的安全级别,默认为0——不受任何约束;一共有5个安全级别,任何大于0的安全级别都不能执行污染的字符串。
为了安全地使用evel,可以为evel()方法创造一个沙盒,并且在沙盒中运行该字符串:
proc{
$SAFE = @safe_level
evel “cmd”,b
}.call
evel()方法的替代
为了避免evel()带来的安全问题,可以使用其他的方法来替代evel():通过动态派发:send()方法来调用方法;通过class_evel()来进入类,并为类添加方法或者实例变量,并且用define_method()方法来动态添加方法;使用Object#instance_variable_set()和Object#instance_variable_get()方法来设置或者访问实例变量。
钩子方法
通过改写Class#inherited()方法、Module#included()方法、Module#method_added()方法等等,可以在相应的事件发生时执行所需要的代码。如在包含一个模块的时候打印提示:
module M
def self.included(othermod)
puts “M was mixed into #(othermod)”
end
end
class C
include M
end
在C类中包含M模块时,会打印:M was mixed into C 提示字符串。
钩子方法默认实现时只是捕获一个事件,并不会执行其他的动作, 可以通过改写Module#include()方法来完成上述功能:
class C
def self.include(*modules)
puts “#(modules) is included in C”
super
end
include M
end
上述方法直接修改了include方法,由于include()方法除了捕获到事件之外,还有其他的事情要做,所以需要通过super来进行原始的工作,其中super的作用是在父类(当前类是C,父类是Module)中调用同名的函数,并且将本函数的所有参数传入到同名函数中。还有一个方法super()带括号,则表示调用父类中的同名函数,但是不传入任何参数。*表示传入多个参数打包为一个数组,并且在方法调用时解开数组使每个元素成为一个独立参数,通过*modules可以一次包含多个模块。
通过环绕别名来实现钩子方法:
class C
Class.class_eval {
alias :real_include :include
def include (mod)
real_include mod
puts "#{mod} was included!"
end
}
include M
end
类扩展混入
当一个类包含模块时,只会获得一组实例方法,而不会获得任何类方法,通过在eigenclass中包含一个模块来实现类扩展(或者使用extend()方法),如果一个模块期望被包含时一直可以作为类扩展,则可以通过在模块中添加钩子方法来实现:
module M
def self.included(base)
base.extend(ExtendMethods)
end
module ExtendMethods
def my_method()
#…
end
end
end
此时,如果在类中include M,则会调用钩子方法M.included(),将M中的子模块ExtendMethods(纯净室)作为类扩展,将Methods中的方法添加到包含类的eigenclass中。
上述将类扩展和钩子方法结合的技术叫做类扩展混入。而且,如果在M中又不需要被扩展的方法,则可以放到ExtendMethods外部定义一些额外的方法,这些方法不会被扩展为包含着的类方法。如果M中所有的方法都需要被扩展为类方法,则把所有的方法都定义在M本身即可。
Ruby学习之元编程的更多相关文章
- Ruby学习: 类的定义和实例变量
ruby是完全面向对象的,所有的数据都是对象,没有独立在类外的方法,所有的方法都在类中定义的. 一.类的定义语法 类的定义以 class 关键字开头,后面跟类名,以 end标识符结尾. 类中的方法以 ...
- ES6中的元编程-Proxy & Reflect
前言 ES6已经出来好久了,但是工作中比较常用的只有let const声明,通过箭头函数改this指向,使用promise + async 解决异步编程,还有些数据类型方法...所以单独写一篇文章学习 ...
- C++模板元编程----选择排序
目录 目录 前言 代码详解 数据的结构 数据的操作 分割向量 合并向量 寻找最大值 排序 总结 前言 模板在C++一直是比较神秘的存在.STL和Boost中都有大量运用模板,但是对于普通的程序员来说, ...
- 3-20 标准库:find库; 学习编程语言3节课(大多是旧识,全*栈)3-21 面向对象. Percent Strings; 元编程和Rails的相互理解
Find The Find module supports the top-down traversal of a set of file paths.(一系列文件的路径的遍历) find(*path ...
- 3-11 《Ruby元编程》第4章block块 3-12
第4章代码块blocks 基础知识 作用域:用代码块携带variables through scopes 通过传递block给instance_eval方法来控制作用域. 把block转换为Proc, ...
- 3-8《Ruby元编程》第二章对象模型
<Ruby元编程> 第二章 对象模型 类定义揭秘inside class definitions: class关键字更像一个作用域操作符,核心作用是可以在里面随时定义方法. [].meth ...
- Ruby元编程:动态添加类属性及其实际应用
上个星期测试道的Monkey老师和我聊到测试用例参数过多的问题,其实这样的问题在我这里也同样经历过.比如我的测试用例必须面对不同的测试环境,每个环境有无数的参数,开发的最初阶段,因为参数少,所以就放在 ...
- Ruby元编程:单元测试框架如何找到测试用例
前几天看了Google Testing Blog上的一篇文章讲到C++因为没有反射机制,所以如何注册测试用例就成了一件需要各显神通的事情.从我的经验来看,无论是Google的GTest还是微软的LTM ...
- 201707《Ruby元编程》
元编程不过是编程--经典必读 作用域(绑定) 打破作用域门的方式 对象模型图 七条规则 法术手册 作用域(绑定) 改变作用域的关键字, 分别是module,class和def.我们称为作用域的门(sc ...
随机推荐
- 开源API测试工具 Hitchhiker v0.6更新 - 改进压力测试
Hitchhiker 是一款开源的支持多人协作的 Restful Api 测试工具,支持Schedule, 数据对比,压力测试,支持上传脚本定制请求,可以轻松部署到本地,和你的team成员一起协作测试 ...
- QScintilla 编译
直接上英文了,不翻译了.看不懂的可以留言哈. ———————————————————————————————————————— Installation As supplied QScintilla ...
- 关于无法全然下载CyanogenMod代码的问题
CyanogenMod真的是一个奇妙的东东,它让开发手机固件不再是手机生产商的专利,每一个有志于此的程序猿都可能为自己的手机定制一份专有的,独一无二的固件,这在曾经是想都不敢想的. 而且Cyanoge ...
- 剑指 offer代码解析——面试题39推断平衡二叉树
题目:输入一颗二叉树的根结点.推断该树是不是平衡二叉树. 假设某二叉树中随意结点的左右子树的高度相差不超过1,那么它就是一棵平衡二叉树. 分析:所谓平衡二叉树就是要确保每一个结点的左子树与右子树的高度 ...
- 5个步骤,将 storyboard 从 iphone 版转变为 ipad 版
1.将 iPhone 版的 Storyboard 复制为 iPad 的,比如 Main_iPad.storyboard 2.用文本编辑器(不要用 Xcode)打开 Main_iPad.storyboa ...
- 家居环境监測系统设计(PC上位机版)(手机APP版待定)
下面是我的毕业设计:家居环境监測系统设计(PC上位机临时版.手机app版待定).本系统採用STC12C5A60S2单片机.结合传感器.分别对空气湿度.空气温度.气压.海拔.进水温度.出水温度.光照强度 ...
- android-xBuild apk差分与合成,zip差分与合成,lua打包,apk打包,png/jpg图片压缩
android-xBuild 是一项集成了apk差分与合成,zip差分与合成,lua打包.apk打包,png/jpg图片压缩五大功能的开源项目 (github地址:https://github.com ...
- XML文档读取-DOM4j
JAXP是sun公司官方提供的java解析工具包,但很多其他企业和机构也都开发了自己的xml解析工具,甚至比JAXP更加优秀,比如DOM4J. Dom4j是一个简单.灵活的开放源代码的库.Dom4j是 ...
- Winform开发框架中工作流模块的业务表单开发
在我们开发工作流的时候,往往需要设计到具体业务表单信息的编辑,有些是采用动态编辑的,有些则是在开发过程中处理的,各有各的优点,动态编辑的则方便维护各种各样的表单,但是数据的绑定及处理则比较麻烦,而自定 ...
- mysql 常用sql语句 一
创建数据库 create database if not exists wsp_test default charset utf8 collate utf8_general_ci 使用数据库 use ...