├── .gitignore ├── Gemfile ├── README.md ├── _config.yml ├── _includes ├── footer.html ├── head.html └── header.html ├── _layouts ├── default.html ├── page.html └── post.html ├── about.md ├── css ├── main.css └── style.css ├── en ├── anyeval.textile ├── class.textile ├── contextual.textile ├── evaluator.textile ├── fin.textile ├── gc.textile ├── index.textile ├── intro.textile ├── iterator.textile ├── load.textile ├── method.textile ├── minimum.textile ├── module.textile ├── name.textile ├── object.textile ├── parser.textile ├── preface.textile ├── security.textile ├── spec.textile ├── syntree.textile ├── thread.textile ├── variable.textile └── yacc.textile ├── feed.xml ├── images ├── book_cover.jpg ├── ch_abstract_build.jpg ├── ch_abstract_build.png ├── ch_abstract_ci.jpg ├── ch_abstract_ci.png ├── ch_abstract_repo.jpg ├── ch_abstract_repo.png ├── ch_abstract_syntree.jpg ├── ch_abstract_syntree.png ├── ch_anyeval_dynavars.jpg ├── ch_anyeval_speceval.jpg ├── ch_class_addsclass.png ├── ch_class_boot1.png ├── ch_class_include.png ├── ch_class_infloop.png ├── ch_class_metaclass.png ├── ch_class_metaobj.png ├── ch_class_metatree.png ├── ch_class_mmm.png ├── ch_class_multi.png ├── ch_class_real.png ├── ch_class_reqlink.png ├── ch_class_simulate.png ├── ch_class_symbolic.png ├── ch_contextual_condp.jpg ├── ch_contextual_transittobeg.jpg ├── ch_contextual_trees.jpg ├── ch_evaluator_jumptag.jpg ├── ch_evaluator_rbeval.jpg ├── ch_evaluator_setjmp.jpg ├── ch_evaluator_tagstack.jpg ├── ch_evaluator_usetag.jpg ├── ch_evaluator_whilejmp.jpg ├── ch_gc_calloca.jpg ├── ch_gc_calloca.png ├── ch_gc_cycle.jpg ├── ch_gc_cycle.png ├── ch_gc_gcimage.jpg ├── ch_gc_gcimage.png ├── ch_gc_gengc.jpg ├── ch_gc_gengc.png ├── ch_gc_heapitems.jpg ├── ch_gc_heapitems.png ├── ch_gc_heaps.jpg ├── ch_gc_heaps.png ├── ch_gc_macstack.jpg ├── ch_gc_macstack.png ├── ch_gc_mostcopy.jpg ├── ch_gc_mostcopy.png ├── ch_gc_objects.jpg ├── ch_gc_objects.png ├── ch_gc_objid.jpg ├── ch_gc_objid.png ├── ch_gc_refcnt.jpg ├── ch_gc_refcnt.png ├── ch_gc_stop2.jpg ├── ch_gc_stop2.png ├── ch_gc_stop3.jpg ├── ch_gc_stop3.png ├── ch_iterator_dst.jpg ├── ch_iterator_dynavarseval.jpg ├── ch_iterator_flaginfect.jpg ├── ch_iterator_framepush.jpg ├── ch_iterator_insert.jpg ├── ch_iterator_itertrans.jpg ├── ch_iterator_stacks.jpg ├── ch_load_link.jpg ├── ch_load_loadwait.jpg ├── ch_method_anchor.jpg ├── ch_method_mhash.jpg ├── ch_method_msearch.jpg ├── ch_minimum_Kernel.jpg ├── ch_minimum_Kernel.png ├── ch_minimum_ccc.jpg ├── ch_minimum_ccc.png ├── ch_minimum_classclass.jpg ├── ch_minimum_classclass.png ├── ch_minimum_classtree.jpg ├── ch_minimum_classtree.png ├── ch_minimum_const.jpg ├── ch_minimum_const.png ├── ch_minimum_constref.jpg ├── ch_minimum_constref.png ├── ch_minimum_metaobjects.jpg ├── ch_minimum_metaobjects.png ├── ch_minimum_modclass.jpg ├── ch_minimum_modclass.png ├── ch_minimum_modclass2.jpg ├── ch_minimum_modclass2.png ├── ch_minimum_modinherit.jpg ├── ch_minimum_modinherit.png ├── ch_minimum_multiinherit.jpg ├── ch_minimum_multiinherit.png ├── ch_minimum_objimage.jpg ├── ch_minimum_objimage.png ├── ch_minimum_reference.jpg ├── ch_minimum_reference.png ├── ch_minimum_supersub.jpg ├── ch_minimum_supersub.png ├── ch_module_cbase.jpg ├── ch_module_crefstack.jpg ├── ch_module_framestack.jpg ├── ch_module_localvars.jpg ├── ch_module_massign.jpg ├── ch_module_scopestack.jpg ├── ch_module_stack.jpg ├── ch_module_tmpprotecttmp.jpg ├── ch_module_vars.jpg ├── ch_name_array.png ├── ch_name_aset.png ├── ch_name_chain.png ├── ch_name_nexti.png ├── ch_name_sttable.png ├── ch_object_class.png ├── ch_object_classtree.png ├── ch_object_flags.png ├── ch_object_givtable.png ├── ch_object_rbasic.png ├── ch_object_rdata.png ├── ch_object_string.png ├── ch_object_value.png ├── ch_parser_ablist.jpg ├── ch_parser_alist.jpg ├── ch_parser_build.jpg ├── ch_parser_exprloop.jpg ├── ch_parser_heredoc.jpg ├── ch_parser_ibuffer.jpg ├── ch_parser_interf.jpg ├── ch_parser_lexparams.jpg ├── ch_parser_progloop.jpg ├── ch_parser_scanner.jpg ├── ch_parser_tbuffer.jpg ├── ch_syntree_append.jpg ├── ch_syntree_blocklist.jpg ├── ch_syntree_callgraph.jpg ├── ch_syntree_dynavars.jpg ├── ch_syntree_flagUsage.jpg ├── ch_syntree_flags.jpg ├── ch_syntree_lmask.jpg ├── ch_syntree_localtbl.jpg ├── ch_syntree_localvars.jpg ├── ch_syntree_lvtbltbl.jpg ├── ch_syntree_stree.jpg ├── ch_syntree_tbl.jpg ├── ch_thread_fdset.jpg ├── ch_thread_setjmploop.jpg ├── ch_thread_thread.jpg ├── ch_thread_twodirection.jpg ├── ch_variable_gaccess.png ├── ch_variable_gvar.png ├── ch_yacc_build.jpg ├── ch_yacc_yaccvars.jpg ├── somerights20.png └── visual_language.png ├── index.md └── zh ├── 0-0-preface.md ├── 0-1-intro.md ├── 01-minimum.md ├── 02-object.md ├── 03-name.md ├── 04-class.md ├── 05-gc.md ├── 06-variable.md ├── 07-security.md ├── 08-spec.md ├── 09-yacc.md ├── 10-parser.md ├── 11-contextual.md ├── 12-syntree.md ├── 13-evaluator.md ├── 14-module.md ├── 15-method.md ├── 16-iterator.md ├── 17-anyeval.md ├── 18-load.md ├── 19-thread.md ├── 20-fin.md ├── liquid.md ├── markdown.md ├── misc.md ├── r-bnf.md ├── r-options.md ├── r-preface.md ├── r-syntax.md └── rename.rb /.gitignore: -------------------------------------------------------------------------------- 1 | _site 2 | .DS_Store 3 | .jekyll 4 | .bundle 5 | .sass-cache 6 | Gemfile.lock 7 | node_modules 8 | package.json 9 | *.swp 10 | *.swo 11 | .ruby-version 12 | .ruby-gemset 13 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | #备注:精确的版本控制在大型项目中很重要,但是,我觉得自己搞的Jekyll的站点还是别精确控制了,一来我懒,二来世界变化很快,版本更迭很快。 2 | source 'http://ruby.taobao.org' 3 | 4 | gem 'jekyll' 5 | gem 'RedCloth' # textile格式的处理器 6 | gem 'jekyll-sitemap' # 7 | gem 'jemoji' # GitHub风格的表情符号插件 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Ruby Hacking Guide 中文翻译 2 | ============================== 3 | [阅读该翻译文档](http://xiajian.github.io/rhg-zh/) 4 | 备注: 原本是自己新建的版本库,初次建立,没有经验,README都是参考的英文版的RHG翻译的。需要注意的是,Githu生成静态页面的分支是gh-pages,为了避免麻烦,所有修改都在gh-pages分支上,master废弃不用。 5 | 6 | 本地运行 7 | ========== 8 | 9 | ```sh 10 | $ git clone https://github.com/ruby-hacking-guide/ruby-hacking-guide.github.com 11 | $ gem install jekyll jemoji jekyll-sitemap 12 | $ gem install RedCloth 13 | $ jekyll serve -w # this compiles files and starts a server on localhost:4000. 14 | ``` 15 | 16 | 17 | For Bundler users 18 | ```sh 19 | $ git clone https://github.com/ruby-hacking-guide/ruby-hacking-guide.github.com 20 | $ bundle install 21 | $ jekyll serve -w # this compiles files and starts a server on localhost:4000. 22 | ``` 23 | 24 | 25 | [Jekyll usage](https://github.com/mojombo/jekyll/wiki/usage) 26 | 27 | 28 | 英文版的EPUB格式 29 | ========= 30 | 31 | Thanks to @avsej, we can read this book in EPUB. 32 | 33 | To generate an EPUB file, you need to install eeepub additionally. 34 | 35 | ```sh 36 | $ gem install rubyzip -v 0.9.9 37 | $ gem install eeepub 38 | $ ruby script/publish 39 | ``` 40 | 41 | You can convert a generated EPUB file into other formats by using Calibre. 42 | 43 | The generated files in various formats are also available: 44 | 45 | * http://files.avsej.net/rhg-2013-10-03_e5203a.epub 46 | * http://files.avsej.net/rhg-2013-10-03_e5203a.mobi 47 | * http://files.avsej.net/rhg-2013-10-03_e5203a.pdf 48 | 49 | 50 | About the version of ruby explained 51 | ========== 52 | 53 | The version of ruby used is ruby (1.7.3 2002-09-12). 54 | 55 | It's almost a year before the release of Ruby 1.8.0, 56 | so things explained in this book are basically the same in Ruby 1.8. 57 | 58 | The details about this version are written in the 59 | [Introduction](http://ruby-hacking-guide.github.io/intro.html) 60 | 61 | You can download it from the official support site of the book. 62 | * http://i.loveruby.net/ja/rhg/ar/ruby-rhg.tar.gz 63 | * http://i.loveruby.net/ja/rhg/ar/ruby-rhg.zip 64 | 65 | It's also available from this Organization's repo at 66 | * https://github.com/ruby-hacking-guide/ruby-1.7.3 67 | 68 | 69 | License 70 | ======= 71 | 72 | Copyright (c) 2002-2004 Minero Aoki, All rights reserved. 73 | 74 | 该翻译使用[知识共享署名-非商业使用条约](http://creativecommons.org/licenses/by-nc-sa/2.5/) 75 | 76 | 想要翻译成其他语言,请联系原作者Minero Aoki 。 77 | 78 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | # Site settings 2 | title: Ruby Hacking Guide 中文版 3 | email: jhqy2011@gmail.com 4 | github_username: xiajian 5 | description: 本指南最初是由青木峰郎(Copyright © 2002 - 2004 Minero AOKI)完成, 英文翻译由Vincent ISAMBART和Clifford Escobar CAOILE贡献。中文翻译第一部分源自axgle,其余部分的我打算翻译下来,不知能走多远。本指南采用Creative Commons Attribution-NonCommercial-ShareAlike2.5 License发布 6 | 7 | baseurl: /rhg-zh 8 | url: http://xiajian.github.io/rhg-zh 9 | 10 | # 指定本地服务器运行端口,运行多个Jekyll时特别有用 11 | port: 5000 12 | # source: zh 13 | # Build settings 14 | markdown: kramdown 15 | permalink: pretty 16 | 17 | # Use the following plug-ins 18 | gems: 19 | - jemoji # Emoji please! 20 | - jekyll-sitemap # Create a sitemap using the official Jekyll sitemap gem 21 | 22 | # Exclude these files from your production _site 23 | exclude: 24 | - Gemfile 25 | - Gemfile.lock 26 | - LICENSE 27 | - README.md 28 | -------------------------------------------------------------------------------- /_includes/footer.html: -------------------------------------------------------------------------------- 1 | 59 | -------------------------------------------------------------------------------- /_includes/head.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {% if page.title %}{{ page.title }}{% else %}{{ site.title }}{% endif %} 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /_includes/header.html: -------------------------------------------------------------------------------- 1 | 26 | -------------------------------------------------------------------------------- /_layouts/default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {% include head.html %} 5 | 6 | 7 | 8 | {% include header.html %} 9 | 10 | 11 |
12 |
13 | {{ content }} 14 |
15 |
16 | 17 | {% include footer.html %} 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /_layouts/page.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | --- 4 |
5 | 6 |
7 |

{{ page.title }}

8 |
9 | 10 |
11 | {{ content }} 12 |
13 | 14 |
-------------------------------------------------------------------------------- /_layouts/post.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | --- 4 |
5 | 6 |
7 |

{{ page.title }}

8 |

{{ page.date | date: "%b %-d, %Y" }}{% if page.author %} • {{ page.author }}{% endif %}{% if page.meta %} • {{ page.meta }}{% endif %}

9 |
10 | 11 |
12 | {{ content }} 13 |
14 | 15 |
-------------------------------------------------------------------------------- /about.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: 关于 邪王真眼的夏 4 | permalink: /about/ 5 | --- 6 | 7 | 一定要看下蛋的母鸡,请允许我自吹自擂一下: 8 | 9 | 来自地球的 中二 患者,不知何时毕业。目前,生活在伟大的天朝的繁华的上海。动漫宅,程序员,VIM用户,Ubuntu使用者。 10 | 11 | ## 更多信息 12 | ---- 13 | 14 | ###动漫宅 15 | 看过数以打计的漫画,简单介绍如下: 16 | 17 | - 高桥留美子:《人鱼之森》,《乱马 1/2 》,《相聚一刻》,《犬夜叉》,《境界之轮回》 18 | - 富奸义博:《幽游白书》,《全职猎人》 19 | - 宫崎峻的诸多作品,比如《魔女宅急便》,《天空之城》,《千与千寻》等 20 | - 新海城的作品:《秒速5厘米》,《言叶之庭》等 21 | - 八木教广:《大剑》 22 | - K社的三大催泪弹中的:AIR, Cland 23 | - 三大民工漫:死神,海贼王 和 火影 24 | - 真岛浩的:《圣石小子》,《妖尾》 25 | - 以及《凉宫春日的忧郁》,《魔法禁书目录》,《某科学的超电磁炮》,《空之境界》,《蔷薇少女》,《Hellsing》,《EVA》,《叛逆的露鲁修》等等 26 | 27 | ###程序员 28 | 29 | - 相比动漫,我赖以为生的编程却没什么建树,悲哀啊,悲哀。 30 | - markdown编辑一定要注意空行和空格!! 31 | 32 | ### 联系我 33 | ---- 34 | 35 | * [jhqy2011@gmail.com](mailto:jhqy2011@gmail.com) 36 | * [CSDN的博客](http://blog.csdn.net/xiajian2010/) 37 | * [邪王真眼的夏](http:xiajian.github.io) 38 | 39 | ### 呓语 40 | ---- 41 | 42 | 1. 每当我折腾一个新的东西时,我总是要自我欣赏一番,几乎达到无可复加的境界,我在想,是不是太自恋?? 43 | -------------------------------------------------------------------------------- /css/main.css: -------------------------------------------------------------------------------- 1 | /* Base */ 2 | /* ----------------------------------------------------------*/ 3 | 4 | * { 5 | margin: 0; 6 | padding: 0; 7 | } 8 | 9 | html, body { height: 100%; } 10 | 11 | body { 12 | font-family: Helvetica, Arial, sans-serif; 13 | font-size: 16px; 14 | line-height: 1.5; 15 | font-weight: 300; 16 | background-color: #fdfdfd; 17 | } 18 | 19 | h1, h2, h3, h4, h5, h6 { font-size: 100%; font-weight: 400; } 20 | 21 | a { color: #2a7ae2; text-decoration: none; } 22 | a:hover { color: #000; text-decoration: underline; } 23 | a:visited { color: #205caa; } 24 | 25 | /* Utility */ 26 | 27 | .wrap:before, 28 | .wrap:after { content:""; display:table; } 29 | .wrap:after { clear: both; } 30 | .wrap { 31 | max-width: 800px; 32 | padding: 0 30px; 33 | margin: 0 auto; 34 | zoom: 1; 35 | } 36 | 37 | 38 | /* Layout Styles */ 39 | /* ----------------------------------------------------------*/ 40 | 41 | /* Site header */ 42 | 43 | .site-header { 44 | border-top: 5px solid #333; 45 | border-bottom: 1px solid #e8e8e8; 46 | min-height: 56px; 47 | background-color: white; 48 | } 49 | 50 | .site-title, 51 | .site-title:hover, 52 | .site-title:visited { 53 | display: block; 54 | color: #333; 55 | font-size: 26px; 56 | letter-spacing: -1px; 57 | float: left; 58 | line-height: 56px; 59 | position: relative; 60 | z-index: 1; 61 | } 62 | 63 | .site-nav { 64 | float: right; 65 | line-height: 56px; 66 | } 67 | 68 | .site-nav .menu-icon { display: none; } 69 | 70 | .site-nav .page-link { 71 | margin-left: 20px; 72 | color: #727272; 73 | letter-spacing: -.5px; 74 | } 75 | 76 | /* Site footer */ 77 | 78 | .site-footer { 79 | border-top: 1px solid #e8e8e8; 80 | padding: 30px 0; 81 | } 82 | 83 | .footer-heading { 84 | font-size: 18px; 85 | font-weight: 300; 86 | letter-spacing: -.5px; 87 | margin-bottom: 15px; 88 | } 89 | 90 | .site-footer .column { float: left; margin-bottom: 15px; } 91 | 92 | .footer-col-1 { 93 | width: 270px; /*fallback*/ 94 | width: -webkit-calc(35% - 10px); 95 | width: -moz-calc(35% - 10px); 96 | width: -o-calc(35% - 10px); 97 | width: calc(35% - 10px); 98 | margin-right: 10px 99 | } 100 | .footer-col-2 { 101 | width: 175px; /*fallback*/ 102 | width: -webkit-calc(23.125% - 10px); 103 | width: -moz-calc(23.125% - 10px); 104 | width: -o-calc(23.125% - 10px); 105 | width: calc(23.125% - 10px); 106 | margin-right: 10px 107 | } 108 | .footer-col-3 { 109 | width: 335px; /*fallback*/ 110 | width: -webkit-calc(41.875%); 111 | width: -moz-calc(41.875%); 112 | width: -o-calc(41.875%); 113 | width: calc(41.875%); 114 | } 115 | 116 | .site-footer ul { list-style: none; } 117 | 118 | .site-footer li, 119 | .site-footer p { 120 | font-size: 15px; 121 | letter-spacing: -.3px; 122 | color: #828282; 123 | } 124 | 125 | .github-icon-svg, 126 | .twitter-icon-svg { 127 | display: inline-block; 128 | width: 16px; 129 | height: 16px; 130 | position: relative; 131 | top: 3px; 132 | } 133 | 134 | 135 | /* Page Content styles */ 136 | /* ----------------------------------------------------------*/ 137 | 138 | .page-content { 139 | padding: 30px 0; 140 | background-color: #fff; 141 | } 142 | 143 | 144 | /* Home styles */ 145 | /* ----------------------------------------------------------*/ 146 | 147 | .home h1 { margin-bottom: 25px; } 148 | 149 | .posts { list-style-type: none; } 150 | 151 | .posts li { margin-bottom: 30px; } 152 | 153 | .posts .post-link { 154 | font-size: 24px; 155 | letter-spacing: -1px; 156 | line-height: 1; 157 | } 158 | 159 | .posts .post-date { 160 | display: block; 161 | font-size: 15px; 162 | color: #818181; 163 | } 164 | 165 | 166 | /* Post styles */ 167 | /* ----------------------------------------------------------*/ 168 | 169 | .post-header { margin: 10px 0 30px; } 170 | 171 | .post-header h1 { 172 | font-size: 42px; 173 | letter-spacing: -1.75px; 174 | line-height: 1; 175 | font-weight: 300; 176 | } 177 | 178 | .post-header .meta { 179 | font-size: 15px; 180 | color: #818181; 181 | margin-top: 5px; 182 | } 183 | 184 | .post-content { margin: 0 0 30px; } 185 | 186 | .post-content > * { margin: 20px 0; } 187 | 188 | 189 | .post-content h1, 190 | .post-content h2, 191 | .post-content h3, 192 | .post-content h4, 193 | .post-content h5, 194 | .post-content h6 { 195 | line-height: 1; 196 | font-weight: 300; 197 | margin: 40px 0 20px; 198 | } 199 | 200 | .post-content h2 { 201 | font-size: 32px; 202 | letter-spacing: -1.25px; 203 | } 204 | 205 | .post-content h3 { 206 | font-size: 26px; 207 | letter-spacing: -1px; 208 | } 209 | 210 | .post-content h4 { 211 | font-size: 20px; 212 | letter-spacing: -1px; 213 | } 214 | 215 | .post-content blockquote { 216 | border-left: 4px solid #e8e8e8; 217 | padding-left: 20px; 218 | font-size: 18px; 219 | opacity: .6; 220 | letter-spacing: -1px; 221 | font-style: italic; 222 | margin: 30px 0; 223 | } 224 | 225 | .post-content ul, 226 | .post-content ol { padding-left: 20px; } 227 | 228 | .post pre, 229 | .post code { 230 | border: 1px solid #d5d5e9; 231 | background-color: #eef; 232 | padding: 8px 12px; 233 | -webkit-border-radius: 3px; 234 | -moz-border-radius: 3px; 235 | border-radius: 3px; 236 | font-size: 15px; 237 | overflow:scroll; 238 | } 239 | 240 | .post code { padding: 1px 5px; } 241 | 242 | .post ul, 243 | .post ol { margin-left: 1.35em; } 244 | 245 | .post pre code { 246 | border: 0; 247 | padding-right: 0; 248 | padding-left: 0; 249 | } 250 | 251 | /* terminal */ 252 | .post pre.terminal { 253 | border: 1px solid #000; 254 | background-color: #333; 255 | color: #FFF; 256 | -webkit-border-radius: 3px; 257 | -moz-border-radius: 3px; 258 | border-radius: 3px; 259 | } 260 | 261 | .post pre.terminal code { background-color: #333; } 262 | 263 | /* Syntax highlighting styles */ 264 | /* ----------------------------------------------------------*/ 265 | 266 | .highlight { background: #ffffff; } 267 | .highlight .c { color: #999988; font-style: italic } /* Comment */ 268 | .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ 269 | .highlight .k { font-weight: bold } /* Keyword */ 270 | .highlight .o { font-weight: bold } /* Operator */ 271 | .highlight .cm { color: #999988; font-style: italic } /* Comment.Multiline */ 272 | .highlight .cp { color: #999999; font-weight: bold } /* Comment.Preproc */ 273 | .highlight .c1 { color: #999988; font-style: italic } /* Comment.Single */ 274 | .highlight .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */ 275 | .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ 276 | .highlight .gd .x { color: #000000; background-color: #ffaaaa } /* Generic.Deleted.Specific */ 277 | .highlight .ge { font-style: italic } /* Generic.Emph */ 278 | .highlight .gr { color: #aa0000 } /* Generic.Error */ 279 | .highlight .gh { color: #999999 } /* Generic.Heading */ 280 | .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ 281 | .highlight .gi .x { color: #000000; background-color: #aaffaa } /* Generic.Inserted.Specific */ 282 | .highlight .go { color: #888888 } /* Generic.Output */ 283 | .highlight .gp { color: #555555 } /* Generic.Prompt */ 284 | .highlight .gs { font-weight: bold } /* Generic.Strong */ 285 | .highlight .gu { color: #aaaaaa } /* Generic.Subheading */ 286 | .highlight .gt { color: #aa0000 } /* Generic.Traceback */ 287 | .highlight .kc { font-weight: bold } /* Keyword.Constant */ 288 | .highlight .kd { font-weight: bold } /* Keyword.Declaration */ 289 | .highlight .kp { font-weight: bold } /* Keyword.Pseudo */ 290 | .highlight .kr { font-weight: bold } /* Keyword.Reserved */ 291 | .highlight .kt { color: #445588; font-weight: bold } /* Keyword.Type */ 292 | .highlight .m { color: #009999 } /* Literal.Number */ 293 | .highlight .s { color: #d14 } /* Literal.String */ 294 | .highlight .na { color: #008080 } /* Name.Attribute */ 295 | .highlight .nb { color: #0086B3 } /* Name.Builtin */ 296 | .highlight .nc { color: #445588; font-weight: bold } /* Name.Class */ 297 | .highlight .no { color: #008080 } /* Name.Constant */ 298 | .highlight .ni { color: #800080 } /* Name.Entity */ 299 | .highlight .ne { color: #990000; font-weight: bold } /* Name.Exception */ 300 | .highlight .nf { color: #990000; font-weight: bold } /* Name.Function */ 301 | .highlight .nn { color: #555555 } /* Name.Namespace */ 302 | .highlight .nt { color: #000080 } /* Name.Tag */ 303 | .highlight .nv { color: #008080 } /* Name.Variable */ 304 | .highlight .ow { font-weight: bold } /* Operator.Word */ 305 | .highlight .w { color: #bbbbbb } /* Text.Whitespace */ 306 | .highlight .mf { color: #009999 } /* Literal.Number.Float */ 307 | .highlight .mh { color: #009999 } /* Literal.Number.Hex */ 308 | .highlight .mi { color: #009999 } /* Literal.Number.Integer */ 309 | .highlight .mo { color: #009999 } /* Literal.Number.Oct */ 310 | .highlight .sb { color: #d14 } /* Literal.String.Backtick */ 311 | .highlight .sc { color: #d14 } /* Literal.String.Char */ 312 | .highlight .sd { color: #d14 } /* Literal.String.Doc */ 313 | .highlight .s2 { color: #d14 } /* Literal.String.Double */ 314 | .highlight .se { color: #d14 } /* Literal.String.Escape */ 315 | .highlight .sh { color: #d14 } /* Literal.String.Heredoc */ 316 | .highlight .si { color: #d14 } /* Literal.String.Interpol */ 317 | .highlight .sx { color: #d14 } /* Literal.String.Other */ 318 | .highlight .sr { color: #009926 } /* Literal.String.Regex */ 319 | .highlight .s1 { color: #d14 } /* Literal.String.Single */ 320 | .highlight .ss { color: #990073 } /* Literal.String.Symbol */ 321 | .highlight .bp { color: #999999 } /* Name.Builtin.Pseudo */ 322 | .highlight .vc { color: #008080 } /* Name.Variable.Class */ 323 | .highlight .vg { color: #008080 } /* Name.Variable.Global */ 324 | .highlight .vi { color: #008080 } /* Name.Variable.Instance */ 325 | .highlight .il { color: #009999 } /* Literal.Number.Integer.Long */ 326 | 327 | 328 | /* media queries */ 329 | /* ----------------------------------------------------------*/ 330 | 331 | 332 | @media screen and (max-width: 750px) { 333 | 334 | .footer-col-1 { width: 50%; } 335 | 336 | .footer-col-2 { 337 | width: 45%; /*fallback*/ 338 | width: -webkit-calc(50% - 10px); 339 | width: -moz-calc(50% - 10px); 340 | width: -o-calc(50% - 10px); 341 | width: calc(50% - 10px); 342 | margin-right: 0; 343 | } 344 | 345 | .site-footer .column.footer-col-3 { 346 | width: auto; 347 | float: none; 348 | clear: both; 349 | } 350 | 351 | } 352 | 353 | @media screen and (max-width: 600px) { 354 | 355 | .wrap { padding: 0 12px; } 356 | 357 | .site-nav { 358 | position: fixed; 359 | z-index: 10; 360 | top: 14px; right: 8px; 361 | background-color: white; 362 | -webkit-border-radius: 5px; 363 | -moz-border-radius: 5px; 364 | border-radius: 5px; 365 | border: 1px solid #e8e8e8; 366 | } 367 | 368 | .site-nav .menu-icon { 369 | display: block; 370 | font-size: 24px; 371 | color: #505050; 372 | float: right; 373 | width: 36px; 374 | text-align: center; 375 | line-height: 36px; 376 | } 377 | 378 | .site-nav .menu-icon svg { width: 18px; height: 16px; } 379 | 380 | .site-nav .trigger { 381 | clear: both; 382 | margin-bottom: 5px; 383 | display: none; 384 | } 385 | 386 | .site-nav:hover .trigger { display: block; } 387 | 388 | .site-nav .page-link { 389 | display: block; 390 | text-align: right; 391 | line-height: 1.25; 392 | padding: 5px 10px; 393 | margin: 0; 394 | } 395 | 396 | .post-header h1 { font-size: 36px; } 397 | .post-content h2 { font-size: 28px; } 398 | .post-content h3 { font-size: 22px; } 399 | .post-content h4 { font-size: 18px; } 400 | .post-content blockquote { padding-left: 10px; } 401 | .post-content ul, 402 | .post-content ol { padding-left: 10px; } 403 | 404 | .site-footer .column { 405 | float: none; 406 | clear: both; 407 | width: auto; 408 | margin: 0 0 15px; } 409 | 410 | } 411 | 412 | /* 表格样式控制 */ 413 | table { 414 | margin-bottom: 20px; 415 | max-width: 100%; 416 | border-collapse: collapse; 417 | border: 1px solid rgba(50,118,177,0.167); 418 | transition: all 0.3s 419 | } 420 | 421 | table:hover { 422 | border: 1px solid rgba(50,118,177,0.35); 423 | box-shadow: 0 0 3 rgba(50,118,177,0.267); 424 | transition: all 0.3s 425 | } 426 | 427 | table thead tr th { 428 | border: 1px solid rgba(50,118,177,0.167); 429 | border-top: 0 none; 430 | border-bottom-width: 2px; 431 | vertical-align: bottom; 432 | padding: 8px 433 | } 434 | 435 | table tbody tr td { 436 | border: 1px solid rgba(50,118,177,0.167); 437 | vertical-align: middle; 438 | padding: 8px 439 | } 440 | 441 | table thead>tr { 442 | background-color: rgba(249,249,249,0.9) 443 | } 444 | 445 | table tbody>tr:nth-child(2n+1) { 446 | background-color: rgba(249,249,249,0.5) 447 | } 448 | 449 | table tbody tr:hover { 450 | background-color: rgba(235,235,235,0.7); 451 | transition: all 0.3s 452 | } 453 | 454 | table li { 455 | margin: 5px 0 456 | } 457 | 458 | table img { 459 | max-width: 85%; 460 | margin: 0 auto; 461 | display: inherit; 462 | border-radius: 6px; 463 | padding: 4px; 464 | line-height: 1.429 465 | } 466 | 467 | table code { 468 | background-color: rgba(255,204,204,0.3); 469 | box-shadow: 0 0 1px rgba(0,0,0,0.167); 470 | border: 1px solid rgba(102,102,102,0.167); 471 | font-family: Monaco, Consolas, Terminal, monospace 472 | } 473 | -------------------------------------------------------------------------------- /css/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: white; 3 | color: black; 4 | text-align: left; 5 | line-height: 140%; 6 | margin-top: 5%; 7 | margin-left: 20%; 8 | width: 40em; 9 | } 10 | 11 | h1 { 12 | text-align: left; 13 | font-size: 200%; 14 | margin-top: 0em; 15 | margin-bottom: 1em; 16 | padding-left: 12px; 17 | border-left: 80px solid #33a; 18 | line-height: 80px; 19 | } 20 | 21 | h2 { 22 | text-align: left; 23 | font-size: 150%; 24 | margin-top: 3em; 25 | margin-bottom: 1em; 26 | border-bottom: 2px solid #33a; 27 | } 28 | 29 | h3 { 30 | text-align: left; 31 | font-size: 150%; 32 | margin-top: 1em; 33 | margin-bottom: 0.1em; 34 | padding-left: 8px; 35 | border-left: 12px solid #33a; 36 | } 37 | 38 | h4 { 39 | text-align: left; 40 | font-size: 150%; 41 | margin-top: 1em; 42 | margin-bottom: 0.1em; 43 | } 44 | 45 | ul { 46 | padding-left: 1em; 47 | } 48 | 49 | li { 50 | padding-left: 0em; 51 | } 52 | 53 | dl { 54 | margin-top: 0em; 55 | margin-bottom: 0em; 56 | margin-left: 0em; 57 | margin-right: 0em; 58 | } 59 | 60 | dt { 61 | margin-top: 0.5em; 62 | margin-bottom: 0.2em; 63 | margin-left: 0em; 64 | margin-right: 0em; 65 | } 66 | 67 | dd { 68 | margin-top: 0em; 69 | margin-bottom: 0em; 70 | margin-left: 4em; 71 | margin-right: 0em; 72 | } 73 | 74 | p.caption { 75 | margin-botton: 0px; 76 | } 77 | 78 | pre { 79 | line-height: 120%; 80 | padding: 8px; 81 | background: #eee; 82 | } 83 | 84 | span.ami { 85 | color: black; 86 | background-color: #ccc; 87 | } 88 | 89 | .image { 90 | align: center; 91 | margin-top: 2em; 92 | margin-bottom: 2em; 93 | } 94 | 95 | address { 96 | font-style: normal; 97 | line-height: 110%; 98 | text-align: right; 99 | } 100 | 101 | a:link, a:visited { 102 | color: #33a; 103 | text-decoration: none; 104 | } 105 | 106 | a:active, a:visited { 107 | color: #666; 108 | text-decoration: none; 109 | } 110 | 111 | a:hover, a:focus { 112 | text-decoration: underline; 113 | } 114 | 115 | /* -- */ 116 | footer { 117 | margin-top: 2em; 118 | } 119 | 120 | body { 121 | font-family: Georgia, serif; 122 | font-size: 15px; 123 | } 124 | 125 | h1 code, h2 code, h3 code, h4 code, h5 code{ 126 | font-family: Menlo, Monaco, "Andale Mono", "Lucida console", "courier New", monospace; 127 | font-weight: normal; 128 | } 129 | 130 | 131 | pre { 132 | font-family: Menlo, Monaco, "Andale Mono", "Lucida console", "courier New", monospace; 133 | font-size: .10em; 134 | } 135 | 136 | code { 137 | font-family: Menlo, Monaco, "Andale Mono", "Lucida console", "courier New", monospace; 138 | font-size: .10em; 139 | } 140 | 141 | h1#chapter { font-size: 150%; } 142 | 143 | th { padding-right: .5em } 144 | 145 | pre.longlist, pre.screen { 146 | padding: 8px; 147 | background: #eee; 148 | } 149 | 150 | pre.emlist { 151 | background: white; 152 | padding-left: 2em; 153 | } 154 | 155 | p { width: 35em } 156 | 157 | .image ul { 158 | list-style-type: none; 159 | padding-left: 0; 160 | font-size: .8em; 161 | margin: 0 162 | } 163 | 164 | .image p { margin: 0 } 165 | 166 | /* for chapter 16 */ 167 | div.longlist { 168 | padding: 8px; 169 | background: #eee; 170 | font-size: .8em; 171 | font-family: Menlo, Monaco, "Andale Mono", "Lucida console", "courier New", monospace; 172 | } 173 | 174 | div.longlist p { margin: 0 } 175 | 176 | .container { 177 | margin: 0 auto; 178 | max-width: 740px; 179 | padding: 0 10px; 180 | width: 100%; 181 | } 182 | /* 表格样式控制 */ 183 | table { 184 | margin-bottom: 20px; 185 | max-width: 100%; 186 | border-collapse: collapse; 187 | border: 1px solid rgba(50,118,177,0.167); 188 | transition: all 0.3s 189 | } 190 | 191 | table:hover { 192 | border: 1px solid rgba(50,118,177,0.35); 193 | box-shadow: 0 0 3 rgba(50,118,177,0.267); 194 | transition: all 0.3s 195 | } 196 | 197 | table thead tr th { 198 | border: 1px solid rgba(50,118,177,0.167); 199 | border-top: 0 none; 200 | border-bottom-width: 2px; 201 | vertical-align: bottom; 202 | padding: 8px 203 | } 204 | 205 | table tbody tr td { 206 | border: 1px solid rgba(50,118,177,0.167); 207 | vertical-align: middle; 208 | padding: 8px 209 | } 210 | 211 | table thead>tr { 212 | background-color: rgba(249,249,249,0.9) 213 | } 214 | 215 | table tbody>tr:nth-child(2n+1) { 216 | background-color: rgba(249,249,249,0.5) 217 | } 218 | 219 | table tbody tr:hover { 220 | background-color: rgba(235,235,235,0.7); 221 | transition: all 0.3s 222 | } 223 | 224 | table li { 225 | margin: 5px 0 226 | } 227 | 228 | table img { 229 | max-width: 85%; 230 | margin: 0 auto; 231 | display: inherit; 232 | border-radius: 6px; 233 | padding: 4px; 234 | line-height: 1.429 235 | } 236 | 237 | table code { 238 | background-color: rgba(255,204,204,0.3); 239 | box-shadow: 0 0 1px rgba(0,0,0,0.167); 240 | border: 1px solid rgba(102,102,102,0.167); 241 | font-family: Monaco, Consolas, Terminal, monospace 242 | } 243 | 244 | -------------------------------------------------------------------------------- /en/fin.textile: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | --- 4 | 5 | h1. Final Chapter: Ruby's future 6 | 7 | h2. Issues to be addressed 8 | 9 | @ruby@ isn't 'completely finished' software. It's still being developed, 10 | there are still a lot of issues. Firstly, we want to try removing 11 | inherent problems in the current interpreter. 12 | 13 | The order of the topics is mostly in the same order as the chapters of 14 | this book. 15 | 16 | 17 | h3. Performance of GC 18 | 19 | The performance of the current GC might be 20 | "not notably bad, but not notably good". 21 | "not notably bad" means "it won't cause troubles in our daily life", 22 | and "not notably good" means "its downside will be exposed under heavy load". 23 | For example, if it is an application which creates plenty of objects and keeps 24 | holding them, its speed would slow down radically. 25 | Every time doing GC, it needs to mark all of the objects, 26 | and furthermore it would becomes to need to invoke GC more often 27 | because it can't collect them. 28 | To counter this problem, Generational GC, which was mentioned in Chapter 5, 29 | must be effective. (At least, it is said so in theory.) 30 | 31 | Also regarding its response speed, 32 | there are still rooms we can improve. 33 | With the current GC, while it is running, the entire interpretor stops. 34 | Thus, when the program is an editor or a GUI application, 35 | sometimes it freezes and stops to react. 36 | Even if it's just 0.1 second, 37 | stopping when typing characters would give a very bad impression. 38 | Currently, there are few such applications created or, 39 | even if exists, its size might be enough small not to expose this problem. 40 | However, if such application will actually be created in the future, 41 | there might be the necessity to consider Incremental GC. 42 | 43 | 44 | h3. Implementation of parser 45 | 46 | As we saw in Part 2, the implementation of @ruby@ parser has already utilized 47 | @yacc@'s ability to almost its limit, thus I can't think it can endure further 48 | expansions. It's all right if there's nothing planned to expand, 49 | but a big name "keyword argument" is planned next 50 | and it's sad if we could not express another demanded grammar because of the 51 | limitation of @yacc@. 52 | 53 | 54 | h3. Reuse of parser 55 | 56 | Ruby's parser is very complex. In particular, dealing with around @lex_state@ 57 | seriously is very hard. Due to this, embedding a Ruby program or creating a 58 | program to deal with a Ruby program itself is quite difficult. 59 | 60 | For example, I'm developing a tool named @racc@, 61 | which is prefixed with R because it is a Ruby-version @yacc@. 62 | With @racc@, the syntax of grammar files are almost the same as @yacc@ 63 | but we can write actions in Ruby. 64 | To do so, it could not determine the end of an action without parsing Ruby code 65 | properly, but "properly" is very difficult. Since there's no other choice, 66 | currently I've compromised at the level that it can parse "almost all". 67 | 68 | As another example which requires analyzing Ruby program, 69 | I can enumerate some tools like @indent@ and @lint@, 70 | but creating such tool also requires a lot efforts. 71 | It would be desperate if it is something complex like a refactoring tool. 72 | 73 | Then, what can we do? If we can't recreate the same thing, 74 | what if @ruby@'s original parser can be used as a component? 75 | In other words, making the parser itself a library. 76 | This is a feature we want by all means. 77 | 78 | However, what becomes problem here is, as long as @yacc@ is used, 79 | we cannot make parser reentrant. 80 | It means, say, we cannot call @yyparse()@ recursively, 81 | and we cannot call it from multiple threads. 82 | Therefore, it should be implemented in the way of not returning control to Ruby 83 | while parsing. 84 | 85 | 86 | 87 | h3. Hiding Code 88 | 89 | With current @ruby@, it does not work without the source code of the program to 90 | run. Thus, people who don't want others to read their source code might have 91 | trouble. 92 | 93 | 94 | h3. Interpretor Object 95 | 96 | Currently each process cannot have multiple @ruby@ interpretors, 97 | this was discussed in Chapter 13. 98 | If having multiple interpretors is practically possible, it seems better, 99 | but is it possible to implement such thing? 100 | 101 | 102 | h3. The structure of evaluator 103 | 104 | Current @eval.c@ is, above all, too complex. 105 | Embedding Ruby's stack frames to machine stack could occasionally become the 106 | source of trouble, using @setjmp() longjmp()@ aggressively makes it less easy to 107 | understand and slows down its speed. 108 | Particularly with RISC machine, which has many registers, using @setjmp()@ 109 | aggressively can easily cause slowing down because @setjmp()@ set aside all 110 | things in registers. 111 | 112 | 113 | h3. The performance of evaluator 114 | 115 | @ruby@ is already enough fast for ordinary use. 116 | But aside from it, regarding a language processor, 117 | definitely the faster is the better. 118 | To achieve better performance, in other words to optimize, 119 | what can we do? 120 | In such case, the first thing we have to do is profiling. 121 | So I profiled. 122 | 123 |
124 |   %   cumulative   self              self     total
125 |  time   seconds   seconds    calls  ms/call  ms/call  name
126 |  20.25      1.64     1.64  2638359     0.00     0.00  rb_eval
127 |  12.47      2.65     1.01  1113947     0.00     0.00  ruby_re_match
128 |   8.89      3.37     0.72  5519249     0.00     0.00  rb_call0
129 |   6.54      3.90     0.53  2156387     0.00     0.00  st_lookup
130 |   6.30      4.41     0.51  1599096     0.00     0.00  rb_yield_0
131 |   5.43      4.85     0.44  5519249     0.00     0.00  rb_call
132 |   5.19      5.27     0.42   388066     0.00     0.00  st_foreach
133 |   3.46      5.55     0.28  8605866     0.00     0.00  rb_gc_mark
134 |   2.22      5.73     0.18  3819588     0.00     0.00  call_cfunc
135 | 
136 | 137 | This is a profile when running some application but 138 | this is approximately the profile of a general Ruby program. 139 | @rb_eval()@ appeared in the overwhelming percentage being at the top, 140 | after that, in addition to functions of GC, evaluator core, 141 | functions that are specific to the program are mixed. 142 | For example, in the case of this application, 143 | it takes a lot of time for regular expression match (@ruby_re_match@). 144 | 145 | However, even if we understood this, the question is how to improve it. 146 | To think simply, it can be archived by making @rb_eval()@ faster. 147 | That said, but as for @ruby@ core, there are almost not any room which can be 148 | easily optimized. For instance, apparently "tail recursive -> @goto@ conversion" 149 | used in the place of @NODE_IF@ and others has already applied almost all 150 | possible places it can be applied. 151 | In other words, without changing the way of thinking fundamentally, 152 | there's no room to improve. 153 | 154 | 155 | h3. The implementation of thread 156 | 157 | This was also discussed in Chapter 19. There are really a lot of issues about 158 | the implementation of the current ruby's thread. Particularly, it cannot mix 159 | with native threads so badly. The two great advantages of @ruby@'s thread, 160 | (1) high portability (2) the same behavior everywhere, 161 | are definitely incomparable, but probably that implementation is something we 162 | cannot continue to use eternally, isn't it? 163 | 164 | 165 | 166 | 167 | h2. `ruby` 2 168 | 169 | Subsequently, on the other hand, I'll introduce the trend of the original `ruby`, 170 | how it is trying to counter these issues. 171 | 172 | 173 | h3. Rite 174 | 175 | At the present time, ruby's edge is 1.6.7 as the stable version and 1.7.3 as the 176 | development version, but perhaps the next stable version 1.8 will come out in 177 | the near future. Then at that point, the next development version 1.9.0 will 178 | start at the same time. And after that, this is a little irregular but 1.9.1 179 | will be the next stable version. 180 | 181 | |_. stable |_. development |_. when to start | 182 | | 1.6.x | 1.7.x | 1.6.0 was released on 2000-09-19 | 183 | | 1.8.x | 1.9.x | probably it will come out within 6 months | 184 | | 1.9.1~ | 2.0.0 | maybe about 2 years later | 185 | 186 | 187 | And the next-to-next generational development version is `ruby` 2, whose code 188 | name is Rite. Apparently this name indicates a respect for the inadequacy that 189 | Japanese cannot distinguish the sounds of L and R. 190 | 191 | What will be changed in 2.0 is, in short, almost all the entire core. 192 | Thread, evaluator, parser, all of them will be changed. 193 | However, nothing has been written as a code yet, so things written here is 194 | entirely just a "plan". If you expect so much, it's possible it will turn out 195 | disappointments. Therefore, for now, let's just expect slightly. 196 | 197 | 198 | h3. The language to write 199 | 200 | Firstly, the language to use. Definitely it will be C. Mr. Matsumoto said to 201 | `ruby-talk`, which is the English mailing list for Ruby, 202 | 203 |
204 | I hate C++. 205 |
206 | 207 | So, C++ is most unlikely. Even if all the parts will be recreated, 208 | it is reasonable that the object system will remain almost the same, 209 | so not to increase extra efforts around this is necessary. 210 | However, chances are good that it will be ANSI C next time. 211 | 212 | 213 | h3. GC 214 | 215 | Regarding the implementation of GC, 216 | the good start point would be 217 | `Boehm GC`\footnote{Boehm GC `http://www.hpl.hp.com/personal/Hans_Boehm/gc`}. 218 | Bohem GC is a conservative and incremental and generational GC, 219 | furthermore, it can mark all stack spaces of all threads even while native 220 | threads are running. It's really an impressive GC. 221 | Even if it is introduced once, it's hard to tell whether it will be used 222 | perpetually, but anyway it will proceed for the direction to which we can expect 223 | somewhat improvement on speed. 224 | 225 | 226 | h3. Parser 227 | 228 | Regarding the specification, it's very likely that the nested method calls 229 | without parentheses will be forbidden. As we've seen, `command_call` has a great 230 | influence on all over the grammar. If this is simplified, both the parser and 231 | the scanner will also be simplified a lot. 232 | However, the ability to omit parentheses itself will never be disabled. 233 | 234 | And regarding its implementation, whether we continue to use `yacc` is still 235 | under discussion. If we won't use, it would mean hand-writing, but is it 236 | possible to implement such complex thing by hand? Such anxiety might left. 237 | Whichever way we choose, the path must be thorny. 238 | 239 | 240 | h3. Evaluator 241 | 242 | The evaluator will be completely recreated. 243 | Its aims are mainly to improve speed and to simplify the implementation. 244 | There are two main viewpoints: 245 | 246 | 247 | * remove recursive calls like `rb_eval()` 248 | * switch to a bytecode interpretor 249 | 250 | First, removing recursive calls of `rb_eval()`. The way to remove is, 251 | maybe the most intuitive explanation is that it's like the "tail recursive -> 252 | `goto` conversion". Inside a single `rb_eval()`, circling around by using 253 | `goto`. That decreases the number of function calls and removes the necessity of 254 | `setjmp()` that is used for `return` or `break`. 255 | However, when a function defined in C is called, calling a function is 256 | inevitable, and at that point `setjmp()` will still be required. 257 | 258 | 259 | Bytecode is, in short, something like a program written in machine language. 260 | It became famous because of the virtual machine of Smalltalk90, 261 | it is called bytecode because each instruction is one-byte. 262 | For those who are usually working at more abstract level, byte would seem 263 | so natural basis in size to deal with, 264 | but in many cases each instruction consists of bits in machine languages. 265 | For example, in Alpha, among a 32-bit instruction code, the beginning 6-bit 266 | represents the instruction type. 267 | 268 | 269 | The advantage of bytecode interpretors is mainly for speed. There are two 270 | reasons: Firstly, unlike syntax trees, there's no need to traverse pointers. 271 | Secondly, it's easy to do peephole optimization. 272 | 273 | 274 | And in the case when bytecode is saved and read in later, 275 | because there's no need to parse, we can naturally expect better performance. 276 | However, parsing is a procedure which is done only once at the beginning of a 277 | program and even currently it does not take so much time. Therefore, its 278 | influence will not be so much. 279 | 280 | 281 | If you'd like to know about how the bytecode evaluator could be, 282 | `regex.c` is worth to look at. 283 | For another example, Python is a bytecode interpretor. 284 | 285 | 286 | 287 | 288 | h3. Thread 289 | 290 | Regarding thread, the thing is native thread support. 291 | The environment around thread has been significantly improved, 292 | comparing with the situation in 1994, the year of Ruby's birth. 293 | So it might be judged that 294 | we can get along with native thread now. 295 | 296 | 297 | Using native thread means being preemptive also at C level, 298 | thus the interpretor itself must be multi-thread safe, 299 | but it seems this point is going to be solved by using a global lock 300 | for the time being. 301 | 302 | 303 | Additionally, that somewhat arcane "continuation", it seems likely to be removed. 304 | `ruby`'s continuation highly depends on the implementation of thread, 305 | so naturally it will disappear if thread is switched to native thread. 306 | The existence of that feature is because "it can be implemented" 307 | and it is rarely actually used. Therefore there might be no problem. 308 | 309 | 310 | 311 | h3. M17N 312 | 313 | In addition, I'd like to mention a few things about class libraries. 314 | This is about multi-lingualization (M17N for short). 315 | What it means exactly in the context of programming is 316 | being able to deal with multiple character encodings. 317 | 318 | 319 | `ruby` with Multi-lingualization support has already implemented and you can 320 | obtain it from the `ruby_m17m` branch of the CVS repository. 321 | It is not absorbed yet because it is judged that its specification is immature. 322 | If good interfaces is designed, 323 | it will be absorbed at some point in the middle of 1.9. 324 | 325 | 326 | 327 | 328 | h3. IO 329 | 330 | 331 | The `IO` class in current Ruby is a simple wrapper of `stdio`, 332 | but in this approach, 333 | 334 | * there are too many but slight differences between various platforms. 335 | * we'd like to have finer control on buffers. 336 | 337 | these two points cause complaints. 338 | Therefore, it seems Rite will have its own `stdio`. 339 | 340 | 341 | 342 | 343 | 344 | 345 | h2. Ruby Hacking Guide 346 | 347 | 348 | So far, we've always acted as observers who look at `ruby` from outside. 349 | But, of course, `ruby` is not a product which displayed in in a showcase. 350 | It means we can influence it if we take an action for it. 351 | In the last section of this book, 352 | I'll introduce the suggestions and activities for `ruby` from community, 353 | as a farewell gift for Ruby Hackers both at present and in the future. 354 | 355 | 356 | h3. Generational GC 357 | 358 | First, as also mentioned in Chapter 5, 359 | the generational GC made by Mr. Kiyama Masato. 360 | As described before, with the current patch, 361 | 362 | * it is less fast than expected. 363 | * it needs to be updated to fit the edge `ruby` 364 | 365 | these points are problems, but here I'd like to highly value it because, 366 | more than anything else, it was the first large non-official patch. 367 | 368 | 369 | 370 | 371 | h3. Oniguruma 372 | 373 | The regular expression engine used by current Ruby is a remodeled version of GNU 374 | regex. That GNU regex was in the first place written for Emacs. And then it was 375 | remodeled so that it can support multi-byte characters. And then Mr. Matsumoto 376 | remodeled so that it is compatible with Perl. 377 | As we can easily imagine from this history, 378 | its construction is really intricate and spooky. 379 | Furthermore, due to the LPGL license of this GNU regex, 380 | the license of `ruby` is very complicated, 381 | so replacing this engine has been an issue from a long time ago. 382 | 383 | What suddenly emerged here is the regular expression engine "Oniguruma" by 384 | Mr. K. Kosako. I heard this is written really well, it is likely being 385 | absorbed as soon as possible. 386 | 387 | You can obtain Oniguruma from the `ruby`'s CVS repository in the following way. 388 | 389 |
390 | % cvs -d :pserver:anonymous@cvs.ruby-lang.org:/src co oniguruma
391 | 
392 | 393 | 394 | 395 | h3. ripper 396 | 397 | Next, ripper is my product. It is an extension library made by remodeling 398 | `parse.y`. It is not a change applied to the `ruby`'s main body, but I 399 | introduced it here as one possible direction to make the parser a component. 400 | 401 | It is implemented with kind of streaming interface and 402 | it can pick up things such as token scan or parser's reduction as events. 403 | It is put in the attached CD-ROM 404 | \footnote{ripper:`archives/ripper-0.0.5.tar.gz` of the attached CD-ROM}, 405 | so I'd like you to give it a try. 406 | Note that the supported grammar is a little different from the current one 407 | because this version is based on `ruby` 1.7 almost half-year ago. 408 | 409 | I created this just because "I happened to come up with this idea", 410 | if this is accounted, I think it is constructed well. 411 | It took only three days or so to implement, really just a piece of cake. 412 | 413 | 414 | h3. A parser alternative 415 | 416 | This product has not yet appeared in a clear form, 417 | there's a person who write a Ruby parser in C++ which can be used totally 418 | independent of `ruby`. (`[ruby-talk:50497]`). 419 | 420 | 421 | h3. JRuby 422 | 423 | More aggressively, there's an attempt to rewrite entire the interpretor. 424 | For example, a Ruby written in Java, 425 | Ruby\footnote{JRuby `http://jruby.sourceforge.net`}, 426 | has appeared. 427 | It seems it is being implemented by a large group of people, 428 | Mr. Jan Arne Petersen and many others. 429 | 430 | 431 | I tried it a little and as my reviews, 432 | 433 | * the parser is written really well. It does precisely handle even finer 434 | behaviors such as spaces or here document. 435 | * `instance_eval` seems not in effect (probably it couldn't be helped). 436 | * it has just a few built-in libraries yet (couldn't be helped as well). 437 | * we can't use extension libraries with it (naturally). 438 | * because Ruby's UNIX centric is all cut out, 439 | there's little possibility that we can run already-existing scripts without 440 | any change. 441 | * slow 442 | 443 | perhaps I could say at least these things. 444 | Regarding the last one "slow", its degree is, 445 | the execution time it takes is 20 times longer than the one of the original 446 | `ruby`. Going this far is too slow. 447 | It is not expected running fast because that Ruby VM runs on Java VM. 448 | Waiting for the machine to become 20 times faster seems only way. 449 | 450 | 451 | However, the overall impression I got was, it's way better than I imagined. 452 | 453 | 454 | 455 | h3. NETRuby 456 | 457 | If it can run with Java, it should also with C#. 458 | Therefore, a Ruby written in C# appeared, 459 | "NETRuby\footnote{NETRuby `http://sourceforge.jp/projects/netruby/`}". 460 | The author is Mr. arton. 461 | 462 | Because I don't have any .NET environment at hand, 463 | I checked only the source code, 464 | but according to the author, 465 | 466 | * more than anything, it's slow 467 | * it has a few class libraries 468 | * the compatibility of exception handling is not good 469 | 470 | such things are the problems. 471 | But `instance_eval` is in effect (astounding!). 472 | 473 | 474 | h3. How to join `ruby` development 475 | 476 | `ruby`'s developer is really Mr. Matsumoto as an individual, 477 | regarding the final decision about the direction `ruby` will take, 478 | he has the definitive authority. 479 | But at the same time, `ruby` is an open source software, 480 | anyone can join the development. 481 | Joining means, you can suggest your opinions or send patches. 482 | The below is to concretely tell you how to join. 483 | 484 | In `ruby`'s case, the mailing list is at the center of the development, 485 | so it's good to join the mailing list. 486 | The mailing lists currently at the center of the community are three: 487 | `ruby-list`, `ruby-dev`, `ruby-talk`. 488 | `ruby-list` is a mailing list for "anything relating to Ruby" in Japanese. 489 | `ruby-dev` is for the development version `ruby`, this is also in Japanese. 490 | `ruby-talk` is an English mailing list. 491 | The way to join is shown on the page "mailing lists" at Ruby's official site 492 | \footnote{Ruby's official site: `http://www.ruby-lang.org/ja/`}. 493 | For these mailing lists, read-only people are also welcome, 494 | so I recommend just joining first and watching discussions 495 | to grasp how it is. 496 | 497 | Though Ruby's activity started in Japan, 498 | recently sometimes it is said "the main authority now belongs to `ruby-talk`". 499 | But the center of the development is still `ruby-dev`. 500 | Because people who has the commit right to `ruby` (e.g. core members) are mostly 501 | Japanese, the difficulty and reluctance of using English 502 | naturally lead them to `ruby-dev`. 503 | If there will be more core members who prefer to use English, 504 | the situation could be changed, 505 | but meanwhile the core of `ruby`'s development might remain `ruby-dev`. 506 | 507 | However, it's bad if people who cannot speak Japanese cannot join the 508 | development, so currently the summary of `ruby-dev` is translated once a week 509 | and posted to `ruby-talk`. 510 | I also help that summarising, but only three people do it in turn now, 511 | so the situation is really harsh. 512 | The members to help summarize is always in demand. 513 | If you think you're the person who can help, 514 | I'd like you to state it at `ruby-list`. 515 | 516 | And as the last note, 517 | only its source code is not enough for a software. 518 | It's necessary to prepare various documents and maintain web sites. 519 | And people who take care of these kind of things are always in short. 520 | There's also a mailing list for the document-related activities, 521 | but as the first step you just have to propose "I'd like to do something" to `ruby-list`. 522 | I'll answer it as much as possible, 523 | and other people would respond to it, too. 524 | 525 | 526 | h3. Finale 527 | 528 | The long journey of this book is going to end now. 529 | As there was the limitation of the number of pages, 530 | explaining all of the parts comprehensively was impossible, 531 | however I told everything I could tell about the `ruby`'s core. 532 | I won't add extra things any more here. 533 | If you still have things you didn't understand, 534 | I'd like you to investigate it by reading the source code by yourself as much as 535 | you want. 536 | -------------------------------------------------------------------------------- /en/index.textile: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | --- 4 | 5 | h2. Table of contents 6 | 7 | Some chapters are previews. It means they have not been fully reviewed, 8 | some diagrams may be missing and some sentences may be a little 9 | rough. But it also means they are in open review, so do not hesitate 10 | to address issues. 11 | 12 | * "Preface":preface/index.html 13 | * "Introduction":intro/index.html 14 | 15 | h3. Part 1: Objects 16 | 17 | * "Chapter 1: A Minimal Introduction to Ruby":minimum/index.html 18 | * "Chapter 2: Objects":object/index.html 19 | * "Chapter 3: Names and name tables":name/index.html 20 | * "Chapter 4: Classes and modules":class/index.html 21 | * "Chapter 5: Garbage collection":gc/index.html 22 | * "Chapter 6: Variables and constants":variable/index.html 23 | * "Chapter 7: Security":security/index.html 24 | 25 | h3. Part 2: Syntax analysis 26 | 27 | * "Chapter 8: Ruby Language Details":spec/index.html 28 | * "Chapter 9: yacc crash course":yacc/index.html 29 | * "Chapter 10: Parser":parser/index.html 30 | * "Chapter 11: Finite-state scanner":contextual/index.html 31 | * "Chapter 12: Syntax tree construction":syntree/index.html 32 | 33 | h3. Part 3: Evaluation 34 | 35 | * "Chapter 13: Structure of the evaluator":evaluator/index.html 36 | * "Chapter 14: Context":module/index.html 37 | * "Chapter 15: Methods":method/index.html 38 | * "Chapter 16: Blocks":iterator/index.html 39 | * "Chapter 17: Dynamic evaluation":anyeval/index.html 40 | 41 | h3. Part 4: Around the evaluator 42 | 43 | * "Chapter 18: Loading":load/index.html 44 | * "Chapter 19: Threads":thread/index.html 45 | 46 | * "Final chapter: Ruby's future - translation unstarted":fin/index.html 47 | 48 | h1. About this Guide 49 | 50 | This is a new effort to gather efforts to help translate 51 | "Ruby Hacking Guide":http://i.loveruby.net/ja/rhg/book/ into English. 52 | 53 | The official support site of the original book is 54 | http://i.loveruby.net/ja/rhg/ 55 | 56 | You can download the version of the source code explained and 57 | the tool used in the book 58 | from the official support site of the original book. 59 | * "ruby (1.7.3 2002-09-12) in tar.gz format":http://i.loveruby.net/ja/rhg/ar/ruby-rhg.tar.gz 60 | * "ruby (1.7.3 2002-09-12) in zip format":http://i.loveruby.net/ja/rhg/ar/ruby-rhg.zip 61 | * "Pragmatic Programmers' nodeDump 0.1.7":http://i.loveruby.net/ja/rhg/ar/nodeDump-0.1.7.tgz 62 | * "RHG-version nodedump":http://i.loveruby.net/ja/rhg/ar/nodedump-rhg.tar.gz 63 | 64 | The original translating project is hosted at RubyForge 65 | http://rubyforge.org/projects/rhg 66 | 67 | Many thanks to "RubyForge":http://rubyforge.org for hosting us and to 68 | Minero AOKI for letting us translate his work. 69 | 70 | You can get further information about this project from 71 | "the archives of rhg-discussion mailing list":http://rubyforge.org/pipermail/rhg-discussion/ 72 | 73 | 74 | h2. Help us! 75 | 76 | People who are good at Ruby, C and Japanese or English are 77 | needed. Those good at Japanese (native Japanese speakers are of course 78 | welcome) can help translate and those good at English (preferably 79 | native speakers) can help correct mistakes, and rewrite badly written 80 | parts... Knowing Ruby and C well is really a requirement because it 81 | helps avoiding many mistranslations and misinterpretations. 82 | 83 | People good at making diagrams would also be helpful because there is 84 | quite a lot to redo and translators would rather spend their time 85 | translating instead of making diagrams. 86 | 87 | There have been multiple efforts to translate this book, and we want to see if 88 | we can renew efforts by creating an organisation on github. Interested parties 89 | can join in by starting a pull request on this repo 90 | https://github.com/ruby-hacking-guide/ruby-hacking-guide.github.com 91 | There is a mostly derelict mailing list at 92 | "rhg-discussion mailing list":http://rubyforge.org/mailman/listinfo/rhg-discussion 93 | feel free to introduce yourself (who you are, your skills, how much free time you 94 | have), but we think the best way to propose or send corrections/improvements 95 | is to send a pull request. If you start a feature branch along with a pull 96 | request at the start of your work then people can comment as you work. 97 | 98 | There is an old SVN repo, that is hosted at 99 | The RubyForge project page is http://rubyforge.org/projects/rhg. 100 | It has been imported here, and I will attempt to give credit and re-write the 101 | SVN/Git history when I can. 102 | 103 | As for now the contributors to that repo were: 104 | 105 | * Vincent ISAMBART 106 | * meinrad recheis 107 | * Laurent Sansonetti 108 | * Clifford Caoile 109 | * Jean-Denis Vauguet 110 | -------------------------------------------------------------------------------- /en/preface.textile: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | --- 4 | 5 | h2. Preface 6 | 7 | 8 | This book explores several themes with the following goals in mind: 9 | 10 | 11 | * To have knowledge of the structure of @ruby@ 12 | * To gain knowledge about language processing systems in general 13 | * To acquire skills in reading source code 14 | 15 | 16 | Ruby is an object-oriented language developed by Yukihiro Matsumoto. The 17 | official implementation of the Ruby language is called @ruby@. It is actively 18 | developed and maintained by the open source community. Our first goal is to 19 | understand the inner-workings of the @ruby@ implementation. This book is going 20 | to investigate @ruby@ as a whole. 21 | 22 | 23 | Secondly, by knowing about the implementation of Ruby, we will be able to know 24 | about other language processing systems. I tried to cover all topics necessary 25 | for implementing a language, such as hash table, scanner and parser, evaluation 26 | procedure, and many others. Because this book is not intended as a text book, 27 | going through entire areas and ideas without any lack was not reasonable. 28 | However the parts relating to the essential structures of a language 29 | implementation are adequately explained. 30 | And a brief summary of Ruby language itself is also included 31 | so that readers who don't know about Ruby can read this book. 32 | 33 | 34 | The main themes of this book are the first and the second point above. Though, 35 | what I want to emphasize the most is the third one: To acquire skill in reading 36 | source code. I dare to say it's a "hidden" theme. I will explain why I thought 37 | it is necessary. 38 | 39 | 40 | It is often said "To be a skilled programmer, you should read source code 41 | written by others." This is certainly true. But I haven't found a book that 42 | explains how you can actually do it. There are many books that explain OS 43 | kernels and the interior of language processing systems by showing the concrete 44 | structure or "the answer," but they don't explain the way to reach that answer. 45 | It's clearly one-sided. 46 | 47 | 48 | Can you, perhaps, naturally read code just because you know how to write a 49 | program? Is it true that reading codes is so easy that all people in this world 50 | can read code written by others with no sweat? I don't think so. 51 | Reading programs is certainly as difficult as writing programs. 52 | 53 | 54 | Therefore, this book does not simply explain @ruby@ as something already known, 55 | rather demonstrate the analyzing process as graphic as possible. 56 | Though I think I'm a reasonably seasoned Ruby programmer, 57 | I did not fully understand the inner structure of @ruby@ at the time when I 58 | started to write this book. 59 | In other words, regarding the content of @ruby@, 60 | I started from the position as close as possible to readers. 61 | This book is the summary of both the analyzing process started from that point 62 | and its result. 63 | 64 | 65 | I asked Yukihiro Matsumoto, the author of @ruby@, for supervision. But I 66 | thought the spirit of this book would be lost if each analysis was monitored by 67 | the author of the language himself. Therefore I limited his review to the final 68 | stage of writing. In this way, 69 | without loosing the sense of actually reading the source codes, 70 | I think I could also assure the correctness of the contents. 71 | 72 | 73 | To be honest, this book is not easy. In the very least, it is limited in its 74 | simplicity by the inherent complexity of its aim. However, this complexity may 75 | be what makes the book interesting to you. Do you find it interesting to be 76 | chattering around a piece of cake? Do you take to your desk to solve a puzzle 77 | that you know the answer to in a heartbeat? How about a suspense novel whose 78 | criminal you can guess halfway through? If you really want to come to new 79 | knowledge, you need to solve a problem engaging all your capacities. This is 80 | the book that lets you practice such idealism exhaustively. 81 | "It's interesting because it's difficult." I'm glad if the number of people 82 | who think so will increase because of this book. 83 | 84 | h2. Target audience 85 | 86 | Firstly, knowledge about the Ruby language isn't required. However, since the 87 | knowledge of the Ruby language is absolutely necessary to understand certain 88 | explanations of its structure, supplementary explanations of the language are 89 | inserted here and there. 90 | 91 | 92 | Knowledge about the C language is required, to some extent. I assume you can 93 | allocate some structs with @malloc()@ at runtime to create a list or a stack 94 | and you have experience of using function pointers at least a few times. 95 | 96 | 97 | Also, since the basics of object-oriented programming will not be explained so 98 | seriously, without having any experience of using at least one of 99 | object-oriented languages, you will probably have a difficult time. 100 | In this book, I tried to use many examples in Java and C++. 101 | 102 | h2. Structure of this book 103 | 104 | This book has four main parts: 105 | 106 | 107 | | Part 1: Objects | 108 | | Part 2: Syntactic analysis | 109 | | Part 3: Evaluation | 110 | | Part 4: Peripheral around the evaluator | 111 | 112 | 113 | Supplementary chapters are included at the beginning of each part when 114 | necessary. These provide a basic introduction for those who are not familiar 115 | with Ruby and the general mechanism of a language processing system. 116 | 117 | 118 | Now, we are going through the overview of the four main parts. The symbol in 119 | parentheses after the explanation indicates the difficulty gauge. They are ==(C)==, 120 | (B), (A) in order of easy to hard, (S) being the highest. 121 | 122 | h4. Part 1: Object 123 | 124 | | Chapter1 | Focuses the basics of Ruby to get ready to accomplish Part 1. ==(C)== | 125 | | Chapter2 | Gives concrete inner structure of Ruby objects. ==(C)== | 126 | | Chapter3 | States about hash table. ==(C)== | 127 | | Chapter4 | Writes about Ruby class system. You may read through this chapter quickly at first, because it tells plenty of abstract stories. (A) | 128 | | Chapter5 | Shows the garbage collector which is responsible for generating and releasing objects. The first story in low-level series. (B) | 129 | | Chapter6 | Describes the implementation of global variables, class variables, and constants. ==(C)== | 130 | | Chapter7 | Outline of the security features of Ruby. ==(C)== | 131 | 132 | h4. Part 2: Syntactic analysis 133 | 134 | | Chapter8 | Talks about almost complete specification of the Ruby language, in order to prepare for Part 2 and Part 3. ==(C)== | 135 | | Chapter9 | Introduction to @yacc@ required to read the syntax file at least. (B) | 136 | | Chapter10 | Look through the rules and physical structure of the parser. (A) | 137 | | Chapter11 | Explore around the peripherals of @lex_state@, which is the most difficult part of the parser. The most difficult part of this book. (S) | 138 | | Chapter12 | Finalization of Part 2 and connection to Part 3. ==(C)== | 139 | 140 | h4. Part 3: Evaluator 141 | 142 | | Chapter13 | Describe the basic mechanism of the evaluator. ==(C)== | 143 | | Chapter14 | Reads the evaluation stack that creates the main context of Ruby. (A) | 144 | | Chapter15 | Talks about search and initialization of methods. (B) | 145 | | Chapter16 | Defies the implementation of the iterator, the most characteristic feature of Ruby. (A) | 146 | | Chapter17 | Describe the implementation of the eval methods. (B) | 147 | 148 | h4. Part 4: Peripheral around the evaluator 149 | 150 | | Chapter18 | Run-time loading of libraries in C and Ruby. (B) | 151 | | Chapter19 | Describes the implementation of thread at the end of the core part. (A) | 152 | 153 | h2. Environment 154 | 155 | This book describes on @ruby@ 1.7.3 2002-09-12 version. It's attached on the 156 | CD-ROM. Choose any one of @ruby-rhg.tar.gz@, @ruby-rhg.lzh@, or @ruby-rhg.zip@ 157 | according to your convenience. Content is the same for all. Alternatively you 158 | can obtain from the support site (footnote{`http://i.loveruby.net/ja/rhg/`}) of 159 | this book. 160 | 161 | 162 | For the publication of this book, the following build environment was prepared 163 | for confirmation of compiling and testing the basic operation. The details of 164 | this build test are given in @doc/buildtest.html@ in the attached CD-ROM. 165 | However, it doesn't necessarily assume the probability of the execution even 166 | under the same environment listed in the table. The author doesn't guarantee 167 | in any form the execution of @ruby@. 168 | 169 | 170 | * BeOS 5 Personal Edition/i386 171 | * Debian GNU/Linux potato/i386 172 | * Debian GNU/Linux woody/i386 173 | * Debian GNU/Linux sid/i386 174 | * FreeBSD 4.4-RELEASE/Alpha (Requires the local patch for this book) 175 | * FreeBSD 4.5-RELEASE/i386 176 | * FreeBSD 4.5-RELEASE/PC98 177 | * FreeBSD 5-CURRENT/i386 178 | * HP-UX 10.20 179 | * HP-UX 11.00 (32bit mode) 180 | * HP-UX 11.11 (32bit mode) 181 | * Mac OS X 10.2 182 | * NetBSD 1.6F/i386 183 | * OpenBSD 3.1 184 | * Plamo Linux 2.0/i386 185 | * Linux for PlayStation2 Release 1.0 186 | * Redhat Linux 7.3/i386 187 | * Solaris 2.6/Sparc 188 | * Solaris 8/Sparc 189 | * UX/4800 190 | * Vine Linux 2.1.5 191 | * Vine Linux 2.5 192 | * VineSeed 193 | * Windows 98SE (Cygwin, MinGW+Cygwin, MinGW+MSYS) 194 | * Windows Me (Borland C++ Compiler 5.5, Cygwin, MinGW+Cygwin, MinGW+MSYS, Visual C++ 6) 195 | * Windows NT 4.0 (Cygwin, MinGW+Cygwin) 196 | * Windows 2000 (Borland C++ Compiler 5.5, Visual C++ 6, Visual C++.NET) 197 | * Windows XP (Visual C++.NET, MinGW+Cygwin) 198 | 199 | 200 | These numerous tests aren't of a lone effort by the author. Those test build 201 | couldn't be achieved without magnificent cooperations by the people listed 202 | below. 203 | 204 | I'd like to extend warmest thanks from my heart. 205 | 206 | 207 | | Tietew | 208 | | kjana | 209 | | nyasu | 210 | | sakazuki | 211 | | Masahiro Sato | 212 | | Kenichi Tamura | 213 | | Morikyu | 214 | | Yuya Kato | 215 | | Yasuhiro Kubo | 216 | | Kentaro Goto | 217 | | Tomoyuki Shimomura | 218 | | Masaki Sukeda | 219 | | Koji Arai | 220 | | Kazuhiro Nishiyama | 221 | | Shinya Kawaji | 222 | | Tetsuya Watanabe | 223 | | Naokuni Fujimoto | 224 | 225 | 226 | However, the author owes the responsibility for this test. Please refrain from 227 | attempting to contact these people directly. If there's any flaw in execution, 228 | please be advised to contact the author by e-mail: `aamine@loveruby.net`. 229 | 230 | h2. Web site 231 | 232 | The web site for this book is `http://i.loveruby.net/ja/rhg/`. 233 | I will add information about related programs and additional documentation, as 234 | well as errata. In addition, I'm going to publisize the first few chapters of 235 | this book at the same time of the release. I will look for a certain 236 | circumstance to publicize more chapters, and the whole contents of the book 237 | will be at this website at the end. 238 | 239 | h2. Acknowledgment 240 | 241 | First of all, I would like to thank Mr. Yukihiro Matsumoto. He is the author of 242 | Ruby, and he made it in public as an open source software. Not only he 243 | willingly approved me to publish a book about analyzing @ruby@, but also he 244 | agreed to supervise the content of it. In addition, he helped my stay in 245 | Florida with simultaneous translation. There are plenty of things beyond 246 | enumeration I have to say thanks to him. Instead of writing all the things, I 247 | give this book to him. 248 | 249 | 250 | Next, I would like to thank arton, who proposed me to publish this book. The 251 | words of arton always moves me. One of the things I'm currently struggled due 252 | to his words is that I have no reason I don't get a .NET machine. 253 | 254 | 255 | Koji Arai, the 'captain' of documentation in the Ruby society, conducted a 256 | scrutiny review as if he became the official editor of this book while I was 257 | not told so. I thank all his review. 258 | 259 | 260 | Also I'd like to mention those who gave me comments, pointed out mistakes and 261 | submitted proposals about the construction of the book throughout all my work. 262 | 263 | Tietew, 264 | Yuya, 265 | Kawaji, 266 | Gotoken, 267 | Tamura, 268 | Funaba, 269 | Morikyu, 270 | Ishizuka, 271 | Shimomura, 272 | Kubo, 273 | Sukeda, 274 | Nishiyama, 275 | Fujimoto, 276 | Yanagawa, 277 | (I'm sorry if there's any people missing), 278 | I thank all those people contributed. 279 | 280 | 281 | As a final note, I thank Otsuka , Haruta, and Kanemitsu who you for arranging 282 | everything despite my broke deadline as much as four times, and that the 283 | manuscript exceeded 200 pages than originally planned. 284 | 285 | 286 | I cannot expand the full list here to mention the name of all people 287 | contributed to this book, but I say that I couldn't successfully publish this 288 | book without such assistance. Let me take this place to express my 289 | appreciation. Thank you very much. 290 | 291 | p(right). Minero Aoki 292 | 293 | 294 | If you want to send remarks, suggestions and reports of typographcal errors, 295 | please address to "Minero Aoki <aamine@loveruby.net>":mailto:aamine@loveruby.net . 296 | 297 | 298 | "Rubyソースコード完全解説" can be reserved/ordered at ImpressDirect. 299 | "(Jump to the introduction page)":http://direct.ips.co.jp/directsys/go_x_TempChoice.cfm?sh_id=EE0040&spm_id=1&GM_ID=1721 300 | 301 | Copyright (c) 2002-2004 Minero Aoki, All rights reserved. 302 | -------------------------------------------------------------------------------- /en/security.textile: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Security 4 | --- 5 | Translated by Clifford Escobar CAOILE & ocha- 6 | 7 | h1. Chapter 7: Security 8 | 9 | h3. Fundamentals 10 | 11 | I say security but I don't mean passwords or encryption. The Ruby security 12 | feature is used for handling untrusted objects in a environment like CGI 13 | programming. 14 | 15 | For example, when you want to convert a string representing a number into a 16 | integer, you can use the `eval` method. However. `eval` is a method that "runs 17 | a string as a Ruby program." If you `eval` a string from a unknown person from 18 | the network, it is very dangerous. However for the programmer to fully 19 | differentiate between safe and unsafe things is very tiresome and cumbersome. 20 | Therefore, it is for certain that a mistake will be made. So, let us make it 21 | part of the language, was reasoning for this feature. 22 | 23 | So then, how Ruby protect us from that sort of danger? Causes of dangerous 24 | operations, for example, opening unintended files, are roughly divided into two 25 | groups: 26 | 27 | * Dangerous data 28 | * Dangerous code 29 | 30 | For the former, the code that handles these values is created by the 31 | programmers themselves, so therefore it is (relatively) safe. For the latter, 32 | the program code absolutely cannot be trusted. 33 | 34 | Because the solution is vastly different between the two causes, it is important to 35 | differentiate them by level. This are called security levels. The Ruby security 36 | level is represented by the `$SAFE` global variable. The value ranges from 37 | minimum value 0 to maximum value 4. When the variable is assigned, the level 38 | increases. Once the level is raised it can never be lowered. And for each 39 | level, the operations are limited. 40 | 41 | I will not explain level 1 or 3. 42 | Level 0 is the normal program environment and the security system is not 43 | running. Level 2 handles dangerous values. Level 4 handles dangerous code. 44 | We can skip 0 and move on to explain in detail levels 2 and 4. 45 | 46 | ((errata: Level 1 handles dangerous values. 47 | "Level 2 has no use currently" is right.)) 48 | 49 | 50 | h4. Level 1 51 | 52 | This level is for dangerous data, for example, in normal CGI 53 | applications, etc. 54 | 55 | A per-object "tainted mark" serves as the basis for the Level 1 56 | implementation. All objects read in externally are marked tainted, and 57 | any attempt to `eval` or `File.open` with a tainted object will cause an 58 | exception to be raised and the attempt will be stopped. 59 | 60 | This tainted mark is "infectious". For example, when taking a part of a 61 | tainted string, that part is also tainted. 62 | 63 | h4. Level 4 64 | 65 | This level is for dangerous programs, for example, running external 66 | (unknown) programs, etc. 67 | 68 | At level 1, operations and the data it uses are checked, but at level 69 | 4, operations themselves are restricted. For example, `exit`, file 70 | I/O, thread manipulation, redefining methods, etc. Of course, the 71 | tainted mark information is used, but basically the operations are the 72 | criteria. 73 | 74 | h4. Unit of Security 75 | 76 | `$SAFE` looks like a global variable but is in actuality a thread 77 | local variable. In other words, Ruby's security system works on units 78 | of thread. In Java and .NET, rights can be set per component (object), 79 | but Ruby does not implement that. The assumed main target was probably 80 | CGI. 81 | 82 | Therefore, if one wants to raise the security level of one part of the 83 | program, then it should be made into a different thread and have its 84 | security level raised. I haven't yet explained how to create a thread, 85 | but I will show an example here: 86 | 87 |
 88 | # Raise the security level in a different thread
 89 | p($SAFE)   # 0 is the default
 90 | Thread.fork {    # Start a different thread
 91 |     $SAFE = 4    # Raise the level
 92 |     eval(str)    # Run the dangerous program
 93 | }
 94 | p($SAFE)   # Outside of the block, the level is still 0
 95 | 
96 | 97 | h4. Reliability of `$SAFE` 98 | 99 | Even with implementing the spreading of tainted marks, or restricting 100 | operations, ultimately it is still handled manually. In other words, 101 | internal libraries and external libraries must be completely 102 | compatible and if they don't, then the partway the "tainted" operations 103 | will not spread and the security will be lost. And actually this kind 104 | of hole is often reported. For this reason, this writer does not 105 | wholly trust it. 106 | 107 | That is not to say, of course, that all Ruby programs are dangerous. 108 | Even at `$SAFE=0` it is possible to write a secure program, and even 109 | at `$SAFE=4` it is possible to write a program that fits your whim. 110 | However, one cannot put too much confidence on `$SAFE` (yet). 111 | 112 | In the first place, functionality and security do not go together. It 113 | is common sense that adding new features can make holes easier to 114 | open. Therefore it is prudent to think that `ruby` can probably be 115 | dangerous. 116 | 117 | 118 | h3. Implementation 119 | 120 | 121 | From now on, we'll start to look into its implementation. 122 | In order to wholly grasp the security system of `ruby`, 123 | we have to look at "where is being checked" rather than its mechanism. 124 | However, this time we don't have enough pages to do it, 125 | and just listing them up is not interesting. 126 | Therefore, in this chapter, I'll only describe about the 127 | mechanism used for security checks. 128 | The APIs to check are mainly these below two: 129 | 130 | 131 | * `rb_secure(n)` : If more than or equal to level n, it would raise `SecurityError`. 132 | * `SafeStringValue()` : 133 | If more than or equal to level 1 and a string is tainted, 134 | then it would raise an exception. 135 | 136 | 137 | We won't read `SafeStringValue()` here. 138 | 139 | 140 | h4. Tainted Mark 141 | 142 | 143 | The taint mark is, to be concrete, the `FL_TAINT` flag, which is set to 144 | `basic->flags`, and what is used to infect it is the `OBJ_INFECT()` macro. 145 | Here is its usage. 146 | 147 | 148 |
149 | OBJ_TAINT(obj)            /* set FL_TAINT to obj */
150 | OBJ_TAINTED(obj)          /* check if FL_TAINT is set to obj */
151 | OBJ_INFECT(dest, src)     /* infect FL_TAINT from src to dest */
152 | 
153 | 154 | 155 | Since `OBJ_TAINT()` and `OBJ_TAINTED()` can be assumed not important, 156 | let's briefly look over only `OBJ_INFECT()`. 157 | 158 | 159 |

▼ `OBJ_INFECT`

160 |
161 |  441  #define OBJ_INFECT(x,s) do {                             \
162 |           if (FL_ABLE(x) && FL_ABLE(s))                        \
163 |               RBASIC(x)->flags |= RBASIC(s)->flags & FL_TAINT; \
164 |       } while (0)
165 | 
166 | (ruby.h)
167 | 
168 | 169 | 170 | `FL_ABLE()` checks if the argument `VALUE` is a pointer or not. 171 | If the both objects are pointers (it means each of them has its `flags` member), 172 | it would propagate the flag. 173 | 174 | 175 | 176 | 177 | h4. $SAFE 178 | 179 | 180 |

▼ `ruby_safe_level`

181 |
182 |  124  int ruby_safe_level = 0;
183 | 
184 | 7401  static void
185 | 7402  safe_setter(val)
186 | 7403      VALUE val;
187 | 7404  {
188 | 7405      int level = NUM2INT(val);
189 | 7406
190 | 7407      if (level < ruby_safe_level) {
191 | 7408          rb_raise(rb_eSecurityError, "tried to downgrade safe level from %d to %d",
192 | 7409                   ruby_safe_level, level);
193 | 7410      }
194 | 7411      ruby_safe_level = level;
195 | 7412      curr_thread->safe = level;
196 | 7413  }
197 | 
198 | (eval.c)
199 | 
200 | 201 | 202 | The substance of `$SAFE` is `ruby_safe_level` in `eval.c`. 203 | As I previously wrote, `$SAFE` is local to each thread, 204 | It needs to be written in `eval.c` where the implementation of threads is located. 205 | In other words, it is in `eval.c` only because of the restrictions of C, 206 | but it can essentially be located in another place. 207 | 208 | 209 | `safe_setter()` is the `setter` of the `$SAFE` global variable. 210 | It means, because this function is the only way to access it from Ruby level, 211 | the security level cannot be lowered. 212 | 213 | 214 | However, as you can see, from C level, 215 | because `static` is not attached to `ruby_safe_level`, 216 | you can ignore the interface and modify the security level. 217 | 218 | 219 | 220 | 221 | 222 | h4. `rb_secure()` 223 | 224 | 225 |

▼ `rb_secure()`

226 |
227 |  136  void
228 |  137  rb_secure(level)
229 |  138      int level;
230 |  139  {
231 |  140      if (level <= ruby_safe_level) {
232 |  141          rb_raise(rb_eSecurityError, "Insecure operation `%s' at level %d",
233 |  142                   rb_id2name(ruby_frame->last_func), ruby_safe_level);
234 |  143      }
235 |  144  }
236 | 
237 | (eval.c)
238 | 
239 | 240 | 241 | If the current safe level is more than or equal to `level`, 242 | this would raise `SecurityError`. It's simple. 243 | -------------------------------------------------------------------------------- /feed.xml: -------------------------------------------------------------------------------- 1 | --- 2 | layout: none 3 | --- 4 | 5 | 6 | 7 | {{ site.title | xml_escape }} 8 | {{ site.description | xml_escape }} 9 | {{ site.url }}{{ site.baseurl }}/ 10 | 11 | {{ site.time | date_to_rfc822 }} 12 | {{ site.time | date_to_rfc822 }} 13 | Jekyll v{{ jekyll.version }} 14 | {% for post in site.posts limit:10 %} 15 | 16 | {{ post.title | xml_escape }} 17 | {{ post.content | xml_escape }} 18 | {{ post.date | date_to_rfc822 }} 19 | {{ post.url | prepend: site.baseurl | prepend: site.url }} 20 | {{ post.url | prepend: site.baseurl | prepend: site.url }} 21 | {% for tag in post.tags %} 22 | {{ tag | xml_escape }} 23 | {% endfor %} 24 | {% for cat in post.categories %} 25 | {{ cat | xml_escape }} 26 | {% endfor %} 27 | 28 | {% endfor %} 29 | 30 | 31 | -------------------------------------------------------------------------------- /images/book_cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/book_cover.jpg -------------------------------------------------------------------------------- /images/ch_abstract_build.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_abstract_build.jpg -------------------------------------------------------------------------------- /images/ch_abstract_build.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_abstract_build.png -------------------------------------------------------------------------------- /images/ch_abstract_ci.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_abstract_ci.jpg -------------------------------------------------------------------------------- /images/ch_abstract_ci.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_abstract_ci.png -------------------------------------------------------------------------------- /images/ch_abstract_repo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_abstract_repo.jpg -------------------------------------------------------------------------------- /images/ch_abstract_repo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_abstract_repo.png -------------------------------------------------------------------------------- /images/ch_abstract_syntree.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_abstract_syntree.jpg -------------------------------------------------------------------------------- /images/ch_abstract_syntree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_abstract_syntree.png -------------------------------------------------------------------------------- /images/ch_anyeval_dynavars.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_anyeval_dynavars.jpg -------------------------------------------------------------------------------- /images/ch_anyeval_speceval.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_anyeval_speceval.jpg -------------------------------------------------------------------------------- /images/ch_class_addsclass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_class_addsclass.png -------------------------------------------------------------------------------- /images/ch_class_boot1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_class_boot1.png -------------------------------------------------------------------------------- /images/ch_class_include.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_class_include.png -------------------------------------------------------------------------------- /images/ch_class_infloop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_class_infloop.png -------------------------------------------------------------------------------- /images/ch_class_metaclass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_class_metaclass.png -------------------------------------------------------------------------------- /images/ch_class_metaobj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_class_metaobj.png -------------------------------------------------------------------------------- /images/ch_class_metatree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_class_metatree.png -------------------------------------------------------------------------------- /images/ch_class_mmm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_class_mmm.png -------------------------------------------------------------------------------- /images/ch_class_multi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_class_multi.png -------------------------------------------------------------------------------- /images/ch_class_real.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_class_real.png -------------------------------------------------------------------------------- /images/ch_class_reqlink.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_class_reqlink.png -------------------------------------------------------------------------------- /images/ch_class_simulate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_class_simulate.png -------------------------------------------------------------------------------- /images/ch_class_symbolic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_class_symbolic.png -------------------------------------------------------------------------------- /images/ch_contextual_condp.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_contextual_condp.jpg -------------------------------------------------------------------------------- /images/ch_contextual_transittobeg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_contextual_transittobeg.jpg -------------------------------------------------------------------------------- /images/ch_contextual_trees.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_contextual_trees.jpg -------------------------------------------------------------------------------- /images/ch_evaluator_jumptag.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_evaluator_jumptag.jpg -------------------------------------------------------------------------------- /images/ch_evaluator_rbeval.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_evaluator_rbeval.jpg -------------------------------------------------------------------------------- /images/ch_evaluator_setjmp.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_evaluator_setjmp.jpg -------------------------------------------------------------------------------- /images/ch_evaluator_tagstack.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_evaluator_tagstack.jpg -------------------------------------------------------------------------------- /images/ch_evaluator_usetag.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_evaluator_usetag.jpg -------------------------------------------------------------------------------- /images/ch_evaluator_whilejmp.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_evaluator_whilejmp.jpg -------------------------------------------------------------------------------- /images/ch_gc_calloca.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_gc_calloca.jpg -------------------------------------------------------------------------------- /images/ch_gc_calloca.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_gc_calloca.png -------------------------------------------------------------------------------- /images/ch_gc_cycle.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_gc_cycle.jpg -------------------------------------------------------------------------------- /images/ch_gc_cycle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_gc_cycle.png -------------------------------------------------------------------------------- /images/ch_gc_gcimage.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_gc_gcimage.jpg -------------------------------------------------------------------------------- /images/ch_gc_gcimage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_gc_gcimage.png -------------------------------------------------------------------------------- /images/ch_gc_gengc.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_gc_gengc.jpg -------------------------------------------------------------------------------- /images/ch_gc_gengc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_gc_gengc.png -------------------------------------------------------------------------------- /images/ch_gc_heapitems.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_gc_heapitems.jpg -------------------------------------------------------------------------------- /images/ch_gc_heapitems.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_gc_heapitems.png -------------------------------------------------------------------------------- /images/ch_gc_heaps.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_gc_heaps.jpg -------------------------------------------------------------------------------- /images/ch_gc_heaps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_gc_heaps.png -------------------------------------------------------------------------------- /images/ch_gc_macstack.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_gc_macstack.jpg -------------------------------------------------------------------------------- /images/ch_gc_macstack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_gc_macstack.png -------------------------------------------------------------------------------- /images/ch_gc_mostcopy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_gc_mostcopy.jpg -------------------------------------------------------------------------------- /images/ch_gc_mostcopy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_gc_mostcopy.png -------------------------------------------------------------------------------- /images/ch_gc_objects.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_gc_objects.jpg -------------------------------------------------------------------------------- /images/ch_gc_objects.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_gc_objects.png -------------------------------------------------------------------------------- /images/ch_gc_objid.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_gc_objid.jpg -------------------------------------------------------------------------------- /images/ch_gc_objid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_gc_objid.png -------------------------------------------------------------------------------- /images/ch_gc_refcnt.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_gc_refcnt.jpg -------------------------------------------------------------------------------- /images/ch_gc_refcnt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_gc_refcnt.png -------------------------------------------------------------------------------- /images/ch_gc_stop2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_gc_stop2.jpg -------------------------------------------------------------------------------- /images/ch_gc_stop2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_gc_stop2.png -------------------------------------------------------------------------------- /images/ch_gc_stop3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_gc_stop3.jpg -------------------------------------------------------------------------------- /images/ch_gc_stop3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_gc_stop3.png -------------------------------------------------------------------------------- /images/ch_iterator_dst.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_iterator_dst.jpg -------------------------------------------------------------------------------- /images/ch_iterator_dynavarseval.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_iterator_dynavarseval.jpg -------------------------------------------------------------------------------- /images/ch_iterator_flaginfect.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_iterator_flaginfect.jpg -------------------------------------------------------------------------------- /images/ch_iterator_framepush.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_iterator_framepush.jpg -------------------------------------------------------------------------------- /images/ch_iterator_insert.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_iterator_insert.jpg -------------------------------------------------------------------------------- /images/ch_iterator_itertrans.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_iterator_itertrans.jpg -------------------------------------------------------------------------------- /images/ch_iterator_stacks.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_iterator_stacks.jpg -------------------------------------------------------------------------------- /images/ch_load_link.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_load_link.jpg -------------------------------------------------------------------------------- /images/ch_load_loadwait.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_load_loadwait.jpg -------------------------------------------------------------------------------- /images/ch_method_anchor.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_method_anchor.jpg -------------------------------------------------------------------------------- /images/ch_method_mhash.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_method_mhash.jpg -------------------------------------------------------------------------------- /images/ch_method_msearch.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_method_msearch.jpg -------------------------------------------------------------------------------- /images/ch_minimum_Kernel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_minimum_Kernel.jpg -------------------------------------------------------------------------------- /images/ch_minimum_Kernel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_minimum_Kernel.png -------------------------------------------------------------------------------- /images/ch_minimum_ccc.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_minimum_ccc.jpg -------------------------------------------------------------------------------- /images/ch_minimum_ccc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_minimum_ccc.png -------------------------------------------------------------------------------- /images/ch_minimum_classclass.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_minimum_classclass.jpg -------------------------------------------------------------------------------- /images/ch_minimum_classclass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_minimum_classclass.png -------------------------------------------------------------------------------- /images/ch_minimum_classtree.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_minimum_classtree.jpg -------------------------------------------------------------------------------- /images/ch_minimum_classtree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_minimum_classtree.png -------------------------------------------------------------------------------- /images/ch_minimum_const.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_minimum_const.jpg -------------------------------------------------------------------------------- /images/ch_minimum_const.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_minimum_const.png -------------------------------------------------------------------------------- /images/ch_minimum_constref.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_minimum_constref.jpg -------------------------------------------------------------------------------- /images/ch_minimum_constref.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_minimum_constref.png -------------------------------------------------------------------------------- /images/ch_minimum_metaobjects.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_minimum_metaobjects.jpg -------------------------------------------------------------------------------- /images/ch_minimum_metaobjects.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_minimum_metaobjects.png -------------------------------------------------------------------------------- /images/ch_minimum_modclass.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_minimum_modclass.jpg -------------------------------------------------------------------------------- /images/ch_minimum_modclass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_minimum_modclass.png -------------------------------------------------------------------------------- /images/ch_minimum_modclass2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_minimum_modclass2.jpg -------------------------------------------------------------------------------- /images/ch_minimum_modclass2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_minimum_modclass2.png -------------------------------------------------------------------------------- /images/ch_minimum_modinherit.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_minimum_modinherit.jpg -------------------------------------------------------------------------------- /images/ch_minimum_modinherit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_minimum_modinherit.png -------------------------------------------------------------------------------- /images/ch_minimum_multiinherit.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_minimum_multiinherit.jpg -------------------------------------------------------------------------------- /images/ch_minimum_multiinherit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_minimum_multiinherit.png -------------------------------------------------------------------------------- /images/ch_minimum_objimage.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_minimum_objimage.jpg -------------------------------------------------------------------------------- /images/ch_minimum_objimage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_minimum_objimage.png -------------------------------------------------------------------------------- /images/ch_minimum_reference.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_minimum_reference.jpg -------------------------------------------------------------------------------- /images/ch_minimum_reference.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_minimum_reference.png -------------------------------------------------------------------------------- /images/ch_minimum_supersub.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_minimum_supersub.jpg -------------------------------------------------------------------------------- /images/ch_minimum_supersub.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_minimum_supersub.png -------------------------------------------------------------------------------- /images/ch_module_cbase.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_module_cbase.jpg -------------------------------------------------------------------------------- /images/ch_module_crefstack.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_module_crefstack.jpg -------------------------------------------------------------------------------- /images/ch_module_framestack.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_module_framestack.jpg -------------------------------------------------------------------------------- /images/ch_module_localvars.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_module_localvars.jpg -------------------------------------------------------------------------------- /images/ch_module_massign.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_module_massign.jpg -------------------------------------------------------------------------------- /images/ch_module_scopestack.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_module_scopestack.jpg -------------------------------------------------------------------------------- /images/ch_module_stack.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_module_stack.jpg -------------------------------------------------------------------------------- /images/ch_module_tmpprotecttmp.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_module_tmpprotecttmp.jpg -------------------------------------------------------------------------------- /images/ch_module_vars.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_module_vars.jpg -------------------------------------------------------------------------------- /images/ch_name_array.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_name_array.png -------------------------------------------------------------------------------- /images/ch_name_aset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_name_aset.png -------------------------------------------------------------------------------- /images/ch_name_chain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_name_chain.png -------------------------------------------------------------------------------- /images/ch_name_nexti.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_name_nexti.png -------------------------------------------------------------------------------- /images/ch_name_sttable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_name_sttable.png -------------------------------------------------------------------------------- /images/ch_object_class.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_object_class.png -------------------------------------------------------------------------------- /images/ch_object_classtree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_object_classtree.png -------------------------------------------------------------------------------- /images/ch_object_flags.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_object_flags.png -------------------------------------------------------------------------------- /images/ch_object_givtable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_object_givtable.png -------------------------------------------------------------------------------- /images/ch_object_rbasic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_object_rbasic.png -------------------------------------------------------------------------------- /images/ch_object_rdata.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_object_rdata.png -------------------------------------------------------------------------------- /images/ch_object_string.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_object_string.png -------------------------------------------------------------------------------- /images/ch_object_value.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_object_value.png -------------------------------------------------------------------------------- /images/ch_parser_ablist.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_parser_ablist.jpg -------------------------------------------------------------------------------- /images/ch_parser_alist.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_parser_alist.jpg -------------------------------------------------------------------------------- /images/ch_parser_build.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_parser_build.jpg -------------------------------------------------------------------------------- /images/ch_parser_exprloop.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_parser_exprloop.jpg -------------------------------------------------------------------------------- /images/ch_parser_heredoc.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_parser_heredoc.jpg -------------------------------------------------------------------------------- /images/ch_parser_ibuffer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_parser_ibuffer.jpg -------------------------------------------------------------------------------- /images/ch_parser_interf.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_parser_interf.jpg -------------------------------------------------------------------------------- /images/ch_parser_lexparams.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_parser_lexparams.jpg -------------------------------------------------------------------------------- /images/ch_parser_progloop.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_parser_progloop.jpg -------------------------------------------------------------------------------- /images/ch_parser_scanner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_parser_scanner.jpg -------------------------------------------------------------------------------- /images/ch_parser_tbuffer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_parser_tbuffer.jpg -------------------------------------------------------------------------------- /images/ch_syntree_append.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_syntree_append.jpg -------------------------------------------------------------------------------- /images/ch_syntree_blocklist.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_syntree_blocklist.jpg -------------------------------------------------------------------------------- /images/ch_syntree_callgraph.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_syntree_callgraph.jpg -------------------------------------------------------------------------------- /images/ch_syntree_dynavars.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_syntree_dynavars.jpg -------------------------------------------------------------------------------- /images/ch_syntree_flagUsage.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_syntree_flagUsage.jpg -------------------------------------------------------------------------------- /images/ch_syntree_flags.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_syntree_flags.jpg -------------------------------------------------------------------------------- /images/ch_syntree_lmask.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_syntree_lmask.jpg -------------------------------------------------------------------------------- /images/ch_syntree_localtbl.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_syntree_localtbl.jpg -------------------------------------------------------------------------------- /images/ch_syntree_localvars.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_syntree_localvars.jpg -------------------------------------------------------------------------------- /images/ch_syntree_lvtbltbl.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_syntree_lvtbltbl.jpg -------------------------------------------------------------------------------- /images/ch_syntree_stree.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_syntree_stree.jpg -------------------------------------------------------------------------------- /images/ch_syntree_tbl.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_syntree_tbl.jpg -------------------------------------------------------------------------------- /images/ch_thread_fdset.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_thread_fdset.jpg -------------------------------------------------------------------------------- /images/ch_thread_setjmploop.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_thread_setjmploop.jpg -------------------------------------------------------------------------------- /images/ch_thread_thread.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_thread_thread.jpg -------------------------------------------------------------------------------- /images/ch_thread_twodirection.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_thread_twodirection.jpg -------------------------------------------------------------------------------- /images/ch_variable_gaccess.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_variable_gaccess.png -------------------------------------------------------------------------------- /images/ch_variable_gvar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_variable_gvar.png -------------------------------------------------------------------------------- /images/ch_yacc_build.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_yacc_build.jpg -------------------------------------------------------------------------------- /images/ch_yacc_yaccvars.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/ch_yacc_yaccvars.jpg -------------------------------------------------------------------------------- /images/somerights20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/somerights20.png -------------------------------------------------------------------------------- /images/visual_language.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajian/rhg-zh/fae977a399eba793fecaebd322b7426718ffc889/images/visual_language.png -------------------------------------------------------------------------------- /index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | --- 4 | 5 | [Ruby Hacking Guide](http://i.loveruby.net/ja/rhg/book) (简称RHG,原版为日文),是青木峰郎(Minero AOKI)创作的一本剖析ruby实现的书。 6 | 7 | Ruby Hacking Guide中文版 就是将[Ruby Hacking Guide](http://ruby-hacking-guide.github.io)这本书翻译成中文,让更多对Ruby有兴趣的人了解Ruby语言的实现。 8 | 9 | ### **目 录** 10 | ---- 11 | - [前言](/rhg-zh/zh/0-0-preface) 12 | - [导读](/rhg-zh/zh/0-1-intro) 13 | 14 | ## **第一部分:对象** 15 | ---- 16 | 17 | - [第一章:Ruby语言最小化](/rhg-zh/zh/01-minimum) 18 | - [第二章:对象](/rhg-zh/zh/02-object) 19 | - [第三章:名称与名称表](/rhg-zh/zh/03-name) 20 | - [第四章:类与模块](/rhg-zh/zh/04-class) 21 | - [第五章:垃圾回收](/rhg-zh/zh/05-gc) 22 | - [第六章:变量和常量](/rhg-zh/zh/06-variable) 23 | - [第七章:安全](/rhg-zh/zh/07-security) 24 | 25 | ## **第二部分:语法解析** 26 | ---- 27 | 28 | - [第八章:Ruby语言详解](/rhg-zh/zh/08-spec) 29 | - [第九章:yacc快速教程](/rhg-zh/zh/09-yacc) 30 | - [第十章:解析器](/rhg-zh/zh/10-parser) 31 | - [第十一章:上下文相关的扫描器](/rhg-zh/zh/11-contextual) 32 | - [第十二章:构建语法树](/rhg-zh/zh/12-syntree) 33 | 34 | ## **第三部分:评估** 35 | ---- 36 | 37 | - [第十三章:评估器的结构](/rhg-zh/zh/13-evaluator) 38 | - [第十四章:上下文](/rhg-zh/zh/14-module) 39 | - [第十五章:方法](/rhg-zh/zh/15-method) 40 | - [第十六章:代码块](/rhg-zh/zh/16-iterator) 41 | - [第十七章:动态评估](/rhg-zh/zh/17-anyeval) 42 | 43 | ## **第四部分:评估器的周边** 44 | ---- 45 | 46 | - [第十八章:加载](/rhg-zh/zh/18-load) 47 | - [第十九章:线程](/rhg-zh/zh/19-thread) 48 | 49 | - [第二十章:Ruby的未来](/rhg-zh/zh/20-fin) 50 | 51 | ## **杂记** 52 | ---- 53 | - [翻译杂记](/rhg-zh/zh/misc) 54 | - [Markdown语法](/rhg-zh/zh/markdown) 55 | - [Liquid模板语言](/rhg-zh/zh/liquid) 56 | 57 | ## **附录** 58 | ---- 59 | - [Ruby语言参考手册](http://www.ruby-doc.org/docs/ruby-doc-bundle/Manual/man-1.4/index.html) 60 | * [前言](/rhg-zh/zh/r-preface) 61 | * [命令行选项](/rhg-zh/zh/r-options) 62 | * [Ruby语法](/rhg-zh/zh/r-syntax) 63 | * [标准库](/rhg-zh/zh/) 64 | * [Bundled库](/rhg-zh/zh/) 65 | * [Ruby语法的伪BNF表达](/rhg-zh/zh/r-bnf) 66 | 67 | ## **致谢** 68 | ---- 69 | 70 | 感谢青木峰郎创作这样一本优秀的书籍,并允许我们翻译他的作品。 71 | 72 | RHG中文版制作采用了RHG英文版 的脚本。 第二、三、四和六章是根据英文版进行翻译,并且这几章的图片是在英文版的基础上修改得来。 在此对RHG英文版制作团队表示感谢! 73 | 74 | 感谢RHG中文版翻译团队的所有成员,利用自己业余时间参与到这个项目中来。 75 | 76 | ## **制作名单(原先第一部分)** 77 | ---- 78 | 79 | 章节 | 翻译 | 图 80 | --------- | ------------- | -------- 81 | 前 言 | 陈赛力、郑晔 | 82 | 序 章 | 陈赛力、郑晔 | 李彦辉 83 | 第一章 | 陈赛力、郑晔 | Steven 84 | 第二章 | 郑晔 | RHG英文版、李彦辉 85 | 第三章 | 郑晔 | RHG英文版 86 | 第四章 | 郑晔 | RHG英文版 87 | 第五章 | 陈赛力、姜超凡、郑晔 | 李彦辉 88 | 第六章 | 郑晔 | RHG英文版 89 | 第七章 | 郑晔、姜超凡 | 90 | 91 | 92 | 审校: [axgle](http://axgle.github.com/) 93 | 94 | 第2部分至最后,[邪王真眼的夏]({{site.url}})打算全部翻译下来,一切尽在计划中。。。 95 | 96 | ## 加入我们 97 | ---- 98 | 99 | 如你所见,RHG中文版目前还没有全部完成。所以,欢迎有兴趣的朋友加入到RHG中文版的制作过程中来。 100 | 101 | 如果你懂日语,可以加入翻译团队,协助完成剩余部分的翻译,或是校验已完成部分的正确性。 102 | 103 | 如果你擅长做图,可以帮助我们制作后续章节的图片,也可以调整已经完成的图片使其看上去更加完美。 104 | 105 | 如果你了解Ruby的实现,可以从技术的角度,对已经完成的部分校验,让译稿在技术上更加准确。 106 | 107 | 如果你对Ruby的实现感兴趣,欢迎阅读已完成的部分。阅读过程中发现的任何问题,都可以报告给我们,以便我们今后的发布中进行修改,让译稿更加完美。 108 | 109 | 这是原先项目主页(估计已废弃): 110 | 新的项目主页: 111 | 112 | -------------------------------------------------------------------------------- /zh/0-0-preface.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: 前言 4 | --- 5 | 6 | ## 前言 7 | ---- 8 | 9 | 本书探索了这样几个主题: 10 | 11 | * 了解ruby的构造 12 | * 学会语言处理的一般知识 13 | * 学会如何阅读源代码(source code) 14 | 15 | Ruby是松本行弘一手打造的一种面向对象语言。现在大家所看到的ruby是Ruby语言的官方实现,它的产生依赖于活跃的网络开发社区。 探明ruby内部结构是本书的第一目标,希望本书可以为大家展现ruby的全貌。 16 | 17 | 此外,Ruby的处理系统与一般计算机语言的处理系统关系密切,有许多类似的地方,比如hash表, 扫描器、解析器和评估的方法等等, 所有这些必要的内容都在其中有对应的实现。本书并不是一本讲解如何设计计算机语言的教科书,无法全面涵盖计算机语言设计领域的各种概念, 但会尽可能介绍语言处理系统的概貌(框架)。另外,书中加入了对Ruby语言的简要介绍,尽量让不了解Ruby的读者也能阅读本书。 18 | 19 | 很明显,前述目的的第一点和第二点是本书的主要目标。但是我最想强调的是第三点,也就是“学会如何阅读源代码”。 为什么需要学会阅读源代码呢?这里要说明一下。 20 | 21 | 平时总说,“为了能够熟练的编程,最好的方法的就是阅读别人的代码”。的确如此。不过,“实际怎样做”,很少有书回答这个问题。 讲解OS内核和计算机语言处理系统内部实现的书汗牛充栋,但这些书通常都是直接给出(内核或语言的)实现,也就是最终的答案,很少提及获得答案的过程, 显然,这是这些书考虑不周的地方。 22 | 23 | 对于会编程的人来说,阅读程序是一件非常自然的事情。实际上,阅读程序代码也很简单,不过,是不是生活在这个世界上的人都有闲暇去阅读程序代码呢? 我不这么认为。因为,阅读程序和编写程序这两件事几乎同样困难。 24 | 25 | 在本书中,我们并不是将ruby作为已知的东西来讲解,而是将其当作一个未知事物,尽可能将分析过程展现得生动一些。虽然我对Ruby语言实现有一定认识, 不过,执笔本书时,却不是完全理解ruby的内部实现。总之,我会尽可能从贴近读者的角度对ruby进行讲解。 将从始至终的分析过程和结果汇集在一起,这就是本书。 26 | 27 | 此外,ruby的作者matz为本书严把质量关,但是,我觉得在他对本书的检查,会让本书失去它原有的“生动”。所以matz的检查仅限于最终阶段。 这样一来,保留阅读ruby源代码的现场感的同时,质量也得到了保证。 28 | 29 | 说实话,本书介绍的内容并不简单。至少对象的本质就不是那么容易理解。或许,这正是本书有趣的地方。只对付一些弱于自己的对手是很无趣的, 没人喜欢解那些一眼就能看出答案的迷题,没人愿意读那些书到一半就能发现罪犯的侦探小说,穷尽能力解答问题才能获得真知。 本书是一本实践着“让笨蛋喜欢读”这样理想理论的书。“因为难而有趣”,如果通过阅读本书多一个人这么想,我也会觉得很高兴。 30 | 31 | ## 本书的目标读者 32 | ---- 33 | 34 | 首先Ruby语言不作为必须的前提条件。但是为了讲解语言实现,无论如何要用到一些Ruby语言的知识,因此,添加了几个讲解的章节,内容很少。 35 | 36 | 最好有一些C语言的知识,能够在运行时通过malloc分配结构体创建链表和堆栈,用过几次函数指针,这样的程度就可以了。 37 | 38 | 再者,考虑到面向对象基础部分的解释并不深入,如果没用过一些面向对象的语言的话,阅读可能会比较吃力。注意,书中大量的使用了Java/C++作为例子。 39 | 40 | ## 结构组织 41 | ---- 42 | 43 | 本书主要由4个部分组成。 44 | 45 | 第一部分 对象 46 | 47 | 第二部分 语法分析 48 | 49 | 第三部分 评估 50 | 51 | 第四部分 评估器的周边 52 | 53 | 每个部分的开始都会加入一个章节,适当补充一些的基础知识,这样,不了解计算机语言的机制和Ruby语言的人也可以阅读。 54 | 55 | 下面给出了四个主要部分的组成。说明后括号里的记号表明该章的难易程度。按照CBA的逐渐变难,S为最高难度。 56 | 57 | ### 第一部分 对象 58 | 59 | 第1章 谈谈阅读第一部分所需的Ruby基础知识(C) 60 | 61 | 第2章 讲解Ruby语言对象的具体内部构造(C) 62 | 63 | 第3章 探讨Hash表(C) 64 | 65 | 第4章 描述Ruby的类系统。如果觉得这章内容抽象的话,开始的时候可以只是浏览一遍。 (A) 66 | 67 | 第5章 看看掌管对象的生成和释放的垃圾回收机制(GC: Garbage Collection),底层系列故事的第一集。(B) 68 | 69 | 第6章 讲解全局变量,类变量,常量的实现。(C) 70 | 71 | 第7章 Ruby安全机制的大致框架。(C) 72 | 73 | ### 第二部分 语法分析 74 | 75 | 第8章 全面讨论阅读第二部分和第三部分所需的Ruby语言知识。(C) 76 | 77 | 第9章 讲解阅读语法文件所需的最低限度的yacc知识。(B) 78 | 79 | 第10章 解读解析器的构造和规则。(A) 80 | 81 | 第11章 探索解析器中的难点lex_state及其周边。这是本书最难的地方。(S) 82 | 83 | 第12章 总结第二部分,展开第三部分的话题。(C) 84 | 85 | ### 第三部分 评估 86 | 87 | 第13章 描述评估器的基本机制。(C) 88 | 89 | 第14章 解读评估器堆栈,它创建了Ruby主要的上下文。(A) 90 | 91 | 第15章 探索方法的查找和调用。(B) 92 | 93 | 第16章 Ruby的最大特征,挑战迭代器(iterator)的实现。(A) 94 | 95 | 第17章 讲解eval系列方法的实现。(B) 96 | 97 | ### 第四部分 模拟器及其周边 98 | 99 | 第18章 探讨运行时加载Ruby和C的程序库。(B) 100 | 101 | 第19章 作为核心的最后一章描述了线程的实现。(A) 102 | 103 | ## 环境 104 | ---- 105 | 106 | 本书讲解的是ruby 1.7.3 2002-09-12版。如果需要,可以到 http://i.loveruby.net/ja/rhg 下载。 本书出版之前,已经在以下环境通过了编译,并确认了基本的操作。 107 | 108 | BeOS 5 Personal Edition/i386 109 | Debian GNU/Linux potato/i386 110 | Debian GNU/Linux woody/i386 111 | Debian GNU/Linux sid/i386 112 | FreeBSD 4.4-RELEASE/Alpha 113 | FreeBSD 4.5-RELEASE/i386 114 | FreeBSD 4.5-RELEASE/PC98 115 | FreeBSD 5-CURRENT/i386 116 | HP-UX 10.20 117 | HP-UX 11.00 (32bit mode) 118 | HP-UX 11.11 (32bit mode) 119 | Mac OS X 10.2 120 | NetBSD 1.6F/i386 121 | OpenBSD 3.1 122 | Plamo Linux 2.0/i386 123 | Linux for PlayStation2 Release 1.0 124 | Redhat Linux 7.3/i386 125 | Solaris 2.6/Sparc 126 | Solaris 8/Sparc 127 | UX/4800 128 | Vine Linux 2.1.5 129 | Vine Linux 2.5 130 | VineSeed 131 | Windows 98SE (Cygwin, MinGW+Cygwin, MinGW+MSYS) 132 | Windows Me (Borland C++ Compiler 5.5, Cygwin, MinGW+Cygwin, MinGW+MSYS, Visual C++ 6) 133 | Windows NT 4.0 (Cygwin, MinGW+Cygwin) 134 | Windows 2000 (Borland C++ Compiler 5.5, Visual C++ 6, Visual C++.NET) 135 | Windows XP (Visual C++.NET, MinGW+Cygwin) 136 | 137 | ## 网站 138 | ---- 139 | 140 | 本书网站: [http://i.loveruby.net/ja/rhg], 网站上提供了附加的程序的信息、附加的文档以及勘错表。并且,也会渐渐的包含整本书的全部内容。 141 | -------------------------------------------------------------------------------- /zh/03-name.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: 第三章:名称与名称表 4 | --- 5 | 6 | ## st_table 7 | ---- 8 | 9 | 作为方法表和实例表,st_table在前面提到过。在本章中,让我们详细看一下st_table的机制。 10 | 11 | ### 概要 12 | 13 | 我之前提到过,st_table是一个hash表。什么是hash表呢?它是一种数据结构,记录一对一的关系,比如变量名与其值,函数名与其体,等等。 14 | 15 | 然而,除hash表外,当然还有其它的数据结构,可以记录一对一的关系。比如下面的list数据结构也能满足这个目的。 16 | 17 | struct entry { 18 | ID key; 19 | VALUE val; 20 | struct entry *next; /* 指向下一项 */ 21 | }; 22 | 23 | 然而,这种方法缓慢。如果list中包含上千项,在最差的情况下,必需穿越上千次的链。 换句话说,搜索时间随元素数量的比例而增长。这很糟糕。从远古时代开始, 就酝酿出许多不同的提速方法。hash表就是提速方法之一。换句话说,这里的要点不在于是否需要hash表,而是因为它可以更快一些。 24 | 25 | 那么接下来,我们来看看st_table。但首先说一下,这个库并非Matsumoto所创,而是: 26 | ▼ st.c credits 27 | 28 | 1 /* This is a public domain general purpose hash table package 29 | written by Peter Moore @ UCB. */ 30 | 31 | (st.c) 32 | 33 | 如上所示。 34 | 35 | 顺便说一下,当我用Google搜索时,找到了另一个版本,它提到st_table是“STring TABLE”的缩写。 然而,我发现一个矛盾,它有“通用目的”和“字符串”两个方面。 36 | 37 | #### hash表是什么? 38 | 39 | 可以这样理解hash表:让我们把它看作一个拥有n项的数组。比如,假设n=64(图1)。 40 | 41 | 数组 42 | 图1: 数组 43 | 44 | 然后,我们指定一个函数f,用一个键值产生一个0到n-1(0-63)的整数i。我们称这个f为hash函数。 对于给定的相同键值,f总会产生i。比如,如果我们做个假设,把键值限定为正整数,那么如果键值被64整除, 那么,余数总是在0到63之间。这个计算方法就可以作为函数f。 45 | 46 | 记录关系时,给定一个键值,函数f产生i,把它放到我们预备好的数组中索引为i的位置上。 换句话说,通过索引访问数组非常快。因此,基本的想法就是把键值变成整数。 47 | 48 | 数组赋值 49 | 图2: 数组赋值 50 | 51 | 然而,在现实世界中,问题没那么简单。这个想法有一个关键的问题。因为n只是64,如果要记录多于64个的关系, 肯定会有两个不同的键值有相同的索引。即便少于64,也可能会有相同的发生。以前面hash函数“key % 64”为例, 键值65和129的hash值都是1。这称为hash值冲突。有许多办法用来解决冲突。 52 | 53 | 比如,如果发生冲突,把它插入下一个元素的位置。这种方法叫做开放寻址。(图3) 54 | 55 | 开放寻址 56 | 图3: 开放寻址 57 | 58 | 除了像这样使用数组,还有其它的方式,比如使用指针,数组的每个元素都是一个指向各自链表的指针。 那么当发生冲突时,链表随之生长。这称为链接(chaining)。(图4)st_table使用的就是这种链接的方法。 59 | 60 | 链接 61 | 图4: 链接 62 | 63 | 然而,如果确定用到是哪些键值,那么可以想象有一个绝不会产生冲突的hash函数。这种函数称为“完美hash函数”。 实际上,确实有一些工具能够对一套给定的任意字符串创建了一个完美hash函数。GNU gpref就是其中之一。 ruby的解析器实现就使用了GNU gperf,但是……这还不到我们讨论它的时候。我们会在本书的第二部分讨论它。 64 | 数据结构 65 | 66 | 让我们从看源码起步。正如在引介的章节中所写,如果既有数据又有代码,最好先看数据。下面就是st_table的数据类型。 67 | ▼ st_table 68 | 69 | 9 typedef struct st_table st_table; 70 | 71 | 16 struct st_table { 72 | 17 struct st_hash_type *type; 73 | 18 int num_bins; /* slot count */ 74 | 19 int num_entries; /* total number of entries */ 75 | 20 struct st_table_entry **bins; /* slot */ 76 | 21 }; 77 | 78 | (st.h) 79 | 80 | ▼ struct st_table_entry 81 | 82 | 16 struct st_table_entry { 83 | 17 unsigned int hash; 84 | 18 char *key; 85 | 19 char *record; 86 | 20 st_table_entry *next; 87 | 21 }; 88 | 89 | (st.c) 90 | 91 | st_table主要是一个表的数据结构。st_table_entry持有存储的一个值。st_table_entry包含一个称为next的成员, 用于将st_table_entry放入一个链表。这是链接方法链的部分。这里用到了st_hash_type数据类型,稍后解释。 先让我解释其它部分,这样,你就能够对比和理解其角色了。 92 | 93 | st_table数据结构 94 | 图5: st_table数据结构 95 | 96 | 那么让我们来看看st_hash_type。 97 | ▼ struct st_hash_type 98 | 99 | 11 struct st_hash_type { 100 | 12 int (*compare)(); /* comparison function */ 101 | 13 int (*hash)(); /* hash function */ 102 | 14 }; 103 | 104 | (st.h) 105 | 106 | 这还是第三章,那么我们换种方式来看它。 107 | 108 | int (*compare)() 109 | 110 | 这个部分表示compare成员的数据类型是一个函数指针,其返回值为int。hash也具有同样的类型。 这个变量可以用下面的方式替代: 111 | 112 | int 113 | great_function(int n) 114 | { 115 | /* ToDo: 做一些伟大的事情! */ 116 | return n; 117 | } 118 | 119 | { 120 | int (*f)(); 121 | f = great_function; 122 | 123 | 这样调用: 124 | 125 | (*f)(7); 126 | } 127 | 128 | 我们回到st_hash_type。hash和compare两个成员之中,hash就是前面提到的hash函数f。 129 | 130 | 另一方面,compare这个函数的作用是评估值是否相同。在链接方法中,相同hash值的点里可能插入了多个元素。 为了准确知道查找的是哪个元素,必需使用一个我们绝对信任的比较函数。compare就是那个函数。 131 | 132 | 这个st_hash_type是一项很好的泛化的技术。hash表本身并不确定存储键值的数据类型是什么。 比如,在ruby中,st_table的键值是ID或char*或VALUE,但是对每个(数据类型)都使用同样的hash是愚蠢的。 通常,随键值数据类型不同而改变的就是hasn函数之类的东西。对于内存管理和冲突检测之类的东西,通常大部分代码都一样。 只有实现需要随数据类型不同而改变的部分绑定到一个函数中,使用一个函数指针指向那个函数。 这样的话,组成hash表实现的主体代码就可以使用它了。 133 | 134 | 在面向对象的语言中,你可以把过程附着在一个对象上,传递它,因此,不需要这种机制。 也许说这种机制作为一种语言特征内建其中更合适。 135 | st_hash_type的例子 136 | 137 | 使用一个类似于st_hash_type的数据结构是一种很好的抽象,但另一方面,理解它实际传递是何种代码可能就有些困难了。 如果不检查hash或compare用的是什么函数,我们便无法掌握事实。为了理解这点,可能要看一下st_init_numtable()才行, 在前面一章中,我们介绍过它。这个函数创建了一个表,其键值的数据类型为整数。 138 | ▼ st_init_numtable() 139 | 140 | 182 st_table* 141 | 183 st_init_numtable() 142 | 184 { 143 | 185 return st_init_table(&type_numhash); 144 | 186 } 145 | 146 | (st.c) 147 | 148 | st_init_table()是这样一个函数,它完成表内存分配等工作。type_numhash是一个st_hash_type (它是一个名为st_table“类型”的成员)。看看这个type_numhash: 149 | ▼ type_numhash 150 | 151 | 37 static struct st_hash_type type_numhash = { 152 | 38 numcmp, 153 | 39 numhash, 154 | 40 }; 155 | 156 | 552 static int 157 | 553 numcmp(x, y) 158 | 554 long x, y; 159 | 555 { 160 | 556 return x != y; 161 | 557 } 162 | 163 | 559 static int 164 | 560 numhash(n) 165 | 561 long n; 166 | 562 { 167 | 563 return n; 168 | 564 } 169 | 170 | (st.c) 171 | 172 | 非常简单。ruby使用的这个表基本上就是这个type_numhash。 173 | st_lookup() 174 | 175 | 接下来,我们看一下使用这个数据结构的函数。首先,从搜索的函数看起是个好主意。 下面就是搜索hash表的函数st_lookup()。 176 | 177 | ▼ st_lookup() 178 | 179 | 247 int 180 | 248 st_lookup(table, key, value) 181 | 249 st_table *table; 182 | 250 register char *key; 183 | 251 char **value; 184 | 252 { 185 | 253 unsigned int hash_val, bin_pos; 186 | 254 register st_table_entry *ptr; 187 | 255 188 | 256 hash_val = do_hash(key, table); 189 | 257 FIND_ENTRY(table, ptr, hash_val, bin_pos); 190 | 258 191 | 259 if (ptr == 0) { 192 | 260 return 0; 193 | 261 } 194 | 262 else { 195 | 263 if (value != 0) *value = ptr->record; 196 | 264 return 1; 197 | 265 } 198 | 266 } 199 | 200 | (st.c) 201 | 202 | 重要的部分几乎都在do_hash()和FIND_ENTRY()中。让我们按顺序看一下。 203 | 204 | ▼ do_hash() 205 | 206 | 68 #define do_hash(key,table) (unsigned int)(*(table)->type->hash)((key)) 207 | 208 | (st.c) 209 | 210 | 慎重起见,我们记下这个难于理解的宏的主体: 211 | 212 | > (table)->type->hash 213 | 214 | 是一个函数指针,key作为参数传递给它。这是调用函数的语法。*不是用在表上。换句话说,这个宏是一个hash值产生器, 每个数据类型都有事先预备好的hash函数type->hash,用它对键值产生一个hash值。 215 | 216 | 下面,继续来看FIND_ENTRY()。 217 | 218 | ▼ FIND_ENTRY() 219 | 220 | 235 #define FIND_ENTRY(table, ptr, hash_val, bin_pos) do {\ 221 | 236 bin_pos = hash_val%(table)->num_bins;\ 222 | 237 ptr = (table)->bins[bin_pos];\ 223 | 238 if (PTR_NOT_EQUAL(table, ptr, hash_val, key)) {\ 224 | 239 COLLISION;\ 225 | 240 while (PTR_NOT_EQUAL(table, ptr->next, hash_val, key)) {\ 226 | 241 ptr = ptr->next;\ 227 | 242 }\ 228 | 243 ptr = ptr->next;\ 229 | 244 }\ 230 | 245 } while (0) 231 | 232 | 227 #define PTR_NOT_EQUAL(table, ptr, hash_val, key) ((ptr) != 0 && \ 233 | (ptr->hash != (hash_val) || !EQUAL((table), (key), (ptr)->key))) 234 | 235 | 66 #define EQUAL(table,x,y) \ 236 | ((x)==(y) || (*table->type->compare)((x),(y)) == 0) 237 | 238 | (st.c) 239 | 240 | COLLISION是一个调试宏,所以,我们(应该)忽略它。 241 | 242 | FIND_ENTRY()的参数,从左开始是: 243 | 244 | - st_table 245 | - 这个参数指向的找到项 246 | - hash值 247 | - 临时变量 248 | 249 | 第二个参数会指向找到的`st_table_entry*`。 250 | 251 | 在最外层的,do .. while(0)用于对多表达式的宏进行安全封装。与其说是ruby, 不如说这是C语言预处理器的一种常用手法。在if(1)的情况下,可能需要附加else。 在while(1)的情况下,可能需要在最后添加一个break。 252 | 253 | 还有,while(0)后面没有分号。说到原因 254 | 255 | > FIND_ENTRY(); 256 | 257 | 这样就不会让出现在通常表达式后的逗号成为徒劳。 258 | > st_add_direct() 259 | 260 | 继续,让我们来看看st_add_direct(),它向hash表中添加一个新的关系。 这个函数并不检查键值是否已经存在。它总会添加一个新的项。这就是函数名中direct的含义所在。 261 | 262 | ▼ st_add_direct() 263 | 264 | 308 void 265 | 309 st_add_direct(table, key, value) 266 | 310 st_table *table; 267 | 311 char *key; 268 | 312 char *value; 269 | 313 { 270 | 314 unsigned int hash_val, bin_pos; 271 | 315 272 | 316 hash_val = do_hash(key, table); 273 | 317 bin_pos = hash_val % table->num_bins; 274 | 318 ADD_DIRECT(table, key, value, hash_val, bin_pos); 275 | 319 } 276 | 277 | (st.c) 278 | 279 | 如同前面一样,这里调用do_hash()宏获取一个值。随后,下一个计算等同于FIND_ENTRY()开始的部分, 它以hash值得到真正的索引。 280 | 281 | 插入操作看上去是以ADD_DIRECT()实现的,既然名字全部大写,我们期待它是一个宏。 282 | 283 | ▼ ADD_DIRECT() 284 | 285 | 268 #define ADD_DIRECT(table, key, value, hash_val, bin_pos) \ 286 | 269 do { \ 287 | 270 st_table_entry *entry; \ 288 | 271 if (table->num_entries / (table->num_bins) \ 289 | > ST_DEFAULT_MAX_DENSITY) { \ 290 | 272 rehash(table); \ 291 | 273 bin_pos = hash_val % table->num_bins; \ 292 | 274 } \ 293 | 275 \ 294 | /* (A) */ \ 295 | 276 entry = alloc(st_table_entry); \ 296 | 277 \ 297 | 278 entry->hash = hash_val; \ 298 | 279 entry->key = key; \ 299 | 280 entry->record = value; \ 300 | /* (B) */ \ 301 | 281 entry->next = table->bins[bin_pos]; \ 302 | 282 table->bins[bin_pos] = entry; \ 303 | 283 table->num_entries++; \ 304 | 284 } while (0) 305 | 306 | (st.c) 307 | 308 | 第一个if是一个异常情况,我稍后解释它。 309 | 310 | (A) 分配以及初始化一个st_table_entry。 311 | 312 | (B) 把entry插入到列表的起始位置。这是处理列表的常见手法。换句话说, 313 | 314 | entry->next = list_beg; 315 | list_beg = entry; 316 | 317 | 将一个项插入到列表的前端。这类似于Lisp语言中的“cons-ing”。自己检查一下, 即便list_beg为空,这段代码也是正确的。 318 | 319 | 现在,让我来解释一下我留下的那段代码。 320 | 321 | ▼ ADD_DIRECT()-rehash 322 | 323 | 271 if (table->num_entries / (table->num_bins) \ 324 | > ST_DEFAULT_MAX_DENSITY) { \ 325 | 272 rehash(table); \ 326 | 273 bin_pos = hash_val % table->num_bins; \ 327 | 274 } \ 328 | 329 | (st.c) 330 | 331 | DENSITY is“浓度”。换句话说,这个条件检查hash表是否“拥挤”。在st_table中, 随着使用相同bin_pos的增长,链表会变得更长。换句话说,搜索会变慢。 如果bin中的元素过多,那么就应该增加bin的数量,降低拥挤程度。 332 | 333 | 当前ST_DEFAULT_MAX_DENSITY是 334 | 335 | ▼ ST_DEFAULT_MAX_DENSITY 336 | 337 | 23 #define ST_DEFAULT_MAX_DENSITY 5 338 | 339 | (st.c) 340 | 341 | 因为这个设置,如果在所有的bin_pos都有5个st_table_entries,那么大小就要增加。 342 | st_insert() 343 | 344 | st_insert()只是将st_add_direct()和st_lookup()组合了起来,因此, 如果你理解了那两个,这个就容易了。 345 | 346 | ▼ st_insert() 347 | 348 | 286 int 349 | 287 st_insert(table, key, value) 350 | 288 register st_table *table; 351 | 289 register char *key; 352 | 290 char *value; 353 | 291 { 354 | 292 unsigned int hash_val, bin_pos; 355 | 293 register st_table_entry *ptr; 356 | 294 357 | 295 hash_val = do_hash(key, table); 358 | 296 FIND_ENTRY(table, ptr, hash_val, bin_pos); 359 | 297 360 | 298 if (ptr == 0) { 361 | 299 ADD_DIRECT(table, key, value, hash_val, bin_pos); 362 | 300 return 0; 363 | 301 } 364 | 302 else { 365 | 303 ptr->record = value; 366 | 304 return 1; 367 | 305 } 368 | 306 } 369 | 370 | (st.c) 371 | 372 | 它会检查元素是否已经在表中存在。只有它不存在时,才会添加。如果插入,返回0,否则,返回1。 373 | ID和符号 374 | 375 | 我已经讨论过什么是ID了。它将一个字符串对应为一个值,以它声明不同的名字。 实际的数据类型是unsigned int。 376 | 从char*到ID 377 | 378 | 字符串到ID的转换由rb_intern()完成。这个函数相当长,让我们省略掉中间的部分。 379 | 380 | ▼ rb_intern() (simplified) 381 | 382 | 5451 static st_table *sym_tbl; /* char* to ID */ 383 | 5452 static st_table *sym_rev_tbl; /* ID to char* */ 384 | 385 | 5469 ID 386 | 5470 rb_intern(name) 387 | 5471 const char *name; 388 | 5472 { 389 | 5473 const char *m = name; 390 | 5474 ID id; 391 | 5475 int last; 392 | 5476 393 | /* If for a name, there is a corresponding ID that is already 394 | registered, then return that ID */ 395 | 5477 if (st_lookup(sym_tbl, name, &id)) 396 | 5478 return id; 397 | 398 | /* omitted ... create a new ID */ 399 | 400 | /* register the name and ID relation */ 401 | 5538 id_regist: 402 | 5539 name = strdup(name); 403 | 5540 st_add_direct(sym_tbl, name, id); 404 | 5541 st_add_direct(sym_rev_tbl, id, name); 405 | 5542 return id; 406 | 5543 } 407 | 408 | (parse.y) 409 | 410 | 字符串和ID的对应关系由st_table完成。这里可能没有什么特别难的部分。 411 | 412 | 省略的部分做了些什么呢?它对全局变量名和实例变量名进行特殊处理,给它们设上了标记。 这是因为,在解析器中,根据ID了解变量的分类是必要的。然而,ID的基础部分与此无关, 因此,我就不在这里解释了。 413 | 从ID到char* 414 | 415 | rb_intern()的反向操作是rb_id2name(),它用一个ID产生一个char*。你或许已经知道, id2name中2是“to”。“To”和“Two”同音,因此用“2”表示“to”。这种用法很常见。 416 | 417 | 这个函数也要设置ID分类标志,因此它也很长,让我们简化一下。 418 | 419 | ▼ rb_id2name() (简化版) 420 | 421 | char * 422 | rb_id2name(id) 423 | ID id; 424 | { 425 | char *name; 426 | 427 | if (st_lookup(sym_rev_tbl, id, &name)) 428 | return name; 429 | return 0; 430 | } 431 | 432 | 或许它看上去有些过于简化,但事实上,如果我们去掉了细节,它真的就是这么简单。 433 | 434 | 我想强调的是,找到name之后,并不进行复制。ruby API并不需要(甚至禁止)对返回值free()。 传递参数后,总是要复制来用。换句话说,创建和释放都是由一方完成,用户或是ruby。 435 | 436 | 因此,当创建和释放无法在一个值上完成(传递而不返回时),就要使用Ruby对象。我还没有讨论过它。 当Ruby对象不再使用,即便我们不关心它,它也可以自动释放。 437 | VALUE和ID的转换 438 | 439 | 在Ruby的层次上,ID是一个Symbol类的实例。可以这样得到它:"string".intern。 String#intern的实现是rb_str_intern()。 440 | 441 | ▼ rb_str_intern() 442 | 443 | 2996 static VALUE 444 | 2997 rb_str_intern(str) 445 | 2998 VALUE str; 446 | 2999 { 447 | 3000 ID id; 448 | 3001 449 | 3002 if (!RSTRING(str)->ptr || RSTRING(str)->len == 0) { 450 | 3003 rb_raise(rb_eArgError, "interning empty string"); 451 | 3004 } 452 | 3005 if (strlen(RSTRING(str)->ptr) != RSTRING(str)->len) 453 | 3006 rb_raise(rb_eArgError, "string contains `\\0'"); 454 | 3007 id = rb_intern(RSTRING(str)->ptr); 455 | 3008 return ID2SYM(id); 456 | 3009 } 457 | 458 | (string.c) 459 | 460 | 作为ruby类库代码的样例,这个函数相当合理。注意使用RSTRING()转型的地方,这里访问了数据结构的成员。 461 | 462 | 我们来读读代码。首先,rb_raise()只是一个错误处理,我们暂时忽略它。这里有我们之前看过的rb_intern()。 ID2SYM() 是一个宏,它将ID转换为Symbol。 463 | 464 | 反向操作由Symbol#to_s完成,实现在sym_to_s中。 465 | 466 | ▼ sym_to_s() 467 | 468 | 522 static VALUE 469 | 523 sym_to_s(sym) 470 | 524 VALUE sym; 471 | 525 { 472 | 526 return rb_str_new2(rb_id2name(SYM2ID(sym))); 473 | 527 } 474 | 475 | (object.c) 476 | 477 | SYM2ID()是一个宏,它将Symbol(VALUE)转换为一个ID。 478 | 479 | 看上去,这个函数什么都没做。然而,可能需要注意一下内存处理的部分。`rb_id2name()`返回一个`char*`, 它不能用 free()释放。`rb_str_new2()`复制了参数的char*,使用的是它的拷贝。按照这种方式,如果采用一致的策略,就允许以链的方式编写函数。 480 | -------------------------------------------------------------------------------- /zh/06-variable.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: 第六章:变量和常量 4 | --- 5 | 6 | ##本章提纲 7 | ---- 8 | 9 | ## Ruby的变量 10 | 11 | Ruby中有相当多不同类型的变量和常量。让我们列举一下,从范围最大的开始。 12 | 13 | - 全局变量 14 | - 常量 15 | - 类变量 16 | - 实例变量 17 | - 局部变量 18 | 19 | 实例变量已经在第2章《对象》中解释过了。在本章中,我们要讨论的是: 20 | 21 | - 全局变量 22 | - 类变量 23 | - 常量 24 | 25 | 部变量会在本书的第三部分讨论。 26 | 变量API 27 | 28 | 本章的分析目标是variable.c。我们先来看一下可用的API。 29 | 30 | VALUE rb_iv_get(VALUE obj, char *name) 31 | VALUE rb_ivar_get(VALUE obj, ID name) 32 | VALUE rb_iv_set(VALUE obj, char *name, VALUE val) 33 | VALUE rb_ivar_set(VALUE obj, ID name, VALUE val) 34 | 35 | 我们已经讨论过这些函数,但是必须再次提起它们,因为它们都在variable.c中。 当然,它们是用来访问实例变量的。 36 | 37 | VALUE rb_cv_get(VALUE klass, char *name) 38 | VALUE rb_cvar_get(VALUE klass, ID name) 39 | VALUE rb_cv_set(VALUE klass, char *name, VALUE val) 40 | VALUE rb_cvar_set(VALUE klass, ID name, VALUE val) 41 | 42 | 这些函数是访问类变量的API。类变量直接属于类,因此函数需要用一个类作为参数。 根据名字是以rb_Xv还是rb_Xvar开头,函数分为两组。差别在于变量“名”。 稍短名字的函数通常更易用,因为它们以char*为参数。稍长名字的参数更多在内部使用, 它们以ID为参数。 43 | 44 | VALUE rb_const_get(VALUE klass, ID name) 45 | VALUE rb_const_get_at(VALUE klass, ID name) 46 | VALUE rb_const_set(VALUE klass, ID name, VALUE val) 47 | 48 | 这些函数用于访问常量。常量属于类,因此它们要以类为为参数。 rb_const_get()会沿超类链查询,而rb_const_get_at()不会(它只查询klass)。 49 | 50 | struct global_entry *rb_global_entry(ID name) 51 | VALUE rb_gv_get(char *name) 52 | VALUE rb_gvar_get(struct global_entry *ent) 53 | VALUE rb_gv_set(char *name, VALUE val) 54 | VALUE rb_gvar_set(struct global_entry *ent, VALUE val) 55 | 56 | 最后的这些函数用以访问全局变量。因为使用struct global_entry了,它们显得与众不同。 我们会在描述实现的时候对此进行解释。 57 | 58 | ### 本章的要点 59 | 60 | 本章最重要的话题是“变量存在哪里以及如何存储?”,也就是,数据结构。 61 | 62 | 第二重要的在于如何搜索值。Ruby变量和常量的范围相当复杂, 因为变量和常量有时可以继承,有时可以在局部范围外看到……为了有个更好的理解, 你应该先从行为上猜测一下其如何实现,然后与真正的实现进行对比。 63 | 64 | ## 类变量 65 | ---- 66 | 67 | 类变量是属于类的变量。在Java或C++中,它们叫做静态变量。它们既可以从类中访问, 也可以从实例中访问。但是“从实例中”或“从类中”,只是求值器可用的信息。 我们此刻并不知道。因此,从C的层次上来看,它像是没有访问的范围。 我们只关注这些变量存储的方式。 68 | 读取 69 | 70 | 获取类变量的函数是rb_cvar_get()和rb_cv_get()。名字稍长的函数以ID为参数, 短一些的以char*为参数。因为以ID为参数看上去和内核部分更接近,我们来看一下。 71 | 72 | ▼ rb_cvar_get() 73 | 74 | 1508 VALUE 75 | 1509 rb_cvar_get(klass, id) 76 | 1510 VALUE klass; 77 | 1511 ID id; 78 | 1512 { 79 | 1513 VALUE value; 80 | 1514 VALUE tmp; 81 | 1515 82 | 1516 tmp = klass; 83 | 1517 while (tmp) { 84 | 1518 if (RCLASS(tmp)->iv_tbl) { 85 | 1519 if (st_lookup(RCLASS(tmp)->iv_tbl,id,&value)) { 86 | 1520 if (RTEST(ruby_verbose)) { 87 | 1521 cvar_override_check(id, tmp); 88 | 1522 } 89 | 1523 return value; 90 | 1524 } 91 | 1525 } 92 | 1526 tmp = RCLASS(tmp)->super; 93 | 1527 } 94 | 1528 95 | 1529 rb_name_error(id,"uninitialized class variable %s in %s", 96 | 1530 rb_id2name(id), rb_class2name(klass)); 97 | 1531 return Qnil; /* not reached */ 98 | 1532 } 99 | 100 | (variable.c) 101 | 102 | 这个函数读取klass的一个类变量。 103 | 104 | 正如我之前所说,像rb_raise()这样的错误处理函数可以简单的忽略。 这次出现的rb_name_error()是一个生成异常的函数,因此,基于同样的原因, 也可以忽略它。在ruby中,你可以假设所有以_error结尾的函数都会产生异常。 105 | 106 | 去除所有这些之后,我们看到的是,沿着klass的超类链,在iv_tbl中搜索。 在这里,你会说“什么?iv_tbl不是实例变量表吗?”事实上, 类变量就是存在实例变量表中。 107 | 108 | 我们可以这么做,因为创建ID时,考虑的是变量的全名,包括前缀: rb_intern()对“@var”和“@@var”返回的是不同的ID。 在Ruby的层次上,变量类型有前缀唯一确定,因此在Ruby中无法访问一个叫做@var的类变量。 109 | 110 | ## 常量 111 | ---- 112 | 113 | 有些唐突,但是我希望你能记住struct RClass的成员。如果我们排除basic, struct RClass包括: 114 | 115 | - VALUE super 116 | - struct st_table *iv_tbl 117 | - struct st_table *m_tbl 118 | 119 | 然后,考虑一下: 120 | 121 | - 常量属于类 122 | - 在struct RClass中,我们没有看到任何常量专用的表 123 | - 类变量和实例变量都在iv_tbl中 124 | 125 | 或许常量也…… 126 | 127 | ### 赋值 128 | 129 | rb_const_set()是一个为常量设置值的函数: 它将类klass的常量id设为值val。 130 | 131 | ▼ rb_const_set() 132 | 133 | 1377 void 134 | 1378 rb_const_set(klass, id, val) 135 | 1379 VALUE klass; 136 | 1380 ID id; 137 | 1381 VALUE val; 138 | 1382 { 139 | 1383 mod_av_set(klass, id, val, Qtrue); 140 | 1384 } 141 | 142 | (variable.c) 143 | 144 | mod_av_set()完成了所有艰苦的工作: 145 | 146 | ▼ mod_av_set() 147 | 148 | 1352 static void 149 | 1353 mod_av_set(klass, id, val, isconst) 150 | 1354 VALUE klass; 151 | 1355 ID id; 152 | 1356 VALUE val; 153 | 1357 int isconst; 154 | 1358 { 155 | 1359 char *dest = isconst ? "constant" : "class variable"; 156 | 1360 157 | 1361 if (!OBJ_TAINTED(klass) && rb_safe_level() >= 4) 158 | 1362 rb_raise(rb_eSecurityError, "Insecure: can't set %s", dest); 159 | 1363 if (OBJ_FROZEN(klass)) rb_error_frozen("class/module"); 160 | 1364 if (!RCLASS(klass)->iv_tbl) { 161 | 1365 RCLASS(klass)->iv_tbl = st_init_numtable(); 162 | 1366 } 163 | 1367 else if (isconst) { 164 | 1368 if (st_lookup(RCLASS(klass)->iv_tbl, id, 0) || 165 | 1369 (klass == rb_cObject && st_lookup(rb_class_tbl, id, 0))) { 166 | 1370 rb_warn("already initialized %s %s", dest, rb_id2name(id)); 167 | 1371 } 168 | 1372 } 169 | 1373 170 | 1374 st_insert(RCLASS(klass)->iv_tbl, id, val); 171 | 1375 } 172 | 173 | (variable.c) 174 | 175 | 这里你可以再次忽略警告检查(rb_raise(),rb_error_frozen()和rb_warn())。 这是剩下的部分: 176 | 177 | ▼ mod_av_set() (只有重要的部分) 178 | 179 | if (!RCLASS(klass)->iv_tbl) { 180 | RCLASS(klass)->iv_tbl = st_init_numtable(); 181 | } 182 | st_insert(RCLASS(klass)->iv_tbl, id, val); 183 | 184 | 我们现在可以确定,常量是在实例表中。这也就意味着,在struct RClass的iv_tbl中, 下面这些东西混在一起: 185 | 186 | 1. 类自己的实例变量 187 | 2. 类变量 188 | 3. 常量 189 | 190 | ### 读取 191 | 192 | 我们现在知道了常量如何存储。这回,我们把目光转向常量如何工作。 193 | rb_const_get() 194 | 195 | 我们现在来看一下rb_const_get(),一个读取常量的函数。 这个函数从klass中返回id所引用的常量。 196 | 197 | ▼ rb_const_get() 198 | 199 | 1156 VALUE 200 | 1157 rb_const_get(klass, id) 201 | 1158 VALUE klass; 202 | 1159 ID id; 203 | 1160 { 204 | 1161 VALUE value, tmp; 205 | 1162 int mod_retry = 0; 206 | 1163 207 | 1164 tmp = klass; 208 | 1165 retry: 209 | 1166 while (tmp) { 210 | 1167 if (RCLASS(tmp)->iv_tbl && 211 | st_lookup(RCLASS(tmp)->iv_tbl,id,&value)) { 212 | 1168 return value; 213 | 1169 } 214 | 1170 if (tmp == rb_cObject && top_const_get(id, &value)) 215 | return value; 216 | 1171 tmp = RCLASS(tmp)->super; 217 | 1172 } 218 | 1173 if (!mod_retry && BUILTIN_TYPE(klass) == T_MODULE) { 219 | 1174 mod_retry = 1; 220 | 1175 tmp = rb_cObject; 221 | 1176 goto retry; 222 | 1177 } 223 | 1178 224 | 1179 /* Uninitialized constant */ 225 | 1180 if (klass && klass != rb_cObject) { 226 | 1181 rb_name_error(id, "uninitialized constant %s at %s", 227 | 1182 rb_id2name(id), 228 | 1183 RSTRING(rb_class_path(klass))->ptr); 229 | 1184 } 230 | 1185 else { /* global_uninitialized */ 231 | 1186 rb_name_error(id, "uninitialized constant %s",rb_id2name(id)); 232 | 1187 } 233 | 1188 return Qnil; /* not reached */ 234 | 1189 } 235 | 236 | (variable.c) 237 | 238 | 一路上有许多代码。首先,我们至少该去除后半部分的rb_name_error()。在中间部分, mod_entry附近好像是对模块的特殊处理,我们也暂时去掉。函数化简为这样: 239 | 240 | ▼ rb_const_get (简化版) 241 | 242 | VALUE 243 | rb_const_get(klass, id) 244 | VALUE klass; 245 | ID id; 246 | { 247 | VALUE value, tmp; 248 | 249 | tmp = klass; 250 | while (tmp) { 251 | if (RCLASS(tmp)->iv_tbl && st_lookup(RCLASS(tmp)->iv_tbl,id,&value)) { 252 | return value; 253 | } 254 | if (tmp == rb_cObject && top_const_get(id, &value)) return value; 255 | tmp = RCLASS(tmp)->super; 256 | } 257 | } 258 | 259 | 现在应该很容易看懂了。这个函数沿着klass的超类链在iv_tbl中搜索常量。这就意味着: 260 | {% highlight ruby %} 261 | class A 262 | Const = "ok" 263 | end 264 | class B < A 265 | p(Const) # 可以被访问 266 | end 267 | {% endhighlight %} 268 | 唯一剩下的问题就是top_const_get()。这个函数仅限于rb_cObject调用。 top一定是“顶层”。先和你确认一下,顶层的类是Object。 “在定义C的类语句中,类成为C”,这等同于“顶层的类就是Object”。 269 | {% highlight ruby %} 270 | # 顶层的类是`Object` 271 | class A 272 | # 类是A 273 | class B 274 | # 类是B 275 | end 276 | end 277 | {% endhighlight %} 278 | 因此,可以预期,top_const_get()是专门针对顶层进行的处理。 279 | top_const_get() 280 | 281 | 我们来看看这个top_const_get函数。它查询id,把值写入klassp,然后返回。 282 | 283 | ▼ top_const_get() 284 | 285 | 1102 static int 286 | 1103 top_const_get(id, klassp) 287 | 1104 ID id; 288 | 1105 VALUE *klassp; 289 | 1106 { 290 | 1107 /* pre-defined class */ 291 | 1108 if (st_lookup(rb_class_tbl, id, klassp)) return Qtrue; 292 | 1109 293 | 1110 /* autoload */ 294 | 1111 if (autoload_tbl && st_lookup(autoload_tbl, id, 0)) { 295 | 1112 rb_autoload_load(id); 296 | 1113 *klassp = rb_const_get(rb_cObject, id); 297 | 1114 return Qtrue; 298 | 1115 } 299 | 1116 return Qfalse; 300 | 1117 } 301 | 302 | (variable.c) 303 | 304 | rb_class_tbl在第四章《类与模块》中已经提到过了。它是一个表,用来存储已经定义的顶层类。 比如内建类String或Array都登记在其中。因此,搜索顶层变量时,不要忘了这个表。 305 | 306 | 下一块同自动加载相关。这允许我们在第一次访问顶层常量时自动加载一个库。 比如这样使用: 307 | 308 | > autoload(:VeryBigClass, "verybigclass") # VeryBigClass定义在其中 309 | 310 | 之后,第一次访问VeryBigClass时,就会加载verybigclass(以require方式)。 只要VeryBigClass定义在库中,就可以顺利的执行。当库特别大,需要很长时间加载时, 这种方式就显得很高效了。 311 | 312 | 这种自动加载由rb_autoload_xxxx()完成。我们就不在本章进一步讨论自动加载了, 因为很快它的工作方式就会发生巨大的改变(译注:自动加载确实在1.8中发生了改变: 自动加载的常量不再需要定义在顶层了)。 313 | 314 | ### 其它的类? 315 | 316 | 对了,查询其它类常量的代码到底在哪?毕竟,常量的查询应该先从外面的类开始, 然后才是超类。 317 | 318 | 实际上,对此,我们还没有足够的知识。外部类的改变依赖于在程序中的位置。 总之,它与程序上下文相关。因此,我们先来理解求值器的内部状态。特别是, eval.c中的ev_const_get()函数,它完成在其它类中的搜索。 常量故事的结局会在本书的第三部分中出现。 319 | 320 | ## 全局变量 321 | ---- 322 | 323 | ### 总论 324 | 325 | 全局变量可以在任何地方访问。反过来说,没有必要限制对它们的访问。因为它们与上下文无关, 有个地方用来存放表就可以,没有必要做任何检查。因此,实现非常简单。 326 | 327 | 尽管如此,仍有一大堆代码。原因是全局变量与普通变量有很大差异。下面的功能只用于全局变量。 328 | 329 | - 你可以对全局变量的访问设置钩子 330 | - 你可以用alias为它们起个别名 331 | 332 | 我们来简单解释一下。 333 | 334 | #### 变量的别名 335 | 336 | > alias $newname $oldname 337 | 338 | 随后,你就可以用$newname代替$oldname。 339 | 340 | 变量的alias主要是为了“符号变量”而准备的。“符号变量”是一种源自Perl的变量, 比如$=或$0。$=用以确定字符串比较是是否区分大小写。$0表示Ruby主程序的名字。 还有一些其它的符号变量,但它们的名字只有一个字符长,对于不了解Perl的人来说, 它们难于记忆。因此才创建了别名,让它们好记一点。 341 | 342 | 现在不推荐使用符号变量,它们也一个个的移到适当模块的singleton方法中。 现在的氛围是2.0会废弃$=和其它符号变量。 343 | 344 | #### 钩子 345 | 346 | 你可以对全局变量的读写设置“钩子”。 347 | 348 | 钩子可以在Ruby的层次上设置,但是我一直在想:为什么不在C层次上看看系统用的特殊变量, 比如$KCODE?$KCODE是一个包含了编码信息的变量,解释器用它来处理字符串。 它只能设置为特殊的值,比如"EUC"或"UTF8"。但是这很讨厌,因此,也可以设为"e"或"u"。 349 | 350 | p($KCODE) # "NONE" (缺省) 351 | $KCODE = "e" 352 | p($KCODE) # "EUC" 353 | $KCODE = "u" 354 | p($KCODE) # "UTF8" 355 | 356 | 我想如果能够对全局变量的赋值设置钩子,就能更好的理解这里的所做的。顺便说一下, $KCODE的K来自“kanji”(日语中中文字符的名字)。 357 | 358 | 你也许会说,即便有了alias或是钩子,全局变量也不要用得那么多,所以, 它的功能没多大关系。不用的函数就让它适当的结束,我还需要篇幅分析解析器和求值器。 因此,下面的讨论中我抛弃一些不重要的东西。 359 | 360 | ### 数据结构 361 | 362 | 看变量结构的时候,我说过,它们的存储方式很重要。希望你可以好好掌握全局变量的结构。 363 | ▼ 全局变量的数据结构 364 | 365 | 21 static st_table *rb_global_tbl; 366 | 367 | 334 struct global_entry { 368 | 335 struct global_variable *var; 369 | 336 ID id; 370 | 337 }; 371 | 372 | 324 struct global_variable { 373 | 325 int counter; /* 引用计数 */ 374 | 326 void *data; /* 变量值 */ 375 | 327 VALUE (*getter)(); /* 取值函数 */ 376 | 328 void (*setter)(); /* 设置函数 */ 377 | 329 void (*marker)(); /* 标记函数 */ 378 | 330 int block_trace; 379 | 331 struct trace_var *trace; 380 | 332 }; 381 | 382 | (variable.c) 383 | 384 | `rb_global_tbl`是主要的表。所有的全局变量都存在这个表里。这个表的键值当然就是变量名(ID)。 值由`struct global_entry和struct global_variable`表示。(图1) 385 | ![执行时的全局变量表]({{site.url}}/images/ch_variable_gvar.png) 386 | 图1: 执行时的全局变量表 387 | 388 | 表示变量的结构分为两个部分,以便创建别名。如果创建了别名, 两个global_entry会指向同一个struct global_variable。 389 | 390 | 这里,引用计数器(struct global_variable的counter)是必需的。 我在前一章《垃圾回收》中解释过引用计数的概念。简单回顾一下,生成新的引用时, 计数器加1。引用不再使用时,计数器减1。计数器为0时,结构不再使用,调用free()。 391 | 392 | 如果在Ruby的层次上设置了钩子,就有一个struct trace_var列表存在struct global_variable 的trace成员中,这个就不说了,省略struct trace_var。 393 | 394 | ### 读取 395 | 396 | 只要看一下如何读取全局变量,就可以对全局变量有个大概的认识。 读取的函数是rb_gv_get()和rb_gvar_get()。 397 | ▼ rb_gv_get() rb_gvar_get() 398 | 399 | 716 VALUE 400 | 717 rb_gv_get(name) 401 | 718 const char *name; 402 | 719 { 403 | 720 struct global_entry *entry; 404 | 721 405 | 722 entry = rb_global_entry(global_id(name)); 406 | 723 return rb_gvar_get(entry); 407 | 724 } 408 | 409 | 649 VALUE 410 | 650 rb_gvar_get(entry) 411 | 651 struct global_entry *entry; 412 | 652 { 413 | 653 struct global_variable *var = entry->var; 414 | 654 return (*var->getter)(entry->id, var->data, var); 415 | 655 } 416 | 417 | (variable.c) 418 | 419 | 实际的内容都在`rb_global_entry()`中,但这并不妨碍我们理解。 global_id函数将`char*`转成ID,并检查它是否是全局变量的ID。 (*var->getter)(...)当然就是使用函数指针var->getter进行的函数调用。 如果p是一个函数指针,(*p)(arg)就在调用函数。 420 | 421 | 剩下的主要部分还是rb_global_entry()。 422 | 423 | ▼ rb_global_entry() 424 | 425 | 351 struct global_entry* 426 | 352 rb_global_entry(id) 427 | 353 ID id; 428 | 354 { 429 | 355 struct global_entry *entry; 430 | 356 431 | 357 if (!st_lookup(rb_global_tbl, id, &entry)) { 432 | 358 struct global_variable *var; 433 | 359 entry = ALLOC(struct global_entry); 434 | 360 st_add_direct(rb_global_tbl, id, entry); 435 | 361 var = ALLOC(struct global_variable); 436 | 362 entry->id = id; 437 | 363 entry->var = var; 438 | 364 var->counter = 1; 439 | 365 var->data = 0; 440 | 366 var->getter = undef_getter; 441 | 367 var->setter = undef_setter; 442 | 368 var->marker = undef_marker; 443 | 369 444 | 370 var->block_trace = 0; 445 | 371 var->trace = 0; 446 | 372 } 447 | 373 return entry; 448 | 374 } 449 | 450 | (variable.c) 451 | 452 | 主要处理由开始的`st_lookup()`完成。随后只是创建(和存储)了一个新项。 访问的项不存在时,便自动创建一项,rb_global_entry()不会返回NULL。 453 | 454 | 这主要是考虑速度。解析器找到一个全局变量时,它得到是相应的`struct global_entry`。 读取变量值时,解析器就是取该项的值(用rb_gv_get()),不必做任何检查。 455 | 456 | 让我们稍微前进一步,接下来的代码,var->getter等几个设为undef_xxxx。 对于当前未定义的全局变量,其setter/getter/marker用undef表示。 457 | 458 | 即便读取未定义的全局变量,`undef_getter()`也只是显示一个警告,返回nil。 undef_setter()则稍微有趣一些,来看一下。 459 | 460 | ▼ undef_setter() 461 | 462 | 385 static void 463 | 386 undef_setter(val, id, data, var) 464 | 387 VALUE val; 465 | 388 ID id; 466 | 389 void *data; 467 | 390 struct global_variable *var; 468 | 391 { 469 | 392 var->getter = val_getter; 470 | 393 var->setter = val_setter; 471 | 394 var->marker = val_marker; 472 | 395 473 | 396 var->data = (void*)val; 474 | 397 } 475 | 476 | (variable.c) 477 | 478 | val_getter()得到entry->data的值,返回它。val_getter()只是把值放到entry->data中。 这样设置处理器使我们不必对为定义变量进行特殊处理(图2)。很有技巧,不是吗? 479 | 480 | ![全局变量的设置和访问]({{site.url}}/images/ch_variable_gaccess.png) 481 | 482 | 图2: 全局变量的设置和访问 483 | -------------------------------------------------------------------------------- /zh/07-security.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: 第七章:安全 4 | --- 5 | 6 | ## 基础 7 | ---- 8 | 9 | 我在这里所说的安全并不是指密码或加密。Ruby的安全特性用于在类似于CGI编程的环境下, 处理不可靠的对象。 10 | 11 | 比如,把一个表示数字的字符串转换为一个整数,你可能使用的是eval方法。 然而,eval是一个“把字符串当作Ruby程序运行”的方法。 如果你eval的字符串来自网络上的不明人物,它可能就非常危险。 然而,对程序员来说,让他们完全负责区分安全和不安全的事物,他们会觉得非常烦琐和累赘, 肯定会犯下一些错误。因此,我们让它成为了语言的一部分。这便是这项特性的起因。 12 | 13 | 那么,Ruby如何保护我们免受这种危险呢?危险的操作,比如打开意图不明的文件, 其原因大体可分为两种: 14 | 15 | - 危险数据 16 | - 危险代码 17 | 18 | 对于前者,处理这些数据的代码是由程序员本身编写的,因此,它是(相当)安全的。 对于后者,程序代码是绝对不能信任的。 19 | 20 | 基于上面的两个原因,应该采用不同的解决方案,因此,有必要划分出不同的级别。 这个级别叫做安全级别。Ruby的安全级别由$SAFE这个全局变量表示。 值的范围最小为0,最大为4。当这个变量赋值时,级别就会增加。 因为级别一旦升高,就不会再降低。对于每个级别而言,都会限制一些操作。 21 | 22 | 我就不解释级别2和3了。级别0是通常的程序环境,安全系统不起作用。 级别1处理危险数据。级别4处理危险代码。 我们略过0,详细解释一下级别1和4。 23 | 24 | ### 级别1 25 | 26 | 这个级别用来处理危险数据,比如,在通常的CGI应用中,等等。 27 | 28 | 作为级别1实现的基础,每个对象都有“脏标记”。所有外部读来的对象都标记为脏, 脏对象尝试eval或File.open就会引发异常,尝试便就此终止。 29 | 30 | 脏标记是“可感染的”。比如,从一个脏字符串中取出一部分,这个部分也还是脏的。 31 | 32 | ### 级别4 33 | 34 | 这个级别用来处理危险代码,比如,运行外部(未知)程序,等等。 35 | 36 | 在级别2中,操作及其用到的数据之间会进行双向检查,但是在级别4中,操作本身也要受到约束。 比如,exit、文件I/O、线程操作、重定义方法等等。当然,在这个过程中,会用到脏标记信息, 但基本上是以操作为基准的。 37 | 38 | ### 安全单位 39 | 40 | $SAFE看上去像个全局变量,但实际上,它是一个线程局部变量。换句话说, Ruby的安全系统工作在线程单元上。在Java和.NET中,可以授权给每个组件(对象), 但是,Ruby没有那么做。因为估计的主要目标是CGI吧! 41 | 42 | 如果想提升程序某一部分的安全级别,那它应该创建一个不同的线程,提升线程的安全级别。 我还没有解释如何创建一个线程,但是我们在这里需要的只是一个例子,先忍耐一下: 43 | {% highlight ruby %} 44 | # 在不同的线程中提升安全级别 45 | p($SAFE) # 缺省值为0 46 | Thread.fork { # 启动一个不同的线程 47 | $SAFE = 4 # 提升安全级别 48 | eval(str) # 运行危险程序 49 | } 50 | p($SAFE) # block之外,安全级别仍为0。 51 | {% endhighlight %} 52 | 53 | ### $SAFE的可靠性 54 | 55 | 即便实现了脏标志的感染,即便限制了操作,最终还是全要由手工处理。 换句话说,内部库和扩展库必需完全兼容,如果不能,“脏”操作中途就不再传染, 安全便会就此终止。实际上,经常有这种漏洞报出。基于这个原因,我也不太信任它。 56 | 57 | 当然,这并不是说所有的Ruby程序都是危险的。即便是$SAFE=0, 也可能写出安全程序,即便是$SAFE=4,也可能写出为所欲为的程序。 简单说来,你(还)不能对$SAFE抱有过度的信任。 58 | 59 | 首先,“添加功能”和“安全”并不兼容。添加新特性同打开漏洞是成正比的, 这是一个常识。因此,我们应该假定ruby也可能是危险的。 60 | 61 | ## 实现 62 | ---- 63 | 64 | 从这开始,我们进入实现部分,为了从机制上完全地理解ruby安全系统,我们必须要注意“在哪里检查?”。 然而,这次没有页面讨论这个问题,当然,我们也不会仅仅满足于将它们一一列出。 在本章结束前,我们来解释一下安全检查的机制。用于检查的API主要有以下两个。 65 | 66 | - rb_secure(n),如果安全级别是n或是更大的时候,抛出异常SecurityError 67 | - SafeStringValue(),如果安全级别是1或更大,而且字符串已感染,抛出异常。 68 | 69 | SafeStringValue()就不在这里讨论了。 70 | 71 | ### 脏标记 72 | 73 | 脏标记实际存放在basic->flags中,标志为FL_TAINT, 可以使用宏OBJ_INFECT()完成传染。用法如下: 74 | {% highlight ruby %} 75 | OBJ_TAINT(obj) /* 给obj附上FL_TAINT标志 */ 76 | OBJ_TAINTED(obj) /* 确认obj是否附上了FL_TAINT标志 */ 77 | OBJ_INFECT(dest, src) /* 从src到dest传染FL_TAINT标志 */ 78 | {% endhighlight %} 79 | 80 | 抛开OBJ_TAINT()、OBJ_TAINTED(),我们这里只看一下OBJ_INFECT()。 81 | {% highlight ruby %} 82 | ▼ OBJ_INFECT 83 | 84 | 441 #define OBJ_INFECT(x,s) do { \ 85 | if (FL_ABLE(x) && FL_ABLE(s)) \ 86 | RBASIC(x)->flags |= RBASIC(s)->flags & FL_TAINT; \ 87 | } while (0) 88 | 89 | (ruby.h) 90 | {% endhighlight %} 91 | FL_ABLE()用来确认传入参数VALUE是否为指针。 只有双方都是指针(也就是有flags成员),标志才会传播。 92 | 93 | ### $SAFE 94 | 95 | {% highlight ruby %} 96 | ▼ ruby_safe_level 97 | 98 | 124 int ruby_safe_level = 0; 99 | 100 | 7401 static void 101 | 7402 safe_setter(val) 102 | 7403 VALUE val; 103 | 7404 { 104 | 7405 int level = NUM2INT(val); 105 | 7406 106 | 7407 if (level < ruby_safe_level) { 107 | 7408 rb_raise(rb_eSecurityError, "tried to downgrade safe level from %d to %d", 108 | 7409 ruby_safe_level, level); 109 | 7410 } 110 | 7411 ruby_safe_level = level; 111 | 7412 curr_thread->safe = level; 112 | 7413 } 113 | 114 | (eval.c) 115 | {% endhighlight %} 116 | $SAFE的实体是eval.c的ruby_safe_level。如前所述,$SAFE是线程所有的, 所以,需要放在“实现了线程”的eval.c中。也就是说,本来放在别的地方会更好, 因为C语言的关系,只能把它写在eval.c里。 117 | 118 | safe_setter()是全局变量$SAFE的setter。也就是说,在Ruby层次上, 只能通过这个函数进行访问,这样,就不可能降低安全级别。 119 | 120 | 但是,如你所见,ruby_safe_level没有static修饰符,因此,在C层次上, 完全可以无视接口的存在,直接对安全级别进行修改。 121 | 122 | ### rb_secure() 123 | {% highlight ruby %} 124 | ▼ rb_secure() 125 | 126 | 136 void 127 | 137 rb_secure(level) 128 | 138 int level; 129 | 139 { 130 | 140 if (level <= ruby_safe_level) { 131 | 141 rb_raise(rb_eSecurityError, "Insecure operation `%s' at level %d", 132 | 142 rb_id2name(ruby_frame->last_func), ruby_safe_level); 133 | 143 } 134 | 144 } 135 | (eval.c) 136 | {% endhighlight %} 137 | 138 | 如果当前的安全级别是level或者更大,就会抛出异常SecurityError。很简单。 139 | -------------------------------------------------------------------------------- /zh/20-fin.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | --- 4 | 5 | h1. Final Chapter: Ruby's future 6 | 7 | h2. Issues to be addressed 8 | 9 | @ruby@ isn't 'completely finished' software. It's still being developed, 10 | there are still a lot of issues. Firstly, we want to try removing 11 | inherent problems in the current interpreter. 12 | 13 | The order of the topics is mostly in the same order as the chapters of 14 | this book. 15 | 16 | 17 | h3. Performance of GC 18 | 19 | The performance of the current GC might be 20 | "not notably bad, but not notably good". 21 | "not notably bad" means "it won't cause troubles in our daily life", 22 | and "not notably good" means "its downside will be exposed under heavy load". 23 | For example, if it is an application which creates plenty of objects and keeps 24 | holding them, its speed would slow down radically. 25 | Every time doing GC, it needs to mark all of the objects, 26 | and furthermore it would becomes to need to invoke GC more often 27 | because it can't collect them. 28 | To counter this problem, Generational GC, which was mentioned in Chapter 5, 29 | must be effective. (At least, it is said so in theory.) 30 | 31 | Also regarding its response speed, 32 | there are still rooms we can improve. 33 | With the current GC, while it is running, the entire interpretor stops. 34 | Thus, when the program is an editor or a GUI application, 35 | sometimes it freezes and stops to react. 36 | Even if it's just 0.1 second, 37 | stopping when typing characters would give a very bad impression. 38 | Currently, there are few such applications created or, 39 | even if exists, its size might be enough small not to expose this problem. 40 | However, if such application will actually be created in the future, 41 | there might be the necessity to consider Incremental GC. 42 | 43 | 44 | h3. Implementation of parser 45 | 46 | As we saw in Part 2, the implementation of @ruby@ parser has already utilized 47 | @yacc@'s ability to almost its limit, thus I can't think it can endure further 48 | expansions. It's all right if there's nothing planned to expand, 49 | but a big name "keyword argument" is planned next 50 | and it's sad if we could not express another demanded grammar because of the 51 | limitation of @yacc@. 52 | 53 | 54 | h3. Reuse of parser 55 | 56 | Ruby's parser is very complex. In particular, dealing with around @lex_state@ 57 | seriously is very hard. Due to this, embedding a Ruby program or creating a 58 | program to deal with a Ruby program itself is quite difficult. 59 | 60 | For example, I'm developing a tool named @racc@, 61 | which is prefixed with R because it is a Ruby-version @yacc@. 62 | With @racc@, the syntax of grammar files are almost the same as @yacc@ 63 | but we can write actions in Ruby. 64 | To do so, it could not determine the end of an action without parsing Ruby code 65 | properly, but "properly" is very difficult. Since there's no other choice, 66 | currently I've compromised at the level that it can parse "almost all". 67 | 68 | As another example which requires analyzing Ruby program, 69 | I can enumerate some tools like @indent@ and @lint@, 70 | but creating such tool also requires a lot efforts. 71 | It would be desperate if it is something complex like a refactoring tool. 72 | 73 | Then, what can we do? If we can't recreate the same thing, 74 | what if @ruby@'s original parser can be used as a component? 75 | In other words, making the parser itself a library. 76 | This is a feature we want by all means. 77 | 78 | However, what becomes problem here is, as long as @yacc@ is used, 79 | we cannot make parser reentrant. 80 | It means, say, we cannot call @yyparse()@ recursively, 81 | and we cannot call it from multiple threads. 82 | Therefore, it should be implemented in the way of not returning control to Ruby 83 | while parsing. 84 | 85 | 86 | 87 | h3. Hiding Code 88 | 89 | With current @ruby@, it does not work without the source code of the program to 90 | run. Thus, people who don't want others to read their source code might have 91 | trouble. 92 | 93 | 94 | h3. Interpretor Object 95 | 96 | Currently each process cannot have multiple @ruby@ interpretors, 97 | this was discussed in Chapter 13. 98 | If having multiple interpretors is practically possible, it seems better, 99 | but is it possible to implement such thing? 100 | 101 | 102 | h3. The structure of evaluator 103 | 104 | Current @eval.c@ is, above all, too complex. 105 | Embedding Ruby's stack frames to machine stack could occasionally become the 106 | source of trouble, using @setjmp() longjmp()@ aggressively makes it less easy to 107 | understand and slows down its speed. 108 | Particularly with RISC machine, which has many registers, using @setjmp()@ 109 | aggressively can easily cause slowing down because @setjmp()@ set aside all 110 | things in registers. 111 | 112 | 113 | h3. The performance of evaluator 114 | 115 | @ruby@ is already enough fast for ordinary use. 116 | But aside from it, regarding a language processor, 117 | definitely the faster is the better. 118 | To achieve better performance, in other words to optimize, 119 | what can we do? 120 | In such case, the first thing we have to do is profiling. 121 | So I profiled. 122 | 123 |
124 |   %   cumulative   self              self     total
125 |  time   seconds   seconds    calls  ms/call  ms/call  name
126 |  20.25      1.64     1.64  2638359     0.00     0.00  rb_eval
127 |  12.47      2.65     1.01  1113947     0.00     0.00  ruby_re_match
128 |   8.89      3.37     0.72  5519249     0.00     0.00  rb_call0
129 |   6.54      3.90     0.53  2156387     0.00     0.00  st_lookup
130 |   6.30      4.41     0.51  1599096     0.00     0.00  rb_yield_0
131 |   5.43      4.85     0.44  5519249     0.00     0.00  rb_call
132 |   5.19      5.27     0.42   388066     0.00     0.00  st_foreach
133 |   3.46      5.55     0.28  8605866     0.00     0.00  rb_gc_mark
134 |   2.22      5.73     0.18  3819588     0.00     0.00  call_cfunc
135 | 
136 | 137 | This is a profile when running some application but 138 | this is approximately the profile of a general Ruby program. 139 | @rb_eval()@ appeared in the overwhelming percentage being at the top, 140 | after that, in addition to functions of GC, evaluator core, 141 | functions that are specific to the program are mixed. 142 | For example, in the case of this application, 143 | it takes a lot of time for regular expression match (@ruby_re_match@). 144 | 145 | However, even if we understood this, the question is how to improve it. 146 | To think simply, it can be archived by making @rb_eval()@ faster. 147 | That said, but as for @ruby@ core, there are almost not any room which can be 148 | easily optimized. For instance, apparently "tail recursive -> @goto@ conversion" 149 | used in the place of @NODE_IF@ and others has already applied almost all 150 | possible places it can be applied. 151 | In other words, without changing the way of thinking fundamentally, 152 | there's no room to improve. 153 | 154 | 155 | h3. The implementation of thread 156 | 157 | This was also discussed in Chapter 19. There are really a lot of issues about 158 | the implementation of the current ruby's thread. Particularly, it cannot mix 159 | with native threads so badly. The two great advantages of @ruby@'s thread, 160 | (1) high portability (2) the same behavior everywhere, 161 | are definitely incomparable, but probably that implementation is something we 162 | cannot continue to use eternally, isn't it? 163 | 164 | 165 | 166 | 167 | h2. `ruby` 2 168 | 169 | Subsequently, on the other hand, I'll introduce the trend of the original `ruby`, 170 | how it is trying to counter these issues. 171 | 172 | 173 | h3. Rite 174 | 175 | At the present time, ruby's edge is 1.6.7 as the stable version and 1.7.3 as the 176 | development version, but perhaps the next stable version 1.8 will come out in 177 | the near future. Then at that point, the next development version 1.9.0 will 178 | start at the same time. And after that, this is a little irregular but 1.9.1 179 | will be the next stable version. 180 | 181 | |_. stable |_. development |_. when to start | 182 | | 1.6.x | 1.7.x | 1.6.0 was released on 2000-09-19 | 183 | | 1.8.x | 1.9.x | probably it will come out within 6 months | 184 | | 1.9.1~ | 2.0.0 | maybe about 2 years later | 185 | 186 | 187 | And the next-to-next generational development version is `ruby` 2, whose code 188 | name is Rite. Apparently this name indicates a respect for the inadequacy that 189 | Japanese cannot distinguish the sounds of L and R. 190 | 191 | What will be changed in 2.0 is, in short, almost all the entire core. 192 | Thread, evaluator, parser, all of them will be changed. 193 | However, nothing has been written as a code yet, so things written here is 194 | entirely just a "plan". If you expect so much, it's possible it will turn out 195 | disappointments. Therefore, for now, let's just expect slightly. 196 | 197 | 198 | h3. The language to write 199 | 200 | Firstly, the language to use. Definitely it will be C. Mr. Matsumoto said to 201 | `ruby-talk`, which is the English mailing list for Ruby, 202 | 203 |
204 | I hate C++. 205 |
206 | 207 | So, C++ is most unlikely. Even if all the parts will be recreated, 208 | it is reasonable that the object system will remain almost the same, 209 | so not to increase extra efforts around this is necessary. 210 | However, chances are good that it will be ANSI C next time. 211 | 212 | 213 | h3. GC 214 | 215 | Regarding the implementation of GC, 216 | the good start point would be 217 | `Boehm GC`\footnote{Boehm GC `http://www.hpl.hp.com/personal/Hans_Boehm/gc`}. 218 | Bohem GC is a conservative and incremental and generational GC, 219 | furthermore, it can mark all stack spaces of all threads even while native 220 | threads are running. It's really an impressive GC. 221 | Even if it is introduced once, it's hard to tell whether it will be used 222 | perpetually, but anyway it will proceed for the direction to which we can expect 223 | somewhat improvement on speed. 224 | 225 | 226 | h3. Parser 227 | 228 | Regarding the specification, it's very likely that the nested method calls 229 | without parentheses will be forbidden. As we've seen, `command_call` has a great 230 | influence on all over the grammar. If this is simplified, both the parser and 231 | the scanner will also be simplified a lot. 232 | However, the ability to omit parentheses itself will never be disabled. 233 | 234 | And regarding its implementation, whether we continue to use `yacc` is still 235 | under discussion. If we won't use, it would mean hand-writing, but is it 236 | possible to implement such complex thing by hand? Such anxiety might left. 237 | Whichever way we choose, the path must be thorny. 238 | 239 | 240 | h3. Evaluator 241 | 242 | The evaluator will be completely recreated. 243 | Its aims are mainly to improve speed and to simplify the implementation. 244 | There are two main viewpoints: 245 | 246 | 247 | * remove recursive calls like `rb_eval()` 248 | * switch to a bytecode interpretor 249 | 250 | First, removing recursive calls of `rb_eval()`. The way to remove is, 251 | maybe the most intuitive explanation is that it's like the "tail recursive -> 252 | `goto` conversion". Inside a single `rb_eval()`, circling around by using 253 | `goto`. That decreases the number of function calls and removes the necessity of 254 | `setjmp()` that is used for `return` or `break`. 255 | However, when a function defined in C is called, calling a function is 256 | inevitable, and at that point `setjmp()` will still be required. 257 | 258 | 259 | Bytecode is, in short, something like a program written in machine language. 260 | It became famous because of the virtual machine of Smalltalk90, 261 | it is called bytecode because each instruction is one-byte. 262 | For those who are usually working at more abstract level, byte would seem 263 | so natural basis in size to deal with, 264 | but in many cases each instruction consists of bits in machine languages. 265 | For example, in Alpha, among a 32-bit instruction code, the beginning 6-bit 266 | represents the instruction type. 267 | 268 | 269 | The advantage of bytecode interpretors is mainly for speed. There are two 270 | reasons: Firstly, unlike syntax trees, there's no need to traverse pointers. 271 | Secondly, it's easy to do peephole optimization. 272 | 273 | 274 | And in the case when bytecode is saved and read in later, 275 | because there's no need to parse, we can naturally expect better performance. 276 | However, parsing is a procedure which is done only once at the beginning of a 277 | program and even currently it does not take so much time. Therefore, its 278 | influence will not be so much. 279 | 280 | 281 | If you'd like to know about how the bytecode evaluator could be, 282 | `regex.c` is worth to look at. 283 | For another example, Python is a bytecode interpretor. 284 | 285 | 286 | 287 | 288 | h3. Thread 289 | 290 | Regarding thread, the thing is native thread support. 291 | The environment around thread has been significantly improved, 292 | comparing with the situation in 1994, the year of Ruby's birth. 293 | So it might be judged that 294 | we can get along with native thread now. 295 | 296 | 297 | Using native thread means being preemptive also at C level, 298 | thus the interpretor itself must be multi-thread safe, 299 | but it seems this point is going to be solved by using a global lock 300 | for the time being. 301 | 302 | 303 | Additionally, that somewhat arcane "continuation", it seems likely to be removed. 304 | `ruby`'s continuation highly depends on the implementation of thread, 305 | so naturally it will disappear if thread is switched to native thread. 306 | The existence of that feature is because "it can be implemented" 307 | and it is rarely actually used. Therefore there might be no problem. 308 | 309 | 310 | 311 | h3. M17N 312 | 313 | In addition, I'd like to mention a few things about class libraries. 314 | This is about multi-lingualization (M17N for short). 315 | What it means exactly in the context of programming is 316 | being able to deal with multiple character encodings. 317 | 318 | 319 | `ruby` with Multi-lingualization support has already implemented and you can 320 | obtain it from the `ruby_m17m` branch of the CVS repository. 321 | It is not absorbed yet because it is judged that its specification is immature. 322 | If good interfaces is designed, 323 | it will be absorbed at some point in the middle of 1.9. 324 | 325 | 326 | 327 | 328 | h3. IO 329 | 330 | 331 | The `IO` class in current Ruby is a simple wrapper of `stdio`, 332 | but in this approach, 333 | 334 | * there are too many but slight differences between various platforms. 335 | * we'd like to have finer control on buffers. 336 | 337 | these two points cause complaints. 338 | Therefore, it seems Rite will have its own `stdio`. 339 | 340 | 341 | 342 | 343 | 344 | 345 | h2. Ruby Hacking Guide 346 | 347 | 348 | So far, we've always acted as observers who look at `ruby` from outside. 349 | But, of course, `ruby` is not a product which displayed in in a showcase. 350 | It means we can influence it if we take an action for it. 351 | In the last section of this book, 352 | I'll introduce the suggestions and activities for `ruby` from community, 353 | as a farewell gift for Ruby Hackers both at present and in the future. 354 | 355 | 356 | h3. Generational GC 357 | 358 | First, as also mentioned in Chapter 5, 359 | the generational GC made by Mr. Kiyama Masato. 360 | As described before, with the current patch, 361 | 362 | * it is less fast than expected. 363 | * it needs to be updated to fit the edge `ruby` 364 | 365 | these points are problems, but here I'd like to highly value it because, 366 | more than anything else, it was the first large non-official patch. 367 | 368 | 369 | 370 | 371 | h3. Oniguruma 372 | 373 | The regular expression engine used by current Ruby is a remodeled version of GNU 374 | regex. That GNU regex was in the first place written for Emacs. And then it was 375 | remodeled so that it can support multi-byte characters. And then Mr. Matsumoto 376 | remodeled so that it is compatible with Perl. 377 | As we can easily imagine from this history, 378 | its construction is really intricate and spooky. 379 | Furthermore, due to the LPGL license of this GNU regex, 380 | the license of `ruby` is very complicated, 381 | so replacing this engine has been an issue from a long time ago. 382 | 383 | What suddenly emerged here is the regular expression engine "Oniguruma" by 384 | Mr. K. Kosako. I heard this is written really well, it is likely being 385 | absorbed as soon as possible. 386 | 387 | You can obtain Oniguruma from the `ruby`'s CVS repository in the following way. 388 | 389 |
390 | % cvs -d :pserver:anonymous@cvs.ruby-lang.org:/src co oniguruma
391 | 
392 | 393 | 394 | 395 | h3. ripper 396 | 397 | Next, ripper is my product. It is an extension library made by remodeling 398 | `parse.y`. It is not a change applied to the `ruby`'s main body, but I 399 | introduced it here as one possible direction to make the parser a component. 400 | 401 | It is implemented with kind of streaming interface and 402 | it can pick up things such as token scan or parser's reduction as events. 403 | It is put in the attached CD-ROM 404 | \footnote{ripper:`archives/ripper-0.0.5.tar.gz` of the attached CD-ROM}, 405 | so I'd like you to give it a try. 406 | Note that the supported grammar is a little different from the current one 407 | because this version is based on `ruby` 1.7 almost half-year ago. 408 | 409 | I created this just because "I happened to come up with this idea", 410 | if this is accounted, I think it is constructed well. 411 | It took only three days or so to implement, really just a piece of cake. 412 | 413 | 414 | h3. A parser alternative 415 | 416 | This product has not yet appeared in a clear form, 417 | there's a person who write a Ruby parser in C++ which can be used totally 418 | independent of `ruby`. (`[ruby-talk:50497]`). 419 | 420 | 421 | h3. JRuby 422 | 423 | More aggressively, there's an attempt to rewrite entire the interpretor. 424 | For example, a Ruby written in Java, 425 | Ruby\footnote{JRuby `http://jruby.sourceforge.net`}, 426 | has appeared. 427 | It seems it is being implemented by a large group of people, 428 | Mr. Jan Arne Petersen and many others. 429 | 430 | 431 | I tried it a little and as my reviews, 432 | 433 | * the parser is written really well. It does precisely handle even finer 434 | behaviors such as spaces or here document. 435 | * `instance_eval` seems not in effect (probably it couldn't be helped). 436 | * it has just a few built-in libraries yet (couldn't be helped as well). 437 | * we can't use extension libraries with it (naturally). 438 | * because Ruby's UNIX centric is all cut out, 439 | there's little possibility that we can run already-existing scripts without 440 | any change. 441 | * slow 442 | 443 | perhaps I could say at least these things. 444 | Regarding the last one "slow", its degree is, 445 | the execution time it takes is 20 times longer than the one of the original 446 | `ruby`. Going this far is too slow. 447 | It is not expected running fast because that Ruby VM runs on Java VM. 448 | Waiting for the machine to become 20 times faster seems only way. 449 | 450 | 451 | However, the overall impression I got was, it's way better than I imagined. 452 | 453 | 454 | 455 | h3. NETRuby 456 | 457 | If it can run with Java, it should also with C#. 458 | Therefore, a Ruby written in C# appeared, 459 | "NETRuby\footnote{NETRuby `http://sourceforge.jp/projects/netruby/`}". 460 | The author is Mr. arton. 461 | 462 | Because I don't have any .NET environment at hand, 463 | I checked only the source code, 464 | but according to the author, 465 | 466 | * more than anything, it's slow 467 | * it has a few class libraries 468 | * the compatibility of exception handling is not good 469 | 470 | such things are the problems. 471 | But `instance_eval` is in effect (astounding!). 472 | 473 | 474 | h3. How to join `ruby` development 475 | 476 | `ruby`'s developer is really Mr. Matsumoto as an individual, 477 | regarding the final decision about the direction `ruby` will take, 478 | he has the definitive authority. 479 | But at the same time, `ruby` is an open source software, 480 | anyone can join the development. 481 | Joining means, you can suggest your opinions or send patches. 482 | The below is to concretely tell you how to join. 483 | 484 | In `ruby`'s case, the mailing list is at the center of the development, 485 | so it's good to join the mailing list. 486 | The mailing lists currently at the center of the community are three: 487 | `ruby-list`, `ruby-dev`, `ruby-talk`. 488 | `ruby-list` is a mailing list for "anything relating to Ruby" in Japanese. 489 | `ruby-dev` is for the development version `ruby`, this is also in Japanese. 490 | `ruby-talk` is an English mailing list. 491 | The way to join is shown on the page "mailing lists" at Ruby's official site 492 | \footnote{Ruby's official site: `http://www.ruby-lang.org/ja/`}. 493 | For these mailing lists, read-only people are also welcome, 494 | so I recommend just joining first and watching discussions 495 | to grasp how it is. 496 | 497 | Though Ruby's activity started in Japan, 498 | recently sometimes it is said "the main authority now belongs to `ruby-talk`". 499 | But the center of the development is still `ruby-dev`. 500 | Because people who has the commit right to `ruby` (e.g. core members) are mostly 501 | Japanese, the difficulty and reluctance of using English 502 | naturally lead them to `ruby-dev`. 503 | If there will be more core members who prefer to use English, 504 | the situation could be changed, 505 | but meanwhile the core of `ruby`'s development might remain `ruby-dev`. 506 | 507 | However, it's bad if people who cannot speak Japanese cannot join the 508 | development, so currently the summary of `ruby-dev` is translated once a week 509 | and posted to `ruby-talk`. 510 | I also help that summarising, but only three people do it in turn now, 511 | so the situation is really harsh. 512 | The members to help summarize is always in demand. 513 | If you think you're the person who can help, 514 | I'd like you to state it at `ruby-list`. 515 | 516 | And as the last note, 517 | only its source code is not enough for a software. 518 | It's necessary to prepare various documents and maintain web sites. 519 | And people who take care of these kind of things are always in short. 520 | There's also a mailing list for the document-related activities, 521 | but as the first step you just have to propose "I'd like to do something" to `ruby-list`. 522 | I'll answer it as much as possible, 523 | and other people would respond to it, too. 524 | 525 | 526 | h3. Finale 527 | 528 | The long journey of this book is going to end now. 529 | As there was the limitation of the number of pages, 530 | explaining all of the parts comprehensively was impossible, 531 | however I told everything I could tell about the `ruby`'s core. 532 | I won't add extra things any more here. 533 | If you still have things you didn't understand, 534 | I'd like you to investigate it by reading the source code by yourself as much as 535 | you want. 536 | -------------------------------------------------------------------------------- /zh/liquid.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: liquid模板语言 4 | --- 5 | 来自: [Liquid for Designers][liquid] 6 | 7 | ##缘起 8 | ---- 9 | Jekyll使用Liquid模板,因此,想要用好Jekyll,需要了解一些关于Liquid相关的知识。本文翻译自[Liquid for Designers][liquid],用作自己学习参考。 10 | 11 | 12 | Liquid中存在两种类型的标签(markup): Output and Tag 13 | - Output markup (which may resolve to text) is surrounded by 14 | 15 | > {% raw %} {{ 匹配成对出现的大括号 }} {% endraw %} 16 | 17 | - Tag markup (which cannot resolve to text) is surrounded by 18 | 19 | > {% raw %} {% 匹配成对出现的大括号以及百分号 %} {% endraw %} 20 | 21 | ## Output 22 | ---- 23 | 24 | Here is a simple example of Output: 25 | 下面是一些Output标签的简单例子: 26 | Hello {{name}} 27 | Hello {{user.name}} 28 | Hello {{ 'tobi' }} 29 | Hello ,this is {{site.title}} 30 | 31 | ### 高级Output标签:过滤器(Filters) 32 | 33 | Output markup takes filters. Filters are simple methods. The first parameter is always the output of the left side of the filter. The return value of the filter will be the new left value when the next filter is run. When there are no more filters, the template will receive the resulting string. 34 | 35 | Output标签中可以使用过滤器。所谓的过滤器,其实就是一些简单的方法。过滤器总是将左边输出作为第一个参数,其返回值将作为下一个过滤器的输入。一旦处理结束,即没有更多的过滤器时,模板处理器将接受最后的处理结果(字符串)。 36 | 37 | 示例如下: 38 | {% raw %} 39 | Hello {{ 'tobi' | upcase }} 40 | Hello tobi has {{ 'tobi' | size }} letters! 41 | Hello {{ '*tobi*' | textilize | upcase }} 42 | Hello {{ 'now' | date: "%Y %h" }} 43 | {% endraw %} 44 | 45 | 处理结果为: 46 | 47 | Hello {{ 'tobi' | upcase }} 48 | Hello tobi has {{ 'tobi' | size }} letters! 49 | Hello {{ '*tobi*' | textilize | upcase }} 50 | Hello {{ 'now' | date: "%Y %h" }} 51 | 52 | ### 标准过滤器(Standard Filters) 53 | 54 | date - 格式化日期 (syntax reference) 55 | capitalize - 将输入句子中的单词大写 56 | downcase - 将输入字符串转为小写 57 | upcase - 将输入字符串转为大写 58 | first - 获取传递的数组中的第一个元素get the first element of the passed in array 59 | last - 获取传递的数组中的最后一个元素 60 | join - join elements of the array with certain character between them 61 | sort - 数组元素排序 62 | map - map/collect an array on a given property 63 | size - 返回字符串或者数组的大小 64 | escape - 转义字符串 65 | escape_once - 返回转义版的html,并且不影响已存在的转义实体(escaped entities) 66 | strip_html - 剔除字符串中的html(strip html from string) 67 | strip_newlines - 剔除字符串中所有的换行符(\n) 68 | newline_to_br - 将字符串中换行符替换成html断行(
) 69 | replace - replace each occurrence e.g. {{ 'foofoo' | replace:'foo','bar' }} #=> 'barbar' 70 | replace_first - replace the first occurrence e.g. {{ 'barbar' | replace_first:'bar','foo' }} #=> 'foobar' 71 | remove - remove each occurrence e.g. {{ 'foobarfoobar' | remove:'foo' }} #=> 'barbar' 72 | remove_first - remove the first occurrence e.g. {{ 'barbar' | remove_first:'bar' }} #=> 'bar' 73 | truncate - 将字符串截断为x个字符 74 | truncatewords - 将字符串截断为x个字(主要用来处理多字符的字,比如CKJ的字符集) 75 | prepend - 向前追加一个字符串 例如: {{ 'bar' | prepend:'foo' }} #=> 'foobar' 76 | append - 向后追加一个字符串 e.g. {{ 'foo' | append:'bar' }} #=> 'foobar' 77 | minus - 减subtraction e.g. {{ 4 | minus:2 }} #=> 2 78 | plus - 加addition e.g. {{ '1' | plus:'1' }} #=> '11', {{ 1 | plus:1 }} #=> 2 79 | times - 乘multiplication e.g {{ 5 | times:4 }} #=> 20 80 | divided_by - 除division e.g. {{ 10 | divided_by:2 }} #=> 5 81 | split - 以给定的模式分隔字符串 e.g. {{ "a~b" | split:"~" }} #=> ['a','b'] 82 | modulo - 求余remainder, e.g. {{ 3 | modulo:2 }} #=> 1 83 | 84 | ## Tags 85 | ---- 86 | 87 | Tags are used for the logic in your template. New tags are very easy to code, so I hope to get many contributions to the standard tag library after releasing this code. 88 | 89 | Tags标签用作模板的逻辑。Tag实现很简单,所以很容易扩展出新的Tag。所以,原作者希望在发布Liquid之后,能有更多贡献者的编写tag并添加到tab库中。 90 | 91 | Here is a list of currently supported tags: 92 | 如下是当前支持的一些标签: 93 | 94 | assign - 赋值给某个变量Assigns some value to a variable 95 | capture - 可江文本捕获到变量中的块标签 Block tag that captures text into a variable 96 | case - Block tag, its the standard case...when block 97 | comment - Block tag, comments out the text in the block 98 | cycle - Cycle is usually used within a loop to alternate between values, like colors or DOM classes. 99 | for - For loop 100 | if - Standard if/else block 101 | include - Includes another template; useful for partials 102 | raw - temporarily disable tag processing to avoid syntax conflicts. 103 | unless - Mirror of if statement 104 | 105 | ### Comments 106 | 107 | Comment is the simplest tag. It just swallows content. 108 | {% raw %} 109 | We made 1 million dollars {% comment %} in losses {% endcomment %} this year 110 | {% endraw %} 111 | 112 | We made 1 million dollars {% comment %} in losses {% endcomment %} this year 113 | 114 | ### Raw 115 | 116 | Raw temporarily disables tag processing. This is useful for generating content (eg, Mustache, Handlebars) which uses conflicting syntax. 117 | 118 | >{% raw %} 119 | > In Handlebars, {{ this }} will be HTML-escaped, but {{{ that }}} will not. 120 | >{% endraw %} 121 | 122 | ### If / Else 123 | 124 | if / else should be well-known from any other programming language. Liquid allows you to write simple expressions in the if or unless (and optionally, elsif and else) clause: 125 | 126 | {% raw %} 127 | {% if user %} 128 | Hello {{ user.name }} 129 | {% endif %} 130 | 131 | # Same as above 132 | {% if user != null %} 133 | Hello {{ user.name }} 134 | {% endif %} 135 | 136 | {% if user.name == 'tobi' %} 137 | Hello tobi 138 | {% elsif user.name == 'bob' %} 139 | Hello bob 140 | {% endif %} 141 | 142 | {% if user.name == 'tobi' or user.name == 'bob' %} 143 | Hello tobi or bob 144 | {% endif %} 145 | 146 | {% if user.name == 'bob' and user.age > 45 %} 147 | Hello old bob 148 | {% endif %} 149 | 150 | {% if user.name != 'tobi' %} 151 | Hello non-tobi 152 | {% endif %} 153 | 154 | # Same as above 155 | {% unless user.name == 'tobi' %} 156 | Hello non-tobi 157 | {% endunless %} 158 | 159 | # Check for the size of an array 160 | {% if user.payments == empty %} 161 | you never paid ! 162 | {% endif %} 163 | 164 | {% if user.payments.size > 0 %} 165 | you paid ! 166 | {% endif %} 167 | 168 | {% if user.age > 18 %} 169 | Login here 170 | {% else %} 171 | Sorry, you are too young 172 | {% endif %} 173 | 174 | # array = 1,2,3 175 | {% if array contains 2 %} 176 | array includes 2 177 | {% endif %} 178 | 179 | # string = 'hello world' 180 | {% if string contains 'hello' %} 181 | string includes 'hello' 182 | {% endif %} 183 | {% endraw %} 184 | 185 | ### Case Statement 186 | 187 | If you need more conditions, you can use the case statement: 188 | 如果需要更多的条件,可以使用case语句: 189 | 190 | {% raw %} 191 | {% case condition %} 192 | {% when 1 %} 193 | hit 1 194 | {% when 2 or 3 %} 195 | hit 2 or 3 196 | {% else %} 197 | ... else ... 198 | {% endcase %} 199 | {% endraw %} 200 | 201 | Example: 202 | 203 | {% raw %} 204 | {% case template %} 205 | 206 | {% when 'label' %} 207 | // {{ label.title }} 208 | {% when 'product' %} 209 | // {{ product.vendor | link_to_vendor }} / {{ product.title }} 210 | {% else %} 211 | // {{page_title}} 212 | {% endcase %} 213 | {% endraw %} 214 | 215 | ### Cycle 216 | 217 | Often you have to alternate between different colors or similar tasks. Liquid has built-in support for such operations, using the cycle tag. 218 | 219 | {% raw %} 220 | {% cycle 'one', 'two', 'three' %} 221 | {% cycle 'one', 'two', 'three' %} 222 | {% cycle 'one', 'two', 'three' %} 223 | {% cycle 'one', 'two', 'three' %} 224 | {% endraw %} 225 | 226 | will result in 227 | 228 | one 229 | two 230 | three 231 | one 232 | 233 | If no name is supplied for the cycle group, then it's assumed that multiple calls with the same parameters are one group. 234 | 235 | If you want to have total control over cycle groups, you can optionally specify the name of the group. This can even be a variable. 236 | 237 | {% raw %} 238 | {% cycle 'group 1': 'one', 'two', 'three' %} 239 | {% cycle 'group 1': 'one', 'two', 'three' %} 240 | {% cycle 'group 2': 'one', 'two', 'three' %} 241 | {% cycle 'group 2': 'one', 'two', 'three' %} 242 | {% endraw %} 243 | 244 | will result in 245 | 246 | one 247 | two 248 | one 249 | two 250 | 251 | ### For loops 252 | 253 | Liquid allows for loops over collections: 254 | Liquid同样允许对集合应用循环: 255 | 256 | {% raw %} 257 | {% for item in array %} 258 | {{ item }} 259 | {% endfor %} 260 | {% endraw %} 261 | When iterating a hash, item[0] contains the key, and item[1] contains the value: 262 | 如果对哈希表进行迭代,item[0]表示键,item[1]表示键所对应的值: 263 | 264 | {% raw %} 265 | {% for item in hash %} 266 | {{ item[0] }}: {{ item[1] }} 267 | {% endfor %} 268 | {% endraw %} 269 | During every for loop, the following helper variables are available for extra styling needs: 270 | 在每次循环中,提供如下的辅助变量以供特殊的样式需求: 271 | 272 | forloop.length # => length of the entire for loop 273 | forloop.index # => index of the current iteration 274 | forloop.index0 # => index of the current iteration (zero based) 275 | forloop.rindex # => how many items are still left? 276 | forloop.rindex0 # => how many items are still left? (zero based) 277 | forloop.first # => is this the first iteration? 278 | forloop.last # => is this the last iteration? 279 | 280 | There are several attributes you can use to influence which items you receive in your loop 281 | 282 | limit:int lets you restrict how many items you get. offset:int lets you start the collection with the nth item. 283 | 284 | {% raw %} 285 | # array = [1,2,3,4,5,6] 286 | {% for item in array limit:2 offset:2 %} 287 | {{ item }} 288 | {% endfor %} 289 | # results in 3,4 290 | {% endraw %} 291 | 292 | ### Reversing the loop 293 | 294 | {% for item in collection reversed %} {{item}} {% endfor %} 295 | 296 | Instead of looping over an existing collection, you can define a range of numbers to loop through. The range can be defined by both literal and variable numbers: 297 | 298 | {% raw %} 299 | # if item.quantity is 4... 300 | {% for i in (1..item.quantity) %} 301 | {{ i }} 302 | {% endfor %} 303 | # results in 1,2,3,4 304 | {% endraw %} 305 | 306 | ### Variable Assignment 307 | 308 | You can store data in your own variables, to be used in output or other tags as desired. The simplest way to create a variable is with the assign tag, which has a pretty straightforward syntax: 309 | 310 | 可以将数据存放在自己设定的变量里,然后output标签或者tags标签中使用。最简单的创建变量的方法是通过`assign`标签,其语法简洁明了。 311 | 312 | {% raw %} 313 | {% assign name = 'freestyle' %} 314 | {% for t in collections.tags %}{% if t == name %} 315 |

Freestyle!

316 | {% endif %}{% endfor %} 317 | {% endraw %} 318 | 319 | Another way of doing this would be to assign true / false values to the variable: 320 | 上述代码的另一种处理方式是通过给变量赋 `true/false` 值: 321 | 322 | {% raw %} 323 | {% assign freestyle = false %} 324 | 325 | {% for t in collections.tags %}{% if t == 'freestyle' %} 326 | {% assign freestyle = true %} 327 | {% endif %}{% endfor %} 328 | 329 | {% if freestyle %} 330 |

Freestyle!

331 | {% endif %} 332 | {% endraw %} 333 | If you want to combine a number of strings into a single string and save it to a variable, you can do that with the `capture` tag. This tag is a block which "captures" whatever is rendered inside it, then assigns the captured value to the given variable instead of rendering it to the screen. 334 | 335 | 如果想要将一组字符串组合成单个字符串并将其包存到变量中,可以使用capture标签,该标签是一个捕获任何在其内部渲染的内容代码块,然后将其赋值到给定的变量而不是渲染到屏幕上。 336 | 337 | {% raw %} 338 | {% capture attribute_name %}{{ item.title | handleize }}-{{ i }}-color{% endcapture %} 339 | 340 | 341 | 346 | {% endraw %} 347 | 处理结果如下: 348 | {% capture attribute_name %}{{ item.title | handleize }}-{{ i }}-color{% endcapture %} 349 | 350 | 351 | 356 | 357 | ## 后记 358 | ---- 359 | Liquid模板还是相当的简洁好学的,剩下的就剩如何使用了。 360 | 361 | [liquid]: https://github.com/shopify/liquid/wiki/liquid-for-designers 362 | -------------------------------------------------------------------------------- /zh/markdown.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: Markdown语法小结 4 | --- 5 | 6 | ## 概述 7 | ---- 8 | 9 | Markdown的优点: 10 | 11 | - 纯文本,所以兼容性极强,可以用所有文本编辑器打开。 12 | - 让你专注于文字而不是排版。 13 | - 格式转换方便,Markdown 的文本你可以轻松转换为 html、电子书等。 14 | - Markdown 的标记语法有极好的可读性。 15 | 16 | ## 基本语法 17 | ---- 18 | 19 | 1.标题: 20 | #, ##, ###, ####, #####, ###### 分别代表

-

21 | 2.链接: 22 | 23 | - 文本链接 [title](url), 24 | - 脚注形式:即先在正文使用:[链接文字][链接引用标签],然后在文档末尾使用:[链接引用标签]: 链接地址 "链接标题" 25 | 比如: 26 | > I get 10 times more traffic from [Google] [1] than from 27 | [Yahoo] [2] or [MSN] [3]. 28 | 29 | [1]: http://google.com/ "Google" 30 | [2]: http://search.yahoo.com/ "Yahoo Search" 31 | [3]: http://search.msn.com/ "MSN Search" 32 | - 直接连接地址: 33 | - 图片 ![](imgurl) 34 | - 电子邮件: 35 | 36 | 3.换行:至少在一行后面连输2个空格。 37 | 38 | 4.列表: 39 | - 无序列表 - + * 都可以 40 | - xby 41 | * hahah 42 | 43 | - 有序列表:有序的列表则是使用一般的数字接着一个英文句点作为项目标记: 44 | 1. xby 45 | 2. hahah 46 | 47 | 5引用:> 48 | > xbaiasjksa 49 | 50 | 6.代码段 ``或使用四个空格缩进,或使用tab键缩进。所以注意,千万别在markdown中随意使用缩进,或tab键 51 | `import java.util.Date` 52 | 53 | 也可以这样: 54 | 55 | 这是一个普通段落: 56 | u 这是一个代码区块。 57 | 58 | Markdown 会转换成: 59 | 60 |

这是一个普通段落:

61 |
这是一个代码区块。
62 | 63 | 7.粗体斜体: 64 | **粗体**, *斜体* 65 | 66 | 8.表格: 67 | 68 | | Tables | Are | Cool | 69 | | ------------- |:-------------:| -----:| 70 | | col 3 is | right-aligned | $1600 | 71 | | col 2 is | centered | $12 | 72 | | zebra stripes | are neat | $1 | 73 | 74 | 9.水平分隔线: 75 | 几种形式如下: 76 | * * * 77 | *** 78 | ***** 79 | ---- 80 | - - - 81 | --------------------------------------- 82 | 效果大多相同: 83 | ----- 84 | 85 | 10.在markdown文件中使用html标签: 86 | 87 | Markdown 语法的目标是:成为一种适用于网络的书写语言。 88 | 89 | Markdown 不是想要取代 HTML,甚至也没有要和它相近,它的语法种类很少,只对应 HTML 标记的一小部分。Markdown 的构想不是要使得 HTML 文档更容易书写。在我看来, HTML 已经很容易写了。Markdown 的理念是,能让文档更容易读、写和随意改。HTML 是一种发布的格式,Markdown 是一种书写的格式。 90 | 91 | HTML 区块元素――比如
、、

等标签,必须在前后加上空行与其它内容区隔开,还要求它们的开始标签与结尾标签不能用制表符或空格来缩进。Markdown 的生成器有足够智能,不会在 HTML 区块标签外加上不必要的

标签。 92 | 93 | 例子如下,在 Markdown 文件里加上一段 HTML 表格: 94 | 95 | 这是一个普通段落。 96 | 97 |

98 | 99 | 100 | 101 |
Foo
102 | 103 | 这是另一个普通段落。 104 | 105 | 请注意,在HTML区块标签间的 Markdown 格式语法将不会被处理。比如,你在 HTML 区块内使用 Markdown 样式的*强调*会没有效果。 106 | 107 | 11.特殊字符自动转换 108 | 109 | 在 HTML 文件中,有两个字符需要特殊处理: < 和 & 。 < 符号用于起始标签,& 符号则用于标记 HTML 实体,如果你只是想要显示这些字符的原型,你必须要使用实体的形式,像是 < 和 &。 110 | 111 | 12.代码段: 112 | 113 | ``` 114 | 这是一个代码段 115 | ``` 116 | 117 | > 不知为何,本地安装的Jekyll 2.3.0 好像不支持```这种格式的代码段,难道这根Markdown语法格式有关?! 118 | 119 | ## 二、总结 120 | ---- 121 | 122 | 链接的添加,共有三种形式,Markdown支持相对链接。 123 | 124 | <链接> :这种形式只是简单的标出链接; 125 | [文字](链接 “标题”):给文字添加链接,其中标题是可选的; 126 | [文字][标记]:给文字添加链接,链接在下面的一个以[标记]开头的新行(一般是文章末尾)给出。或者直接以[文字][]这种形式编写,在下面的新行中使用[文字]:链接的形式声明链接。 127 | 128 | 图片的添加:跟链接比起来,图片只是多了在前面多了一个叹号”!”。 129 | 标题格式:Markdown提供了2种方式。 130 | 131 | 第一种是在标题前面加上1~6个”#”表示”

”~”

”。 132 | 第二种是在标题下面另起一行,输入四个以上的等号“=”来表示”

”,输入四个以上的减号“-”来表示”

”。 133 | 134 | 粗体和斜体:用星号”*”或者下划线”_” 135 | 136 | 一个表示斜体; 137 | 两个表示粗体; 138 | 三个表示粗斜体。 139 | 140 | 引用内容:就是html标记的”
”,只要在行首用右尖括号>就行了。如果要嵌套引用,那就多打几个>。 141 | 原文输出:如果不想Markdown解释某些内容,有两种方式: 142 | 143 | 第一个是转义为html的”
”标签:要在要原样输出的内容前面加入至少4个空格或者1个tab的宽度;
144 |     第二个是转义为””标签:给要输出的内容加上”`”号(就是esc下头那个键)。
145 | 
146 | 无序列表:在文字前面使用星号”*”、加号”+”、减号”-”中的任意一个,注意在这些符号后面要留一个空格。   
147 | 
148 | 有序列表:在第一条前添加一个数字,后跟一个英文句点”.”。无论第一个条目前加的数字是什么,列表都会从1开始计数。
149 | 
150 | 转义符:”\”。只要给不希望被转义的字符前面加上\就可以了。
151 | 
152 | HTML实体:如果要在内容中输出”<”或者”&”符号,那么必须用[HTML实体][]代替。Markdown会把HTML的特殊符号直接翻译为HTML实体。
153 | 
154 | 换行符:Markdown中在一行的末尾使用两个以上的空格标示HTML中的一个换行符”
”。 155 | 156 | 段落:只要两行之间有一个空行,Markdown就会把它识别为一个段落。 157 | (在列表之前一定要加入一个空行,要不然Markdown是不会把”*”识别为列表的。) 158 | 159 | 水平线:使用三个以上的”*”或”-”来表示。这些星号跟减号之间可以用空格,如果减号没有空格,那它必须在单独的一个段落里,要不它会被识别为标题的。 160 | 161 | 直接使用HTML标记:有些Markdown不支持的标签可以直接写HTML标记,例如表格。 162 | 163 | ## 语法速查 164 | ---- 165 | 166 | Markdown 语法速查表 167 | 168 | 1 标题与文字格式 169 | 标题 170 | 171 | # 这是 H1 <一级标题> 172 | ## 这是 H2 <二级标题> 173 | ###### 这是 H6 <六级标题> 174 | 175 | 文字格式 176 | 177 | **这是文字粗体格式** 178 | *这是文字斜体格式* 179 | ~~在文字上添加删除线~~ 180 | 181 | 2 列表 182 | 无序列表 183 | 184 | * 项目1 185 | * 项目2 186 | * 项目3 187 | 188 | 有序列表 189 | 190 | 1. 项目1 191 | 2. 项目2 192 | 3. 项目3 193 | * 项目1 194 | * 项目2 195 | 196 | 3 其它 197 | 图片 198 | 199 | ![图片名称](http://gitcafe.com/image.png) 200 | 201 | 链接 202 | 203 | [链接名称](http://gitcafe.com) 204 | 205 | 引用 206 | 207 | > 第一行引用文字 208 | > 第二行引用文字 209 | 210 | 水平线 211 | 212 | *** 213 | 214 | 代码 215 | 216 | `` 217 | 218 | 代码块高亮 219 | 220 | ```ruby 221 | def add(a, b) 222 | return a + b 223 | end 224 | ``` 225 | 226 | 表格 227 | 228 | 表头 | 表头 229 | ------------- | ------------- 230 | 单元格内容 | 单元格内容 231 | 单元格内容l | 单元格内容 232 | 233 | ## 参考文献 234 | ---- 235 | 236 | 1. [MarkDown语法小结 ](http://www.myexception.cn/program/1629426.html) 237 | -------------------------------------------------------------------------------- /zh/misc.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | --- 4 | ## 翻译杂记 5 | 6 | 翻译使用Jekyll的模板来自[Jekyll-bootstrap](https://github.com/plusjade/jekyll-bootstrap),模板这种事情明显不想自己折腾,现成的拿来用就好。 7 | 最初的想法是直接用原先的模板就好了,不过,英文版的库使用的textile并且里面的样式不太喜欢,原先中文版的库只有HTML,自己又像用markdown,思前想后,折腾了好久,下定决心自己重做个库。 8 | 9 | 将原先的textile文件的复制过来转换为md后缀时,使用了一个shell语句: 10 | 11 | > for file in $(ls) ; do mv $file ${file%%.*}.md ; done 12 | 13 | 其中,${file%%.*}截获不含后缀名的文件名,而记忆中的basename命令是从包含路径的字符串中截取文件名。 14 | 15 | Jekyll中使用的Liquid模板中的注释: 16 | > {% comment %} in losses {% endcomment %} 17 | 18 | 更多关于Liquid模板的介绍参考: https://github.com/shopify/liquid/wiki/liquid-for-designers 19 | 20 | 给文件取带有顺序规则的名字时,自己首先是实在vim中修改,觉得蛋疼,后来在文件管理器中修改,依然蛋疼,最后,还是写个脚本来的方便。 21 | {% highlight ruby %} 22 | # rename.rb - 用来排序重命名文件 23 | # 功能:用来按照某一顺序(order字符串)排列文件名 24 | # 知识点:在Ruby中调用shell命令,在shell命令中插入ruby变量。正则表达式。 25 | # #{}中是可以进行运算的 26 | order= "intro,minimum,object,name,class,gc,variable,security,spec,yacc,parser,contextual,syntree,evaluator,module,method,iterator,anyeval,load,thread,fin" 27 | o = order.split(",") 28 | f = `ls` 29 | o.each_with_index do |x,idx| 30 | f.split("\n").grep(Regexp.new(x)) do |y| 31 | p "#{y} include #{x}" 32 | if idx >= 10 33 | system "mv #{y} #{idx}-#{y}" 34 | else 35 | system "mv #{y} 0#{idx}-#{y}" 36 | end 37 | end 38 | end 39 | {% endhighlight %} 40 | 41 | 备注:写脚本其实也不方便,想着要怎么写,还要调试查看功能是否正确。不过自己ruby了解不多,刚好学习一下。 42 | 43 | 将英文链接添加进去,修改了连接的文件名时使用了一个vim的全局替换: 44 | > g/\.html/s//\/index\.html/g 45 | 46 | 想要在Markdown中加入表格,搜了几个试了一下,发现自己被坑了,最后找到了一个,语法格式如下: 47 | 48 | > First Header | Second Header | Third Header 49 | > ------------ | ------------- | ------------ 50 | > Content Cell | Content Cell | Content Cell 51 | > Content Cell | Content Cell | Content Cell 52 | 53 | 放置到远程github上时,出现了一些问题,获得了一些经验,首先: 54 | 55 | - Github利用Jekyll生成静态页时,其使用的是gh-pages分支 56 | - Github Pages分为用户相关和项目相关,前置的URL为http://name.github.io ,后者为http://name.github.io/projectname 57 | - 如果已经存在name.github.io时,出现如下问题: 58 | * 项目相关的css会乱掉,需要设置_config.yml中的baseurl: /projectiname 59 | * md中的html路径也需要重新设置 60 | 61 | MarkDown语法相关的资料: 62 | 63 | 1. [Markdown 语法说明](http://wowubuntu.com/markdown/) 64 | 2. [MarkDown语法小结 ](http://www.myexception.cn/program/1629426.html) 65 | 66 | # Jekyll错误: 67 | 1. `Liquid Exception: Syntax Error in tag 'highlight' while parsing the following markup: Valid syntax: highlight [linenos] in zh/0-1-intro.md` 68 | 发现错误的起因: 自己在相关的页面编辑添加图片时,总是不成功,查看了生成的html中没有包含img的标签,尝试很几种方法,都没能解决,最后打算重启Jekyll时,看到了上述错误,修复后,发现图片可以引用了。 69 | 解决方法:就是将相关的错误的highlight全部删除掉。 70 | 副产品: 71 | - 在搜图片显示时,从Vex上看到一个不错的Jekyll的博客: 72 | - Jekyll编译出错后,将会影响剩余的页面内容的处理。 73 | {% raw %} 74 | 2. `Liquid Exception: Tag '{%' was not properly terminated with regexp: /\%\}/ in zh/04-class.md` 75 | Jekyll报错都不给出解析错误的行号的,找起来相当的麻烦。 76 | {% endraw %} 77 | # 迷惑: 78 | 自己写个jekyll的shell函数,居然把系统给崩溃了,我觉的这个函数很正常啊: 79 | {% highlight ruby %} 80 | function jekyll() { 81 | if [ $# == 0 ] ; then 82 | jekyll serve -w 83 | else 84 | jekyll "$@" 85 | fi 86 | } 87 | {% endhighlight %} 88 | > 思:别名可以运行,而函数不可以运行,我想这和自己使用rvm安装的ruby环境有关。Jekyll这个命令行工具存在于rvm加载到当前shell进程的环境中。别名是在当前进程中运行,而函数则是另开一个子进程运行。问题在于,新开的子进程没有加rvm环境。但是,崩溃的行为就很奇怪。 89 | 90 | Liquid模板中的for语句和if语句格式 91 | 92 | {% for page in site.pages %} 93 | {% if page.title %}{{ page.title }}{% endif %} 94 | {% endfor %} 95 | 96 | jekyll自己生成的文件的中的样式,具有借鉴意义的格式: 97 | 98 | 1. 取消Markdown元字符的解释含义的 `_post char* ` 符号 99 | 2. 语法高亮格式 100 | > {% highlight ruby %}...{% endhighlight %} 101 | 102 | 3. 新的超链接的写法 [Jekyll docs][jekyll] 103 | [jekyll]: http://jekyllrb.com 104 | 105 | 有了三个Jekyll的站点,远程的都在xiajian.github.io域名之下,突发奇想,想在本地将三个站点整合起来,尝试了一下,好想不太可以。webrick会霸占端口,不同的webricks进程不能共用端口。 106 | 107 | 9月6:自从8月30回家感冒并在家挂了几天水之后,来公司做事一直没有激情,干啥事都觉得有气无力的,烦躁倦怠,身体也变差了,时常觉的嘴里没有味道。翻译也停滞了很久,提不起精神来。想到是不是换件事情处理并回退到之前步行来公司,或许会改变自己倦怠的情绪和每况日下的身体。 108 | 109 | 9月6:中午睡了个很长时间的午觉,感觉睡了很久,具体的时间也没有仔细计算。下午,大概是5点钟,不想呆在公司了,一来灯光的问题,二来想回去锻炼身体跑步。回来之后,跑步+洗澡+吃饭,等到自己坐下来想看书时,发现看不下去,打开了自己很久没有使用的机器。继续翻译RHG。但是,自己机器上的环境没有搭建完成,就在那里搭环境,先是VIM的环境,然后是Jekyll。 110 | 111 | - VIM的环境其实就是安装了一些插件:delimitMate和vim-markdown 112 | - Jekyll的环境稍微复杂些,除了安装Jekyll,貌似好像还要安装其他两个Gems包(jemoji,jekyll-sitemap)。决定自己写个Gemfile。 113 | 114 | markdown和textile之间的区别: 115 | - h2之类的标签的表示,markdown通过##, textile通过h2.。就感觉而言,textile的表示更为简洁,不过其后缀名实在太繁琐了,不如markdown的md后缀简洁,这也是我不太喜欢它的原因。 116 | 117 | 突然的需求,在vim中对多个文件进行全局替换的方法: 118 | 119 | 120 | ## 后记 121 | ---- 122 | 现在的我要比四年前的我更有耐心,在还没开始翻译之前,先是各种处理HTML到markdown格式的装换,这其实是一件相当繁琐的事情,我居然有耐心做了下去。看来自己确实是慢下来了,尽管之前也不快,但是特别急躁,什么事都赶着去似的。 123 | 124 | 多亏了看了介绍诸时健的相关文章,勾起了我对建立下一个十年的计划的想法,尽管不知道下一个十年后会变成什么样,我有预感,我以后会很NB,哈哈。 125 | 126 | 14年五月份时,最初看到RHG及其中文版翻译状况时,就想到将其翻译下来。不过,彼时既不会用git,也不会用Jekyll。等到了14八月时,两个工具都差不过会折腾了,出于深入学习Ruby的想法,就开始着手翻译的准备工作。 127 | 128 | 仔细想想,自己工作还是相当的轻松的,不然,也不会有时间来翻译。Ruby和Rails都学的不怎么样,工作做的事情也是少少的(由于自己是新手,磕磕伴伴的学习和试错,又是好几天纠结在某一点上),希望以后会顺畅些。 129 | 130 | 自从上周末(14.8.24)在Github上鼓捣起了rhg-zh,这一周就一直没在干事,比如说现在,忙着自己Github的站点,工作都抛到脑后了。这样子是要被开的节奏,这样不好不好!! 131 | 132 | VIM编辑,Jekyll本地查看效果,git推送部署。不要忍受别的博客空间提供的各种奇葩难用的编辑器,又可以学习新的东西markdown、jekyll之类的,这样也挺好的。 133 | 134 | 135 | ## 参考文献 136 | ---- 137 | 1.[六种用ruby调用执行shell命令的方法](http://blackanger.blog.51cto.com/140924/43730/) 138 | 139 | -------------------------------------------------------------------------------- /zh/r-bnf.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: Ruby的伪BNF语法 4 | --- 5 | 6 | Here is the syntax of Ruby in pseudo BNF. For more detail, see parse.y in Ruby distribution. 7 | 8 | 下面是Ruby的BNF语法描述,更多细节,参考Ruby分发包中的parse.y文件。 9 | 10 | > BNF是语言的形式化描述,是最能体现设计和品味的地方,同样也是yacc的输入文件。之前,个人曾经想要自动生成一个c--的编译器,结果一直卡在语法解释器上,也不知道如何处理,最后,由于当时还有其他的事情想做,就放弃了。 11 | 12 | {% highlight ruby %} 13 | PROGRAM : COMPSTMT 14 | 15 | COMPSTMT : STMT (TERM EXPR)* [TERM] 16 | 17 | STMT : CALL do [`|' [BLOCK_VAR] `|'] COMPSTMT end 18 | | undef FNAME 19 | | alias FNAME FNAME 20 | | STMT if EXPR 21 | | STMT while EXPR 22 | | STMT unless EXPR 23 | | STMT until EXPR 24 | | `BEGIN' `{' COMPSTMT `}' 25 | | `END' `{' COMPSTMT `}' 26 | | LHS `=' COMMAND [do [`|' [BLOCK_VAR] `|'] COMPSTMT end] 27 | | EXPR 28 | 29 | EXPR : MLHS `=' MRHS 30 | | return CALL_ARGS 31 | | yield CALL_ARGS 32 | | EXPR and EXPR 33 | | EXPR or EXPR 34 | | not EXPR 35 | | COMMAND 36 | | `!' COMMAND 37 | | ARG 38 | 39 | CALL : FUNCTION 40 | | COMMAND 41 | 42 | COMMAND : OPERATION CALL_ARGS 43 | | PRIMARY `.' OPERATION CALL_ARGS 44 | | PRIMARY `::' OPERATION CALL_ARGS 45 | | super CALL_ARGS 46 | 47 | FUNCTION : OPERATION [`(' [CALL_ARGS] `)'] 48 | | PRIMARY `.' OPERATION `(' [CALL_ARGS] `)' 49 | | PRIMARY `::' OPERATION `(' [CALL_ARGS] `)' 50 | | PRIMARY `.' OPERATION 51 | | PRIMARY `::' OPERATION 52 | | super `(' [CALL_ARGS] `)' 53 | | super 54 | 55 | ARG : LHS `=' ARG 56 | | LHS OP_ASGN ARG 57 | | ARG `..' ARG 58 | | ARG `...' ARG 59 | | ARG `+' ARG 60 | | ARG `-' ARG 61 | | ARG `*' ARG 62 | | ARG `/' ARG 63 | | ARG `%' ARG 64 | | ARG `**' ARG 65 | | `+' ARG 66 | | `-' ARG 67 | | ARG `|' ARG 68 | | ARG `^' ARG 69 | | ARG `&' ARG 70 | | ARG `<=>' ARG 71 | | ARG `>' ARG 72 | | ARG `>=' ARG 73 | | ARG `<' ARG 74 | | ARG `<=' ARG 75 | | ARG `==' ARG 76 | | ARG `===' ARG 77 | | ARG `!=' ARG 78 | | ARG `=~' ARG 79 | | ARG `!~' ARG 80 | | `!' ARG 81 | | `~' ARG 82 | | ARG `<<' ARG 83 | | ARG `>>' ARG 84 | | ARG `&&' ARG 85 | | ARG `||' ARG 86 | | defined? ARG 87 | | PRIMARY 88 | 89 | PRIMARY : `(' COMPSTMT `)' 90 | | LITERAL 91 | | VARIABLE 92 | | PRIMARY `::' IDENTIFIER 93 | | `::' IDENTIFIER 94 | | PRIMARY `[' [ARGS] `]' 95 | | `[' [ARGS [`,']] `]' 96 | | `{' [(ARGS|ASSOCS) [`,']] `}' 97 | | return [`(' [CALL_ARGS] `)'] 98 | | yield [`(' [CALL_ARGS] `)'] 99 | | defined? `(' ARG `)' 100 | | FUNCTION 101 | | FUNCTION `{' [`|' [BLOCK_VAR] `|'] COMPSTMT `}' 102 | | if EXPR THEN 103 | COMPSTMT 104 | (elsif EXPR THEN COMPSTMT)* 105 | [else COMPSTMT] 106 | end 107 | | unless EXPR THEN 108 | COMPSTMT 109 | [else COMPSTMT] 110 | end 111 | | while EXPR DO COMPSTMT end 112 | | until EXPR DO COMPSTMT end 113 | | case COMPSTMT 114 | (when WHEN_ARGS THEN COMPSTMT)+ 115 | [else COMPSTMT] 116 | end 117 | | for BLOCK_VAR in EXPR DO 118 | COMPSTMT 119 | end 120 | | begin 121 | COMPSTMT 122 | [rescue [ARGS] DO COMPSTMT]+ 123 | [else COMPSTMT] 124 | [ensure COMPSTMT] 125 | end 126 | | class IDENTIFIER [`<' IDENTIFIER] 127 | COMPSTMT 128 | end 129 | | module IDENTIFIER 130 | COMPSTMT 131 | end 132 | | def FNAME ARGDECL 133 | COMPSTMT 134 | end 135 | | def SINGLETON (`.'|`::') FNAME ARGDECL 136 | COMPSTMT 137 | end 138 | 139 | WHEN_ARGS : ARGS [`,' `*' ARG] 140 | | `*' ARG 141 | 142 | THEN : TERM 143 | | then 144 | | TERM then 145 | 146 | DO : TERM 147 | | do 148 | | TERM do 149 | 150 | BLOCK_VAR : LHS 151 | | MLHS 152 | 153 | MLHS : MLHS_ITEM `,' [MLHS_ITEM (`,' MLHS_ITEM)*] [`*' [LHS]] 154 | | `*' LHS 155 | 156 | MLHS_ITEM : LHS 157 | | '(' MLHS ')' 158 | 159 | LHS : VARIABLE 160 | | PRIMARY `[' [ARGS] `]' 161 | | PRIMARY `.' IDENTIFIER 162 | 163 | MRHS : ARGS [`,' `*' ARG] 164 | | `*' ARG 165 | 166 | CALL_ARGS : ARGS 167 | | ARGS [`,' ASSOCS] [`,' `*' ARG] [`,' `&' ARG] 168 | | ASSOCS [`,' `*' ARG] [`,' `&' ARG] 169 | | `*' ARG [`,' `&' ARG] 170 | | `&' ARG 171 | | COMMAND 172 | 173 | ARGS : ARG (`,' ARG)* 174 | 175 | ARGDECL : `(' ARGLIST `)' 176 | | ARGLIST TERM 177 | 178 | ARGLIST : IDENTIFIER(`,'IDENTIFIER)*[`,'`*'[IDENTIFIER]][`,'`&'IDENTIFIER] 179 | | `*'IDENTIFIER[`,'`&'IDENTIFIER] 180 | | [`&'IDENTIFIER] 181 | 182 | SINGLETON : VARIABLE 183 | | `(' EXPR `)' 184 | 185 | ASSOCS : ASSOC (`,' ASSOC)* 186 | 187 | ASSOC : ARG `=>' ARG 188 | 189 | VARIABLE : VARNAME 190 | | nil 191 | | self 192 | 193 | LITERAL : numeric 194 | | SYMBOL 195 | | STRING 196 | | STRING2 197 | | HERE_DOC 198 | | REGEXP 199 | 200 | TERM : `;' 201 | | `\n' 202 | 203 | The followings are recognized by lexical analizer. 204 | 205 | 206 | OP_ASGN : `+=' | `-=' | `*=' | `/=' | `%=' | `**=' 207 | | `&=' | `|=' | `^=' | `<<=' | `>>=' 208 | | `&&=' | `||=' 209 | 210 | SYMBOL : `:'FNAME 211 | | `:'VARNAME 212 | 213 | FNAME : IDENTIFIER | `..' | `|' | `^' | `&' 214 | | `<=>' | `==' | `===' | `=~' 215 | | `>' | `>=' | `<' | `<=' 216 | | `+' | `-' | `*' | `/' | `%' | `**' 217 | | `<<' | `>>' | `~' 218 | | `+@' | `-@' | `[]' | `[]=' 219 | 220 | OPERATION : IDENTIFIER 221 | | IDENTIFIER'!' 222 | | IDENTIFIER'?' 223 | 224 | VARNAME : GLOBAL 225 | | `@'IDENTIFIER 226 | | IDENTIFIER 227 | 228 | GLOBAL : `$'IDENTIFIER 229 | | `$'any_char 230 | | `$''-'any_char 231 | 232 | STRING : `"' any_char* `"' 233 | | `'' any_char* `'' 234 | | ``' any_char* ``' 235 | 236 | STRING2 : `%'(`Q'|`q'|`x')char any_char* char 237 | 238 | HERE_DOC : `<<'(IDENTIFIER|STRING) 239 | any_char* 240 | IDENTIFIER 241 | 242 | REGEXP : `/' any_char* `/'[`i'|`o'|`p'] 243 | | `%'`r' char any_char* char 244 | {% endhighlight %} 245 | 246 | IDENTIFIER is the sqeunce of characters in the pattern of /[a-zA-Z_][a-zA-Z0-9_]*/. 247 | 248 | IDENTIFIER是/[a-zA-Z_][a-zA-Z0-9_]*/模式的字符序列。 249 | -------------------------------------------------------------------------------- /zh/r-options.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: 命令行选项 4 | --- 5 | 6 | Ruby interpreter accepts following command-line options (switches). Basically they are quite similar to those of Perl. 7 | 8 | Ruby解释器接受如下的命令行选项(开关),内容基本和Perl相似。 9 | 10 | **-0digit** 11 | 12 | specifies the input record separator ($/) as an octal number. If no digits given, the null character is the separator. Other switches may follow the digits. -00 turns Ruby into paragraph mode. -0777 makes Ruby read whole file at once as a single string, since there is no legal character with that value. 13 | 以八进制数指定输入记录符($/)。如果没有给定digits,默认使用null字符作为分隔符。其他的开关也会跟随该数字。 -00表明Ruby进入段落模式,-0777使得Ruby将整个文件看作单个字符串,这是因为没有值为777的非法字符 14 | 15 | **-a** 16 | 17 | turns on auto-split mode when used with -n or -p. In auto-split mode, Ruby executes `$F = $_.split` at beginning of each loop. 18 | 当指定-n或者-p选项时,打开自动分割模式。在自动分隔模式中,ruby在每个循环开始处执行$F = $_.split 19 | 20 | **-c** 21 | 22 | causes Ruby to check the syntax of the script and exit without executing. If there is no syntax error, Ruby will print "Syntax OK" to the standard output. 23 | 仅检查脚本的语法而不执行脚本。如果没有语法错误,Ruby将向标准输出打印"Syntax OK"。 24 | 25 | **-Kc** 26 | 27 | specifies KANJI (Japanese character) code-set. 28 | 指定KANJI(日本字符集)编码集。 29 | 30 | **-d --debug** 31 | 32 | turns on debug mode. $DEBUG will set true. 33 | 打开debug模式,设置$DEBUG为真。 34 | 35 | **-e script** 36 | 37 | specifies script from command-line. if -e switch specified, Ruby will not look for a script filename in the arguments. 38 | 通过命令行指定脚本,如果设置-e选项,Ruby将不会在参数中寻找脚本的文件名。 39 | 40 | **-F regexp** 41 | 42 | specifies input field separator ($;). 43 | 指定输入文件的分隔符($;). 44 | 45 | **-h --help** 46 | 47 | prints a summary of the options. 48 | 打印选项的综述。 49 | 50 | **-i extension** 51 | 52 | specifies in-place-edit mode. The extension, if specified, is added to old filename to make a backup copy. 53 | 指定参考编辑模式,如果指定该参数,将会对旧的文件制作相应后缀的备份文件。 54 | 55 | example: 56 | 57 | % echo matz > /tmp/junk 58 | % cat /tmp/junk 59 | matz 60 | % ruby -p -i.bak -e '$_.upcase!' /tmp/junk 61 | % cat /tmp/junk 62 | MATZ 63 | % cat /tmp/junk.bak 64 | matz 65 | 66 | **-I directory** 67 | 68 | used to tell Ruby where to load the library scripts. Directory path will be added to the load-path variable (`$:'). 69 | 该选项告诉Ruby从哪里加载库脚本。目录参数将会被添加到加载路径变量(`$:`). 70 | 71 | **-l** 72 | 73 | enables automatic line-ending processing, which means firstly set $\ to the value of $/, and secondly chops every line read using chop!, when used with -n or -p. 74 | 启动自动的行结束符处理,这意味着:在设置-n或者-p选项时,1.将$\设置为$/的值 2.使用chop!切割每行。 75 | 76 | **-n** 77 | 78 | causes Ruby to assume the following loop around your script, which makes it iterate over filename arguments somewhat like sed -n or awk. 79 | 设置Ruby假设脚本被如下的循环包围,使得其像sed -n或awk那样迭代文件名参数。 80 | 81 | while gets 82 | ... 83 | end 84 | 85 | **-p** 86 | 87 | acts mostly same as -n switch, but print the value of variable $_ at the each end of the loop. 88 | 同-n选项类似,但是,在循环的结束处打印变量$_的值。 89 | 90 | example: 91 | 92 | % echo matz | ruby -p -e '$_.tr! "a-z", "A-Z"' 93 | MATZ 94 | 95 | > 以$开头的奇怪的变量名到底是个啥,看起来还相当的常见的。 96 | 97 | **-r filename** 98 | 99 | causes Ruby to load the file using require. It is useful with switches -n or -p. 100 | 触发Ruby通过require加载文件。这在-n和-p选项打开时非常的有用。 101 | 102 | **-s** 103 | 104 | enables some switch parsing for switches after script name but before any filename arguments (or before a --). Any switches found there is removed from ARGV and set the corresponding variable in the script. 105 | 为开关启动一些转换解析。在ARGV中找到的开关将被移除,然后在脚本中设置对应的变量。 106 | 107 | example: 108 | 109 | #! /usr/local/bin/ruby -s 110 | # prints "true" if invoked with `-xyz' switch. 111 | print "true\n" if $xyz 112 | 113 | **-S** 114 | 115 | makes Ruby uses the PATH environment variable to search for script, unless if its name begins with a slash. This is used to emulate #! on machines that don't support it, in the following manner: 116 | 使得Ruby使用PATH环境变量搜索文件,除非名字以斜杠开头。这用来在不支持#!的机器上模仿#!,以如下的方式: 117 | 118 | #!/bin/sh 119 | exec ruby -S -x $0 "$@" 120 | #! ruby 121 | 122 | On some systems $0 does not always contain the full pathname, so you need -S switch to tell Ruby to search for the script if necessary. 123 | 在一些系统中,$0并不总是包含全路径名,所以需要-S选项告诉Ruby搜索需要的脚本。 124 | 125 | **-T [level]** 126 | 127 | Forces "taint" checks to be turned on so you can test them. If level is specified, $SAFE to be set to that level. It's a good idea to turn them on explicitly for programs run on another's behalf, such as CGI programs. 128 | 强制打开污染检查,使得其可以测试。如果level被指定,$SAFE将被设置为对应的等级。在其他环境中运行的程序(比如CGI程序)中,显式打开污染检查是必要的。 129 | 130 | **-v --verbose** 131 | 132 | enables verbose mode. Ruby will prints its version at the beginning, and set the variable `$VERBOSE' to true. Some methods prints extra messages if this variable is true. If this switch is given, and no other switches present, Ruby quits after printing its version. 133 | 启动verbose模式。Ruby将在开头打印版本号,并设置$VERBOSE为true。当$VERBOSE设置为true时,一些方法会打印额外的信息。 134 | 135 | **--version** 136 | 137 | prints the version of Ruby executable. 138 | 打印Ruby执行文件的版本。` 139 | 140 | **-w** 141 | 142 | enables verbose mode without printing version message at the beginning. It set the variable `$VERBOSE' to true. 143 | 144 | **-x[directory]** 145 | 146 | tells Ruby that the script is embedded in a message. Leading garbage will be discarded until the first that starts with "#!" and contains string "ruby". Any meaningful switches on that line will applied. The end of script must be specified with either EOF, ^D (control-D), ^Z (control-Z), or reserved word __END__.If the directory name is specified, Ruby will switch to that directory before executing script. 147 | 告诉Ruby脚本嵌入到消息中。 在以#!开头并包含ruby的行开始之前的行都被遗弃。任何在#!行中有意义的选项都会被应用。脚本的结束必须以EOF、^D (control-D)、^Z (control-Z)或者保留字__END__。如果目录名被指定,Ruby将在执行脚本前切换到其他目录中。 148 | 149 | **-X directory** 150 | 151 | causes Ruby to switch to the directory. 152 | 确保Ruby切换目录。 153 | 154 | **-y --yydebug** 155 | 156 | turns on compiler debug mode. Ruby will print bunch of internal state messages during compiling scripts. You don't have to specify this switch, unless you are going to debug the Ruby interpreter itself. 157 | 打开编译器的debug模式。Ruby在编译脚本时将打印内部状态信息。除非调用解释器自生,否则不需要打开该选项。 158 | -------------------------------------------------------------------------------- /zh/r-preface.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: 前言 4 | --- 5 | 6 | Ruby is the interpreted scripting language for quick and easy object-oriented programming. It has many features to process text files and to do system management tasks (as in Perl). It is simple, straight-forward, and extensible. 7 | 8 | Ruby是一门快速上手且容易学习的解释型脚本语言。其拥有很多文本处理以及系统任务的特性。Ruby简单,直接并且可扩展。 9 | 10 | If you want a language for easy object-oriented programming, or you don't like the PERL ugliness, or you do like the concept of lisp, but don't like too much parentheses, Ruby may be the language of the choice. 11 | 12 | 如果你想要简单的面向对象的编程语言,但又嫌Perl过于丑陋; 或者爱好Lisp提倡的概念,但有不想要太多括号; Ruby或许是个不错的选择。 13 | 14 | Ruby's features are as follows: 15 | Ruby的特性如下: 16 | 17 | - **Interpretive** 18 | Ruby is the interpreted language, so you don't have to recompile to execute the program written in Ruby. 19 | Ruby是解释性的语言,所以,不需要重编译以Ruby编写的程序。 20 | - **Variables have no type (dynamic typing)** 21 | Variables in Ruby can contain data of any type. You don't have to worry about variable typing. Consequently, it has weaker compile time check. 22 | Ruby中的变量可以包含任意类型。不需要担心类型检查。最终,其编译时检查很弱。 23 | - **No declaration needed** 24 | You can use variables in your Ruby programs without any declarations. Variable name itself denotes its scope (local, global, instance, etc.) 25 | 使用变量不需要申明,变量名本身决定了其作用域(局部的,全局的,实例的等等) 26 | - **Simple syntax** 27 | Ruby has simple syntax influenced slightly from Eiffel. 28 | Ruby简洁的语法受Eiffel的影响。 29 | - **No user-level memory management** 30 | Ruby has automatic memory management. Objects no longer referenced from anywhere are automatically collected by the garbage collector built in the interpreter. 31 | Ruby拥有自动内存管理。不再引用的对象将自动的被处理器内建的垃圾回收器回收。 32 | - **Everything is object** 33 | Ruby is the pure object-oriented language from the beginning. Even basic data like integers are treated uniformly as objects. 34 | Ruby是一个彻头彻尾的面向对象语言,甚至像整数这样的基本的类型也被看作为对象。 35 | - **Class, inheritance, methods** 36 | Of course, as a O-O language, Ruby has basic features like classes, inheritance, methods, etc. 37 | 当然,作为一个面向对象的语言。Ruby拥有诸如类、继承、方法之类的基本特性。 38 | - **Singleton methods** 39 | Ruby has the feature to define methods for certain specified object. For example, you can define a press-button action for certain GUI button by defining a singleton method for the button. Or, you can make up your own prototype based object system using singleton methods (if you want to). 40 | Ruby拥有为某些特定的对象定义方法的特征。例如,可以通过为某些GUI的按钮定义一个press-button动作。或者,可以通过单件方法组成自己的基于原型的面向对象系统。 41 | - **Mix-in by modules** 42 | Ruby does not have the multiple inheritance intentionally. IMO, It is the source of confusion. Instead, Ruby has modules to share the implementation across the inheritance tree. It is often called the "Mix-in." 43 | Ruby没有多重继承。某种程度而言,多重继承是冲突之源。取而代之的是,Ruby有可在继承树之间共享实现的模块,通常称之为Mix-in。 44 | - **Iterators** 45 | Ruby has iterators for loop abstraction. 46 | Ruby拥有循环抽象的迭代器。 47 | - **Closures** 48 | In Ruby, you can objectify the procedure. 49 | 在Ruby中可以对象化过程。 50 | - **Text processing and regular expression** 51 | Ruby has bunch of text processing features like in Perl. 52 | Ruby拥有类似Perl的成打的文本处理特性。 53 | - **Bignums** 54 | With built-in bignums, you can calculate factorial(400), for example. 55 | 通过内建的大数类型,可以计算factorial(400)。 56 | - **Exception handling** 57 | As in Java(tm). 同Java类似。 58 | - **Direct access to OS** 59 | Ruby can call most of system calls on UNIX boxes. It can be used in system programming. 60 | Ruby可以调用大多数的UNIX系统调用,这通常用作系统调用。 61 | - **Dynamic loading** 62 | You can load object files into Ruby interpreter on-the-fly, on most of UNIXes. 63 | 可以在Ruby解析器中即刻加载类文件。 64 | -------------------------------------------------------------------------------- /zh/rename.rb: -------------------------------------------------------------------------------- 1 | # rename.rb - 用完就扔的脚本 2 | # 功能:用来按照某一顺序排列文件名 3 | # 知识点:在Ruby中调用shell命令,在shell命令中插入ruby变量。正则表达式。 4 | # #{}中是可以进行运算的 5 | order= "intro,minimum,object,name,class,gc,variable,security,spec,yacc,parser,contextual,syntree,evaluator,module,method,iterator,anyeval,load,thread,fin" 6 | o = order.split(",") 7 | f = `ls` 8 | o.each_with_index do |x,idx| 9 | f.split("\n").grep(Regexp.new(x)) do |y| 10 | p "#{y} include #{x}" 11 | if idx >= 10 12 | system "mv #{y} #{idx}-#{y}" 13 | else 14 | system "mv #{y} 0#{idx}-#{y}" 15 | end 16 | end 17 | end 18 | --------------------------------------------------------------------------------