参考文章:
众所周知,Ruby 语言从 Lisp 中学习了很多东西,可是 Lisp 语言家族中的宏 macro 却被刻意去除。
人民群众强烈要求 macro 的回归。以下是 Ruby 模拟宏的一个实例:
-
#macros.rb:
-
#----------
-
# 定义两个 hash ,作为全局变量
-
-
$__macros__ = {}
-
$__required__ = {}
-
module Kernel
# 替换系统 require
-
alias_method :old_require, :require
-
-
def require(path)
-
# 如果 macro 已经加载过,直接跳过。避免重复加载。
-
return if $__required__[path]
-
-
# 读入源码
-
source = open(path) { |f|
-
f.sysread(f.stat().size())
-
}
-
# 正则匹配,将匹配结果存入 $__macros__ 中
-
source.gsub!(/defmacro\s*\/(.*?)\/\s(.*?)endmacro/m) {
-
$__macros__[Regexp.new($1)] = $2 ; ""
-
}
-
-
# 进行宏定义替换
-
$__macros__.each { |match, replace|
-
source.gsub!(match, replace)
-
}
-
# 打上标志,已经载入过 macro 文件了
-
$__required__[path] = true
-
# 执行替换后文本
-
eval(source)
-
end
-
-
end
-
-
require "test1.rb"
-
require "test2.rb"
-
test1.rb:
-
---------
-
-
defmacro /my_macro\((.*)\)/
-
begin
-
my_function(\1)
-
rescue => ex
-
puts ex
-
end
-
endmacro
-
-
# php style foreach
-
defmacro /foreach\s*\((.*)\s*as(.*)\)/
-
for \2 in \1
-
endmacro
-
-
def my_function(str)
-
puts str
-
end
-
-
class TestClass
-
def another_test
-
words = %w{ simple test }
-
foreach(words as word)
-
puts word
-
end
-
end
-
end
-
test2.rb:
-
---------
-
-
value = "Hello World!"
-
my_macro(value)
-
-
numbers = [1, 2, 3, 4]
-
-
foreach (numbers as i)
-
puts i
-
end
-
-
a = TestClass.new
-
a.another_test()
提示:与其重定义 'require' ,不如在 kernel 中定义个新的方法,比如 'load_macro' 或者 'require_macro'。这样代码更为清晰。另外也可以给包含宏定义的文件使用不同的扩展名,比如 *.rbm。
现在我们可以在文件中定义宏,可以考虑在 string 或者 here-doc 中定义宏。
阅读(2235) | 评论(0) | 转发(0) |