`
love~ruby+rails
  • 浏览: 852318 次
  • 性别: Icon_minigender_1
  • 来自: lanzhou
社区版块
存档分类
最新评论

Metaprogramming in Ruby: It’s All About the Self

阅读更多

After writing my last post on Rails plugin idioms, I realized that Ruby metaprogramming, at its core, is actually quite simple.

It comes down to the fact that all Ruby code is executed code–there is no separate compile or runtime phase. In Ruby, every line of code is executed against a particular self . Consider the following five snippets:

class

 Person
  def

 self

.species


    "Homo Sapien"


  end


end


 
class

 Person
  class

 <<

 self


    def

 species
      "Homo Sapien"


    end


  end


end


 
class

 <<

 Person
  def

 species
    "Homo Sapien"


  end


end


 
Person.instance_eval

 do


  def
   species
    "Homo Sapien"


  end


end


 
def

 Person.species


  "Homo Sapien"


end

All five of these snippets define a Person.species that returns Homo Sapien . Now consider another set of snippets:

class

 Person
  def

 name
    "Matz"


  end


end


 
Person.class_eval

 do


  def

 name
    "Matz"


  end


end

These snippets all define a method called name on the Person class. So Person.new.name will return “Matz”. For those familiar with Ruby, this isn’t news. When learning about metaprogramming, each of these snippets is presented in isolation: another mechanism for getting methods where they “belong”. In fact, however, there is a single unified reason that all of these snippets work the way they do.

First, it is important to understand how Ruby’s metaclass works. When you first learn Ruby, you learn about the concept of the class, and that each object in Ruby has one:

class

 Person
end


 
Person.class

 #=> Class


 
class

 Class


  def

 loud_name
    "#{name.upcase}!"


  end


end


 
Person.loud_name

 #=> "PERSON!"

Person is an instance of Class , so any methods added to Class are available on Person as well. What they don’t tell you, however, is that each object in Ruby also has its own metaclass , a Class that can have methods, but is only attached to the object itself.

matz = Object

.new


def

 matz.speak


  "Place your burden to machine's shoulders"


end

What’s going on here is that we’re adding the speak method to matz ’s metaclass , and the matz object inherits from its metaclass and then Object . The reason this is somewhat less clear than ideal is that the metaclass is invisible in Ruby:

matz = Object

.new


def

 matz.speak


  "Place your burden to machine's shoulders"


end


 
matz.class

 #=> Object

In fact, matz ’s “class” is its invisible metaclass. We can even get access to the metaclass:

metaclass = class

 <<

 matz; self

; end


metaclass.instance_methods

.grep

(

/

speak/

)

 #=> ["speak"]

At this point in other articles on this topic, you’re probably struggling to keep all of the details in your head; it seems as though there are so many rules. And what’s this class << matz thing anyway?

It turns out that all of these weird rules collapse down into a single concept: control over the self in a given part of the code. Let’s go back and take a look at some of the snippets we looked at earlier:

class

 Person
  def

 name
    "Matz"


  end


 
  self

.name

 #=> "Person"


end

Here, we are adding the name method to the Person class. Once we say class Person , the self until the end of the block is the Person class itself.

Person.class_eval

 do


  def

 name
    "Matz"


  end


 
  self

.name

 #=> "Person"


end

Here, we’re doing exactly the same thing: adding the name method to instances of the Person class. In this case, class_eval is setting the self to Person until the end of the block. This is all perfectly straight forward when dealing with classes, but it’s equally straight forward when dealing with metaclasses:

def

 Person.species


  "Homo Sapien"


end


 
Person.name

 #=> "Person"

As in the matz example earlier, we are defining the species method on Person ’s metaclass. We have not manipulated self , but you can see using def with an object attaches the method to the object’s metaclass.

class

 Person
  def

 self

.species


    "Homo Sapien"


  end


 
  self

.name

 #=> "Person"


end

Here, we have opened the Person class, setting the self to Person for the duration of the block, as in the example above. However, we are defining a method on Person ’s metaclass here, since we’re defining the method on an object (self ). Also, you can see that self.name while inside the person class is identical to Person.name while outside it.

class

 <<

 Person
  def

 species
    "Homo Sapien"


  end


 
  self

.name

 #=> ""


end

Ruby provides a syntax for accessing an object’s metaclass directly. By doing class << Person , we are setting self to Person ’s metaclass for the duration of the block. As a result, the species method is added to Person ’s metaclass, rather than the class itself.

class

 Person
  class

 <<

 self


    def

 species
      "Homo Sapien"


    end


 
    self

.name

 #=> ""


  end


end

Here, we combine several of the techniques. First, we open Person , making self equal to the Person class. Next, we do class << self , making self equal to Person ’s metaclass. When we then define the species method, it is defined on Person ’s metaclass.

Person.instance_eval

 do


  def

 species
    "Homo Sapien"


  end


 
  self

.name

 #=> "Person"


end

The last case, instance_eval , actually does something interesting. It breaks apart the self into the self that is used to execute methods and the self that is used when new methods are defined. When instance_eval is used, new methods are defined on the metaclass , but the self is the object itself.

In some of these cases, the multiple ways to achieve the same thing arise naturally out of Ruby’s semantics. After this explanation, it should be clear that def Person.species , class << Person; def species , and class Person; class << self; def species aren’t three ways to achieve the same thing by design , but that they arise out of Ruby’s flexibility with regard to specifying what self is at any given point in your program.

On the other hand, class_eval is slightly different. Because it take a block, rather than act as a keyword, it captures the local variables surrounding it. This can provide powerful DSL capabilities, in addition to controlling the self used in a code block. But other than that, they are exactly identical to the other constructs used here.

Finally, instance_eval breaks apart the self into two parts, while also giving you access to local variables defined outside of it.

In the following table, defines a new scope means that code inside the block does not have access to local variables outside of the block.

mechanism method resolution method definition new scope? class Person class << Person Person.class_eval Person.instance_eval
Person same yes
Person’s metaclass same yes
Person same no
Person Person’s metaclass no

Also note that class_eval is only available to Modules (note that Class inherits from Module) and is an alias for module_eval . Additionally, instance_exec , which was added to Ruby in 1.8.7, works exactly like instance_eval , except that it also allows you to send variables into the block.

UPDATE: Thank you to Yugui of the Ruby core team for correcting the original post , which ignored the fact that self is broken into two in the case of instance_eval .

分享到:
评论

相关推荐

    Metaprogramming.Ruby

    《Metaprogramming Ruby: Programming Like the Ruby Pros》是一本深入探讨Ruby元编程技术的专业书籍,作者Paolo Perrotta通过丰富的实例和清晰的概念解析,帮助读者理解和掌握Ruby中的高级编程技巧。本书不仅适用于...

    MetaProgramming in Ruby系列教程的中译版

    MetaProgramming in Ruby系列教程的中译版。 uby是动态的、魔幻而有趣的。而元编程(Metaprogramming)技术在Ruby中的应用也让我大开眼界,虽然以前也有浅显地介绍反射机制(Reflection),但我仍然觉得才疏学浅,不...

    Ruby元编程 源代码 Metaprogramming Ruby source code

    这本《Metaprogramming Ruby》书籍深入探讨了如何利用Ruby的特性进行元编程,帮助开发者提升代码的灵活性、可扩展性和复用性。源代码提供了书中各个示例的实践,让读者能够更好地理解元编程的概念。 元编程的核心...

    Metaprogramming Ruby 2(Pragmatic,2014)

    Dig under the surface and explore Ruby's most advanced feature: a collection of techniques and tricks known as metaprogramming. In this book, you'll learn metaprogramming as an essential component of ...

    Pragmatic.Metaprogramming.Ruby.Feb.2010.rar

    Pragmatic.Metaprogramming.Ruby.Feb.2010.rar

    Metaprogramming Ruby 2nd Edition ruby元编程

    ### Metaprogramming Ruby 2nd Edition:深入理解Ruby元编程 #### 一、书籍简介与价值 《Metaprogramming Ruby 2nd Edition》是一本深入探讨Ruby语言元编程特性的经典之作。本书不仅适合那些希望深入了解Ruby内部...

    Metaprogramming Ruby

    ### Metaprogramming Ruby:深入理解动态编程的力量 #### 标题解读 “Metaprogramming Ruby”这一标题明确地指出了本书的核心内容——通过元编程技术深入探索Ruby语言的独特魅力。元编程(Metaprogramming)是一种...

    Advanced Metaprogramming in Classic C++, 3rd Edition

    The gain for the reader is that TMP is presented in the book as a set of techniques that will enable a new style to your C++ coding while making it exceptionally clear and efficient. The book deals ...

    Metaprogramming.in.NET

    ### Metaprogramming in .NET #### 知识点概览 - **元编程概念**:定义、目的、实现方式。 - **反射技术**:基本原理、应用领域、操作示例。 - **文本模板转换工具包 (T4)**:工作流程、应用场景、模板语法介绍。 -...

    Addison.Wesley.C++.Template.Metaprogramming.LiB.chm

    C++ Template Metaprogramming: Concepts, Tools, and Techniques from Boost and Beyond By David Abrahams, Aleksey Gurtovoy Publisher : Addison Wesley Professional Pub Date : December 10, 2004 ISBN ...

    Ruby Under a Microscope

    express algorithms in a very natural way, and then it’s just a matter of typing ruby at the command line and pressing enter, and your Ruby script is running. However, Ruby’s syntax is deceptively ...

    Metaprogramming ruby

    《Metaprogramming Ruby》是一本专注于Ruby编程语言元编程技术的书籍,由Paolo Perrotta撰写。元编程是一种编程范式,它允许在程序运行时修改或创建程序结构和行为。在Ruby中,元编程是其核心特性之一,使得代码能够...

    MetaProgramming-Play:重写 Ruby 注入方法以了解元编程

    第 10 周:创客学院在 Ruby 中玩转元编程挑战: 使用method_missing重新定义对象在询问has_unknown_attribute时的Reacthas_unknown_attribute 。 使用define_method创建Ruby 内置attr_accessor方法的布尔版本。代码...

    ruby-metaprogramming-talk:Ruby 中的元编程讨论

    Ruby 元编程演示 由 Leigh Halliday 创建 例子 在示例文件夹中找到。 查看演示文稿的说明 安装 安装 克隆reveal.js 存储库 $ git clone https://github.com/leighhalliday/ruby-dsl-workshop.git 导航到reveal.js...

    Advanced Metaprogramming in Classic C++

    The classic C++ language admits two basic types of templates—function templates and class templates2: Here is a function template: template scalar_t sq(const scalar_t& x) { return x*x; } Here is a ...

    Metaprogramming Ruby(Second Edition)

    《Metaprogramming Ruby(Second Edition)》是Ruby编程语言领域的一本经典著作,由Peter Eberhardt和Paolo Perrotta共同撰写。这本书详细介绍了如何利用Ruby的强大元编程特性来提升代码的灵活性、可扩展性和简洁性。...

    Metaprogramming in .NET [2013] [pdf + epub]

    .NET框架是微软开发的一种软件开发平台,它提供了丰富的类库和...在《Metaprogramming in .NET》这本书中,作者深入探讨了这些主题,旨在帮助开发者充分利用.NET框架的元编程能力,打造更高效、更灵活的软件解决方案。

    MetaprogrammingRuby2ndEditionFreePdfBook.pdf 英文原版

    Metaprogramming Ruby 2nd Edition – FreePdfBook

Global site tag (gtag.js) - Google Analytics