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类定义一个新方法
• 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方法可以在运行时改变定义
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类的一个实例
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.
调用标识符定义的方法,传递任意指定的参数。
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)
missing_method
NoMethodError Exception
• If a method that is not existent is in a class is invoked,NoMethodError exception will be generated
如果一个方法在调用的函数里不存在,将会抛出NoMethodError异常
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)
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实现
define_method
• The define_method defines an instance method in the receiver.
define_method 定义一个实例方法在接收者。
• 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
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类定义一个新方法
- class String
- def encrypt
- tr "a-z","b-za"
- end
- end
- puts "cat"
- puts "cat".encrypt
好处
> 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方法可以在运行时改变定义
- class Logger
- if ENV['DEBUG']
- def log(msg)
- STDERR.puts "LOG:" +msg
- end
- else
- def log(msg)
- end
- end
- end
类是对象化的
• 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类的一个实例
- class Person
- puts self # Person is an instance of Class
- def self.my_class_method
- puts "This is my own class method"
- end
- end
• 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.
调用标识符定义的方法,传递任意指定的参数。
- class Klass
- def hello(*args)
- "Hello " + args.join(' ')
- end
- end
- k = Klass.new
- #The following statements are equivalent
- puts k.hello("gentle", "readers") #=> "Hello gentle readers"
- puts k.hello "gentle", "readers" #=> "Hello gentle readers"
- puts k.send(:hello, "gentle", "readers")#=> "Hello gentle readers"
- 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)
- # The Duck class
- class Duck
- def quack
- puts "Duck is quacking!"
- end
- end
- #The Mallard class
- class Mallard
- def quack
- puts "Mallard is quacking!"
- end
- end
- #If it quacks like a duck, it must be duck
- def quack_em(ducks)
- ducks.each do |duck|
- if duck.respond_to? :quack
- duck.quack
- end
- end
- end
- birds = [Duck.new, Mallard.new, Object.new]
- puts "----Call quack method for each item of the birds array.Only Duck and Mallard should be quacking."
- 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异常
- class Dummy
- end
- puts "----Call a method that does not exist in the Dummy class
- and expect NoMethodError exception."
- dummy = Dummy.new
- dummy.call_a_method_that_does_not_exist
• 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)
- class Dummy
- def method_missing(m, *args)
- puts "There's no method called #{m} here -- so method_missing method is called."
- puts " with arguments #{args}"
- end
- end
- dummy = Dummy.new
- 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实现
- class Finder
- def find(name)
- puts "find(#{name}) is called"
- end
- def method_missing(name, *args)
- if /^find_(.*)/ =~ name.to_s
- return find($1)
- end
- super
- end
- end
- f = Finder.new
- f.find("Something")
- f.find_by_last_name("Shin")
- f.find_by_title("Technology Architect")
define_method
• The define_method defines an instance method in the receiver.
define_method 定义一个实例方法在接收者。
- define_method(symbol, method) => new_method
- define_method(symbol) { block } => proc
方法参数可以是一个Proc或Method对象。如果block被指定,将被作为方法体。
• An example of
> define_method(symbol) { block } => proc
- class Love
- define_method(:my_hello) do |arg1, arg2|
- puts "#{arg1} loves #{arg2}"
- end
- end
- love = Love.new
- love.my_hello("Sang Shin", "Young Shin")