ruby元编程实际使用实例

这篇文章主要介绍了ruby元编程实际使用实例,包含用eval、alias、defind_method、instance_eval等实际使用例子,需要的朋友可以参考下

很喜欢ruby元编程,puppet和chef用到了很多ruby的语言特性,来定义一个新的部署语言。
分享几个在实际项目中用到的场景,能力有限,如果有更优方案,请留言给我:)

rpc接口模板化――使用eval、alias、defind_method

 require 'rack/rpc' class Server  :hello_world end

上面是一个rpc server,编写一个函数,调用rpc命令进行注册。

采用define_method、eval、alias方法,可以实现一个判断rpc/目录下的*.rb文件,进行加载和rpc接口注册的功能,实现代码如下:

 module RPC require 'rack/rpc' #require rpc/*.rb文件 Dir.glob(File.join(File.dirname(__FILE__), 'rpc', "*.rb")) do |file| require file end class Runner  "#{rpc_class.downcase}_#{rpc_name}".to_sym #添加到全局变量,汇总所有的rpc方法 @@rpc_list << "#{rpc_class.downcase}.#{rpc_name}" end end def help rpc_methods = (['help'] + @@rpc_list.sort).join("\n") end rpc "help" => :help end end #RPC

完成上述功能后,可以非常方便的开发rpc接口,例如下面这个IP地址增、删、查的代码,注册ip.list, ip.add和ip.del方法:

 module RPC module Ip #RPC_LIST used for regsiter rpc_call RPC_LIST = %w(list add del) def list $white_lists end def add(ip) if ip =~ /^((25[0-5]|2[0-4]\d|[0-1]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[0-1]?\d\d?)$/ $white_lists << ip write_to_file return "succ" else return "fail" end end def del(ip) if $white_lists.include?(ip) $white_lists.delete ip write_to_file return "succ" else return "fail" end end def write_to_file File.open(IP_yml, "w") do |f| $white_lists.uniq.each {|i| f << "- #{i}\n"} end end end end

DSL――使用instance_eval

instance_eval是ruby语言中的瑞士军刀,特别是支持DSL方面。
我们来看一下chef(一个开源的自动化部署工具)中设置文件模板的API:

复制代码 代码如下:

    template "/path/to/file.conf" do
      source "file.conf.erb"
      owner  "wilbur"
      mode   "0744"
    end

上述代码中,source、owner、mode需要从外部block,传递到template内部的block中,为了实现该目的,采用了instance_eval代码如下:

 class ChefDSL def template(path, &block) TemplateDSL.new(path, &block) end end class TemplateDSL def initialize(path, &block) @path = path instance_eval &block end def source(source); @source = source; end def owner(owner);  @owner = owner; end def mode(mode);   @mode  = mode;  end end

上面这个小技巧使得TemplateDSL对象可以应用block,和在自己的scope一样。block可以访问和调用TemplateDSL中的变量和方法。

如果没有使用instance_eval,如下面的代码,ruby就会抛出一个NoMethodError,因为source、owner、mode无法在block中被访问到。

复制代码 代码如下:

    class TemplateDSL
      def initialize(path, &block)
        @path = path
        block.call
      end
    end

当然也可以使用yeild传递变量的方式实现,但没有instance_eval简洁和灵活。

命令行交互――使用instance_eval

命令行交互,可以采用highline这个gem.
但highline在有些方面不能满足我的需求,比如类似上面介绍的chef template功能,达到的效果如下,大大简化了重复代码:

复制代码 代码如下:

        #检查frigga fail,询问是否继续
        Tip.ask frigga_fail? do
          banner "Check some frigga failed, skip failed host and continue deploy?"
          on :yes
          on :quit do
            raise Odin::TipQuitExcption
          end
        end
        ...

        #运行时显示结果如下:
        Check some frigga failed, skip failed host and continue deploy? [yes/quit]
        #输入yes继续,输入quit退出

以上就是ruby元编程实际使用实例的详细内容,更多请关注0133技术站其它相关文章!

赞(0) 打赏
未经允许不得转载:0133技术站首页 » 脚本专栏