<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>mizuhashi (mizuhashi)</title>
    <link>https://ruby-china.org/mizuhashi</link>
    <description></description>
    <language>en-us</language>
    <item>
      <title>一個用 DIDComm 實現服務器間通信的 Rails demo</title>
      <description>&lt;p&gt;&lt;a href="https://identity.foundation/didcomm-messaging/spec/v2.1/" rel="nofollow" target="_blank" title=""&gt;DIDComm&lt;/a&gt;是一個基於 W3C DID（去中心化 ID）的通信協議。如果一個服務器想和另一個實現了 DIDComm 的服務器通信，它會需要在/.well-known/did.json 提供一個 DID 文檔，文檔裏包含了公鑰以及 DIDComm 的 service endpoint。我的 demo 服務器的 DID 文檔長這樣：&lt;a href="https://dc.mbkr.ca/.well-known/did.json" rel="nofollow" target="_blank"&gt;https://dc.mbkr.ca/.well-known/did.json&lt;/a&gt; 。&lt;/p&gt;

&lt;p&gt;擁有了這個文檔之後，&lt;code&gt;did:web:dc.mbkr.ca&lt;/code&gt;這個 DID 就會對應我的服務器，你只需要這個 id 就可以給我發信息，發信方會根據這個 id 解析到 DID 文檔，獲取公鑰構建信息，並推到 service endpoint 上。&lt;/p&gt;

&lt;p&gt;我也做了一個公開的 demo 服務器， &lt;a href="https://dc-public.mbkr.ca/" rel="nofollow" target="_blank"&gt;https://dc-public.mbkr.ca/&lt;/a&gt; ，你可以用&lt;code&gt;public&lt;/code&gt;做密碼登錄。&lt;/p&gt;

&lt;p&gt;Demo 的 repo: &lt;a href="https://github.com/onyxblade/didcomm-rails-demo" rel="nofollow" target="_blank"&gt;https://github.com/onyxblade/didcomm-rails-demo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;實現上，我本來是讓 AI 生成了一個 Ruby 版本的 DIDComm 實現，不過密碼學的內容很多，我最後還是決定直接用&lt;a href="https://github.com/sicpa-dlab/didcomm-rust" rel="nofollow" target="_blank" title=""&gt;didcomm-rust&lt;/a&gt;這個標準的參考實現。這個 Rust 的實現可以輸出 wasm，但 wasmtime-rb 好像還沒成熟到能直接用，所以最終我做了一個 HTTP 服務器&lt;a href="https://github.com/onyxblade/didcomm-http" rel="nofollow" target="_blank" title=""&gt;didcomm-http&lt;/a&gt;，來把 wasm 接口包裝成 HTTP API。&lt;/p&gt;

&lt;p&gt;Happy Hacking!&lt;/p&gt;</description>
      <author>mizuhashi</author>
      <pubDate>Wed, 04 Mar 2026 07:14:39 +0800</pubDate>
      <link>https://ruby-china.org/topics/44502</link>
      <guid>https://ruby-china.org/topics/44502</guid>
    </item>
    <item>
      <title>WhereableScope: 把 scope 用作 where 參數</title>
      <description>&lt;p&gt;&lt;a href="https://github.com/onyxblade/whereable_scope" rel="nofollow" target="_blank"&gt;https://github.com/onyxblade/whereable_scope&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;例子：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="n"&gt;has_one&lt;/span&gt; &lt;span class="ss"&gt;:order_address&lt;/span&gt;
  &lt;span class="n"&gt;has_one&lt;/span&gt; &lt;span class="ss"&gt;:address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;through: :order_address&lt;/span&gt;

  &lt;span class="n"&gt;scope&lt;/span&gt; &lt;span class="ss"&gt;:by_address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;joins&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:order_address&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;order_addresses: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;address: &lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;# 把by_address scope註冊為可用的where參數&lt;/span&gt;
  &lt;span class="n"&gt;whereable_scope&lt;/span&gt; &lt;span class="ss"&gt;:by_address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;as: :address&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# 現在你可以：&lt;/span&gt;
&lt;span class="no"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;address: &lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;僅供娛樂&lt;/p&gt;</description>
      <author>mizuhashi</author>
      <pubDate>Thu, 29 Jan 2026 13:56:51 +0800</pubDate>
      <link>https://ruby-china.org/topics/44469</link>
      <guid>https://ruby-china.org/topics/44469</guid>
    </item>
    <item>
      <title>Ruby 的 TUI 庫 Ratatui-Ruby </title>
      <description>&lt;p&gt;reddit 上看到的：&lt;a href="https://www.ratatui-ruby.dev/" rel="nofollow" target="_blank"&gt;https://www.ratatui-ruby.dev/&lt;/a&gt;&lt;/p&gt;</description>
      <author>mizuhashi</author>
      <pubDate>Thu, 22 Jan 2026 03:57:41 +0800</pubDate>
      <link>https://ruby-china.org/topics/44462</link>
      <guid>https://ruby-china.org/topics/44462</guid>
    </item>
    <item>
      <title>一點關於 AI 編程的思考</title>
      <description>&lt;p&gt;程序員的工作，本質上是在做語言翻譯，將描述需求的人類語言翻譯到機器語言。其中，需求語言是抽象的，就像用戶說「我要一輛車」，是一種概括性的描述，但要實際把車造出來，就要落實到非常具象的語言，因為無論是計算機還是現實物理，都有非常具體的規則，錯一點就會不能用。這種抽象程度的差異可以理解為信息量的差異，給定一個車的概念，它可以有成千上萬種樣子，但到生產出來的具體型號，就只剩下了一種，其他所有樣子都被排除了，這也是信息論裏提出的「信息量即是排除可能性的多寡」。&lt;/p&gt;

&lt;p&gt;於是程序員的工作本質上是對信息的補足，這種補足是通過不斷疊加約束實現的，每個新增加的細節都是約束，能砍掉一部分可能性，直到最後可能性剩下一種。具體地說，給定一個需求，程序員會想到一些潛在的方案，每個方案會有新加入的約束，提出方案本身就是補充了原本不存在的信息。那麼如何從潛在方案中選擇呢？程序員需要在需求中找到一些能指引選擇的原始約束，例如把方案介紹給產品詢問意見，或者根據自身的經驗預測一下未來的需要，這實際上就是擴充了上下文。&lt;/p&gt;

&lt;p&gt;AI 的代碼生成工作在上述翻譯鏈的後半段，它會從程序員那取得中間階段的語言，然後生成具體的代碼。如果 AI 更聰明，那麼程序員應當可以提供更抽象的語言，讓 AI 自己補足信息，而如果 AI 更笨，程序員就需要提供更多信息，才能保證最終代碼的可用。於是，我們有了一個度量 AI 聰明程度的方法，也有了一種適應 AI 的策略，就是如果 AI 不夠聰明，就提供更多細節直到它能寫出來。&lt;/p&gt;</description>
      <author>mizuhashi</author>
      <pubDate>Wed, 23 Jul 2025 05:29:24 +0800</pubDate>
      <link>https://ruby-china.org/topics/44228</link>
      <guid>https://ruby-china.org/topics/44228</guid>
    </item>
    <item>
      <title>Camille：让前端和 Rails 进行类型安全的通信</title>
      <description>&lt;p&gt;之前在 &lt;a href="https://ruby-china.org/topics/42643" rel="nofollow" target="_blank"&gt;https://ruby-china.org/topics/42643&lt;/a&gt; 这个帖子提到过在 Rails 端生成带类型的 API 调用函数，来让前后端通信实现类型安全，现在终于做成成品 gem 了。&lt;/p&gt;

&lt;p&gt;Github Repo: &lt;a href="https://github.com/onyxblade/camille" rel="nofollow" target="_blank"&gt;https://github.com/onyxblade/camille&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;用 Rails 做 API server 的时候，我们返回的 json 是没有经过类型检查的，这样即使前端用上了 typescript，我们也不能保证 Rails 返回的 JSON 是预期的结构和类型。于是我做了这个 gem 来在 Rails 端定义 API 接口的类型，并生成 ts 的调用函数，这样调用的参数和返回就都是类型安全的了。&lt;/p&gt;

&lt;p&gt;简而言之它的作用就是可以给 controller action 的 params 和 response 加上类型，例如对一个&lt;code&gt;books#create&lt;/code&gt; action，可以通过下面的代码加上类型：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;using&lt;/span&gt; &lt;span class="no"&gt;Camille&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Syntax&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Camille::Schemas::Books&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Camille&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Schema&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Camille&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Types&lt;/span&gt;

  &lt;span class="n"&gt;post&lt;/span&gt; &lt;span class="ss"&gt;:create&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="ss"&gt;book: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="ss"&gt;name: &lt;/span&gt;&lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;author: &lt;/span&gt;&lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;retail_price: &lt;/span&gt;&lt;span class="no"&gt;Decimal&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后可以生成前端的调用函数：&lt;/p&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// This file is automatically generated.&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./request&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;DateTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Decimal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;books&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;book&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;retailPrice&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;}}):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;post&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/books/create&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样前端可以通过下面的方式调用：&lt;/p&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;endpoints&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;books&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;book&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Metaprogramming Ruby&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Paolo Perrotta&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;retailPrice&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;27.95&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个调用的参数和返回值都是类型安全的，如果前端出错了 TS 会给出提示，后端出错则会被运行时检查查出来。同时请求的 path 也是不需要程序员管理的，程序员只要调用函数就好，Camille 会确保请求被正确的 action 处理。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/onyxblade/camille-tutorial" rel="nofollow" target="_blank"&gt;https://github.com/onyxblade/camille-tutorial&lt;/a&gt; 这里有一个 step by step 的 tutorial，感兴趣的也可以看看。&lt;/p&gt;

&lt;p&gt;Camille 目前做到了支持 typescript 的除了 enum 和 utility types 的绝大部分类型语法（utility types 支持 omit 和 pick），基本是一模一样的，在这个过程中用到了至今还没见有人用过的 refinement，算是比较好玩的一点。具体的语法列表可以参见 &lt;a href="https://github.com/onyxblade/camille#available-syntax-for-types" rel="nofollow" target="_blank"&gt;https://github.com/onyxblade/camille#available-syntax-for-types&lt;/a&gt; 。&lt;/p&gt;

&lt;p&gt;欢迎试用和反馈，如果有需要的 feature requests 也可以加上。&lt;/p&gt;</description>
      <author>mizuhashi</author>
      <pubDate>Mon, 20 Mar 2023 08:47:51 +0800</pubDate>
      <link>https://ruby-china.org/topics/42950</link>
      <guid>https://ruby-china.org/topics/42950</guid>
    </item>
    <item>
      <title>各位在写测试的时候会常用 mock 吗？</title>
      <description>&lt;p&gt;有位同事特别喜欢用 mock，测试一个 service 的时候会把所有外部依赖都用 mock 写，以此隔离测试代码。他的理由有，service A 依赖 service B，在 A 的单测中如果直接调用 B 来准备测试数据，那么 B 在后面的时候可能会不断增长，然后引入很多和 A 无关的东西，也可能 break A 的测试。而如果用 mock 的话，A 的测试是不需要改的，写测试的时候关注点也只会在 A 内部。但是我认为如果这么干，会需要一些额外的代码来测 A 对 B 的依赖，不然不能保证 B 的运行结果和最初的 mock 数据是一样的，这实际上增加了测试的代码量，而且测试本来应该是为了发现问题，而不是作为“不会有问题”的代码，如果用维护业务代码的方式维护测试，似乎就失去了测试的意义。&lt;/p&gt;

&lt;p&gt;我想了一种折中方案，就是通过实际调用 service 来准备数据，然后把这些数据 dump 一份，保存来用作 mock，这样 service 改变这个 dump 也不会变，可以很好地满足他想要隔离测试的想法。然后可以监视一个 service 生成的新的 dump 和以往的 dump 是不是有不同，如果有不同，就更新一下 dump 的版本看看单元测试还能不能过。这样如果 dump 更新得勤，就能实现我想要的发现问题。这样好像是不错的，可以实际观测到 service 改动所产生的效应，不过可能需要造一些轮子。&lt;/p&gt;</description>
      <author>mizuhashi</author>
      <pubDate>Fri, 21 Oct 2022 10:23:45 +0800</pubDate>
      <link>https://ruby-china.org/topics/42699</link>
      <guid>https://ruby-china.org/topics/42699</guid>
    </item>
    <item>
      <title>大家觉得在 Rails 端生成带类型的前端 API 调用代码有搞头吗？</title>
      <description>&lt;p&gt;这样可以确保后端返回的 json 和前端 ts 里的 json 是相同类型的，前端在调用 api 的时候也可以确保提供了后端要求的 params。&lt;/p&gt;

&lt;p&gt;例如这样的 ruby 代码：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;endpoint&lt;/span&gt; &lt;span class="ss"&gt;:recipe_data&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="ss"&gt;:id&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;recipe&lt;/span&gt; &lt;span class="ss"&gt;:recipe&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;会生成前端的 ts 代码：&lt;/p&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;recipe&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;subtitle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;api_recipe_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;recipe&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;recipe&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;useApi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;api/recipe_data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;api_recipe_data&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中&lt;code&gt;recipe&lt;/code&gt;是一个自定义的类型，在另一个地方定义了它应该有的 interface。这个目前的实现并不复杂，但是如果要做成通用的 rails 插件估计很麻烦，不知道值不值得&lt;/p&gt;</description>
      <author>mizuhashi</author>
      <pubDate>Fri, 09 Sep 2022 23:14:49 +0800</pubDate>
      <link>https://ruby-china.org/topics/42643</link>
      <guid>https://ruby-china.org/topics/42643</guid>
    </item>
    <item>
      <title>docker 部署可以做成类似 mina 和 cap 的工具吗？</title>
      <description>&lt;p&gt;用 docker 之后的部署流程都是 build push，然后 ssh 到服务器上 pull，但是我觉得这部分应该是可以用类似 mina 的东西解决的。这部分大家都是自己写脚本吗，还是有惯常使用的插件之类的？&lt;/p&gt;</description>
      <author>mizuhashi</author>
      <pubDate>Thu, 25 Nov 2021 16:09:45 +0800</pubDate>
      <link>https://ruby-china.org/topics/41926</link>
      <guid>https://ruby-china.org/topics/41926</guid>
    </item>
    <item>
      <title>Imba - 一个转译到 js 的新编程语言</title>
      <description>&lt;p&gt;&lt;a href="https://imba.io/" rel="nofollow" target="_blank"&gt;https://imba.io/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;缩进语法，element 是第一公民，还怀念 coffeescript 的可以试试&lt;/p&gt;

&lt;p&gt;======更新======&lt;/p&gt;

&lt;p&gt;&lt;a href="https://imba.io/tags/declarative-rendering" rel="nofollow" target="_blank"&gt;https://imba.io/tags/declarative-rendering&lt;/a&gt; 这个描述了 imba 的更新逻辑，它采用的是和 mithril.js 一样的，当每次事件结束的时候全局进行更新，并没有采用任何响应式设计。如果要优化这个更新逻辑，需要先 silence 掉事件，然后手动更新需要更新的组件。&lt;/p&gt;</description>
      <author>mizuhashi</author>
      <pubDate>Wed, 27 Oct 2021 09:57:01 +0800</pubDate>
      <link>https://ruby-china.org/topics/41806</link>
      <guid>https://ruby-china.org/topics/41806</guid>
    </item>
    <item>
      <title>编程语言谜语</title>
      <description>&lt;p&gt;打算写的小说里要用到一些咒语，就根据历史上的编程语言尝试写了些，其中每行代表一个或多个编程语言。&lt;/p&gt;

&lt;p&gt;过程转写的方程式&lt;br&gt;
自解释的树状结构&lt;br&gt;
顺流而下的字母表&lt;br&gt;
模拟世界的活跃体&lt;br&gt;
有限空间的问答机&lt;br&gt;
可变形的红色宝石&lt;br&gt;
D 大调的协和半音&lt;br&gt;
无限延伸的类之类&lt;br&gt;
违规借用的拒绝者&lt;/p&gt;

&lt;p&gt;猜对没奖 lol&lt;/p&gt;

&lt;hr&gt;

&lt;p&gt;谜底更新在 7 楼&lt;/p&gt;</description>
      <author>mizuhashi</author>
      <pubDate>Wed, 02 Sep 2020 16:19:30 +0800</pubDate>
      <link>https://ruby-china.org/topics/40356</link>
      <guid>https://ruby-china.org/topics/40356</guid>
    </item>
    <item>
      <title>PostGraphile：将 Postgres 数据库变成全功能 GraphQL 后端</title>
      <description>&lt;p&gt;&lt;a href="https://www.graphile.org/" rel="nofollow" target="_blank"&gt;https://www.graphile.org/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;这个工具可以直接把一个 postgres 数据库生成为一个 graphql 后端，内置了对每个表格的 crud query 及 mutation。&lt;/p&gt;

&lt;p&gt;为什么说是全功能的呢？因为仅仅通过 graphile 和 pg 可以做到传统后端需要的任何事，而且所有需要写的代码和配置都在 postgres 里，迁移的时候直接导出 postgres 数据库，就能备份整个后端。&lt;/p&gt;

&lt;p&gt;除了生成的 crud，用户可以用 pl/sql 写业务逻辑的函数，一个有副作用（cud）的函数会直接挂载为 graphql 的 mutation，无副作用的则会挂载为 query。&lt;/p&gt;

&lt;p&gt;graphile 对数据库的更新鉴权是使用 pg 内置的 role 和 row level security 实现的。一般应用需要两个 role：登陆前的 anonymous 和登陆后的 user。我们可以通过 grant 来对不同 role 配置他们能对表进行的操作，而 row level security 则允许我们配置一个 session 对行的权限，在 cud 行的时候，可以执行一些 check，例如检查当前用户 id 是不是和要修改的数据一样。&lt;/p&gt;

&lt;p&gt;和 hasura 对比的好处：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;graphile 以 postgres 为中心，没有自己的 metadata。hasura 把关联的配置保存为一份自己的配置，这样在迁移的时候除了导出数据库，还需要导出 hasura 的配置。而 graphile 的关联信息是完全通过 pg 内的外键关联推导出来的。&lt;/li&gt;
&lt;li&gt;hasura 实现登陆鉴权功能的时候需要一个外部服务器。graphile 不需要一个额外的服务器，凭借自身就可以实现登陆注册，签署 jwt。&lt;/li&gt;
&lt;li&gt;graphile 使用 pg 内置的 row level security 来处理权限，而 hasura 是用一套自己的鉴权机制来处理的。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;期待使用 graphile 做出的纯 pg 后端的应用。&lt;/p&gt;</description>
      <author>mizuhashi</author>
      <pubDate>Wed, 26 Aug 2020 18:08:55 +0800</pubDate>
      <link>https://ruby-china.org/topics/40334</link>
      <guid>https://ruby-china.org/topics/40334</guid>
    </item>
    <item>
      <title>bootstrap-sass 3.2.0.3 版本被发现藏有远程执行代码后门</title>
      <description>&lt;p&gt;&lt;a href="https://snyk.io/blog/malicious-remote-code-execution-backdoor-discovered-in-the-popular-bootstrap-sass-ruby-gem/" rel="nofollow" target="_blank"&gt;https://snyk.io/blog/malicious-remote-code-execution-backdoor-discovered-in-the-popular-bootstrap-sass-ruby-gem/&lt;/a&gt;&lt;/p&gt;</description>
      <author>mizuhashi</author>
      <pubDate>Fri, 05 Apr 2019 01:07:07 +0800</pubDate>
      <link>https://ruby-china.org/topics/38345</link>
      <guid>https://ruby-china.org/topics/38345</guid>
    </item>
    <item>
      <title>package-lock.json that doesn't lock</title>
      <description>&lt;p&gt;转自 &lt;a href="https://twitter.com/javan/status/905194268297441285" rel="nofollow" target="_blank"&gt;https://twitter.com/javan/status/905194268297441285&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2017/dcb9a4aa-b817-4e13-924f-12ae7578c11c.png!large" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;根据图中的 &lt;a href="https://stackoverflow.com/questions/45022048/why-does-npm-install-rewrite-package-lock-json/45566871#45566871" rel="nofollow" target="_blank" title=""&gt;stackoverflow 回答&lt;/a&gt; ，npm 5.1.0 之后，package-lock.json 只锁定那些无前缀的声明，如&lt;code&gt;1.2.0&lt;/code&gt;，而不包括&lt;code&gt;^1.2.0&lt;/code&gt;。npm 的这个操作依旧是让人看不懂，有锁定需求的还是继续 yarn 吧....&lt;/p&gt;

&lt;p&gt;======update======&lt;/p&gt;

&lt;p&gt;发现这个"issue"在 5.4.2 被修复，现在能锁了....&lt;/p&gt;

&lt;p&gt;行为如 &lt;a href="https://github.com/npm/npm/issues/17979#issuecomment-332701215" rel="nofollow" target="_blank" title=""&gt;Issue#17979最后一个回复&lt;/a&gt; 。&lt;/p&gt;</description>
      <author>mizuhashi</author>
      <pubDate>Thu, 09 Nov 2017 10:47:11 +0800</pubDate>
      <link>https://ruby-china.org/topics/34542</link>
      <guid>https://ruby-china.org/topics/34542</guid>
    </item>
    <item>
      <title>pretty_ancestors: 打印包含层级的 ancestors 信息</title>
      <description>&lt;p&gt;ruby 使用 mixin 的时候是直接 copy 到原型链的，ancestors 返回的是一维数组，于是尝试了一下用 ancestors 还原出 include 和 prepend 的结构，调试的时候可以用到。&lt;/p&gt;

&lt;p&gt;安装：&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gem &lt;span class="nb"&gt;install &lt;/span&gt;pretty_ancestors
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例子：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;M1&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;M2&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;M1&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;M3&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;M4&lt;/span&gt;
  &lt;span class="n"&gt;prepend&lt;/span&gt; &lt;span class="no"&gt;M3&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;M5&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;C&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;M4&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;M2&lt;/span&gt;
  &lt;span class="n"&gt;prepend&lt;/span&gt; &lt;span class="no"&gt;M5&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;pp&lt;/span&gt; &lt;span class="no"&gt;C&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pretty_ancestors&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;# [[[M5], C, [[M2, [[M1, [#&amp;lt;Module:0x00000000f546f0&amp;gt;]]]], [[M3], M4]]],&lt;/span&gt;
&lt;span class="c1"&gt;#  [Object,&lt;/span&gt;
&lt;span class="c1"&gt;#   [PP::ObjectMixin, Kernel]],&lt;/span&gt;
&lt;span class="c1"&gt;#  BasicObject]&lt;/span&gt;

&lt;span class="n"&gt;pp&lt;/span&gt; &lt;span class="no"&gt;C&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pretty_ancestors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:raw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;# [[[[[], M5, []]],&lt;/span&gt;
&lt;span class="c1"&gt;#   C,&lt;/span&gt;
&lt;span class="c1"&gt;#   [[[], M2, [[[], M1, [[[], #&amp;lt;Module:0x00000000f546f0&amp;gt;, []]]]]],&lt;/span&gt;
&lt;span class="c1"&gt;#    [[[[], M3, []]], M4, []]]],&lt;/span&gt;
&lt;span class="c1"&gt;#  [[], Object, [[[], PP::ObjectMixin, []], [[], Kernel, []]]],&lt;/span&gt;
&lt;span class="c1"&gt;#  [[], BasicObject, []]]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在 raw 数据中每个模块 M 都被表示为&lt;code&gt;[[*prepended], M, [*included]]&lt;/code&gt;，普通输出则是去掉了所有&lt;code&gt;[]&lt;/code&gt;的简化。对于 Class，pretty_ancestors 的第一维是继承链上的类。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;C.pretty_ancestors.flatten&lt;/code&gt; 总是等于 &lt;code&gt;C.ancestors&lt;/code&gt;，所以可以直接按顺序确定优先级。&lt;/p&gt;

&lt;p&gt;github: &lt;a href="https://github.com/CicholGricenchos/pretty_ancestors" rel="nofollow" target="_blank"&gt;https://github.com/CicholGricenchos/pretty_ancestors&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;另求 pretty_print 调教经验。。&lt;/p&gt;</description>
      <author>mizuhashi</author>
      <pubDate>Fri, 28 Apr 2017 12:01:48 +0800</pubDate>
      <link>https://ruby-china.org/topics/32896</link>
      <guid>https://ruby-china.org/topics/32896</guid>
    </item>
    <item>
      <title>ancestry 和 closure_tree 的批量读对比</title>
      <description>&lt;p&gt;update：這篇文章的內容實際上完全是錯的…&lt;/p&gt;</description>
      <author>mizuhashi</author>
      <pubDate>Mon, 17 Apr 2017 20:53:39 +0800</pubDate>
      <link>https://ruby-china.org/topics/32802</link>
      <guid>https://ruby-china.org/topics/32802</guid>
    </item>
    <item>
      <title>用 Ruby 做编译原理大作业</title>
      <description>&lt;p&gt;&lt;a href="https://github.com/CicholGricenchos/tiny-c" rel="nofollow" target="_blank"&gt;https://github.com/CicholGricenchos/tiny-c&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;做了一个微型 c 编译器，大概四百来行，可以编译一些简单的 c 代码（参见测试用例）。&lt;/p&gt;

&lt;p&gt;语法分析自己写了一套 DSL，用深度优先搜索找一个可行的解，大概算是 LL(0)？这样语法定义可以写的比较简洁，但是坏处是不能给出“unexpected token xxx”这样细致的提示，因为在搜索途中不知道哪个规则才是正确的。&lt;/p&gt;

&lt;p&gt;有了语法树（sexp）之后，就可以直接塞到 interpreter 递归执行了，也可以塞到 compiler 生成汇编，同样是在一次递归里完成。&lt;/p&gt;

&lt;p&gt;compiler 会将每个语法树节点直译成汇编代码，途中想了好久应该怎么分配寄存器，但是还是搞不定，所以汇编中有不少多余的出入栈代码，来保证每个操作都是相互隔离的，当然代码也变慢了很多。不过能正确运行就很开心了。。&lt;/p&gt;</description>
      <author>mizuhashi</author>
      <pubDate>Sun, 12 Mar 2017 22:31:23 +0800</pubDate>
      <link>https://ruby-china.org/topics/32512</link>
      <guid>https://ruby-china.org/topics/32512</guid>
    </item>
    <item>
      <title>Ruby as awk</title>
      <description>&lt;p&gt;在 shell 配置添加一个 alias：&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;alias &lt;/span&gt;rawk &lt;span class="s1"&gt;'ruby -r ~/rawk.rb -ne'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在~/rawk.rb 添加要用到的处理方法：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;pid&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;
  &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/\s+/&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;使用它：&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;(&lt;/span&gt;´_ゝ&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;旦 ~ ps aux | &lt;span class="nb"&gt;grep &lt;/span&gt;rails | rawk &lt;span class="s1"&gt;'puts pid $_'&lt;/span&gt;
7940
11478
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中-e 是执行脚本，-n 是对每行输入执行脚本，-r 是执行前引入。&lt;/p&gt;

&lt;p&gt;参考 &lt;a href="http://nithinbekal.com/posts/ruby-sed-awk/" rel="nofollow" target="_blank"&gt;http://nithinbekal.com/posts/ruby-sed-awk/&lt;/a&gt;&lt;/p&gt;</description>
      <author>mizuhashi</author>
      <pubDate>Fri, 20 Jan 2017 12:02:11 +0800</pubDate>
      <link>https://ruby-china.org/topics/32177</link>
      <guid>https://ruby-china.org/topics/32177</guid>
    </item>
    <item>
      <title>Rubinius 正在成为 Ruby 的方言</title>
      <description>&lt;p&gt;&lt;a href="https://medium.com/@rubinius/rubinius-takes-the-fun-out-of-ruby-21db64ce87a6" rel="nofollow" target="_blank"&gt;https://medium.com/@rubinius/rubinius-takes-the-fun-out-of-ruby-21db64ce87a6&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Rubinius 不再自称 Ruby 已经有一段时间了，不过官网上也看不太出他们到底想干什么，刚刚去看了他们的博客，才知道他们打算把 Rubinius 做成 Ruby 的扩展。&lt;/p&gt;

&lt;p&gt;例如这篇博文提到，为 Ruby 添加了函数，类型和模式匹配语法：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;
&lt;span class="c1"&gt;# Note the block syntax to get around not being&lt;/span&gt;
&lt;span class="c1"&gt;# able to make 'data' a keyword.&lt;/span&gt;
&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="n"&gt;str&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="c1"&gt;# ...&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="n"&gt;int&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="c1"&gt;# ...&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="c1"&gt;# ...&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# The types above would be defined at the system level&lt;/span&gt;
&lt;span class="c1"&gt;# and available for import as desired.&lt;/span&gt;

&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="no"&gt;MyModel&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;str&lt;/span&gt;
  &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="ss"&gt;:age&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;int&lt;/span&gt;
  &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="ss"&gt;:color&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt;

  &lt;span class="c1"&gt;# Return type is specified by annotations.&lt;/span&gt;
  &lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="n"&gt;bool&lt;/span&gt;
  &lt;span class="n"&gt;fun&lt;/span&gt; &lt;span class="n"&gt;compare_age&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;a: &lt;/span&gt;&lt;span class="n"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;b: &lt;/span&gt;&lt;span class="n"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;文中提到 Object Oriented 面向组件的交互，而 Functional 面向数据操作，OO 和 FP 是对立的，但是可以各取所需。也就是在实际的工程中，应该依据不同的需求选用不同的范式，而不是分成两个派系相互对立。&lt;/p&gt;

&lt;p&gt;而作者本人花了八年尝试说服 Ruby 团队接受这些新的设计，依旧没有结果，只好自己来做了这个"additions to Ruby"。&lt;/p&gt;

&lt;p&gt;Rubinius 还设计了一个 defm 关键字，可以用来简化 case when：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;
  &lt;span class="n"&gt;defm&lt;/span&gt; &lt;span class="p"&gt;[](&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# return element at index or nil&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;defm&lt;/span&gt; &lt;span class="p"&gt;[](&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# return num elements starting at index&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;defm&lt;/span&gt; &lt;span class="p"&gt;[](&lt;/span&gt;&lt;span class="ss"&gt;index: &lt;/span&gt;&lt;span class="no"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="c1"&gt;# convert index to an Integer if it's not already&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;defm&lt;/span&gt; &lt;span class="p"&gt;[](&lt;/span&gt;&lt;span class="ss"&gt;range: &lt;/span&gt;&lt;span class="no"&gt;Range&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="c1"&gt;# convert range to a Range if it's not already&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个大概就是 [] 的实际定义，index: Integer() 意味着匹配可以被转换为 Integer 的对象。&lt;/p&gt;

&lt;p&gt;其实做方言还是不错的，只能希望未来和 Ruby 本身不会有太多冲突，因为 Ruby 目前没有靠谱的 LLVM 前端，如果 Rubinius 不做了，wasm 平台可能就看不到 Ruby 的身影了。&lt;/p&gt;

&lt;p&gt;我个人认为模式匹配不是真的那么重要，只是些锦上添花的东西，其实用 dsl 写也没差....Ruby 倒是挺需要一个 import/export，来解决常量作用域的问题..&lt;/p&gt;</description>
      <author>mizuhashi</author>
      <pubDate>Wed, 11 Jan 2017 20:51:13 +0800</pubDate>
      <link>https://ruby-china.org/topics/32107</link>
      <guid>https://ruby-china.org/topics/32107</guid>
    </item>
    <item>
      <title>AR 有办法将一个查询虚拟成 has_one 关联吗？(答案是可以)</title>
      <description>&lt;h2 id="场景："&gt;场景：&lt;/h2&gt;
&lt;p&gt;原来 model 里有 product has_one review_summary，review_summary 是一个 reviews 的统计数据，目前由定时任务以及回调更新。&lt;br&gt;
现在这个 summary 的逻辑简化了，可以通过一个简单的查询查出来，所以想将原来的 has_one 关联替换成一个查询，这样可以沿用之前 includes 的代码，逻辑上也是一致的。&lt;/p&gt;

&lt;p&gt;我知道视图可以做这个，但是希望可以在 ruby 的层面上做这个事情，不知可有好的方法？&lt;/p&gt;</description>
      <author>mizuhashi</author>
      <pubDate>Mon, 19 Dec 2016 11:54:44 +0800</pubDate>
      <link>https://ruby-china.org/topics/31931</link>
      <guid>https://ruby-china.org/topics/31931</guid>
    </item>
    <item>
      <title>Ruby 的 pipe</title>
      <description>&lt;p&gt;（误&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;
  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Proxy&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;BasicObject&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;method_missing&lt;/span&gt; &lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;
      &lt;span class="vi"&gt;@target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@target.send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;
      &lt;span class="vi"&gt;@target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;pipe&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;
    &lt;span class="no"&gt;Proxy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;instance_eval&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="sx"&gt;%w{a b c d}&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;capitalize&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; "Bcd"&lt;/span&gt;

&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="sx"&gt;%w{a b c d}&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;join&lt;/span&gt;
  &lt;span class="n"&gt;capitalize&lt;/span&gt;
  &lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; "Bcd"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;</description>
      <author>mizuhashi</author>
      <pubDate>Thu, 08 Dec 2016 17:33:11 +0800</pubDate>
      <link>https://ruby-china.org/topics/31848</link>
      <guid>https://ruby-china.org/topics/31848</guid>
    </item>
  </channel>
</rss>
