Chinaunix首页 | 论坛 | 博客
  • 博客访问: 396498
  • 博文数量: 69
  • 博客积分: 1984
  • 博客等级: 上尉
  • 技术积分: 953
  • 用 户 组: 普通用户
  • 注册时间: 2007-03-28 00:43
个人简介

学无所长,一事无成

文章分类

全部博文(69)

文章存档

2015年(19)

2014年(14)

2013年(9)

2012年(17)

2010年(10)

我的朋友

分类: Python/Ruby

2012-08-10 11:05:09

参考文章:

众所周知,Ruby 语言从 Lisp 中学习了很多东西,可是 Lisp 语言家族中的宏 macro 却被刻意去除。
人民群众强烈要求 macro 的回归。以下是 Ruby 模拟宏的一个实例:


  1. #macros.rb:
  2. #----------
  3. # 定义两个 hash ,作为全局变量

  4. $__macros__ = {}
  5. $__required__ = {}

  1. module Kernel
# 替换系统 require 
  1. alias_method :old_require, :require

  2. def require(path)
  3.     # 如果 macro 已经加载过,直接跳过。避免重复加载。
  4.     return if $__required__[path]    
  5.     
  6.     # 读入源码
  7.     source = open(path) { |f|
  8.         f.sysread(f.stat().size())
  9.     }
  10.     # 正则匹配,将匹配结果存入 $__macros__ 中
  11.     source.gsub!(/defmacro\s*\/(.*?)\/\s(.*?)endmacro/m) {
  12.         $__macros__[Regexp.new($1)] = $2 ; ""
  13.     }
  14.     
  15.     # 进行宏定义替换
  16.     $__macros__.each { |match, replace|
  17.         source.gsub!(match, replace)
  18.     }
  19.     # 打上标志,已经载入过 macro 文件了
  20.     $__required__[path] = true
  21.     # 执行替换后文本
  22.     eval(source)
  23. end

  24. end

  25. require "test1.rb"
  26. require "test2.rb"


  1. test1.rb:
  2. ---------

  3. defmacro /my_macro\((.*)\)/
  4.     begin
  5.         my_function(\1)
  6.     rescue => ex
  7.         puts ex
  8.     end
  9. endmacro

  10. # php style foreach
  11. defmacro /foreach\s*\((.*)\s*as(.*)\)/
  12.     for \2 in \1
  13. endmacro

  14. def my_function(str)
  15.     puts str
  16. end

  17. class TestClass
  18.     def another_test
  19.         words = %w{ simple test }
  20.         foreach(words as word)
  21.             puts word
  22.         end
  23.     end
  24. end



  1. test2.rb:
  2. ---------

  3. value = "Hello World!"
  4. my_macro(value)

  5. numbers = [1, 2, 3, 4]

  6. foreach (numbers as i)
  7.     puts i
  8. end

  9. a = TestClass.new
  10. a.another_test()
提示:与其重定义 'require' ,不如在 kernel 中定义个新的方法,比如 'load_macro' 或者 'require_macro'。这样代码更为清晰。另外也可以给包含宏定义的文件使用不同的扩展名,比如 *.rbm。

现在我们可以在文件中定义宏,可以考虑在 string 或者 here-doc 中定义宏。


阅读(2235) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~