Ruby Meta Programming Practical Example _ruby topic

Source: Internet
Author: User
Tags glob

Like Ruby Metaprogramming, puppet and chef use a lot of Ruby's language features to define a new deployment language.
Share a few in the actual project used in the scene, limited capacity, if there is a better program, please leave a message to me:

RPC Interface templating--using Eval, alias, Defind_method

Require ' RACK/RPC '

class Server < Rack::rpc::server
 def hello_world
  "Hello, world!"
 End

 RPC ' Hello_world ' =>: Hello_world
End

Above is an RPC server that writes a function that invokes the RPC command for registration.

Using Define_method, eval, alias method, you can realize a rpc/directory of *.rb files, loading and RPC interface registration function, the implementation code is as follows:

Module RPC require ' RACK/RPC ' #require rpc/*.rb file Dir.glob (File.join (file.dirname), ' RPC ', ' __file__ ')) do *.rb
   le| Require file End Class Runner < Rack::rpc::server #include the rpc/*.rb and regsiter RPC call #eg.
    RPC/GOD.RB God.hello @ @rpc_list = [] Dir.glob (File.join (File.dirname (__file__), ' RPC ', "*.rb ')) do |file| Rpc_class = File.basename (File). Split ('. RB ') [0].capitalize rpc_list = [] #加载module下的方法到Runner这个类下面 eval Include Frigga::rpc::#{rpc_class} "#获取声明的RPC接口 eval" rpc_list = frigga::rpc::#{rpc_class}::rpc_list "rpc_list.
     Each do |rpc_name| #alias一个新的rpc方法, called Old_xxxx_xxxx eval "Alias:old_#{rpc_class.downcase}_#{rpc_name}: #{rpc_name}" #重新定义rpc方法, add a row
      Log printing, and then call the Old_xxxx_xxxx RPC method Define_method "#{rpc_class.downcase}_#{rpc_name}". To_sym do |*arg| Logger.info ' [#{request.ip}] called #{rpc_class.downcase}.#{rpc_name} #{arg.join (', ')} ' eval ' OLD_#{RPC_CLASS.DOWNC
 Ase}_#{rpc_name} *arg "    End #注册RPC调用 RPC "#{rpc_class.downcase}.#{rpc_name}" => "#{rpc_class.downcase}_#{rpc_name}". To_sym #添加到全局变量, rollup all RPC methods @ @rpc_list << "#{rpc_class.downcase}.#{rpc_name}" End-Def help Rpc_ Methods = ([' Help '] + @ @rpc_list. Sort). Join ("\ n") End RPC "Help" =>: Help End #RPC

After completing the above function, it is very convenient to develop RPC interface, such as the following IP address Add, delete, check code, register ip.list, Ip.add and Ip.del methods:

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 
 

dsl--Use Instance_eval

Instance_eval is a Swiss army knife in the Ruby language, especially for DSL support.
Let's take a look at the API for setting up file templates in chef (an Open-source Automated deployment tool):

Copy Code code as follows:

Template "/path/to/file.conf" do
SOURCE "File.conf.erb"
Owner "Wilbur"
Mode "0744"
End

In the above code, source, owner, mode need to be passed from the external block to the template inside the block, in order to achieve this goal, the use of the Instance_eval code is as follows:

  Class CHEFDSL
   def template (path, &block)
    templatedsl.new (path, &block)
   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
  

This little trick allows the Templatedsl object to apply block, as it does in its own scope. The block can access and invoke variables and methods in TEMPLATEDSL.

If Instance_eval is not used, as in the following code, Ruby throws a nomethoderror because source, owner, mode cannot be accessed in the block.

Copy Code code as follows:

Class TEMPLATEDSL
Def initialize (path, &block)
@path = Path
Block.call
End
End

Of course, you can also use yeild transfer variables, but not instance_eval concise and flexible.

command-line interaction--using Instance_eval

command line interaction, you can use Highline this gem.
However, highline in some ways can not meet my needs, such as the above described in the Chef template function, to achieve the following effect, greatly simplifying the duplicate code:

Copy Code code as follows:

#检查frigga fail, ask if you want to continue
Tip.ask Frigga_fail? Todo
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继续, enter quit exit

The implementation code is as follows:

 require ' Colorize ' class Tip def self.ask (stat = true, &block) new (&block
   ). RET if stat = = True End Attr_reader:ret def initialize (&block) @opt = [] @caller = {} @banner = ""
    @ret = False Self.instance_eval (&block) print "#{@banner} [#{@opt. Join ('/')}]:". Light_yellow Loop Do x = Gets.chomp.strip.to_sym if @opt. Include? (x) @ret = (@caller [x].call if @caller. Key? x) If @ret = =: Retry print "\n#{@banner} [#{@opt. Join ('/')}]:". Light_yellow Next Else retur

  N @ret End Else print input error, please enter [#{@opt. Join ('/')}]: ". Light_yellow End End
  def on (opt, &block) @opt << opt @caller [opt] = block if Block_given? End Def banner (str) @banner = str End-end 
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.