Ruby Meta-Programming(Ruby元編程,SUN官方文檔)

Ruby Meta-Programming
Topics
• What is and Why Meta-programming?
• Ruby language characteristics (that make it a great meta-programming language)
• Introspection
• Object#send
• Dynamic typing (Duck typing)
• missing_method
• define_method


What is Meta-Programming?
什麼是Meta-Programming
• Metaprogramming is the writing of computer programs that write or manipulate other programs (or themselves) as their data
Metaprogramming是一種電腦程序編寫方式,把編寫或操作程序作爲數據
Why Meta-Programming?
• Provides higher-level abstraction of logic
可以有更高層次的邏輯抽象
> Easier to write code
更簡單的寫代碼
> Easier to read code
更容易閱讀代碼
• Metaprogramming feature of Ruby language is what makes Rails a killer application.
Ruby的Metaprogramming特性使Rails更加優秀。
> For example, the Rails declarations such as "find_by_name","belongs_to" are possible because of the Meta-programming feature of Ruby language.
例如,由於Ruby的Meta-programming特性可以使Rails如此聲明,"find_by_name","belongs_to".


Ruby Language Characteristics that Make It a Great Meta-Programming Language
Ruby Language Characteristics
Ruby語言特性
• Classes are open
類是開放的
• Class definitions are executable code
類可擴展
• Every method call has a receiver
每一個方法調用都有接收者
• Classes are objects
類是對象化的

Classes Are Open
• Unlike, Java and C++, methods and instance variables can be added to a class (including core classes provided by Ruby such as String and Fixnum) during runtime.
不同與java和C++,在Ruby裏,方法,實例變量能在運行時添加到一個類裏(包括Ruby的核心類,例如String和Fixnum)
• Example: Define a new method for String class
例:給String類定義一個新方法
  1. class String
  2.   def encrypt
  3.     tr "a-z","b-za"
  4.   end
  5. end

  6. puts "cat"
  7. puts "cat".encrypt
• Benefits
好處
> Applications can be written in higher level abstraction
程序可以更加抽象的編寫
> More readable code
代碼更加可讀
> Less coding
編寫量減少
• How it is used in Rails
怎麼應用在Rails裏
> One can open up Rails classes and add new features to them.
可以打開一個Rails類,並添加新特性
> Rails integration testing
Rails集成測試

Class Definitions are Executable Code
類是可擴展的
• The log(msg) method is defined differently during runtime
log方法可以在運行時改變定義
  1. class Logger
  2.   if ENV['DEBUG']
  3.     def log(msg)
  4.       STDERR.puts "LOG:" +msg
  5.     end
  6.   else
  7.     def log(msg)
  8.     end
  9.   end
  10. end
Classes Are Objects
類是對象化的
• String class is an instance of Class class in the same way Fixnum class (or whatever class) is an instance of Class class
String類是Class類的一個實例,同理,Fixnum類是Class類的一個實例
  1. class Person
  2.   
  3.   puts self # Person is an instance of Class
  4.   
  5.   def self.my_class_method
  6.     puts  "This is my own class method"
  7.   end
  8.   
  9. end
Every Method Call Has a Receiver
• Default receiver is self
默認的接收者就是本身


Introspection
What is Introspection?
• Being able to find information on an object during runtime
可以在運行時查找一個對象的信息
Examples
> Object#respond_to?
> Object#class
> Object#methods
> Object#class.superclass
> Object#class.ancestors
> Object#private_instance_methods()
> Object#public_instance_methods(false)
> ...

Dynamic Method Invocation through Object#send
用Object#send進行動態方法調用
• In Ruby, an object’s methods are not fixed at any compilation time but can be dynamically extended or modified at any point.
在Ruby裏,對象的方法並不一定適合編譯,但能夠動態的擴展或修改在任何地方。
• Instead of calling a method directly by name as following
替代如下的根據名字直接進行方法調用
> an_object_instance.hello(“Good morning!”)
• It is possible instead to invoke generically any object method by using a string or symbol variable to specify the target method
可以通過字符串或符號變量定義目標方法來替代對象方法的直接di
> an_object_instance.send(”#{name_of_method}”, args)

obj.send(symbol [, args...])
• Invokes the method identified by symbol, passing it any arguments specified.
調用標識符定義的方法,傳遞任意指定的參數。
  1. class Klass
  2.   def hello(*args)
  3.     "Hello " + args.join(' ')
  4.   end
  5. end

  6. k = Klass.new

  7. #The following statements are equivalent
  8. puts k.hello("gentle""readers")       #=> "Hello gentle readers"
  9. puts k.hello "gentle""readers"        #=> "Hello gentle readers"
  10. puts k.send(:hello"gentle""readers")#=> "Hello gentle readers"
  11. puts k.send :hello"gentle""readers" #=> "Hello gentle readers"


Dynamic Typing(Duck Typing)
What is Dynamic Typing?
• A programming language is said to use dynamic typing when type checking is performed at run-time (also known as "late-binding") as opposed to compile-time.
使用動態類型的程序語言在運行時檢查數據類型(又稱“懶加載”),這與編譯時相對。
> Examples of languages that use dynamic typing include PHP, Lisp, Perl, Python, Ruby, and Smalltalk.
動態語言包括PHP, Lisp, Perl, Python, Ruby, and Smalltalk.

What is Duck Typing
• Duck typing is a style of dynamic typing in which an object's current set of methods and properties determines the valid semantics, rather than its inheritance from a particular class.
Duck類型是一個對象當前的方法和屬性決定於正確的語義,而不是決定於繼承一個類。
> The name of the concept refers to the duck test, attributed to James Whitcomb Riley, which may be phrased as “If it walks like a duck and quacks like a duck, I would call it a duck”.
這個名字的含義涉及到鴨子,由James Whitcomb Riley提出,可以理解爲“如果一個東西走路像鴨子,叫聲像鴨子,那就叫它鴨子吧
”。
Duck Typing Example (page 1)
  1. # The Duck class
  2. class Duck
  3.   def quack
  4.     puts "Duck is quacking!"
  5.   end
  6. end

  7. #The Mallard class
  8. class Mallard
  9.   def quack
  10.     puts "Mallard is quacking!"
  11.   end
  12. end

  13. #If it quacks like a duck, it must be duck
  14. def quack_em(ducks)
  15.   ducks.each do |duck|
  16.     if duck.respond_to? :quack
  17.       duck.quack
  18.     end
  19.   end
  20. end

  21. birds = [Duck.new, Mallard.newObject.new]

  22. puts "----Call quack method for each item of the birds array.Only Duck and Mallard should be quacking."
  23. quack_em(birds)


missing_method
NoMethodError Exception
• If a method that is not existent is in a class is invoked,NoMethodError exception will be generated
如果一個方法在調用的函數裏不存在,將會拋出NoMethodError異常
  1. class Dummy
  2. end
  3. puts "----Call a method that does not exist in the Dummy class
  4. and expect NoMethodError exception."
  5. dummy = Dummy.new
  6. dummy.call_a_method_that_does_not_exist
method_missing Method
• If method_missing(m, *args) method is defined in a class, it will be called (instead of NoMethodError exception being generated) when a method that does not exist is invoked
如果method_missing(m, *args)方法被定義在一個類裏,當一個不存在方法被調用時,這個方法將被調用(替代拋出NoMethodError)
  1. class Dummy
  2.   def method_missing(m, *args)
  3.     puts "There's no method called #{m} here -- so method_missing method is called."
  4.     puts " with arguments #{args}"
  5.   end
  6. end
  7. dummy = Dummy.new
  8. dummy.a_method_that_does_not_exist

How method_missing Method is used in Rails
method_missing方法如何在Rails裏應用
• Rails' find_by_xxxx() finder method is implemented through method_missing.
Rails的find_by_xxxx()方法就由method_missing實現
  1. class Finder
  2.   def find(name)
  3.     puts "find(#{name}) is called"
  4.   end
  5.   
  6.   def method_missing(name, *args)
  7.     if /^find_(.*)/ =~ name.to_s
  8.       return find($1)
  9.     end
  10.     super
  11.   end
  12. end

  13. f = Finder.new
  14. f.find("Something")
  15. f.find_by_last_name("Shin")
  16. f.find_by_title("Technology Architect")

define_method
• The define_method defines an instance method in the receiver.
define_method 定義一個實例方法在接收者。
  1. define_method(symbol, method) => new_method
  2. define_method(symbol) { block } => proc
• The method parameter can be a Proc or Method object.If a block is specified, it is used as the method body.
方法參數可以是一個Proc或Method對象。如果block被指定,將被作爲方法體。
• An example of
> define_method(symbol) { block } => proc
  1. class Love
  2.   define_method(:my_hellodo |arg1, arg2|
  3.     puts "#{arg1} loves #{arg2}"
  4.   end
  5. end

  6. love = Love.new
  7. love.my_hello("Sang Shin""Young Shin")


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章