<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>lazybios (Eric Liu)</title>
    <link>https://ruby-china.org/lazybios</link>
    <description></description>
    <language>en-us</language>
    <item>
      <title>hey.com 所用到的技术栈</title>
      <description>&lt;p&gt;DHH 在 twitter 上分享了 hey.com 的技术栈以及 Gemfile&lt;/p&gt;
&lt;h5 id="Stack:"&gt;Stack:&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;Vanilla Ruby on Rails on the backend, running on edge&lt;/li&gt;
&lt;li&gt;Stimulus, Turbolinks, Trix + NEW MAGIC on the front end&lt;/li&gt;
&lt;li&gt;MySQL for DB (Vitess for sharding)&lt;/li&gt;
&lt;li&gt;Redis for short-lived data + caching&lt;/li&gt;
&lt;li&gt;ElasticSearch for indexing&lt;/li&gt;
&lt;li&gt;AWS/K8S&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="Gemfile"&gt;Gemfile&lt;/h5&gt;
&lt;p&gt;&lt;a href="https://gist.github.com/dhh/782fb925b57450da28c1e15656779556" rel="nofollow" target="_blank"&gt;https://gist.github.com/dhh/782fb925b57450da28c1e15656779556&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/dhh/status/1275901955995385856" rel="nofollow" target="_blank" title=""&gt;原推&lt;/a&gt;里还有关于项目管理、k8s、客户端等细节讨论，很值得阅读。&lt;/p&gt;</description>
      <author>lazybios</author>
      <pubDate>Fri, 26 Jun 2020 02:06:13 +0800</pubDate>
      <link>https://ruby-china.org/topics/40024</link>
      <guid>https://ruby-china.org/topics/40024</guid>
    </item>
    <item>
      <title>Status Page 里的 Redis 有报错</title>
      <description>&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2020/41cd86cd-5fdb-488b-988a-985e03050e05.png!large" title="" alt=""&gt;&lt;/p&gt;</description>
      <author>lazybios</author>
      <pubDate>Thu, 06 Feb 2020 11:02:16 +0800</pubDate>
      <link>https://ruby-china.org/topics/39485</link>
      <guid>https://ruby-china.org/topics/39485</guid>
    </item>
    <item>
      <title>[北京] 诚招后端 ( Ruby 、Python 、Golang)、前端 (Vue) 工程师</title>
      <description>&lt;h4 id="后端开发工程师"&gt;后端开发工程师&lt;/h4&gt;&lt;h5 id="岗位职责"&gt;岗位职责&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;负责爬虫后端研发工作&lt;/li&gt;
&lt;li&gt;参与后端系统架构设计&lt;/li&gt;
&lt;li&gt;负责对接前端 App 系统和后端相关产品&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="基本要求"&gt;基本要求&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;1 年以上 Ruby on Rails / Python / Go 开发经验&lt;/li&gt;
&lt;li&gt;熟悉 MySQL、Redis、ElasticSearch 的使用，有一定性能优化经验&lt;/li&gt;
&lt;li&gt;熟悉 RESTful Service API 设计，具有良好的编程习惯和代码风格&lt;/li&gt;
&lt;li&gt;熟悉 Git 协作开发流程，并能在 Linux 工作环境下进行日常开发&lt;/li&gt;
&lt;li&gt;熟练使用英语，可无障碍阅读英语文档、技术博客&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="加分项"&gt;加分项&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;有 Openresty、Go 其中任一使用经验者优先&lt;/li&gt;
&lt;li&gt;有 Scrapy 使用经验优先&lt;/li&gt;
&lt;li&gt;有一定的前端经验，了解前端工作流，熟悉 Vue 全家桶者优先&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="前端开发工程师"&gt;前端开发工程师&lt;/h4&gt;&lt;h5 id="岗位职责"&gt;岗位职责&lt;/h5&gt;
&lt;p&gt;负责 H5 活动、后台管理系统、小程序等前端相关工作&lt;/p&gt;
&lt;h5 id="基本要求"&gt;基本要求&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;熟练掌握 JavaScript(ES6)、HTML5、CSS 技术&lt;/li&gt;
&lt;li&gt;熟练掌握 Vue、React 等 Web 开发技术，有移动端 H5 开发经验优先&lt;/li&gt;
&lt;li&gt;有具备一定复杂度的 SPA 开发经验&lt;/li&gt;
&lt;li&gt;热爱编程，技术扎实，对代码优化有着持续不断的追求&lt;/li&gt;
&lt;li&gt;能承担一定工作压力，具备良好的沟通能力和优秀的团队协作能力&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;如果你也活跃于以下社交平台，也欢迎你向我们展示：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Github / Stack Overflow / SegmentFault&lt;/li&gt;
&lt;li&gt;博客 / V2EX / Twitter / 微博 / 知乎 / Instagram&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="薪资范围"&gt;薪资范围&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;薪资：12k - 30k &lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="联系方式"&gt;联系方式&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;投递邮箱：hr#caicheng.tech&lt;/li&gt;
&lt;li&gt;邮件主题：[应聘岗位]+姓名 + 来自 V2EX，例如"[前端工程师] + 姓名 + 来自 V2EX"&lt;/li&gt;
&lt;li&gt;公司地址：北京市海淀区学院路学知轩大厦&lt;/li&gt;
&lt;li&gt;微信：扫码请备注：应聘岗位 + 姓名&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src="http://7b1gwu.com1.z0.glb.clouddn.com/WechatIMG8.jpeg" title="" alt=""&gt;&lt;/p&gt;</description>
      <author>lazybios</author>
      <pubDate>Tue, 21 Aug 2018 21:20:13 +0800</pubDate>
      <link>https://ruby-china.org/topics/37360</link>
      <guid>https://ruby-china.org/topics/37360</guid>
    </item>
    <item>
      <title>关于===你应该知道的几件事儿</title>
      <description>&lt;p&gt;与 JavaScript 里的&lt;code&gt;===&lt;/code&gt;类似，Ruby 里也有一个&lt;code&gt;===&lt;/code&gt;操作符，不过所不同的是 JavaScript 里用&lt;code&gt;===&lt;/code&gt;来验证相等性，而 Ruby 中的&lt;code&gt;===&lt;/code&gt;确是用来验证归属性的， &lt;code&gt;a === b&lt;/code&gt;，的含义可以粗略的描述成表示假设&lt;code&gt;a&lt;/code&gt;是一个集合，那么&lt;code&gt;b&lt;/code&gt;属于&lt;code&gt;a&lt;/code&gt;吗？&lt;/p&gt;

&lt;p&gt;一个比较常见的用例是测试一个对象是否是某个类的实例。这也是为什么会把&lt;code&gt;===&lt;/code&gt;称为&lt;code&gt;case&lt;/code&gt;比较符的原因。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;String&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s2"&gt;"hi"&lt;/span&gt;       &lt;span class="c1"&gt;# True&lt;/span&gt;
&lt;span class="no"&gt;Object&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s2"&gt;"hi"&lt;/span&gt;       &lt;span class="c1"&gt;# True&lt;/span&gt;
&lt;span class="no"&gt;Integer&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s2"&gt;"hi"&lt;/span&gt;      &lt;span class="c1"&gt;# False&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这种行为看起来与&lt;code&gt;is_a?&lt;/code&gt;方法有些类似，不过它还是要比&lt;code&gt;is_a?&lt;/code&gt;考虑的更多一些。它还可以用来验证某个值是否落在一个给定范围内。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;        &lt;span class="c1"&gt;# True&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;      &lt;span class="c1"&gt;# False&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;除了上面这种明确的数值范围比较外，&lt;code&gt;===&lt;/code&gt;还可以处理正则表达式的验证，因为从某种角度正则表达式所代表的也是一个集合，一个符合表达式条件的字符串集合。这样看可以验证正则就不足为奇了。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="sr"&gt;/abcd/&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s2"&gt;"abcdefg"&lt;/span&gt;  &lt;span class="c1"&gt;# True &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不过要指出的是，数组类型并没有实现&lt;code&gt;===&lt;/code&gt;方法，所以在数组对象上调用&lt;code&gt;===&lt;/code&gt;，实际上调用的是&lt;code&gt;Object&lt;/code&gt;对象的&lt;code&gt;===&lt;/code&gt;方法。猜测这样设计应该是因为数组类型是个可变的集合，相比&lt;code&gt;Set&lt;/code&gt;而言，其集合内容不够明确，没有什么元素可以算的上特定属于某个数组的。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;      &lt;span class="c1"&gt;# False&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="Case语句"&gt;Case 语句&lt;/h3&gt;
&lt;p&gt;了解了&lt;code&gt;===&lt;/code&gt;的特性，再看&lt;code&gt;case&lt;/code&gt;语句的好多行为就好理解多了。&lt;code&gt;case&lt;/code&gt;语句中的比较操作，其实就用的&lt;code&gt;===&lt;/code&gt;方法。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;foo&lt;/span&gt;
&lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="s2"&gt;"bar"&lt;/span&gt;
  &lt;span class="n"&gt;do_something&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="s2"&gt;"baz"&lt;/span&gt;
  &lt;span class="n"&gt;do_something_else&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="类型匹配"&gt;类型匹配&lt;/h4&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s2"&gt;"hi"&lt;/span&gt;
&lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"I'm a string"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="范围匹配"&gt;范围匹配&lt;/h4&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;status_code&lt;/span&gt;
&lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;handle_success&lt;/span&gt;
&lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;handle_failure&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="正则匹配"&gt;正则匹配&lt;/h4&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s2"&gt;"abcd"&lt;/span&gt;
&lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="sr"&gt;/ab/&lt;/span&gt;
  &lt;span class="n"&gt;do_something&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="异常捕获"&gt;异常捕获&lt;/h3&gt;
&lt;p&gt;与&lt;code&gt;case&lt;/code&gt;语句一样，&lt;code&gt;rescue&lt;/code&gt;语句在选择要捕获什么异常时候也是用的&lt;code&gt;===&lt;/code&gt;方法：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;begin&lt;/span&gt;
  &lt;span class="n"&gt;do_something&lt;/span&gt;
&lt;span class="k"&gt;rescue&lt;/span&gt; &lt;span class="no"&gt;StandardError&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在知晓这一设定的前提下，你完全可以绕过异常的继承体系，自己自定义个实现了&lt;code&gt;===&lt;/code&gt;方法的异常类，从而让异常捕获的方式更加多变。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FoobarMatcher&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;===&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# rescue all exceptions with messages starting with FOOBAR &lt;/span&gt;
    &lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;/^FOOBAR/&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;begin&lt;/span&gt;
  &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="no"&gt;EOFError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"FOOBAR: there was an eof!"&lt;/span&gt;
&lt;span class="k"&gt;rescue&lt;/span&gt; &lt;span class="no"&gt;FoobarMatcher&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"rescued!"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;-完-&lt;/p&gt;
&lt;h3 id="参考引用"&gt;参考引用&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="" title=""&gt;http://t.cn/RxtqI1g&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="原文地址"&gt;&lt;a href="http://lazybios.com/2017/01/ruby-triple-equals-operator/" rel="nofollow" target="_blank" title=""&gt;原文地址&lt;/a&gt;&lt;/h5&gt;</description>
      <author>lazybios</author>
      <pubDate>Wed, 25 Jan 2017 23:57:59 +0800</pubDate>
      <link>https://ruby-china.org/topics/32211</link>
      <guid>https://ruby-china.org/topics/32211</guid>
    </item>
    <item>
      <title>小程序加密数据解密失败问题 (Ruby 版)</title>
      <description>&lt;h3 id="问题描述"&gt;问题描述&lt;/h3&gt;
&lt;p&gt;Rails 实现的小程序后台，在做原生 APP 与小程序用户数据打通需求时，遇到了&lt;strong&gt;偶发性&lt;/strong&gt;&lt;u&gt;微信加密数据解密&lt;/u&gt;失败的情况。是的没错，解密失败的情况是偶发的!!!。报错信息如下：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OpenSSL::Cipher::CipherError: bad decrypt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2017/6f44726762b2e01f5fb9b607321a6f8b.png!large" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;就是处在了&lt;code&gt;final&lt;/code&gt;那里。&lt;/p&gt;
&lt;h4 id="微信给的解密算法"&gt;微信给的解密算法&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;对称解密使用的算法为 AES-128-CBC，数据采用PKCS#7填充。&lt;/li&gt;
&lt;li&gt;对称解密的目标密文为 Base64_Decode(encryptedData),&lt;/li&gt;
&lt;li&gt;对称解密秘钥 aeskey = Base64_Decode(session_key), aeskey 是 16 字节&lt;/li&gt;
&lt;li&gt;对称解密算法初始向量 iv 会在数据接口中返回。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://mp.weixin.qq.com/debug/wxadoc/dev/api/signature.html" rel="nofollow" target="_blank" title=""&gt;文档地址&lt;/a&gt;，文档里还提供了 Node、Python、C++、Java 的示例代码，没准能用的上。&lt;/p&gt;
&lt;h4 id="Ruby实现的解密算法"&gt;Ruby 实现的解密算法&lt;/h4&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WXBizDataCrypt&lt;/span&gt;
  &lt;span class="nb"&gt;attr_accessor&lt;/span&gt; &lt;span class="ss"&gt;:app_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:session_key&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;session_key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@app_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app_id&lt;/span&gt;
    &lt;span class="vi"&gt;@session_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;session_key&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;decrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encrypted_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;iv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;session_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Base64&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@session_key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;encrypted_data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Base64&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encrypted_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;iv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Base64&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;cipher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;OpenSSL&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Cipher&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;AES128&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:CBC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;cipher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decrypt&lt;/span&gt;
    &lt;span class="n"&gt;cipher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;session_key&lt;/span&gt;
    &lt;span class="n"&gt;cipher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;iv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;iv&lt;/span&gt;

    &lt;span class="n"&gt;decrypted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cipher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encrypted_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;cipher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;final&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Invalid Buffer'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;decrypted&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'watermark'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s1"&gt;'appid'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="vi"&gt;@app_id&lt;/span&gt;

    &lt;span class="n"&gt;decrypted&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="测试代码"&gt;测试代码&lt;/h4&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'./wx_biz_data_crypt'&lt;/span&gt;

&lt;span class="n"&gt;app_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'wx4f4bc4dec97d474b'&lt;/span&gt;
&lt;span class="n"&gt;iv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'r7BXXKkLb8qrSNn05n0qiA=='&lt;/span&gt;
&lt;span class="n"&gt;session_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'tiihtNczf5v6AKRyjwEUhQ=='&lt;/span&gt;
&lt;span class="n"&gt;encrypted_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
  &lt;span class="s1"&gt;'CiyLU1Aw2KjvrjMdj8YKliAjtP4gsMZM'&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;
  &lt;span class="s1"&gt;'QmRzooG2xrDcvSnxIMXFufNstNGTyaGS'&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;
  &lt;span class="s1"&gt;'9uT5geRa0W4oTOb1WT7fJlAC+oNPdbB+'&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;
  &lt;span class="s1"&gt;'3hVbJSRgv+4lGOETKUQz6OYStslQ142d'&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;
  &lt;span class="s1"&gt;'NCuabNPGBzlooOmB231qMM85d2/fV6Ch'&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;
  &lt;span class="s1"&gt;'evvXvQP8Hkue1poOFtnEtpyxVLW1zAo6'&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;
  &lt;span class="s1"&gt;'/1Xx1COxFvrc2d7UL/lmHInNlxuacJXw'&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;
  &lt;span class="s1"&gt;'u0fjpXfz/YqYzBIBzD6WUfTIF9GRHpOn'&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;
  &lt;span class="s1"&gt;'/Hz7saL8xz+W//FRAUid1OksQaQx4CMs'&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;
  &lt;span class="s1"&gt;'8LOddcQhULW4ucetDf96JcR3g0gfRK4P'&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;
  &lt;span class="s1"&gt;'C7E/r7Z6xNrXd2UIeorGj5Ef7b1pJAYB'&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;
  &lt;span class="s1"&gt;'6Y5anaHqZ9J6nKEBvB4DnNLIVWSgARns'&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;
  &lt;span class="s1"&gt;'/8wR2SiRS7MNACwTyrGvt9ts8p12PKFd'&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;
  &lt;span class="s1"&gt;'lqYTopNHR1Vf7XjfhQlVsAJdNiKdYmYV'&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;
  &lt;span class="s1"&gt;'oKlaRv85IfVunYzO0IKXsyl7JCUjCpoG'&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;
  &lt;span class="s1"&gt;'20f0a04COwfneQAGGwd5oa+T8yO5hzuy'&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;
  &lt;span class="s1"&gt;'Db/XcxxmK01EpqOyuxINew=='&lt;/span&gt;

&lt;span class="n"&gt;pc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;WXBizDataCrypt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;session_key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;pc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encrypted_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;iv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里执行这个测试代码是可以通过的，不过不要被它给蒙蔽了，实际生产环境里会有偶发的报错，错误比例大概是 5/1 的样子。在搜解决方案的时候遇到一个用 Node 的同学也有类似问题&lt;a href="https://forum.leancloud.cn/t/aes/12944" rel="nofollow" target="_blank" title=""&gt;地址&lt;/a&gt;，求问最近有没有人遇到类似的问题，或者有啥解决线索提供没。 &lt;img title=":sob:" alt="😭" src="https://twemoji.ruby-china.com/2/svg/1f62d.svg" class="twemoji"&gt; 拜谢~ &lt;img title=":pray:" alt="🙏" src="https://twemoji.ruby-china.com/2/svg/1f64f.svg" class="twemoji"&gt;&lt;/p&gt;</description>
      <author>lazybios</author>
      <pubDate>Sun, 15 Jan 2017 17:02:35 +0800</pubDate>
      <link>https://ruby-china.org/topics/32128</link>
      <guid>https://ruby-china.org/topics/32128</guid>
    </item>
    <item>
      <title>《Ruby 元编程》读书笔记 (十六)[连载完结]</title>
      <description>&lt;p&gt;这篇是这个系列的完结贴，从第一章到最后的附录，每章节的重点知识都有罗列，整个过程下来获益匪浅，强烈建议每位 Rubyist 都能花些时间阅读一下这本书，别的不敢说，至少能保证你看别人代码时，不被绕晕，同时学习一点元编程的知识，在写 Rails 代码的过程中，也更有利于定位问题。最后感谢各位看官捧场！:)&lt;/p&gt;

&lt;p&gt;博客地址 :&lt;a href="http://lazybios.com/2015/08/note-of-meta-pramgraming-with-ruby-16/" rel="nofollow" target="_blank" title=""&gt;《Ruby 元编程》读书笔记 (十六)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;相关文章：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ruby-china.org/topics/27243" title=""&gt;《Ruby 元编程》读书笔记 (一)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27259" title=""&gt;《Ruby 元编程》读书笔记 (二)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27277" title=""&gt;《Ruby 元编程》读书笔记 (三)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27285/" title=""&gt;《Ruby 元编程》读书笔记 (四)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27299/" title=""&gt;《Ruby 元编程》读书笔记 (五)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27311" title=""&gt;《Ruby 元编程》读书笔记 (六)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27317" title=""&gt;《Ruby 元编程》读书笔记 (七)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27344" title=""&gt;《Ruby 元编程》读书笔记 (八)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27367" title=""&gt;《Ruby 元编程》读书笔记 (九)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27371" title=""&gt;《Ruby 元编程》读书笔记 (十)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27385" title=""&gt;《Ruby 元编程》读书笔记 (十一)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27405" title=""&gt;《Ruby 元编程》读书笔记 (十二)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27409" title=""&gt;《Ruby 元编程》读书笔记 (十三)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27426" title=""&gt;《Ruby 元编程》读书笔记 (十四)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27435" title=""&gt;《Ruby 元编程》读书笔记 (十五)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;传神的头图↓↓↓&lt;/p&gt;

&lt;p&gt;&lt;img src="http://freshstu.qiniudn.com/metaprogramming-1.jpg" title="" alt="Ruby元编程"&gt;&lt;/p&gt;
&lt;h3 id="Self Yield"&gt;Self Yield&lt;/h3&gt;
&lt;p&gt;给一个方法传入代码块时，可以通过 yield 占位对块进行回调。除了直接调用块外，还可以通过 yeild 给代码块传递参数，这个 self yield 的惯用法，其实就是通过 yield self，把自身 (当前对象) 传递给代码块。&lt;/p&gt;
&lt;h4 id="使用tap调试方法调用链"&gt;使用 tap 调试方法调用链&lt;/h4&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tap&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="nf"&gt;upcase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;
&lt;span class="c1"&gt;#输出&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里的 tap 方法就是利用了 self yield 技术，将自己传给代码块，从而让我们能打印出当前的状态值，辅助调试方法调用链，避免“火车失事”问题。&lt;/p&gt;

&lt;p&gt;Kernel#tap的定义和文档描述如下:&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;|...&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Yields self to the block, and then returns self.** The primary purpose of this method is to “tap into” a method chain, in order to perform operations on intermediate results within the chain.**&lt;/p&gt;

&lt;p&gt;不过自己实现一个 tap 方法也不难：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;tap&lt;/span&gt;
        &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;
        &lt;span class="nb"&gt;self&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="Symbol#to_proc方法"&gt;Symbol#to_proc方法&lt;/h3&gt;
&lt;p&gt;Symbol#to_proc方法的目的是位了用更简单的方式来替代一次调用代码块。所谓的一次调用代码块是指那些只有一个参数，且对这个参数只调用一个方法。如下:&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;names&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="n"&gt;bob&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="n"&gt;bill&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="n"&gt;heather&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;names&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;name&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;capitalize&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; [“Bob”, “Bill”, “Heather”]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;那么Symbol#to_proc方法又是怎么做到精简的呢？继续往下看&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;names&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="n"&gt;bob&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="n"&gt;bill&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="n"&gt;heather&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;names&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ss"&gt;:capitalize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; [“Bob”, “Bill”, “Heather”]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上面出现了&amp;amp;符号，&amp;amp;符号的含义是：这是一个 Proc 对象，我想把它当成代码块来使用。去掉&amp;amp;符号，将能再次得到一个 Proc 对象。&amp;amp;符号可以用作任何对象，它会调用该对象的 to_proc 方法来把这个对象转换为一个 Proc，之后 map 方法会将 names 数组中的每个值作为这个 Proc 对象的参数进行调用。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Symbol&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;to_proc&lt;/span&gt;
        &lt;span class="no"&gt;Proc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;用到了动态派发，to_proc 方法会返回一个 Proc 对象，该对象会在传入的参数上执行:method_name（符号方法，因为动态调用的是 self，符号对象本身）。&lt;/p&gt;

&lt;p&gt;此外，Ruby 中的对象还支持多于一个参数的块，类似 inject 方法 (ps: 这里还不是很熟),见下面代码。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;memo&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; 8&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; 8&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;-完-&lt;/p&gt;

&lt;p&gt;===============
最后贴一下自己的公众账号&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/651b4463530c3d6d961ae41db40e5377.jpg" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;可以十日不将军，不可一日不拱卒，&lt;strong&gt;日拱一卒 (rigongyizu365)&lt;/strong&gt;&lt;/p&gt;</description>
      <author>lazybios</author>
      <pubDate>Wed, 23 Sep 2015 20:27:51 +0800</pubDate>
      <link>https://ruby-china.org/topics/27452</link>
      <guid>https://ruby-china.org/topics/27452</guid>
    </item>
    <item>
      <title>《Ruby 元编程》读书笔记 (十五)</title>
      <description>&lt;p&gt;博客地址 :&lt;a href="http://lazybios.com/2015/08/note-of-meta-pramgraming-with-ruby-15/" rel="nofollow" target="_blank" title=""&gt;《Ruby 元编程》读书笔记 (十五)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;相关文章：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ruby-china.org/topics/27243" title=""&gt;《Ruby 元编程》读书笔记 (一)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27259" title=""&gt;《Ruby 元编程》读书笔记 (二)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27277" title=""&gt;《Ruby 元编程》读书笔记 (三)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27285/" title=""&gt;《Ruby 元编程》读书笔记 (四)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27299/" title=""&gt;《Ruby 元编程》读书笔记 (五)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27311" title=""&gt;《Ruby 元编程》读书笔记 (六)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27317" title=""&gt;《Ruby 元编程》读书笔记 (七)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27344" title=""&gt;《Ruby 元编程》读书笔记 (八)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27367" title=""&gt;《Ruby 元编程》读书笔记 (九)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27371" title=""&gt;《Ruby 元编程》读书笔记 (十)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27385" title=""&gt;《Ruby 元编程》读书笔记 (十一)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27405" title=""&gt;《Ruby 元编程》读书笔记 (十二)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27409" title=""&gt;《Ruby 元编程》读书笔记 (十三)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27426" title=""&gt;《Ruby 元编程》读书笔记 (十四)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;传神的头图↓↓↓&lt;/p&gt;

&lt;p&gt;&lt;img src="http://freshstu.qiniudn.com/metaprogramming-1.jpg" title="" alt="Ruby元编程"&gt;&lt;/p&gt;

&lt;p&gt;前面介绍了 Ruby 元编程中的各种黑魔法，今天这个 Topic 被作者归纳为&lt;strong&gt;惯用法&lt;/strong&gt;，看了以后帮助巨大！这些用法还真是经常出现在各种 Ruby 大神的代码里，Ruby-China 的源码中就不少，不啰嗦进入正题！&lt;/p&gt;
&lt;h3 id="拟态方法"&gt;拟态方法&lt;/h3&gt;
&lt;p&gt;拟态方法其实就是我们常见类似 puts、private 以及 public 这些方法，它们将自己伪装成类似关键字的样子，但其实它们都是 Ruby 中的方法。在 Rails 中也有大量的这样用法，比如 link_to 这样的方法，常常让人搞不清楚这个方法到底可以接收多少个参数？其实它的定义是这样的：&lt;/p&gt;

&lt;p&gt;link_to(name = nil, options = nil, html_options = nil, &amp;amp;block)&lt;/p&gt;

&lt;p&gt;之所以感觉它的参数多的原因是，其省略了 hash 参数的花括号，&lt;strong&gt;Ruby 中如果最後一個參數是 Hash 的話，它的大括號是可以省略的&lt;/strong&gt;，所以你才见到 link_to 参数总是数不完。&lt;/p&gt;
&lt;h3 id="空指针保护"&gt;空指针保护&lt;/h3&gt;
&lt;p&gt;相信有读过大神代码的同学，一定遇到过这样的赋值语句吧 a ||= [], 这里的重点可以放到||=上，特别是在 Rails 中通过参数对变量赋值什么的。其实它的含义可以用这个表达式表示 a || (a = []) ,这里利用了布尔运算的短路求值。等价于下面这段代码：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;defined?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
    &lt;span class="c1"&gt;# 如果a已经被定义了，且既不为nil也非false，返回a&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="c1"&gt;# 如果a未定义，或未nil，或为false，返回空数组&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上面代码，明显表示出，a ||= [] 这样的表达式，除了能确保变量初始化以外，还能确保其值不为 nil 和 false。所以，不应该在变量值可能是 nil 或 false 的情况下使用&lt;strong&gt;空指针保护&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;空指针保护&lt;/strong&gt;常用于初始化变量，可以取代 initialize 方法。如下面代码：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;C&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;
        &lt;span class="vi"&gt;@a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;elements&lt;/span&gt;
        &lt;span class="vi"&gt;@a&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上面代码通过，initialize 方法对实例变量&lt;a href="/a" class="user-mention" title="@a"&gt;&lt;i&gt;@&lt;/i&gt;a&lt;/a&gt;进行了初始化，确保在调用C#elements方法时，&lt;a href="/a" class="user-mention" title="@a"&gt;&lt;i&gt;@&lt;/i&gt;a&lt;/a&gt;是已经初始化的。同样的结果，使用&lt;strong&gt;惰性实例变量&lt;/strong&gt;技巧，可以让代码更精简&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;C&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;elements&lt;/span&gt;
        &lt;span class="vi"&gt;@a&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;只有在C#elements被调用的时候，才初始化实例变量&lt;a href="/a" class="user-mention" title="@a"&gt;&lt;i&gt;@&lt;/i&gt;a&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;-待续-&lt;/p&gt;

&lt;p&gt;===============
最后贴一下自己的公众账号&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/651b4463530c3d6d961ae41db40e5377.jpg" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;可以十日不将军，不可一日不拱卒，&lt;strong&gt;日拱一卒 (rigongyizu365)&lt;/strong&gt;&lt;/p&gt;</description>
      <author>lazybios</author>
      <pubDate>Tue, 22 Sep 2015 16:35:12 +0800</pubDate>
      <link>https://ruby-china.org/topics/27435</link>
      <guid>https://ruby-china.org/topics/27435</guid>
    </item>
    <item>
      <title>《Ruby 元编程》读书笔记 (十四)</title>
      <description>&lt;p&gt;博客地址 :&lt;a href="http://lazybios.com/2015/08/note-of-meta-pramgraming-with-ruby-14/" rel="nofollow" target="_blank" title=""&gt;《Ruby 元编程》读书笔记 (十四)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;相关文章：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ruby-china.org/topics/27243" title=""&gt;《Ruby 元编程》读书笔记 (一)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27259" title=""&gt;《Ruby 元编程》读书笔记 (二)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27277" title=""&gt;《Ruby 元编程》读书笔记 (三)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27285/" title=""&gt;《Ruby 元编程》读书笔记 (四)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27299/" title=""&gt;《Ruby 元编程》读书笔记 (五)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27311" title=""&gt;《Ruby 元编程》读书笔记 (六)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27317" title=""&gt;《Ruby 元编程》读书笔记 (七)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27344" title=""&gt;《Ruby 元编程》读书笔记 (八)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27367" title=""&gt;《Ruby 元编程》读书笔记 (九)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27371" title=""&gt;《Ruby 元编程》读书笔记 (十)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27385" title=""&gt;《Ruby 元编程》读书笔记 (十一)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27405" title=""&gt;《Ruby 元编程》读书笔记 (十二)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27409" title=""&gt;《Ruby 元编程》读书笔记 (十三)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;传神的头图↓↓↓&lt;/p&gt;

&lt;p&gt;&lt;img src="http://freshstu.qiniudn.com/metaprogramming-1.jpg" title="" alt="Ruby元编程"&gt;&lt;/p&gt;

&lt;p&gt;前面已经对元编程的理论知识走了一遍，后面的内容侧重于实际操作和源码阅读，今天的 Topic 就是由书中第六章中的例子而来。&lt;/p&gt;

&lt;p&gt;书中以迭代的形式，引导读者一步步实现一个名为 attr_checked 的类宏，正所谓上帝造人也需要 7 天，创造和生产这件事儿，过程和迭代都是少不了的，本文完全遵照 guide 而来，美中不足的地方是没有添加，测试用例，不过每个不走都给出了一些简单的实例演示代码。&lt;/p&gt;
&lt;h3 id="任务描述"&gt;任务描述&lt;/h3&gt;
&lt;p&gt;写一个操作方法类似&lt;code&gt;attr_accessor&lt;/code&gt;的&lt;code&gt;attr_checked&lt;/code&gt;的类宏，该类宏用来对属性值做检验，使用方法如下：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;CheckedAttributes&lt;/span&gt;

  &lt;span class="n"&gt;attr_checked&lt;/span&gt; &lt;span class="ss"&gt;:age&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;me&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
&lt;span class="n"&gt;me&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;39&lt;/span&gt;  &lt;span class="c1"&gt;#ok&lt;/span&gt;
&lt;span class="n"&gt;me&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;  &lt;span class="c1"&gt;#抛出异常&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="实施计划"&gt;实施计划&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;使用 eval 方法编写一个名为&lt;code&gt;add_checked_attribute&lt;/code&gt;的内核方法，为指定类添加经过简单校验的属性&lt;/li&gt;
&lt;li&gt;重构 add_checked_attribute 方法，去掉 eval 方法，改用其它手段实现&lt;/li&gt;
&lt;li&gt;添加代码块校验功能&lt;/li&gt;
&lt;li&gt;修改 add_checked_attribute 为要求的 attr_checked，并使其对所有类都可用&lt;/li&gt;
&lt;li&gt;通过引入模块的方式，只对引入该功能模块的类添加 attr_checked 方法&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="Step 1"&gt;Step 1&lt;/h4&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add_checked_attribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;klass&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="s2"&gt;"
    class &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;klass&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
      def &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;=(value)
        raise 'Invalid attribute' unless value
        @&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; = value
      end
      def &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;()
        @&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
      end
    end
  "&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;add_checked_attribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:my_attr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"hello,kitty"&lt;/span&gt;

&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;my_attr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;my_attr&lt;/span&gt;

&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;my_attr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;my_attr&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这一步使用&lt;code&gt;eval&lt;/code&gt;方法，用&lt;code&gt;class&lt;/code&gt;和&lt;code&gt;def&lt;/code&gt;关键词分别打开类，且定义了指定的属性的 get 和 set 方法，其中的 set 方法会简单的判断值是否为空 (nil 或 false)，如果是则抛出&lt;code&gt;Invalid attribute&lt;/code&gt;异常。&lt;/p&gt;
&lt;h4 id="Setp 2"&gt;Setp 2&lt;/h4&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add_checked_attribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;klass&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;klass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;class_eval&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;define_method&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;="&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="s2"&gt;"Invaild attribute"&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
      &lt;span class="nb"&gt;instance_variable_set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"@&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;define_method&lt;/span&gt; &lt;span class="n"&gt;attribute&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="nb"&gt;instance_variable_get&lt;/span&gt; &lt;span class="s2"&gt;"@&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这一步更换掉了&lt;code&gt;eval&lt;/code&gt;方法，同时也分别用&lt;code&gt;class_eval&lt;/code&gt;和&lt;code&gt;define_method&lt;/code&gt;方法替换了之前的&lt;code&gt;class&lt;/code&gt;与&lt;code&gt;def&lt;/code&gt;关键字，实例变量的设置和获取分别改用了&lt;code&gt;instance_variable_set&lt;/code&gt;和&lt;code&gt;instance_variable_get&lt;/code&gt;方法，使用上与第一步没有任何区别，只是一些内部实现的差异。&lt;/p&gt;
&lt;h3 id="Step 3"&gt;Step 3&lt;/h3&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add_checked_attribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;klass&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;klass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;class_eval&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;define_method&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;="&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="s2"&gt;"Invaild attribute"&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nb"&gt;instance_variable_set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"@&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;define_method&lt;/span&gt; &lt;span class="n"&gt;attribute&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="nb"&gt;instance_variable_get&lt;/span&gt; &lt;span class="s2"&gt;"@&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;add_checked_attribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:my_attr&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;180&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"hello,kitty"&lt;/span&gt;

&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;my_attr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;  &lt;span class="c1"&gt;#Invaild attribute (RuntimeError)&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;my_attr&lt;/span&gt;

&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;my_attr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;my_attr&lt;/span&gt;  &lt;span class="c1"&gt;#200&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;没有什么奇特的，只是加了通过&lt;strong&gt;代码块&lt;/strong&gt;验证，增加了校验的灵活性，不再仅仅局限于 nil 和 false 之间了。&lt;/p&gt;
&lt;h3 id="Step 4"&gt;Step 4&lt;/h3&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Class&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;attr_checked&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;define_method&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;="&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="s2"&gt;"Invaild attribute"&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nb"&gt;instance_variable_set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"@&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;

      &lt;span class="n"&gt;define_method&lt;/span&gt; &lt;span class="n"&gt;attribute&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="nb"&gt;instance_variable_get&lt;/span&gt; &lt;span class="s2"&gt;"@&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_checked&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:my_attr&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;180&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"hello,kitty"&lt;/span&gt;

&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;my_attr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;  &lt;span class="c1"&gt;#Invaild attribute (RuntimeError)&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;my_attr&lt;/span&gt;

&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;my_attr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;my_attr&lt;/span&gt;  &lt;span class="c1"&gt;#200&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里我们把之前顶级作用域中方法名放到了&lt;code&gt;Class&lt;/code&gt;中，由于所有对象都是&lt;code&gt;Class&lt;/code&gt;的实例，所以这里定义的实例方法，也能被 Ruby 中的其它所有类访问到，同时在 class 定义中，self 就是当前类，所以也就省去了调用类这个参数和&lt;code&gt;class_eval&lt;/code&gt;方法，并且我们把方法的名字也改成了&lt;code&gt;attr_checked&lt;/code&gt;。&lt;/p&gt;
&lt;h3 id="Step 5"&gt;Step 5&lt;/h3&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;CheckedAttributes&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;included&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;extend&lt;/span&gt; &lt;span class="no"&gt;ClassMethods&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;ClassMethods&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;attr_checked&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;define_method&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;="&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="s2"&gt;"Invaild attribute"&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nb"&gt;instance_variable_set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"@&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;

      &lt;span class="n"&gt;define_method&lt;/span&gt; &lt;span class="n"&gt;attribute&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="nb"&gt;instance_variable_get&lt;/span&gt; &lt;span class="s2"&gt;"@&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;CheckedAttributes&lt;/span&gt;

  &lt;span class="n"&gt;attr_checked&lt;/span&gt; &lt;span class="ss"&gt;:age&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最后一步通过&lt;strong&gt;钩子方法&lt;/strong&gt;，在&lt;code&gt;CheckedAttributes&lt;/code&gt;模块被引入后，对当前类通过被引入模块进行扩展，
从而使当前类支持引入后的方法调用，即这里的 get 与 set 方法组。&lt;/p&gt;

&lt;p&gt;到此，我们已经得到了一个名为&lt;code&gt;attr_checked&lt;/code&gt;，类似&lt;code&gt;attr_accessor&lt;/code&gt;的类宏，通过它你可以对属性进行你想要的校验。&lt;/p&gt;

&lt;p&gt;-待续-&lt;/p&gt;

&lt;p&gt;===============
最后贴一下自己的公众账号&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/651b4463530c3d6d961ae41db40e5377.jpg" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;可以十日不将军，不可一日不拱卒，&lt;strong&gt;日拱一卒 (rigongyizu365)&lt;/strong&gt;&lt;/p&gt;</description>
      <author>lazybios</author>
      <pubDate>Mon, 21 Sep 2015 21:50:27 +0800</pubDate>
      <link>https://ruby-china.org/topics/27426</link>
      <guid>https://ruby-china.org/topics/27426</guid>
    </item>
    <item>
      <title>《Ruby 元编程》读书笔记 (十三)</title>
      <description>&lt;p&gt;博客地址 :&lt;a href="http://lazybios.com/2015/08/note-of-meta-pramgraming-with-ruby-13/" rel="nofollow" target="_blank" title=""&gt;《Ruby 元编程》读书笔记 (十三)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;相关文章：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ruby-china.org/topics/27243" title=""&gt;《Ruby 元编程》读书笔记 (一)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27259" title=""&gt;《Ruby 元编程》读书笔记 (二)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27277" title=""&gt;《Ruby 元编程》读书笔记 (三)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27285/" title=""&gt;《Ruby 元编程》读书笔记 (四)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27299/" title=""&gt;《Ruby 元编程》读书笔记 (五)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27311" title=""&gt;《Ruby 元编程》读书笔记 (六)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27317" title=""&gt;《Ruby 元编程》读书笔记 (七)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27344" title=""&gt;《Ruby 元编程》读书笔记 (八)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27367" title=""&gt;《Ruby 元编程》读书笔记 (九)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27371" title=""&gt;《Ruby 元编程》读书笔记 (十)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27385" title=""&gt;《Ruby 元编程》读书笔记 (十一)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27405" title=""&gt;《Ruby 元编程》读书笔记 (十二)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;传神的头图↓↓↓&lt;/p&gt;

&lt;p&gt;&lt;img src="http://freshstu.qiniudn.com/metaprogramming-1.jpg" title="" alt="Ruby元编程"&gt;&lt;/p&gt;
&lt;h3 id="钩子方法"&gt;钩子方法&lt;/h3&gt;
&lt;p&gt;钩子方法有些类似事件驱动装置，可以在特定的事件发生后执行特定的回调函数，这个回调函数就是&lt;strong&gt;钩子方法&lt;/strong&gt;(更形象的描述：钩子方法可以像钩子一样，勾住一个特定的事件。)，在 Rails 中 before\after 函数就是最常见的钩子方法。&lt;/p&gt;

&lt;p&gt;Class#inherited方法也是这样一个钩子方法，当一个类被继承时，Ruby会调用该方法。默认情况下，Class#inherited什么都不做，但是通过继承，我们可以拦截该事件，对感兴趣的继承事件作出回应。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inherited&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subclass&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="c1"&gt;#{self} was inherited by #{subclass}”&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyString&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="c1"&gt;#输出&lt;/span&gt;
&lt;span class="no"&gt;String&lt;/span&gt; &lt;span class="n"&gt;was&lt;/span&gt; &lt;span class="n"&gt;inherited&lt;/span&gt; &lt;span class="n"&gt;by&lt;/span&gt; &lt;span class="no"&gt;MyString&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;通过使用钩子方法，可以让我们在 Ruby 的类或模块的生命周期中进行干预，可以极大的提高编程的灵活性。&lt;/p&gt;

&lt;p&gt;这些生命周期相关的钩子方法还有下面这些：&lt;/p&gt;
&lt;h4 id="类与模块相关"&gt;类与模块相关&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Class#inherited&lt;/li&gt;
&lt;li&gt;Module#include&lt;/li&gt;
&lt;li&gt;Module#prepended&lt;/li&gt;
&lt;li&gt;Module#extend_object&lt;/li&gt;
&lt;li&gt;Module#method_added&lt;/li&gt;
&lt;li&gt;Module#method_removed&lt;/li&gt;
&lt;li&gt;Module#method_undefined&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="单件类相关"&gt;单件类相关&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;BasicObject#singleton_method_added&lt;/li&gt;
&lt;li&gt;BasicObject#singleton_method_removed&lt;/li&gt;
&lt;li&gt;BasicObject#singleton_method_undefined
##### 示例代码
```ruby
module M1
def self.included(othermod)
    puts“M1 was included into #{othermod}”
end
end&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;module M2
    def self.prepended(othermod)
        puts “M2 was prepended to #{othermod}”
    end
end&lt;/p&gt;

&lt;p&gt;class C
    include M1
    include M2
end&lt;/p&gt;
&lt;h2 id="输出"&gt;输出&lt;/h2&gt;
&lt;p&gt;M1 was included into C
M2 was prepended to C&lt;/p&gt;

&lt;p&gt;module M
    def self.method_added(method)
        puts “New method: M##{method}”
    end&lt;/p&gt;

&lt;p&gt;def my_method; end
end &lt;/p&gt;
&lt;h2 id="输出"&gt;输出&lt;/h2&gt;
&lt;p&gt;New method: M#my_method&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
除了上面列出来的一些方法外，也可以通过重写父类的某个方法，进行一些过滤操作后，再通过调用super方法完成原函数的功能，从而实现类似钩子方法的功效，如出一辙，**环绕别名**也可以作为一种钩子方法的替代实现。

-待续-


===============
最后贴一下自己的公众账号

![](https://l.ruby-china.com/photo/2015/651b4463530c3d6d961ae41db40e5377.jpg)

可以十日不将军，不可一日不拱卒，**日拱一卒(rigongyizu365)**
&lt;/code&gt;&lt;/pre&gt;</description>
      <author>lazybios</author>
      <pubDate>Sun, 20 Sep 2015 23:31:11 +0800</pubDate>
      <link>https://ruby-china.org/topics/27409</link>
      <guid>https://ruby-china.org/topics/27409</guid>
    </item>
    <item>
      <title>《Ruby 元编程》读书笔记 (十二)</title>
      <description>&lt;p&gt;博客地址 :&lt;a href="http://lazybios.com/2015/08/note-of-meta-pramgraming-with-ruby-12/" rel="nofollow" target="_blank" title=""&gt;《Ruby 元编程》读书笔记 (十二)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;相关文章：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ruby-china.org/topics/27243" title=""&gt;《Ruby 元编程》读书笔记 (一)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27259" title=""&gt;《Ruby 元编程》读书笔记 (二)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27277" title=""&gt;《Ruby 元编程》读书笔记 (三)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27285/" title=""&gt;《Ruby 元编程》读书笔记 (四)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27299/" title=""&gt;《Ruby 元编程》读书笔记 (五)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27311" title=""&gt;《Ruby 元编程》读书笔记 (六)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27317" title=""&gt;《Ruby 元编程》读书笔记 (七)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27344" title=""&gt;《Ruby 元编程》读书笔记 (八)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27367" title=""&gt;《Ruby 元编程》读书笔记 (九)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27371" title=""&gt;《Ruby 元编程》读书笔记 (十)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27385" title=""&gt;《Ruby 元编程》读书笔记 (十一)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;传神的头图↓↓↓&lt;/p&gt;

&lt;p&gt;&lt;img src="http://freshstu.qiniudn.com/metaprogramming-1.jpg" title="" alt="Ruby元编程"&gt;&lt;/p&gt;
&lt;h3 id="Kernal#eval方法"&gt;Kernal#eval方法&lt;/h3&gt;
&lt;p&gt;Kernal#eval方法与之前的BasicObject#instance_eval和Module#class_eval一样，都属于*eval家族，都可以赋予程序在运行中进行动态变化的能力。与后两者想比Kernal#eval更加直接，不需要代码块、直接就可以执行字符串代码(String of Code)。&lt;/p&gt;

&lt;p&gt;PS:BasicObject#instance_eval也是可以执行字符串代码的。&lt;/p&gt;
&lt;h4 id="示例代码"&gt;示例代码&lt;/h4&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;
&lt;span class="nb"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;#=&amp;gt; [10, 20, 30]&lt;/span&gt;
&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;instance_eval&lt;/span&gt; &lt;span class="s2"&gt;"self &amp;lt;&amp;lt; element"&lt;/span&gt;  &lt;span class="c1"&gt;#=&amp;gt; [10, 20, 30]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="Here文档(Here documents)"&gt;Here 文档 (Here documents)&lt;/h3&gt;
&lt;p&gt;以&amp;lt;&amp;lt;打头，后面跟一个“结束序列标识”，之后就可以是正式的文档内容了，可以任意换行，直到遇到了独立出现的”结束序号标识”。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;GROCERY_LIST&lt;/span&gt;&lt;span class="sh"&gt;
Grocery list
------------
1. Salad mix.
2. Strawberries.*
3. Cereal.
4. Milk.*

* Organic
&lt;/span&gt;&lt;span class="no"&gt;GROCERY_LIST&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上面代码的输出格式如下：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;Grocery&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;
&lt;span class="o"&gt;------------&lt;/span&gt;
&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="no"&gt;Salad&lt;/span&gt; &lt;span class="n"&gt;mix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="no"&gt;Strawberries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;*&lt;/span&gt;
&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="no"&gt;Cereal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="no"&gt;Milk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;*&lt;/span&gt;

&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="no"&gt;Organic&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="绑定对象"&gt;绑定对象&lt;/h3&gt;
&lt;p&gt;Binding 是一个用对象标识的完整作用域 (上下文环境)。可以通过创建 Binding 对象来捕获并带走当前的作用域。之后，通过 eval 方法在这个 Binding 对象所携带的作用域内执行代码。&lt;/p&gt;

&lt;p&gt;使用Kernel#binding方法可以用来创建Binding对象&lt;/p&gt;
&lt;h4 id="示例代码"&gt;示例代码&lt;/h4&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyClass&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_method&lt;/span&gt;
        &lt;span class="vi"&gt;@x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="nb"&gt;binding&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;MyClass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;my_method&lt;/span&gt;
&lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="vi"&gt;@x&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; 1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上面代码，在 MyClass 类中定义了一个 my_method 方法来返回一个当前的绑定。最后将这个返回的绑定，作为参数传递给 eval 方法。这样“&lt;a href="/x" class="user-mention" title="@x"&gt;&lt;i&gt;@&lt;/i&gt;x&lt;/a&gt;”就可以在返回的绑定作用域中执行了。&lt;/p&gt;

&lt;p&gt;关于绑定还有另外一个知识点，Ruby还提供了一个名为TOPLEVEL_BINDING的预定义常量，表示顶级作用域Binding对象。该常量可以在程序的任何位置访问到。言外之意，你可以在程序的任何位置，通过Kernal#eval方法在顶级作用域中执行代码。&lt;/p&gt;
&lt;h4 id="示例代码"&gt;示例代码&lt;/h4&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AnotherClass&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_method&lt;/span&gt;
        &lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;TOPLEVEL_BINDING&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="no"&gt;AnotherClass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;my_method&lt;/span&gt;  &lt;span class="c1"&gt;#=&amp;gt; main&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="代码注入"&gt;代码注入&lt;/h4&gt;
&lt;p&gt;Kernal#eval执行这样可以灵活执行字符串代码的特性，给编程带来了灵活性之外，也带来了潜在的风险，如果字符串代码来源于不可信的用户输入，如果不做安全检查，保不齐什么时候就会是一段破坏性的恶意代码。&lt;/p&gt;

&lt;p&gt;面对这样的风险，可以选择规避 eval 的使用，换用其它相对安全的方式代替，例如&lt;strong&gt;动态方法&lt;/strong&gt;和&lt;strong&gt;动态派发&lt;/strong&gt;。此外，还可以通过在 Ruby 中通过修改$SAFE 全局变量值，来控制程序的安全性级别，具体就是在你要执行&lt;strong&gt;可信的&lt;/strong&gt;字符串代码前，将安全级别降低，可以使用Object#untaint方法，执行完之后在切换安全级别。这有点像操作系统中使用临界资源的步骤(请求锁，释放锁)&lt;/p&gt;

&lt;p&gt;通过 Object#tainted？方法可以判断一个对象是不是被污染了（是否来自一个不可信的输入源）。&lt;/p&gt;

&lt;p&gt;-待续-&lt;/p&gt;

&lt;p&gt;===============
最后贴一下自己的公众账号&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/651b4463530c3d6d961ae41db40e5377.jpg" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;可以十日不将军，不可一日不拱卒，&lt;strong&gt;日拱一卒 (rigongyizu365)&lt;/strong&gt;&lt;/p&gt;</description>
      <author>lazybios</author>
      <pubDate>Sat, 19 Sep 2015 22:00:22 +0800</pubDate>
      <link>https://ruby-china.org/topics/27405</link>
      <guid>https://ruby-china.org/topics/27405</guid>
    </item>
    <item>
      <title>《Ruby 元编程》读书笔记 (十一)</title>
      <description>&lt;p&gt;博客地址 :&lt;a href="http://lazybios.com/2015/08/note-of-meta-pramgraming-with-ruby-11/" rel="nofollow" target="_blank" title=""&gt;《Ruby 元编程》读书笔记 (十一)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;相关文章：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ruby-china.org/topics/27243" title=""&gt;《Ruby 元编程》读书笔记 (一)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27259" title=""&gt;《Ruby 元编程》读书笔记 (二)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27277" title=""&gt;《Ruby 元编程》读书笔记 (三)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27285/" title=""&gt;《Ruby 元编程》读书笔记 (四)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27299/" title=""&gt;《Ruby 元编程》读书笔记 (五)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27311" title=""&gt;《Ruby 元编程》读书笔记 (六)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27317" title=""&gt;《Ruby 元编程》读书笔记 (七)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27344" title=""&gt;《Ruby 元编程》读书笔记 (八)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27367" title=""&gt;《Ruby 元编程》读书笔记 (九)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27371" title=""&gt;《Ruby 元编程》读书笔记 (十)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;传神的头图↓↓↓&lt;/p&gt;

&lt;p&gt;&lt;img src="http://freshstu.qiniudn.com/metaprogramming-1.jpg" title="" alt="Ruby元编程"&gt;&lt;/p&gt;
&lt;h3 id="方法包装器（Method Wrapper）"&gt;方法包装器（Method Wrapper）&lt;/h3&gt;
&lt;p&gt;方法包装器一般适合于，处理一些你不能直接触碰到的方法，或者需要给某个方法进行一些预处理工作，这个概念有点类似与 Python 中的装饰器&lt;/p&gt;
&lt;h4 id="方法别名"&gt;方法别名&lt;/h4&gt;
&lt;p&gt;Ruby中使用Module#alias_method方法和alias关键字为方法取别名。&lt;/p&gt;
&lt;h5 id="示例代码"&gt;示例代码&lt;/h5&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyClass&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_method&lt;/span&gt;
         &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="n"&gt;my_method&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="kp"&gt;alias_method&lt;/span&gt; &lt;span class="ss"&gt;:m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:my_method&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;MyClass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;my_method&lt;/span&gt;    &lt;span class="c1"&gt;#=&amp;gt; “my_method()”&lt;/span&gt;
&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;m&lt;/span&gt;   &lt;span class="c1"&gt;#=&amp;gt; “my_method()”&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;需要注意的是，在顶级作用域中（main）中只能使用alias关键字来命名别名，因为在那里调用不到Module#alias_method方法&lt;/p&gt;

&lt;p&gt;此外这里，还需要指出一点关于&lt;strong&gt;方法重定义&lt;/strong&gt;的理解误区，一般我们认为方法一旦被重定义了，就找不回原来的方法了，其实在 Ruby 中的重定义只是，对方法名与方法实体绑定的一种重新绑定，如果被重新定义的方法体还有一个其它别名，那么一样还是可以访问到老方法的。&lt;/p&gt;

&lt;p&gt;有了上面这个理解，我们来看&lt;strong&gt;环绕别名&lt;/strong&gt;这个概念。&lt;/p&gt;
&lt;h4 id="环绕别名"&gt;环绕别名&lt;/h4&gt;
&lt;p&gt;经过下面三个步骤可以实现&lt;strong&gt;环绕别名&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;给方法定义一个别名&lt;/li&gt;
&lt;li&gt;重定义这个方法&lt;/li&gt;
&lt;li&gt;在新的方法中调用老的方法&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;上面三步后，即可以保留老方法 (第一步)，同时又为原方法增加了新功能。但其本质上没有改变调用之间的函数名称依赖，是一种名副其实的“新瓶装老酒”的取巧办法。&lt;/p&gt;

&lt;p&gt;不过&lt;strong&gt;环绕别名&lt;/strong&gt;也有缺点，就是它污染了类的命名空间，添加了额外的方法名。不过这一点其实可以通过 Ruby 中的 private 关键字把旧方法限定为私有方法。(Ruby 中的 public 和 private 实际上针对的是方法名，而非方法本身，言外之意为 private 方法取个别名，也可以把私有方法暴露出来)&lt;/p&gt;

&lt;p&gt;最后要注意的是不要尝试 load 两次&lt;strong&gt;环绕别名&lt;/strong&gt;的实现代码，否则得到的执行结果就不是你预期中的了，不信你可以试着连续走两遍上面的 3 个步骤。&lt;/p&gt;
&lt;h4 id="细化"&gt;细化&lt;/h4&gt;
&lt;p&gt;前面提到的细化，也可以作为一种方法包装器，在细化的方法中调用 super 方法，可以调用会细化之前的方法。此外细化相比起&lt;strong&gt;环绕别名&lt;/strong&gt;，细化的作用范围是文件末尾，而环绕别名则是作用在全局。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;StringRefinement&lt;/span&gt;
  &lt;span class="n"&gt;refine&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;length&lt;/span&gt;
      &lt;span class="k"&gt;super&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s1"&gt;'long'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'short'&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;using&lt;/span&gt; &lt;span class="no"&gt;StringRefinement&lt;/span&gt;

&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"War and Peace"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt;  &lt;span class="c1"&gt;#=&amp;gt; “long”&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="下包含包装器 (Module#prepend)"&gt;下包含包装器 (Module#prepend)&lt;/h4&gt;
&lt;p&gt;在介绍&lt;strong&gt;祖先链&lt;/strong&gt;的部分有涉及过 include 与 prepend 两个方法，前者是将模块插入到当前类的上方，后者是插入到下方，而下方的位置，正好是方法查找时优先查找的位置，利用这一优势，可以覆写当前类的同名方法，同时通过 super 关键字还可以调用到该类中的原始方法&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;ExplicitString&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;length&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="n"&gt;long&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="n"&gt;short&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;class_eval&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;prepend&lt;/span&gt; &lt;span class="no"&gt;ExplicitString&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"War and Peace"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt;  &lt;span class="c1"&gt;#=&amp;gt; “long”&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;-待续-&lt;/p&gt;

&lt;p&gt;===============
最后贴一下自己的公众账号&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/651b4463530c3d6d961ae41db40e5377.jpg" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;可以十日不将军，不可一日不拱卒，&lt;strong&gt;日拱一卒 (rigongyizu365)&lt;/strong&gt;&lt;/p&gt;</description>
      <author>lazybios</author>
      <pubDate>Fri, 18 Sep 2015 14:31:16 +0800</pubDate>
      <link>https://ruby-china.org/topics/27385</link>
      <guid>https://ruby-china.org/topics/27385</guid>
    </item>
    <item>
      <title>《Ruby 元编程》读书笔记 (十)</title>
      <description>&lt;p&gt;博客地址 :&lt;a href="http://lazybios.com/2015/08/note-of-meta-pramgraming-with-ruby-10/" rel="nofollow" target="_blank" title=""&gt;《Ruby 元编程》读书笔记 (十)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;相关文章：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ruby-china.org/topics/27243" title=""&gt;《Ruby 元编程》读书笔记 (一)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27259" title=""&gt;《Ruby 元编程》读书笔记 (二)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27277" title=""&gt;《Ruby 元编程》读书笔记 (三)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27285/" title=""&gt;《Ruby 元编程》读书笔记 (四)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27299/" title=""&gt;《Ruby 元编程》读书笔记 (五)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27311" title=""&gt;《Ruby 元编程》读书笔记 (六)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27317" title=""&gt;《Ruby 元编程》读书笔记 (七)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27344" title=""&gt;《Ruby 元编程》读书笔记 (八)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27367" title=""&gt;《Ruby 元编程》读书笔记 (九)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;传神的头图↓↓↓&lt;/p&gt;

&lt;p&gt;&lt;img src="http://freshstu.qiniudn.com/metaprogramming-1.jpg" title="" alt="Ruby元编程"&gt;&lt;/p&gt;
&lt;h3 id="模块与单件类"&gt;模块与单件类&lt;/h3&gt;
&lt;p&gt;当一个类包含一个模块时，他获得的是该模块的实例方法，而不是类方法。类方法存在与模块的单件类中，没有被类获得。&lt;/p&gt;
&lt;h3 id="类扩展"&gt;类扩展&lt;/h3&gt;
&lt;p&gt;类扩展通过向类的单件类中添加模块来定义类方法。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;MyModule&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_method&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="n"&gt;hello&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyClass&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;
        &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;MyModule&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="no"&gt;MyClass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;my_method&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上面代码展示了具体&lt;strong&gt;类扩展&lt;/strong&gt;的实现方式，将一个 MyModule 模块引入到 MyClass 类的单件类中，因为 my_method 方法是 MyClass 的单件类的一个实例方法，这样，my_method 方法也是 MyClass 的一个类方法。&lt;/p&gt;
&lt;h3 id="对象扩展"&gt;对象扩展&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;类方法&lt;/strong&gt;是&lt;strong&gt;单件方法&lt;/strong&gt;的特例，因此可以把类扩展这种技巧应用到&lt;strong&gt;任意对象&lt;/strong&gt;上，这种技巧即为&lt;strong&gt;对象扩展&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# 法一: 打开单件类来扩展&lt;/span&gt;
&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;MyModule&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_method&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="n"&gt;hello&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;
    &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;MyModule&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;my_method&lt;/span&gt;   &lt;span class="c1"&gt;# =&amp;gt; “hello”&lt;/span&gt;
&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;singleton_methods&lt;/span&gt;   &lt;span class="c1"&gt;# =&amp;gt; [:my_method]&lt;/span&gt;
&lt;span class="c1"&gt;# 法二：Object#extend方法&lt;/span&gt;
&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;MyModule&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_method&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="n"&gt;hello&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
&lt;span class="c1"&gt;#对象扩展&lt;/span&gt;
&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;extend&lt;/span&gt; &lt;span class="no"&gt;MyModule&lt;/span&gt;
&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;my_method&lt;/span&gt;   &lt;span class="c1"&gt;# =&amp;gt; “hello”  &lt;/span&gt;
&lt;span class="c1"&gt;#类扩展&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyClass&lt;/span&gt;
    &lt;span class="kp"&gt;extend&lt;/span&gt; &lt;span class="no"&gt;MyModule&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="no"&gt;MyClass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;my_method&lt;/span&gt;  &lt;span class="c1"&gt;# =&amp;gt; “hello”&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Object#extend是在接受者的单件类中包含模块的快键方式。&lt;/p&gt;

&lt;p&gt;-待续-&lt;/p&gt;

&lt;p&gt;===============
最后贴一下自己的公众账号&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/651b4463530c3d6d961ae41db40e5377.jpg" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;可以十日不将军，不可一日不拱卒，&lt;strong&gt;日拱一卒 (rigongyizu365)&lt;/strong&gt;&lt;/p&gt;</description>
      <author>lazybios</author>
      <pubDate>Thu, 17 Sep 2015 12:37:03 +0800</pubDate>
      <link>https://ruby-china.org/topics/27371</link>
      <guid>https://ruby-china.org/topics/27371</guid>
    </item>
    <item>
      <title>《Ruby 元编程》读书笔记 (九)</title>
      <description>&lt;p&gt;博客地址 :&lt;a href="http://lazybios.com/2015/08/note-of-meta-pramgraming-with-ruby-9/" rel="nofollow" target="_blank" title=""&gt;《Ruby 元编程》读书笔记 (九)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;相关文章：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ruby-china.org/topics/27243" title=""&gt;《Ruby 元编程》读书笔记 (一)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27259" title=""&gt;《Ruby 元编程》读书笔记 (二)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27277" title=""&gt;《Ruby 元编程》读书笔记 (三)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27285/" title=""&gt;《Ruby 元编程》读书笔记 (四)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27299/" title=""&gt;《Ruby 元编程》读书笔记 (五)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27311" title=""&gt;《Ruby 元编程》读书笔记 (六)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27317" title=""&gt;《Ruby 元编程》读书笔记 (七)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27344" title=""&gt;《Ruby 元编程》读书笔记 (八)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;传神的头图↓↓↓&lt;/p&gt;

&lt;p&gt;&lt;img src="http://freshstu.qiniudn.com/metaprogramming-1.jpg" title="" alt="Ruby元编程"&gt;&lt;/p&gt;
&lt;h3 id="Ruby对象模型的7条规则"&gt;Ruby 对象模型的 7 条规则&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;只有一个对象 —— 要么是普通对象，要么是模块&lt;/li&gt;
&lt;li&gt;只有一个模块 —— 可以是一个普通模块、一个类或者一个单件类&lt;/li&gt;
&lt;li&gt;只有一个方法，它存在于一个模块中 —— 通常是一个类中&lt;/li&gt;
&lt;li&gt;每个对象（包括类）都有自己的“真正的类”—— 要么是一个普通类，要么是一个单件类&lt;/li&gt;
&lt;li&gt;除了 BasicObject 类没有超类外，每个类有且只有一个祖先 (superclass) —— 要么是一个类，要么是一个模块。这意味着任何类只有一条向上的，直到 BasicObject 的祖先链&lt;/li&gt;
&lt;li&gt;一个&lt;strong&gt;对象&lt;/strong&gt;的单件类的超类是这个对象的类；一个&lt;strong&gt;类&lt;/strong&gt;的单件类的超类是这个类的超类的单件类。(这条建议结合后面的附图来看！)&lt;/li&gt;
&lt;li&gt;调用一个方法时，Ruby 先向右迈出一步进入接收者真正的类 (单件类)，然后向上进入祖先链。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/5b32a80bd2bb67c4eebd7227e937ee0a.jpeg" title="" alt=""&gt;&lt;/p&gt;
&lt;h3 id="类方法"&gt;类方法&lt;/h3&gt;
&lt;p&gt;类方法其实质是生活在该类的单件类中的单件方法。其定义方法有三种，分别是：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# 法一&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;MyClass&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;a_class_method&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;


&lt;span class="c1"&gt;# 法二&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyClass&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;anther_class_method&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;


&lt;span class="c1"&gt;# 法三*&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyClass&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;
        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;yet_another_class_method&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中第三种方法道出了，类方法的实质，特别记忆一下！&lt;/p&gt;

&lt;p&gt;-待续-&lt;/p&gt;

&lt;p&gt;===============
最后贴一下自己的公众账号&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/651b4463530c3d6d961ae41db40e5377.jpg" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;可以十日不将军，不可一日不拱卒，&lt;strong&gt;日拱一卒 (rigongyizu365)&lt;/strong&gt;&lt;/p&gt;</description>
      <author>lazybios</author>
      <pubDate>Wed, 16 Sep 2015 19:41:08 +0800</pubDate>
      <link>https://ruby-china.org/topics/27367</link>
      <guid>https://ruby-china.org/topics/27367</guid>
    </item>
    <item>
      <title>《Ruby 元编程》读书笔记 (八)</title>
      <description>&lt;p&gt;博客地址 :&lt;a href="http://lazybios.com/2015/08/note-of-meta-pramgraming-with-ruby-8/" rel="nofollow" target="_blank" title=""&gt;《Ruby 元编程》读书笔记 (八)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;相关文章：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ruby-china.org/topics/27243" title=""&gt;《Ruby 元编程》读书笔记 (一)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27259" title=""&gt;《Ruby 元编程》读书笔记 (二)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27277" title=""&gt;《Ruby 元编程》读书笔记 (三)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27285/" title=""&gt;《Ruby 元编程》读书笔记 (四)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27299/" title=""&gt;《Ruby 元编程》读书笔记 (五)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27311" title=""&gt;《Ruby 元编程》读书笔记 (六)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27317" title=""&gt;《Ruby 元编程》读书笔记 (七)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;传神的头图↓↓↓&lt;/p&gt;

&lt;p&gt;&lt;img src="http://freshstu.qiniudn.com/metaprogramming-1.jpg" title="" alt="Ruby元编程"&gt;&lt;/p&gt;
&lt;h3 id="单件类"&gt;单件类&lt;/h3&gt;
&lt;p&gt;我们知道 Ruby 中对象的方法的查找顺序是：&lt;strong&gt;先向右，再向上&lt;/strong&gt;，其含义就是先向右找到对象的类，先在类的实例方法中尝试查找，如果没有找到，再继续顺着&lt;strong&gt;祖先链&lt;/strong&gt;找。&lt;/p&gt;

&lt;p&gt;前面一篇中有介绍过&lt;strong&gt;单件方法&lt;/strong&gt;，单件方法是指那些只针对某个对象有效的方法，那么如果为一个对象定义了单件方法，那么这个单件方法的查找顺序又应该是怎样的？&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyClass&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_method&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;MyClass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;my_singleton_method&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;首先，&lt;strong&gt;单件方法&lt;/strong&gt;不会在 obj 中，因为 obj 不是一个类，其次它也不在 MyClass 中，那样的话所有的 MyClass 都应该能共享调用这个方法，也就构不成单件类了。同理，单件方法也不能在&lt;strong&gt;祖先链&lt;/strong&gt;的某个位置 (类似 superclass: Object) 中。正确的位置是在&lt;strong&gt;单件类&lt;/strong&gt;中，这个类其实就是我们在 irb 中向对象询问它的类时 (obj.class) 得到的那个类，不同的是这类与普通的类还是有稍稍不同的。也可以称其为&lt;strong&gt;元类或本征类&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id="打开单件类"&gt;打开单件类&lt;/h3&gt;
&lt;p&gt;Ruby 提供了两种方法获取单件类的引用，一种是通过传统的关键词 class 配合特殊的语法&lt;/p&gt;
&lt;h4 id="法一"&gt;法一&lt;/h4&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;an_object&lt;/span&gt;
    &lt;span class="c1"&gt;# 自己的代码&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
&lt;span class="n"&gt;singleton_class&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;
    &lt;span class="nb"&gt;self&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="n"&gt;singleton_class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;class&lt;/span&gt;  &lt;span class="c1"&gt;# =&amp;gt; Class&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;另一个方法是，通过Object#singleton_class方法来获得单件类的引用:&lt;/p&gt;
&lt;h4 id="法二"&gt;法二&lt;/h4&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="n"&gt;abc&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;singleton_class&lt;/span&gt;   &lt;span class="c1"&gt;# =&amp;gt; #&amp;lt;Class: #&amp;lt;String:0xxxxxx&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="单件类的特性"&gt;单件类的特性&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;每个单件类只有一个实例（被称为单件类的原因），而且不能被继承&lt;/li&gt;
&lt;li&gt;单件类是一个对象的单件方法的存活所在&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="引入单件类后的方法查找"&gt;引入单件类后的方法查找&lt;/h3&gt;
&lt;p&gt;基于上面对单件类的基本认识，引入单件类后，Ruby 的方法查找方式就不应该是先从其类 (普通类) 开始，而是应该先从对象的单件类中开始查找，如果在单件类中没有找到想要的方法，它才会开始沿着类 (普通类) 开始，再到祖先链上去找。这样从单件类之后开始，一切又回到了我们在没有引入单件类时候的次序。&lt;/p&gt;

&lt;p&gt;通过下面这个代码可以自行验证一下&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;C&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;a_method&lt;/span&gt;
        &lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="no"&gt;C&lt;/span&gt;&lt;span class="c1"&gt;#a_method()’&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;D&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;C&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;D&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;

&lt;span class="c1"&gt;#打开单件类定义单件方法&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;a_singleton_method&lt;/span&gt;
        &lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="c1"&gt;#a_singleton_method()’&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;singleton_class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;superclass&lt;/span&gt;  &lt;span class="c1"&gt;#=&amp;gt; D&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/25a713c6953c01d593b4818d6b9cf500.jpg" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;-待续-&lt;/p&gt;

&lt;p&gt;===============
最后贴一下自己的公众账号&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/651b4463530c3d6d961ae41db40e5377.jpg" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;可以十日不将军，不可一日不拱卒，&lt;strong&gt;日拱一卒 (rigongyizu365)&lt;/strong&gt;&lt;/p&gt;</description>
      <author>lazybios</author>
      <pubDate>Tue, 15 Sep 2015 15:50:27 +0800</pubDate>
      <link>https://ruby-china.org/topics/27344</link>
      <guid>https://ruby-china.org/topics/27344</guid>
    </item>
    <item>
      <title>《Ruby 元编程》读书笔记 (七)</title>
      <description>&lt;p&gt;博客地址 :&lt;a href="http://lazybios.com/2015/08/note-of-meta-pramgraming-with-ruby-7/" rel="nofollow" target="_blank" title=""&gt;《Ruby 元编程》读书笔记 (七)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;相关文章：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ruby-china.org/topics/27243" title=""&gt;《Ruby 元编程》读书笔记 (一)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27259" title=""&gt;《Ruby 元编程》读书笔记 (二)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27277" title=""&gt;《Ruby 元编程》读书笔记 (三)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27285/" title=""&gt;《Ruby 元编程》读书笔记 (四)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27299/" title=""&gt;《Ruby 元编程》读书笔记 (五)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27311" title=""&gt;《Ruby 元编程》读书笔记 (六)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;传神的头图↓↓↓&lt;/p&gt;

&lt;p&gt;&lt;img src="http://freshstu.qiniudn.com/metaprogramming-1.jpg" title="" alt="Ruby元编程"&gt;&lt;/p&gt;
&lt;h3 id="单件方法"&gt;单件方法&lt;/h3&gt;
&lt;p&gt;Ruby 允许给单个对象增加方法，这种只针对单个对象生效的方法，称为单件方法&lt;/p&gt;
&lt;h5 id="示例代码"&gt;示例代码&lt;/h5&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="n"&gt;just&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;regular&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;str&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;title?&lt;/span&gt;
    &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upcase&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;title?&lt;/span&gt;  &lt;span class="c1"&gt;# =&amp;gt; false&lt;/span&gt;
&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;methods&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;grep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/title?/&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; [:title?]&lt;/span&gt;
&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;singleton_methods&lt;/span&gt;   &lt;span class="c1"&gt;#=&amp;gt; [:title?]&lt;/span&gt;

&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;class&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; String&lt;/span&gt;
&lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;title?&lt;/span&gt;  &lt;span class="c1"&gt;#=&amp;gt;  NoMethodError&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;另外，除了上面使用的定义方法，还可以通过Object#define_singleton_method方法来定义单件方法&lt;/p&gt;
&lt;h4 id="单件方法与类方法"&gt;单件方法与类方法&lt;/h4&gt;
&lt;p&gt;前面的笔记中有说道在 Ruby 中类也是对象，而类名只是常量，所以，在类上调用方法其实跟在对象上调用方法一样：&lt;/p&gt;

&lt;p&gt;类方法的实质是：它是一个类的单件方法，实际上，如果比较单件方法的定义和类方法的定义，会发现其实二者是一样的&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;a_singleton_method&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;MyClass&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;another_class_method&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;二者均使用了 def 关键词做定义&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;object&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;method&lt;/span&gt;
    &lt;span class="c1"&gt;#方法主体&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上面的 object 可以是*对象的引用、常量类名或者 self。&lt;/p&gt;
&lt;h3 id="类宏attr_accessor"&gt;类宏 attr_accessor&lt;/h3&gt;
&lt;p&gt;Ruby 对象没有属性，如果希望得到一些像属性的东西，需要分别定义一个读方法和写方法（也就是 java、objc 中的 set 和 get 方法)，最直接的可以这样：&lt;/p&gt;
&lt;h5 id="示例代码"&gt;示例代码&lt;/h5&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyClass&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_attribute&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="vi"&gt;@my_attribute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;    
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_attribute&lt;/span&gt;
        &lt;span class="vi"&gt;@my_attribute&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;MyClass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;my_attribute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;
&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;my_attribute&lt;/span&gt;    &lt;span class="c1"&gt;#=&amp;gt; ‘x’&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但是上面这种写法，如果属性众多的话就会存在 Repeat Yourself 的地方，这时就可以用到下面三个类宏：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Module#attr_reader 生成一个读方法&lt;/li&gt;
&lt;li&gt;Module#attr_writer 生成一个写方法&lt;/li&gt;
&lt;li&gt;Module#attr_accessor 同时生成读方法和写方法
##### 示例代码
&lt;code&gt;ruby
class MyClass
attr_accessor :my_attribue
end
&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;这样是不是就简洁多了呢？当然，使用方法 (读与写) 跟上面的实现是一致的。&lt;/p&gt;

&lt;p&gt;-待续-&lt;/p&gt;

&lt;p&gt;===============
最后贴一下自己的公众账号&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/651b4463530c3d6d961ae41db40e5377.jpg" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;可以十日不将军，不可一日不拱卒，&lt;strong&gt;日拱一卒 (rigongyizu365)&lt;/strong&gt;&lt;/p&gt;</description>
      <author>lazybios</author>
      <pubDate>Mon, 14 Sep 2015 11:21:00 +0800</pubDate>
      <link>https://ruby-china.org/topics/27317</link>
      <guid>https://ruby-china.org/topics/27317</guid>
    </item>
    <item>
      <title>《Ruby 元编程》读书笔记 (六)</title>
      <description>&lt;p&gt;博客地址 :&lt;a href="http://lazybios.com/2015/08/note-of-meta-pramgraming-with-ruby-6/" rel="nofollow" target="_blank" title=""&gt;《Ruby 元编程》读书笔记 (六)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;相关文章：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ruby-china.org/topics/27243" title=""&gt;《Ruby 元编程》读书笔记 (一)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27259" title=""&gt;《Ruby 元编程》读书笔记 (二)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27277" title=""&gt;《Ruby 元编程》读书笔记 (三)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27285/" title=""&gt;《Ruby 元编程》读书笔记 (四)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27299/" title=""&gt;《Ruby 元编程》读书笔记 (五)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;传神的头图↓↓↓&lt;/p&gt;

&lt;p&gt;&lt;img src="http://freshstu.qiniudn.com/metaprogramming-1.jpg" title="" alt="Ruby元编程"&gt;&lt;/p&gt;
&lt;h3 id="类的返回值"&gt;类的返回值&lt;/h3&gt;
&lt;p&gt;像方法一样，类定义也会返回最后一条语句的值：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyClass&lt;/span&gt;
    &lt;span class="nb"&gt;self&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; MyClass&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="当前类"&gt;当前类&lt;/h3&gt;
&lt;p&gt;与当前对象 self 一样，同时还存在&lt;strong&gt;当前类（或模块）&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ruby 中并没有类似当前对象 self 一样的明确引用，不过在追踪当前类的时候，可以遵循下面几条：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;在程序顶层，当前类是 Object，这是 main 对象所属的类。&lt;/li&gt;
&lt;li&gt;在一个方法中，当前类就是当前对象的类。(在一个方法中用 def 关键字定义另一个方法，新定义的方法会定义在 self 所属的类中。因为 Ruby 解释器总是追踪当前类 (或模块) 的引用，所以使用 def 定义的方法都成为当前类的实例方法了) &lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="示例代码"&gt;示例代码&lt;/h4&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;C&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;m1&lt;/span&gt;
        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;m2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;D&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;C&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;D&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;m1&lt;/span&gt;

&lt;span class="no"&gt;C&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;instance_methods&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;#=&amp;gt; [:m1, :m2]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;当用 class 关键字打开一个类时 (或 module 关键字打开模块)，那个类称为当前类。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="class_eval方法"&gt;class_eval 方法&lt;/h3&gt;
&lt;p&gt;Module#class_eval方法(别名: module_eval)，会在一个已存在的类的上下文中执行一个块。使用该方法可以在不需要 class 关键字的前提下，打开类。&lt;/p&gt;

&lt;p&gt;Module#class_eval与Object#instance_eval方法相比，后者instance_eval方法只能修改self，而class_eval方法可以同时修改self与当前类。&lt;/p&gt;

&lt;p&gt;此外 class_eval 的另一个优势就是可以利用扁平作用域，规避 class 关键字的作用域门问题。&lt;/p&gt;
&lt;h4 id="instance_eval 与 class_eval的选择"&gt;instance_eval 与 class_eval 的选择&lt;/h4&gt;
&lt;p&gt;通常使用 instance_eval 方法打开非类的对象，而用 class_eval 方法打开类定义，然后用 def 定义方法。&lt;/p&gt;

&lt;p&gt;-待续-&lt;/p&gt;

&lt;p&gt;===============
最后贴一下自己的公众账号&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/651b4463530c3d6d961ae41db40e5377.jpg" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;可以十日不将军，不可一日不拱卒，&lt;strong&gt;日拱一卒 (rigongyizu365)&lt;/strong&gt;&lt;/p&gt;</description>
      <author>lazybios</author>
      <pubDate>Sun, 13 Sep 2015 19:51:31 +0800</pubDate>
      <link>https://ruby-china.org/topics/27311</link>
      <guid>https://ruby-china.org/topics/27311</guid>
    </item>
    <item>
      <title>《Ruby 元编程》读书笔记 (五)</title>
      <description>&lt;p&gt;博客地址 :&lt;a href="http://lazybios.com/2015/08/note-of-meta-pramgraming-with-ruby-5/" rel="nofollow" target="_blank" title=""&gt;《Ruby 元编程》读书笔记 (五)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;相关文章：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ruby-china.org/topics/27243" title=""&gt;《Ruby 元编程》读书笔记 (一)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27259" title=""&gt;《Ruby 元编程》读书笔记 (二)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27277" title=""&gt;《Ruby 元编程》读书笔记 (三)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27285/" title=""&gt;《Ruby 元编程》读书笔记 (四)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;传神的头图↓↓↓&lt;/p&gt;

&lt;p&gt;&lt;img src="http://freshstu.qiniudn.com/metaprogramming-1.jpg" title="" alt="Ruby元编程"&gt;&lt;/p&gt;
&lt;h3 id="可调用对象"&gt;可调用对象&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;代码块 (不是真正的对象，但是它们是”可调用的”) 在定义它们的作用域中执行&lt;/li&gt;
&lt;li&gt;proc: Proc 类的对象与代码块一样，也在定义自身的作用域中执行&lt;/li&gt;
&lt;li&gt;lambda: 同样是 Proc 类的对象，但跟普通的 proc 有细微差别。与代码块与 proc 一样都是闭包，也在定义自身的作用域中执行&lt;/li&gt;
&lt;li&gt;方法：绑定于一个对象，在 所绑定对象的作用域中执行。他们也可以与这个作用域解除绑定，然后再重新绑定到另一个对象的作用域中&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;前三个在之前的笔记中都有详细介绍，今天来详细看下最后一个 Method 对象部分&lt;/p&gt;
&lt;h4 id="Method 对象"&gt;Method 对象&lt;/h4&gt;
&lt;p&gt;通过Kernel#method方法，可以获得一个用Method对象表示的方法，在之后可以用Method#call方法对其进行调用。同样也可以用Kernel#singleton_method方法把单件方法名转换为Method对象&lt;/p&gt;
&lt;h5 id="示例代码"&gt;示例代码&lt;/h5&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyClass&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="vi"&gt;@x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_method&lt;/span&gt;
        &lt;span class="vi"&gt;@x&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;MyClass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;method&lt;/span&gt; &lt;span class="ss"&gt;:my_method&lt;/span&gt;
&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;   &lt;span class="c1"&gt;#=&amp;gt; 1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="自由方法"&gt;自由方法&lt;/h4&gt;
&lt;p&gt;与普通方法类似，不同的是它会从最初定义它的类或模块中脱离出来(即脱离之前的作用域)，通过Method#unbind方法，可以将一个方法变为自由方法。同时，你也可以通过调用Module#instance_method获得一个自由方法.&lt;/p&gt;
&lt;h6 id="示例代码"&gt;示例代码&lt;/h6&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;MyClass&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_method&lt;/span&gt;
        &lt;span class="mi"&gt;42&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;unbound&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;MyModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;instance_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:my_method&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;unbound&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;class&lt;/span&gt;  &lt;span class="c1"&gt;#=&amp;gt; UnboundMethod&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上面代码中的 UnboundMethod 对象，不能够直接用来调用，不过可以将一个 UnboundMethod 方法绑定到一个对象上，使其再次成为一个 Method 对象，然后再被调用执行。&lt;/p&gt;

&lt;p&gt;上面的绑定过程可以通过UnboundMethod#bind方法把UnboundMethod对象绑定到一个对象上，从某个类中分离出来的UnboundMethod对象只能绑定在该类及其子类对象上，不过从模块中分离出来的UnboundMethod对象在Ruby2.0后就不在有此限制了。&lt;/p&gt;

&lt;p&gt;此外还可以将UnboundMethod对象传递给Module#define_method方法，从而实现绑定。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt; &lt;span class="ss"&gt;:define_method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:another_method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unbound&lt;/span&gt;
&lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="n"&gt;abc&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;anther_method&lt;/span&gt;  &lt;span class="c1"&gt;#=&amp;gt; 42&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;PS: 上面代码请与前一小节示例代码，结合起来看！&lt;/p&gt;

&lt;p&gt;-待续-&lt;/p&gt;

&lt;p&gt;===============
最后贴一下自己的公众账号&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/651b4463530c3d6d961ae41db40e5377.jpg" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;可以十日不将军，不可一日不拱卒，&lt;strong&gt;日拱一卒 (rigongyizu365)&lt;/strong&gt;&lt;/p&gt;</description>
      <author>lazybios</author>
      <pubDate>Sat, 12 Sep 2015 18:38:51 +0800</pubDate>
      <link>https://ruby-china.org/topics/27299</link>
      <guid>https://ruby-china.org/topics/27299</guid>
    </item>
    <item>
      <title>《Ruby 元编程》读书笔记 (四)</title>
      <description>&lt;p&gt;博客地址 :&lt;a href="http://lazybios.com/2015/08/note-of-meta-pramgraming-with-ruby-4/" rel="nofollow" target="_blank" title=""&gt;《Ruby 元编程》读书笔记 (四)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;相关文章：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ruby-china.org/topics/27243" title=""&gt;《Ruby 元编程》读书笔记 (一)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27259" title=""&gt;《Ruby 元编程》读书笔记 (二)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27277" title=""&gt;《Ruby 元编程》读书笔记 (三)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27299/" title=""&gt;《Ruby 元编程》读书笔记 (五)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;传神的头图↓↓↓&lt;/p&gt;

&lt;p&gt;&lt;img src="http://freshstu.qiniudn.com/metaprogramming-1.jpg" title="" alt="Ruby元编程"&gt;&lt;/p&gt;
&lt;h3 id="Proc对象"&gt;Proc 对象&lt;/h3&gt;
&lt;p&gt;Proc 是由块转换来的对象。创建一个 Proc 共有四种方法，分别是：&lt;/p&gt;
&lt;h4 id="示例代码"&gt;示例代码&lt;/h4&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# 法一&lt;/span&gt;
&lt;span class="n"&gt;inc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Proc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;inc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;#=&amp;gt; 3&lt;/span&gt;

&lt;span class="c1"&gt;# 法二&lt;/span&gt;
&lt;span class="n"&gt;inc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;lambda&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;inc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;#=&amp;gt; 3&lt;/span&gt;

&lt;span class="c1"&gt;# 法三&lt;/span&gt;
&lt;span class="n"&gt;inc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;inc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; 3&lt;/span&gt;

&lt;span class="c1"&gt;# 法四&lt;/span&gt;
&lt;span class="n"&gt;inc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;proc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;inc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; 3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;除了上面的四种之外，还有一种通过&amp;amp;操作符的方式，将代码块与 Proc 对象进行转换。如果需要将某个代码块作为参数传递给方法，需要通过为这个参数添加&amp;amp;符号，并且其位置必须是在参数的最后一个&lt;/p&gt;

&lt;p&gt;&amp;amp;符号的含义是：这是一个 Proc 对象，我想把它当成代码块来使用。去掉&amp;amp;符号，将能再次得到一个 Proc 对象。&lt;/p&gt;
&lt;h4 id="示例代码"&gt;示例代码&lt;/h4&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;the_proc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;the_proc&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;my_method&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="no"&gt;Hello&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;#{name} !”}&lt;/span&gt;
&lt;span class="nb"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;class&lt;/span&gt;   &lt;span class="c1"&gt;#=&amp;gt; Proc&lt;/span&gt;
&lt;span class="nb"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="no"&gt;Bill&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;#=&amp;gt; “Hello,Bill”&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="c1"&gt;#{greeting}, #{yield}!”&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;my_proc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;proc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="no"&gt;Bill&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;my_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="no"&gt;Hello&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;my_proc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="Proc与Lambda对比"&gt;Proc 与 Lambda 对比&lt;/h3&gt;
&lt;p&gt;使用 Lambda 方法创建的 Proc 与其它方式创建的 Proc 是有一些差别的，用 lambda 方法创建的 Proc 称为 lambda，而用其他方式创建的则称为 proc。通过 Proc#lambda？可以检测 Proc 是不是 lambda。&lt;/p&gt;

&lt;p&gt;二者之间主要的差异有以下两点：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Proc、Lambda 的 return 含义不同; lambda 中的 return 表示的仅仅是从 lambda 中返回。而 proc 中，return 的行为则不同，其并不是从 proc 中返回，而是从定义 proc 的作用域中返回。即相当与在你的业务代码处返回。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="示例代码"&gt;示例代码&lt;/h4&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;double&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;callable_object&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Proc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;   
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="c1"&gt;# 不可达的代码&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;double&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; 10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Proc、Lambda 的 return 参数检查方式不同；Proc 的参数检查要比 Lambda 参数检查要更宽松一些，如果传入 Proc 中的参数数量不匹配其不会发生报错，会自行进行一定的调整到期望参数的样子，但是对于 lambda 则不同，如果出现参数不匹配的情况，其往往会报 ArgumentError 异常，中断程序。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="示例代码"&gt;示例代码&lt;/h4&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Proc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nb"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; [1, 2]&lt;/span&gt;
&lt;span class="nb"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; [1, nil]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="Proc与Lambda之间的选择"&gt;Proc 与 Lambda 之间的选择&lt;/h3&gt;
&lt;p&gt;lambda 更直观，更像是一个方法，参数要求更加严格，return 也更像是方法定义中的 return，往往 Ruby 程序员会将 lambda 作为第一选择。（PS: 这部分还真需要考证一下！）&lt;/p&gt;

&lt;p&gt;-待续-&lt;/p&gt;

&lt;p&gt;===============
最后贴一下自己的公众账号&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/651b4463530c3d6d961ae41db40e5377.jpg" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;可以十日不将军，不可一日不拱卒，&lt;strong&gt;日拱一卒 (rigongyizu365)&lt;/strong&gt;&lt;/p&gt;</description>
      <author>lazybios</author>
      <pubDate>Fri, 11 Sep 2015 14:31:12 +0800</pubDate>
      <link>https://ruby-china.org/topics/27285</link>
      <guid>https://ruby-china.org/topics/27285</guid>
    </item>
    <item>
      <title>《Ruby 元编程》读书笔记 (三)</title>
      <description>&lt;p&gt;还是前面的主题：&lt;/p&gt;

&lt;p&gt;博客地址 :&lt;a href="http://lazybios.com/2015/08/note-of-meta-pramgraming-with-ruby-3/" rel="nofollow" target="_blank" title=""&gt;《Ruby 元编程》读书笔记 (三)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;相关文章：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ruby-china.org/topics/27243" title=""&gt;《Ruby 元编程》读书笔记 (一)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27259" title=""&gt;《Ruby 元编程》读书笔记 (二)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27285" title=""&gt;《Ruby 元编程》读书笔记 (四)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27299/" title=""&gt;《Ruby 元编程》读书笔记 (五)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;传神的头图↓↓↓&lt;/p&gt;

&lt;p&gt;&lt;img src="http://freshstu.qiniudn.com/metaprogramming-1.jpg" title="" alt="Ruby元编程"&gt;&lt;/p&gt;
&lt;h3 id="代码块"&gt;代码块&lt;/h3&gt;
&lt;p&gt;Ruby 中的代码块这个 Topic，之前的文章有介绍过，需要的同学可以翻一翻历史消息，这里做个简短的回顾与总结&lt;/p&gt;

&lt;p&gt;代码块的定义方式有{}花括号与 do...end 关键字定义两种，单行用花括号，多行用 do...end&lt;/p&gt;

&lt;p&gt;代码块只有在方法调用的时候才可以定义，块会被直接传递给这个方法，判断某个方法调用中是否包含代码块，可以通过 Kernel#block_given?&lt;/p&gt;

&lt;p&gt;代码块不仅可以有自己的参数，也会有返回值，往往没有代码块中的最后一行执行结果会被作为返回值返回&lt;/p&gt;

&lt;p&gt;代码块之所以可以执行，是因为其不仅包含代码，同时也涵盖一组相应绑定，即执行环境，也可以称之为上下文环境。代码块可以携带这个上下文环境，到任何一个代码块可以达到的地方。也就可以说，一个代码块是一个闭包，当定义一个代码块时，它会捕获当前环境中的绑定，并带它们四处流动。&lt;/p&gt;
&lt;h3 id="作用域"&gt;作用域&lt;/h3&gt;
&lt;p&gt;Ruby 中不具备嵌套作用域 (即在内部作用域，可以看到外部作用域的) 的特点，它的作用域是截然分开的，一旦进入一个新的作用域，原先的绑定会被替换为一组新的绑定。&lt;/p&gt;

&lt;p&gt;程序会在三个地方关闭前一个作用域，同时打开一个新的作用域，它们是：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;类定义 class&lt;/li&gt;
&lt;li&gt;模块定义 module&lt;/li&gt;
&lt;li&gt;方法定义 def&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;上面三个关键字，每个关键字对应一个作用域门 (进入)，相应的 end 则对应离开这道门。&lt;/p&gt;
&lt;h4 id="扁平化作用域"&gt;扁平化作用域&lt;/h4&gt;
&lt;p&gt;从一个作用域进入另一个作用域的时候，局部变量会立即失效，为了让局部变量持续有效，可以通过规避关键字的方式，使用方法调用来代替作用域门，让一个作用域看到另一个作用域里的变量，从而达到目的。具体做法是，通过Class.new替代class，Module#define_method代替def,Module.new代替module。这种做法称为扁平作用域，表示两个作用域挤压到一起。&lt;/p&gt;
&lt;h5 id="示例代码(Wrong)"&gt;示例代码 (Wrong)&lt;/h5&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;my_var&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="no"&gt;Success&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyClass&lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;my_var&lt;/span&gt;  &lt;span class="c1"&gt;#这里无法正确打印”Success”&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_method&lt;/span&gt;
        &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;my_var&lt;/span&gt;  &lt;span class="c1"&gt;#这里无法正确打印”Success”&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h5 id="示例代码(Right)"&gt;示例代码 (Right)&lt;/h5&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;my_var&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="no"&gt;Success&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;
&lt;span class="no"&gt;MyClass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="c1"&gt;#{my_var} in  the class definition”&lt;/span&gt;
    &lt;span class="n"&gt;define_method&lt;/span&gt; &lt;span class="ss"&gt;:my_method&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="c1"&gt;#{my_var} in the method”&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="共享作用域"&gt;共享作用域&lt;/h4&gt;
&lt;p&gt;将一组方法定义到，某个变量的扁平作用域中，可以保证变量仅被有限的几个方法所共享。这种方式称为共享作用域&lt;/p&gt;
&lt;h3 id="instance_eval方法"&gt;instance_eval 方法&lt;/h3&gt;
&lt;p&gt;这个BasicObject#instance_eval有点类似JS中的bind方法，不同的时，bind是将this传入到对象中，而instance_eval则是将代码块(上下文探针Context Probe) 传入到指定的对象中，一个是传对象，一个是传执行体。通过这种方式就可以在 instance_eval 中的代码块里访问到调用者对象中的变量。&lt;/p&gt;
&lt;h4 id="示例代码"&gt;示例代码&lt;/h4&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyClass&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;
        &lt;span class="vi"&gt;@v&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;MyClass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;

&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;instance_eval&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="nb"&gt;self&lt;/span&gt;    &lt;span class="c1"&gt;#=&amp;gt; #&amp;lt;MyClass:0x33333 @v=1&amp;gt;&lt;/span&gt;
    &lt;span class="vi"&gt;@v&lt;/span&gt;      &lt;span class="c1"&gt;#=&amp;gt; 1  &lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;instance_eval&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="vi"&gt;@v&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;instance_eval&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="vi"&gt;@v&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;   &lt;span class="c1"&gt;# =&amp;gt; 2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;此外，instance_eval 方法还有一个双胞胎兄弟：instance_exec 方法。相比前者后者更加灵活，允许对代码块传入参数。&lt;/p&gt;
&lt;h4 id="示例代码"&gt;示例代码&lt;/h4&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;C&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;
        &lt;span class="vi"&gt;@x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;D&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;twisted_method&lt;/span&gt;
        &lt;span class="vi"&gt;@y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
        &lt;span class="c1"&gt;#C.new.instance_eval { “@x: #{@x}, @y&amp;gt;: #{y}” }&lt;/span&gt;
        &lt;span class="no"&gt;C&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;instance_exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="vi"&gt;@x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;#{@x}, @y: #{y}” }&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="c1"&gt;#D.new.twisted_method   # =&amp;gt; “@x: 1, @y: ”&lt;/span&gt;
&lt;span class="no"&gt;D&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;twisted_method&lt;/span&gt;   &lt;span class="c1"&gt;# =&amp;gt; “@x: 1, @y: 2”&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因为调用 instance_eval 后，将调用者作为了当前的 self，所以作用域更换到了 class C 中，之前的作用域就不生效了。这时如果还想访问到之前&lt;a href="/y" class="user-mention" title="@y"&gt;&lt;i&gt;@&lt;/i&gt;y&lt;/a&gt;变量，就需要通过参数打包上&lt;a href="/y" class="user-mention" title="@y"&gt;&lt;i&gt;@&lt;/i&gt;y&lt;/a&gt;一起随 instance_eval 转义，但因为 instance_eval 不能携带参数，所以使用其同胞兄弟 instance_exec 方法。&lt;/p&gt;
&lt;h3 id="洁净室"&gt;洁净室&lt;/h3&gt;
&lt;p&gt;一个只为在其中执行块的对象，称为洁净室，其只是一个用来执行块的环境。可以使用 BasicObject 作为洁净室是个不错的选择，因为它是白板类，内部的变量和方法都比较有限，不会引起冲突。&lt;/p&gt;

&lt;p&gt;-待续-&lt;/p&gt;

&lt;p&gt;===============
最后贴一下自己的公众账号&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/651b4463530c3d6d961ae41db40e5377.jpg" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;可以十日不将军，不可一日不拱卒，&lt;strong&gt;日拱一卒 (rigongyizu365)&lt;/strong&gt;&lt;/p&gt;</description>
      <author>lazybios</author>
      <pubDate>Thu, 10 Sep 2015 19:21:29 +0800</pubDate>
      <link>https://ruby-china.org/topics/27277</link>
      <guid>https://ruby-china.org/topics/27277</guid>
    </item>
    <item>
      <title>《Ruby 元编程》读书笔记 (二)</title>
      <description>&lt;p&gt;继续昨天的主题&lt;/p&gt;

&lt;p&gt;博客地址 :&lt;a href="http://lazybios.com/2015/08/note-of-meta-pramgraming-with-ruby-2/" rel="nofollow" target="_blank" title=""&gt;《Ruby 元编程》读书笔记 (二)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;相关文章：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ruby-china.org/topics/27243" title=""&gt;《Ruby 元编程》读书笔记 (一)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27277" title=""&gt;《Ruby 元编程》读书笔记 (三)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27285" title=""&gt;《Ruby 元编程》读书笔记 (四)&lt;/a&gt;
&lt;a href="https://ruby-china.org/topics/27299/" title=""&gt;《Ruby 元编程》读书笔记 (五)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;头图还是它↓↓↓&lt;/p&gt;

&lt;p&gt;&lt;img src="http://freshstu.qiniudn.com/metaprogramming-1.jpg" title="" alt="Ruby元编程"&gt;&lt;/p&gt;
&lt;h3 id="动态方法"&gt;动态方法&lt;/h3&gt;&lt;h4 id="动态调用方法"&gt;动态调用方法&lt;/h4&gt;
&lt;p&gt;在Ruby中通过Object#send方法可以代替点标识调用对象的指定实例方法&lt;/p&gt;
&lt;h4 id="示例代码"&gt;示例代码&lt;/h4&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyClass&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;my_arg&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;MyClass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;my_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    &lt;span class="c1"&gt;#=&amp;gt; 6&lt;/span&gt;
&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:my_method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; 6&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上面代码通过直接调用和使用 send 方法调用得到的结果是一样的，使用 send 的好处是，可以在编码中，动态的决定方法调用。这个技巧在元编程中被称为动态派发&lt;/p&gt;

&lt;p&gt;另外需要指出的地方是通过Object#send不仅可以调用公共方法，也可以调用对象的私有方法。如果想保留对象的封装特性，不向外暴露私有方法可以使用Object#public_send方法。&lt;/p&gt;
&lt;h3 id="动态定义方法"&gt;动态定义方法&lt;/h3&gt;
&lt;p&gt;除了方法的动态调用之外，Ruby还通过Module#define_method方法和代码块提供了动态方法定义方式&lt;/p&gt;
&lt;h4 id="示例代码"&gt;示例代码&lt;/h4&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyClass&lt;/span&gt;
    &lt;span class="n"&gt;define_method&lt;/span&gt; &lt;span class="ss"&gt;:my_method&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;my_arg&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
        &lt;span class="n"&gt;my_arg&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
    &lt;span class="k"&gt;do&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;MyClass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;my_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;#=&amp;gt; 6&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上面代码通过 define_method 方法取代了关键词 def，其本质上都是相同的，只是在定义方式上，define_method 的方式更加灵活一些，可以通过在编码中通过推导，完成函数的定义，增加了实现的灵活性。&lt;/p&gt;
&lt;h3 id="method_missing方法"&gt;method_missing 方法&lt;/h3&gt;
&lt;p&gt;严格意义上将 method_missing 方法，并不算是明确的定义 (不会出现在 methods 列表中)，其本质是通过方法查找的机制来截获调用信息进而合理的给出相应方法的回应。有点类似与异常处理中的抛出异常，一层一层的往外抛。&lt;/p&gt;

&lt;p&gt;method_missing利用的机制是，当一个对象进行某个方法调用的时候，会到其对应的类的实例方法中进行查找，如果没有找到，则顺着祖先链向上查找，直到找到BasicObject类为止。如果都没有则会最终调用一个BasicObject#method_missing抛出NoMethodError异常。&lt;/p&gt;

&lt;p&gt;当我们需要定义很多相似的方法时候，可以通过重写 method_missing 方法，对相似的方法进行统一做出回应，这样一来其行为就类似与调用定义过的方法一样。&lt;/p&gt;
&lt;h4 id="示例代码"&gt;示例代码&lt;/h4&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Roulette&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;method_missing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;capitalize&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="sx"&gt;%w[Bob Frank Bill Honda Eric]&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;include?&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;
    &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
      &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;..."&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; got a &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;number_of&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Roulette&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;number_of&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bob&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;number_of&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;kitty&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="动态代理"&gt;动态代理&lt;/h3&gt;
&lt;p&gt;对一些封装过的对象，通过 method_missing 方法收集调用，并把这些调用转发到被封装的对象，这一过程称为动态代理，其中 method_missing 体现了动态，转发体现了代理&lt;/p&gt;
&lt;h3 id="const_missing方法"&gt;const_missing 方法&lt;/h3&gt;
&lt;p&gt;与 method_missing 类似，还有关于常量的 const_missing 方法，当引用一个不存在的常量时，Ruby 会把这个常量名作为一个符号传递给 const_missing 方法。&lt;/p&gt;
&lt;h3 id="白板类(blank slates)"&gt;白板类 (blank slates)&lt;/h3&gt;
&lt;p&gt;拥有极少方法的类称为白板类，通过继承 BasicObject 类，可以迅速的得到一个白板类。除了这种方法以外，还可以通过删除方法来将一个普通类变为白板类。&lt;/p&gt;
&lt;h4 id="删除方法"&gt;删除方法&lt;/h4&gt;
&lt;p&gt;删除某个方法有两种方式：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Module#undef_method&lt;/li&gt;
&lt;li&gt;Module#remove_method&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;二者的区别是Module#undef_method会删除所有(包括继承而来的)方法。而Module#remove_method只删除接受者自己的方法，而保留继承来的方法。&lt;/p&gt;
&lt;h3 id="动态方法与Method_missing的使用原则"&gt;动态方法与 Method_missing 的使用原则&lt;/h3&gt;
&lt;p&gt;当可以使用动态方法时候，尽量使用动态方法。除非必须使用 method_missing 方法 (方法特别多的情况)，否则尽量少使用它。&lt;/p&gt;

&lt;p&gt;-待续-&lt;/p&gt;

&lt;p&gt;===============
最后贴一下自己的公众账号&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/651b4463530c3d6d961ae41db40e5377.jpg" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;可以十日不将军，不可一日不拱卒，&lt;strong&gt;日拱一卒 (rigongyizu365)&lt;/strong&gt;&lt;/p&gt;</description>
      <author>lazybios</author>
      <pubDate>Wed, 09 Sep 2015 18:22:21 +0800</pubDate>
      <link>https://ruby-china.org/topics/27259</link>
      <guid>https://ruby-china.org/topics/27259</guid>
    </item>
  </channel>
</rss>
