论坛首页 编程语言技术论坛

关于Ruby Aop的小试验

浏览 7439 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2007-06-21  
Ruby 的Metaclass功能确实强大,
我仿照Rail的处理的做了一个Aop 的小试验,代码如下:
ruby 代码
 
  1. # aop_test.rb  
  2. # 2007年6月18日  
  3. #  
  4. module AopAspects  
  5.   def log_method(*args)  
  6.     puts "log here"  
  7.     args.each do |arg|  
  8.       puts arg.to_s  
  9.     end  
  10.   end  
  11.     
  12.   def trans_aspect(*args)  
  13.     puts "trans here"  
  14.   end  
  15. end  
  16. module AopBinder  
  17.   def self.included(c)  
  18.     c.extend(AopGenerate)  
  19.   end  
  20.     
  21.   module AopGenerate  
  22.     def run_before(method,*aspects)  
  23.       alias_method "#{method}_old".to_sym, method  
  24.       before_method = ""  
  25.       aspects.inject("") {|before_method,aspect| before_method<<(aspect.to_s + "(*args)\n")}  
  26.       class_eval <<-END  
  27.         def #{method}(*args)  
  28.             #{before_method}  
  29.             #{method}_old(*args)  
  30.           end  
  31.       END  
  32.     end  
  33.       
  34.     def run_after(method,*aspects)  
  35.       alias_method "#{method}_old".to_sym, method  
  36.       before_method = ""  
  37.       aspects.inject("") {|before_method,aspect| before_method<<(aspect.to_s + "(*args)\n")}  
  38.       class_eval <<-END  
  39.         def #{method}(*args)  
  40.             #{method}_old(*args)  
  41.             #{before_method}  
  42.           end  
  43.       END  
  44.     end  
  45.   end  
  46. end  
  47.   
  48. class AopTest  
  49.   include AopAspects  
  50.   include AopBinder  
  51.   def initialize  
  52.   end  
  53.     
  54.   def run  
  55.     puts "hello, my run"  
  56.   end  
  57.     
  58.   def run2(name="")  
  59.     puts "hello, #{name}"  
  60.   end  
  61.   run_before :run ,:log_method  
  62.   run_after :run2 , :log_method ,:trans_aspect  
  63. end  
  64.    
  65.   
  66.   
  67. a = AopTest.new  
  68. a.run  
  69. a.run2("ben")  
结果如下
log here
hello, my run
hello, ben
log here
ben
trans here


充分体现了Ruby 简洁锐利的原编程风格
   发表时间:2007-06-22  
偶觉得动态语言没有必要啥正儿八经的Aop框架,利用现成的hotswap,mixin,method_missing这些特性,来做关注分离是很简单的。

def run_before(m)
  alias_method "__before__#{m}", m
  define_method(m) {|*arg| yield(*arg); send("__before__#{m}", *arg);}
end

class Test  
  def run
    puts "hello, my run"  
  end  
  
  run_before(:run) {puts "before run"} 
end
0 请登录后投票
   发表时间:2007-06-22  
谢谢 readonly 的回复阿
有个小小的疑惑,如果用run_before + block 确认可以省去很多的代码,不过这个切面的实现就被放到block中了。问题是,切面的代码放在哪里才是最合适的呢?是不是应该有个地方专门用来定义这个东西的。
随着代码量的增加,按照DRY的原则,是不是应该继续抽象这个切面的实现方式,放到某个module中呢。
0 请登录后投票
   发表时间:2007-06-22  
这段代码没看懂

class_eval <<->END
      def #{method}(*args) 
        #{before_method} 
        #{method}_old(*args) 
      end 
      END 

:(

END是啥?
0 请登录后投票
   发表时间:2007-06-22  
不好意思
<<->END 的表述不太好
可能用
class_eval <<->EOF
def #{method}(*args)
#{before_method}
#{method}_old(*args)
end
EOF
更加好吧

表示一个字符块
0 请登录后投票
   发表时间:2007-06-22  
nacu 写道
谢谢 readonly 的回复阿
有个小小的疑惑,如果用run_before + block 确认可以省去很多的代码,不过这个切面的实现就被放到block中了。问题是,切面的代码放在哪里才是最合适的呢?是不是应该有个地方专门用来定义这个东西的。
随着代码量的增加,按照DRY的原则,是不是应该继续抽象这个切面的实现方式,放到某个module中呢。

有了block不就可以调用任何地方的代码了么,随便你把要分离的代码放到哪里都可以啊,Class Method, module mixin进来都可以:
class Test    
  def run  
    puts "hello, my run"    
  end    
    
  def self.log
    puts "before run"
  end
  
  run_before(:run) {log}
end
0 请登录后投票
   发表时间:2007-06-22  
对阿 呵呵  没有想到
对于 block的使用还是不太习惯
这样的实现是最简洁的
按照ruby 的惯例
最后的使用应该是
run_before :method1 ,:method2 ...........{do something}
run_after :method1 ,:method2 ...........{do something}
run_around :method1 ,:method2 ...........{do something}
这样的描述吧
0 请登录后投票
   发表时间:2007-06-22  
nacu 写道
不好意思
<<->END 的表述不太好
可能用
class_eval <<->EOF
def #{method}(*args)
#{before_method}
#{method}_old(*args)
end
EOF
更加好吧

表示一个字符块


真的不好意思。能解释一下字符块么?或者给个链接
我google了 ruby 字符块
也没结果。

谢谢了
0 请登录后投票
   发表时间:2007-06-22  
和下面的表述是一样的
class_eval(%Q[
         def #{method_name}
         #{method_body}
         end
         ])
ruby 的语法还真是,实现同一种目的有n种表述方法,在项目应用中看来还是要制定一种表述约定,不然沟通和维护实在是不方便。
0 请登录后投票
   发表时间:2007-06-22  
nacu 写道
对阿 呵呵  没有想到
对于 block的使用还是不太习惯
这样的实现是最简洁的
按照ruby 的惯例
最后的使用应该是
run_before :method1 ,:method2 ...........{do something}
run_after :method1 ,:method2 ...........{do something}
run_around :method1 ,:method2 ...........{do something}
这样的描述吧

参考一下ActiveRecord的Callbacks,共有四种macros,分别为Method references(symbol)/Callback objects/Inline methods(proc)/Inline eval methods(string)
case callback   
            when Symbol   
              self.send(callback)   
            when String   
              eval(callback, binding)   
            when Proc, Method   
              callback.call(self)   
            else  
              if callback.respond_to?(method)   
                callback.send(method, self)   


http://hideto.iteye.com/blog/93084
0 请登录后投票
论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics