meta programing ruby读书笔记

Open Class

给予了你为class增加方法的能力,但是也如同打开了潘多拉魔盒,一旦通过Open Class增加了class方法导致重名问题,将很难定位。

Instance variable

和Java不同,Ruby中的instance_variable 与class之间没有直接联系,你可以从一个class创建不同实例,并且各自拥有不同的instance variable. (What’s the purpose?)

Method

Ruby中,method保存在class中

Object

一个object是一组instance variable以及这个object所属的class的引用.

Class

Ruby中,所有的class都是类Class的instance object. class是一个Class的实例、一组instance method、一个到super class的引用.

Differences between Class and Module

Module is meant to be included (or mixined). Module can be used as namespace. Class is meant to be initlized or inherinted.

Dynamic Methods

ruby中,可以在class定义时通过define_methods动态地定义方法, 如下代码动态地为class Computer添加了三个方法 mouse, cpu, keyboard:

class Computer
  def initialize(computer_id, data_source)
    @id = computer_id
    @data_source = data_source
  end

  def self.define_component(name) 
    define_method(name) {
      info = @data_source.send "get_#{name}_info", @id
      price = @data_source.send "get_#{name}_price", @id 
      "#{name.to_s.capitalize}: #{info} ($#{price})" 
    }
  end

  define_component :mouse
  define_component :cpu
  define_component :keyboard
end

Method Missing

ruby中,当尝试对receiver调用一个不存在的方法时,该receiver的method_missing方法会被调用,利用这一特性,可以通过重载 method_missing实现动态定义属性、方法效果, 通过method missing机制定义出来的方法被称为Ghost Method。 例如:

class Computer
  def initialize(computer_id, data_source)
    @id = computer_id
    @data_source = data_source
  end

  def method_missing(name, *args)
    info = @data_source.send("get_#{name}_info", args[0])
    price = @data_source.send("get_#{name}_price", args[0])
    "#{name.to_s.capitalize}: #{info} ($#{price})"
  end

  #重写respond_to会使利用method_missing实现的动态方法与实际定义的方法无异
  def respond_to?(method)
    @data_source.respond_to?("get_#{method}_info") || super
  end
end

这些通过method_missing机制创建出来的methods被称为ghost method.

Flat Scope

ruby中,classmodule,def被称为scope gate,当程序遇到这几个关键字时,程序的scope就会发生变化,如果需要在scope之间共享变量,则可以使用Class.new代替classmodule, Module#define_method代替def,如:

my_var = 12
MyClass = Class.new do
  # my_var is visiable here
  ...
  define_method :my_method do
    # my_var is visiable here
  end
end

Object#instance_eval()

改变self的值为指定实例,同时改变“current class”为当前实例的eigenclass, 在此实例上下文中执行一个block

Module#class_eval() or Module#module_eval()

改变self的值为指定实例,同时改变“current class”为当前方法的receiver,在此实例上下文中执行一个block

Deferred Evaluation

定义一个block,proc,lambda,然后在其他地方调用此block,proc,lambda,这就叫做Deferred Evaluation

Singleton Method

单独给一个object instance定义的method,称之为singleton method class methods可以认为是一个class对象的singleton method

Class Macro

class macro看起来像是关键字,但是实际上就是普通的方法,但是这些方法常在声明定义class中使用。

Eignclass

对象除了有一个其被创建时声明的那个class外,还会有它自己的一个不可见的,特殊的class,这个class被叫做eigenclass,也被称为singleton class。一个对象的singleton method就存在于这个对象的eignclass上,eignclass的superclass是这个对象的对外呈现的那个class(参考下面的示例代码)。

class Duck
  #code omited
end
#Duck就是a_duck对外呈现的class
a_duck = Duck.new

通过下面的语法,你可以进入到一个对象的eignclass内部

class << obj
  # you are in the eigen class scope.
end

或者可以通过下面的语法获取对eignclass的引用

metaclass = class << matz; self; end

Scope changing

class Person
  #self is the class object `Person` 
  class << self
    #self is the eignclass of class object `Person`
    def species
          "Homo Sapien"
    end
  end
end

Person.instance_eval do
  #method will be defined on eignclass	of class object `Person`
  #but self is the class object `Person`
  def species
    "Homo Sapien"
  end
  self.name #=> "Person"
end

给对象的eignclass增加singleton方法:

#给对象增加singleton方法
matz = Object.new
def matz.speak
  "Place your burden to machine's shoulders"
end

#给类增加singleton方法(class methods)
class Person
end

def Person.speak 
  "Place your burden to machine's shoulders"
end

Class Extension Mixin

module M
  def included(clazz)
clazz.extend ClassMethods
  end

  #定义在这个内部module里的方法会变成inclusor的class method
  module ClassMethods
def a_class_method
    end
  end
end

In Melbourne

第一次出国,所有的事儿都是新鲜的,难免有点忐忑,幸运的是,在机上邻座的是一个话多的澳洲土耳其裔姑娘,告诉我在澳洲如何入境,应该注意什么,该如何填写入境卡,到了墨尔本应该去哪些景点应该去。 到了墨尔本,Luke带我熟悉道路,去Yarra河旁边看风景,Tan带我去吃烤鸡,参加MelbourneJS组活动。Herry带我去吃越南餐,这里有全世界各地的食品,而我也尽量保持每天吃饭的不重样,来之前我妈对我吃不习惯的担心完全是多余的。

天气

墨尔本的天看起来很低,似乎站在楼顶就触手可及了,而且始终是那么的蓝。还有一个特点就是:有时候你可以在一天内有四个季节的体验。

Sky of Melbourne</img>

Social

个人的social技能还是不行,到了一个陌生的地方始终放不开觉,始终担心在某个方面冒犯了别人。本来海拔就低,来到这儿就像是到了巨人国,跟大多数人说话都得仰着头,有个UX竟然高达两米,没去打篮球真是可惜了了。相比之下,Tan就很值得我学习,与周围人都很聊得开,而且,在解决问题时,始终让人感觉很耐心,给新人以安全感。

VIM

从David教我VIM,到现在能够比较自如得使用,也就不到俩月。兴趣是最好的老师。

MelbJS

Tan 带我去参加一次Melbourne JS的活动,来自不同公司的技术达人在一起分享工作中的心得,Melbourne的的开源氛围真得不错。

prototype based 继承机制

与Java,C#,Ruby中”class-based”继承机制不同,javascript是一种”prototype-based”的继承机制。 关于prototype-based和class-based的区别,我想通过一个例子来描述下:
你是一个陶艺师,我给你一个图纸,说:”照着这个图纸的样子帮我做5个罐子”,于是你照着图纸上描述的形状,颜色,材质做出5个,这就是class-based 的模式

我拿给你一个罐子,说:”照着这个样子帮我做个罐子”,于是你参照这个罐子的形状,颜色,材质做出5个,你就是采用了prototype-based 的模式。

class based OO

我们再来看一段class-based 面向对象语言的代码示例:

class Animal
  private String name
  public Animal(String name)
  {
  this.name = name;
  }
  public void run(){
    ...
  }
}
  class Wolf extends Animal
{
  public void hunt ()
  {
    ...
  }
}

class Wolf继承自class Animal拥有了run技能,并且扩展了自己的hunt技能。

prototype based OO

下面我们来看看一段prototype-based面向对象语言的代码示例:

    function Animal(name)
    {
      this.name = name;
      this.run = function () {
        console.log(this.name + " is runing")
      }
    }

    function Wolf(name)
    {
      this.name = name;
      this.hunt = function () {
        console.log(this.name + " is hunting")
      }
    }
    //继承的魔法在这里显现
    Wolf.prototype = new Animal();
    var someone = new Animal("Some one");
    var wolf = new Wolf("Wolf");
    someone.run();
    wolf.run();
    wolf.hunt();
    //should got exception here
    someone.hunt();

在这里,把function Wolf的prototype设置为一个Animal的实例,当尝试调用wolf上的run方法时,由于Wolf中没有run方法,于是javascript解释器会查找Wolf的prototype(一个Animal的实例)是否有run方法,如果有,则调用此方法,如果没有,则尝试调用此实例的prototype上的run方法,如此持续下去,直到找到这个run方法或者到达继承顶部 - Object.prototype。这就是基于”prototype-chain”的继承机制。

声明:本文翻译自How Browser Work,我将会逐步发布所翻译的章节。

网页浏览器可以算得上世界使用范围最广的软件了,在这篇文章中,我将介绍下浏览器的内部工作机制。你将会理解从你在地址栏输入“google.com” 到你看到Google网站页面的这个期间究竟发生了什么。

 

1. 简介

1.1 浏览器

     如今使用范围较广的浏览器有Internet Explorer,Firefox,Safari,Chrome和Opera。我将简单介绍几个开源浏览器——Firefox,Chrome,Safari(部分开源)。根据StatCounter browser statistics,现在(2011/08)Firefox,Safari,Chrome在全世界市场占有率已经接近60%。所以开源浏览器是浏览器市场中一只不可小觑的力量。

 

1.2 浏览器的主要功能

     浏览器的主要功能是从web服务器上获取用户所请求的资源并展示在浏览器窗口中。在大多数情况下,用户所请求的资源是HTML文档,当然也可以是PDF,图片,音频等其他文件类型。资源的位置是采用URI(Uniform Resource Identifier)标识的。

     浏览器解释、显示HTML文档的方式定义在HTML(http://www.w3.org/TR/REC-html40/)、CSS(http://www.w3.org/TR/CSS/)规范中。这些规范是由web标准化组织W3C维护的。

     很多年前,很多浏览器开发商都只遵从了部分规范,并且发展出他们自己对标准的扩展,这导致了很多严重的兼容性问题。而现在,大部分浏览器都遵从了这些规范。

     浏览器的用户界面大都类似,基本都包括了以下几个控件:

  • 用于输入地址的地址栏
  • 前进、返回按钮
  • 加为书签功能选项
  • 用于刷新、终止当前文档加载过程的按钮
  • 用于返回主页面的按钮

1.3 浏览器架构概述

     浏览器的主要组件见下图(1.1):

     1.  用户界面 - 包括地址栏,前进、后退按钮、加书签按钮等。包括了除了用于展示网页窗口的其他所有用户可以看见的部分。

     2.  浏览器引擎 - 配置UI和渲染引擎之间动作

     3.  渲染引擎 - 展示请求到的内容。例如,请求的资源是一个HTML文档,渲染引擎就会解析这个HTML文档和CSS并且把解析好的内容展示在网页窗口上。

     4.  Networking - 用于网络交互,例如HTTP 请求。它有一个独立于操作系统的接口,对于每个操作系统有不同实现。

     5.  用户界面后台 - 用于绘制一些基本的控件如下拉框,单选框等。它暴露了一组平台独立的接口,在底层调用了操作系统的用户界面方法进行绘制组件。

     6.  JavaScript引擎 - 用于解释执行javascript

     7.  数据存储 - 浏览器需要存储一些数据到本地磁盘上,例如cookie。新的HTML规范(HTML5)定义一个 web database ,提供一个嵌入浏览器中的完整的轻量级数据库。

 

          图 1: 浏览器主要组件图

     值得注意的是,Chrome浏览器与其他浏览器不同,它为每个tab创建了一个独立的渲染引擎,每个tab是一个独立的进程。

 

2. 渲染引擎

     渲染引擎的职责当然就是渲染了,具体点就是把获取到的内容展示到屏幕上。

     一般情况下,渲染引擎可以展示HTML、XML和图片,当然,可以通过安装插件或者浏览器扩展展示其他类型的内容。如通过安装PDF查看器插件展示PDF文件。当然,在本章,我们还是关注最主要的功能:展示应用了CSS的HTML、图片。

 

2.1 渲染引擎

     Firefox、Chrome、Safari分别使用了两种渲染引擎。Firefox使用的是Gecko - 一个由Mozilla研发的渲染引擎。Safari和Chrome则都使用Webkit做为其渲染引擎。

     Webkit最初是Linux上的开源渲染引擎,后来Apple对Webkit进行了修改使其支持Mac和Windows平台。更多详细信息请参见webkit.org。

 

2.2 主流程

     渲染引擎会首先调用Networking获取被请求的文档的内容。一般文档会被划分为8k大小的块进行传输。

     在此之后,渲染引擎的处理流程如下:

 

 

     图 2:渲染引擎主流程

     首先,渲染引擎会解析HTML文档构建DOM树,把遇到的HTML标记转换成“内容树”上的DOM节点。同时它也会解析外部CSS文件和HTML文档中的样式数据,然后根据这些样式数据和“内容树”创建另一棵树-“渲染树”。

 

     渲染树包含一些带有颜色、大小信息的矩形,这些矩形按照其在屏幕上展示的顺序进行排列。

 

     渲染树构建完成后,将进入“布局”环节,在这个环节中会给每个节点设置其将被展示的位置坐标。接下来将进入“显示”环节 - 遍历整个渲染树,通过用户界面后台把各个节点展示在屏幕上。

 

     值得一提的是,这是个顺序的流程,为了获得更好的用户体验,渲染引擎会尽可能快地把内容显示在屏幕上。它不会等到所有的HTML文档解析完成才开始构建“渲染树”,当渲染引擎还在获取、解析其他内容时,已加载到的部分内容会先被展示在屏幕上。

 

 

 

 

Thread per connection VS Event loop

Advantage:
more memory consumption thread blocked waiting for I/O operation

  • Q: So why not Event loop, callbacks, non-blocking I/O
  • A: cultural and infrastructural.
    1. cultural, we thought that the I/O should be blocking.
    2. infrastructural
      • single threaded event loops require I/O to be non-blocking, but most libraries are not.
      • too much options: EventMachine, Twisted
  • Q: Why javascript?
  • A: javascript has the following features:
    1. Anonymous functions, closures. – easy to create callback
    2. Only one callback at a time. – only one callback at a time
    3. I/O through DOM event callbacks –non-blocking
    4. promise: a promise is a kind of EventEmitter which emits either “success” or “error”. (But not both.)