<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>gingerhot (B1nj0y)</title>
    <link>https://ruby-china.org/gingerhot</link>
    <description></description>
    <language>en-us</language>
    <item>
      <title>在 Hugo 中使用 GitFx</title>
      <description>&lt;p&gt;文章原文：&lt;a href="https://gitx.io/post/hugo-with-gitfx-zh_cn/" rel="nofollow" target="_blank"&gt;https://gitx.io/post/hugo-with-gitfx-zh_cn/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/gitx-io/GitFx" rel="nofollow" target="_blank" title=""&gt;GitFx&lt;/a&gt; 是我写的一个可以运行多种语言的代码片段的工具。同时提供了 &lt;a href="https://github.com/gitx-io/ActionServerless" rel="nofollow" target="_blank" title=""&gt;ActionServerless&lt;/a&gt; 这个 action 方便在 GitHub 的 workflow 里运行 GitFx。之所以把它命名为 &lt;code&gt;ActionServerless&lt;/code&gt; 这样的“热词”，除了蹭热度之外，你的确可以把用它实现的程序看作是一个 async 的 Serverless 应用。&lt;/p&gt;

&lt;p&gt;使用 GitFx/ActionServerless 可以方便快速地为开发、测试创建一个静态资源的 API 服务。而且只需要把代码推到 GitHub 上就可以使用了。&lt;/p&gt;

&lt;p&gt;我曾经想在博客中嵌入代码，同时通过一些服务去运行该代码，然后再把结果展示到文章里。可以使用 Docker 创建类似的功能，可以达到类似 Go playground 的那种效果。但是这对于个人博客不但有服务器开销，还会有安全问题。我们现在很多技术博客都是运行在 GitHub pages 上，所以用 GitFx 就方便多了：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;使用 GitFx 运行代码，把运行的输出存到一个路径&lt;/li&gt;
&lt;li&gt;对于 &lt;a href="http://gohugo.io/" rel="nofollow" target="_blank" title=""&gt;Hugo&lt;/a&gt; 的使用者，我们提供了一个 shortcode 插件可以很方便地把插入代码、展示运行结果变成一行代码&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;这样你就可以轻松地写技术博客了。下面我们通过一个 Hello world 的示例看下如何使用。&lt;/p&gt;
&lt;h2 id="Hello world 示例"&gt;Hello world 示例&lt;/h2&gt;&lt;h3 id="在 GitHub action 中运行 GitFx"&gt;在 GitHub action 中运行 GitFx&lt;/h3&gt;
&lt;p&gt;在本例我们把代码放到根目录下的 'app' 目录中。我们创建一个名为 &lt;code&gt;hello.py&lt;/code&gt; 的源文件，写上一行简单的 &lt;code&gt;print("Hello world!")&lt;/code&gt; 再加上一行用注释定义的存储输出的文件路径（具体写法可见下文的代码或参考 GitFx 的文档）。&lt;/p&gt;

&lt;p&gt;然后我们需要创建一个 GitHub action workflow，其中和 GitFx 有关的部分配置如下：&lt;/p&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;...&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gitx-io/ActionServerless@master&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;filepath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;./app'&lt;/span&gt;
&lt;span class="nn"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;完整的配置可参考&lt;a href="https://github.com/gitx-io/gitx-io.github.io/blob/master/hugo-gitfx_workflow_example.yml" rel="nofollow" target="_blank" title=""&gt;这里&lt;/a&gt;。&lt;/p&gt;
&lt;h3 id="在 Hugo 博客中展示代码和结果"&gt;在 Hugo 博客中展示代码和结果&lt;/h3&gt;
&lt;p&gt;我们提供了一个 Hugo shortcode 的插件 &lt;a href="https://github.com/gitx-io/hugo-gitfx" rel="nofollow" target="_blank" title=""&gt;hugo-gitfx&lt;/a&gt; 来展示 &lt;code&gt;hello.py&lt;/code&gt; 和它的运行结果。你只需要在文章需要插入代码的地方写上：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;{{&amp;lt; gitfx "app/hello.py" &amp;gt;}}&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;然后就会有下面这样的效果：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/gingerhot/2c25bee1-2b99-46e8-a948-f3cfc03009e7.png!large" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;如果你也恰好使用 Hugo 架设博客，也可以试一下哦！&lt;/p&gt;</description>
      <author>gingerhot</author>
      <pubDate>Thu, 06 Jan 2022 13:47:06 +0800</pubDate>
      <link>https://ruby-china.org/topics/42060</link>
      <guid>https://ruby-china.org/topics/42060</guid>
    </item>
    <item>
      <title>TabHub：一个为持续学习者准备的浏览器插件</title>
      <description>&lt;p&gt;TabHub 是一个 Chrome/Edge 浏览器的扩展应用。可以用它定制你在打开新的标签页时默认显示的内容。可以是你喜欢的一幅图片，或者一门语言的单词卡片，可以是你喜欢的 RSS 源，也可以是一个你常用的网页。通过我们额外提供的编辑工具，你可以定制一切。&lt;/p&gt;

&lt;p&gt;距离在谷歌扩展程序商店上架这个插件已经过去两年多了，一直感觉功能不是特别完善。但是对于爱鼓捣的程序员们，这个工具目前达到可用。发出来供有需要的同学把玩：）&lt;/p&gt;

&lt;p&gt;比如用它看 Hacker News 感觉还不错：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/gingerhot/f7861b5f-1b0d-4379-89d5-17c6fe485d59.png!large" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;记单词也行：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/gingerhot/fea109f1-eece-4735-9be8-b9ecc4cefaab.png!large" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;读 Ruby weekly：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/gingerhot/93875d94-828a-4eae-821f-03d80200345e.png!large" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;已知缺点&lt;/strong&gt;：图片等资源放在 GitHub 上，国内不翻墙会有影响&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;更多介绍看这里&lt;/strong&gt;：&lt;a href="https://tabhub.github.io/README_zh.html" rel="nofollow" target="_blank"&gt;https://tabhub.github.io/README_zh.html&lt;/a&gt;&lt;/p&gt;</description>
      <author>gingerhot</author>
      <pubDate>Fri, 30 Jul 2021 17:58:27 +0800</pubDate>
      <link>https://ruby-china.org/topics/41509</link>
      <guid>https://ruby-china.org/topics/41509</guid>
    </item>
    <item>
      <title>命令行工具：在浏览器预览 Markdown 文档</title>
      <description>&lt;p&gt;先贴下 GitHub 地址：&lt;a href="https://github.com/beijingrb/mdopen" rel="nofollow" target="_blank"&gt;https://github.com/beijingrb/mdopen&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="简介"&gt;简介&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;mdopen&lt;/code&gt; 是一个命令行工具，用来在浏览器中预览 Markdown 文档。如果你习惯使用 Markdown 编辑器编辑文档，那你可能不大需要这个工具。&lt;/p&gt;

&lt;p&gt;该命令行更适合那些喜欢用 vim 等在终端窗口写 Markdown 文档的人。比如在项目下写 &lt;code&gt;README&lt;/code&gt; 的时候。&lt;/p&gt;

&lt;p&gt;其实之前有想写个这样的工具自用，后来发现已经有人用 Go &lt;a href="https://github.com/romanyx/mdopen" rel="nofollow" target="_blank" title=""&gt;写了一个&lt;/a&gt;，预览页面使用 GitHub 的风格。用起来很好用，于是就想着移植到 Ruby，这样对于那些没有安装 Go 环境的 Rubyists 也能用啦。&lt;/p&gt;
&lt;h3 id="安装"&gt;安装&lt;/h3&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;gem &lt;span class="nb"&gt;install &lt;/span&gt;mdopen
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="用法"&gt;用法&lt;/h3&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;mdopen &amp;lt;markdown_file_path&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果没有给参数，或者给定的文件不存在，则会读取当前目录下的 &lt;code&gt;README&lt;/code&gt; 或者 &lt;code&gt;README.md&lt;/code&gt; 文件。如果你在项目目录下想预览 README 文档，直接运行 &lt;code&gt;mdopen&lt;/code&gt; 即可。&lt;/p&gt;</description>
      <author>gingerhot</author>
      <pubDate>Tue, 12 Jun 2018 18:30:40 +0800</pubDate>
      <link>https://ruby-china.org/topics/36937</link>
      <guid>https://ruby-china.org/topics/36937</guid>
    </item>
    <item>
      <title>使用 Ruby FFI 调用 Go 函数：十倍效率提升</title>
      <description>&lt;p&gt;注：本文根据几篇网文和 GitHub 资源综合编译，链接在文末给出。&lt;/p&gt;

&lt;p&gt;本文主要介绍：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;如何使用 Go 编写和生成共享库（shared library）&lt;/li&gt;
&lt;li&gt;然后如何使用  Ruby FFI 对这些共享库进行调用&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="环境要求"&gt;环境要求&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Ruby 环境，本文使用 &lt;code&gt;2.3.4p301&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Golang 版本最低 1.5 或以上，本文使用 &lt;code&gt;go1.9.2 darwin/amd64&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="什么是共享库"&gt;什么是共享库&lt;/h2&gt;
&lt;p&gt;共享库和静态库都属于库文件，可以理解为编译好的程序，但是自己没有执行入口，供其它程序调用来执行。&lt;/p&gt;

&lt;p&gt;可参考：&lt;a href="http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html" rel="nofollow" target="_blank"&gt;http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="先比较一下 fibonacci 计算的执行速度"&gt;先比较一下 fibonacci 计算的执行速度&lt;/h2&gt;
&lt;p&gt;作为类型语言的 Go 对于 Ruby 的优势更多的在 CPU 密集计算方面，所以我们先来比较一下 Ruby 和 Go 实现的 fibonacci 函数的效率。为了简化比较的考虑，我们采用同样的算法。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# fib.ruby&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="n"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// fib.go&lt;/span&gt;
&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"fmt"&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="kt"&gt;uint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;uint&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;40&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;Ruby 的用时：&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;time &lt;/span&gt;ruby fib.rb
102334155

real    0m14.027s
user    0m13.827s
sys 0m0.067s
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;直接运行 &lt;code&gt;go run&lt;/code&gt; 执行的用时：&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;time &lt;/span&gt;go run fib.go
102334155

real    0m1.691s
user    0m0.957s
sys 0m0.362s
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以看到 Go 编译 + 运行的时间也要 10 倍于 Ruby 的速度。下面是直接执行 Go 二进制程序的速度（直接执行使用 &lt;code&gt;go build fib.go&lt;/code&gt; 编译生成的 &lt;code&gt;fib&lt;/code&gt; 二进制文件，相比 go run 省去了编译时间）：&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;time&lt;/span&gt; ./fib
102334155

real    0m0.753s
user    0m0.741s
sys 0m0.007s
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;差不多是 Ruby 程序的 18 倍。可以看到执行效率的差距还是很大的。&lt;/p&gt;
&lt;h2 id="使用 Go 编写和生成共享库"&gt;使用 Go 编写和生成共享库&lt;/h2&gt;
&lt;p&gt;使用 Go 编写共享库和写普通的 Go 程序差别不大，主要是在代码里 import 一个名为 "C" 的伪包，然后在执行 go build 编译的时候加上 &lt;code&gt;-buildmode=c-shared&lt;/code&gt; 参数。这样在编译的时候会自动调用 Cgo 进行相应的操作。有关 Cgo 的一些细节，可以阅读 &lt;a href="https://golang.org/cmd/cgo/" rel="nofollow" target="_blank" title=""&gt;C? Go? Cgo!&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;我们先来写一下作为共享库的 fibonacci 函数：&lt;/p&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// fib_lib.go&lt;/span&gt;
&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"C"&lt;/span&gt;

&lt;span class="c"&gt;//export fib&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="kt"&gt;uint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;uint&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&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;code&gt;//export fib&lt;/code&gt; 来实现的，因此这行注释是必须的。&lt;/p&gt;

&lt;p&gt;然后我们来编译生成共享库，因为我是在 macOS 上执行，macOS 和 Linux 生成的命令略有不同，分别是：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# macOS
go build -buildmode=c-shared -ldflags -s -o fib.dylib fib_lib.go  
&lt;/code&gt;&lt;/pre&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Linux
go build -buildmode=c-shared -o fib.so fib_lib.go  
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="从 Ruby 调用 Go 函数"&gt;从 Ruby 调用 Go 函数&lt;/h3&gt;
&lt;p&gt;我们使用 FFI 这个 gem 提供的接口来从 Ruby 调用外部函数。有关 &lt;a href="https://ja.wikipedia.org/wiki/Foreign_function_interface" rel="nofollow" target="_blank" title=""&gt;Foreign Function Interface&lt;/a&gt; 和 &lt;a href="https://github.com/ffi/ffi" rel="nofollow" target="_blank" title=""&gt;FFI Gem&lt;/a&gt; 可以点击相应链接了解。我们先来安装 FFI Gem：&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gem &lt;span class="nb"&gt;install &lt;/span&gt;ffi
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后我们使用 Ruby FFI 来调用我们用 Go 编写的 fib 函数：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# go-fib.rb&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"ffi"&lt;/span&gt;

&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Fib&lt;/span&gt;
  &lt;span class="kp"&gt;extend&lt;/span&gt; &lt;span class="no"&gt;FFI&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Library&lt;/span&gt;
  &lt;span class="c1"&gt;# 下面是我在 macOS 上运行的写法，如果在 Linux 上调用的文件为 "fib.so"&lt;/span&gt;
  &lt;span class="n"&gt;ffi_lib&lt;/span&gt; &lt;span class="s2"&gt;"fib.dylib"&lt;/span&gt;
  &lt;span class="n"&gt;attach_function&lt;/span&gt; &lt;span class="ss"&gt;:fib&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:uint&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="ss"&gt;:uint&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="no"&gt;Fib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里需要关注的是 &lt;code&gt;attach_function&lt;/code&gt; 这个函数的参数，分别是要从外部引用的 &lt;code&gt;函数的名称&lt;/code&gt;, &lt;code&gt;该函数的参数类型的数组&lt;/code&gt; 以及 &lt;code&gt;该函数的返回值类型&lt;/code&gt;。这个可以和我们写的 Go 的函数对应起来：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="n"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="n"&gt;uint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;uint&lt;/span&gt;
&lt;span class="ss"&gt;:fib&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:uint&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="ss"&gt;:uint&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ruby 的类型和外部函数的类型对照可以参考 FFI Gem 的 &lt;a href="https://github.com/ffi/ffi/wiki/Types" rel="nofollow" target="_blank" title=""&gt;wiki&lt;/a&gt;。 &lt;/p&gt;
&lt;h3 id="运行比较"&gt;运行比较&lt;/h3&gt;
&lt;p&gt;接下来我们比较一下 Ruby 原生的 fibonacci 和通过 FFI 调用 Go 共享库的运行效率：&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;time &lt;/span&gt;ruby fib.rb
102334155

real    0m13.673s
user    0m13.600s
sys 0m0.042s
&lt;/code&gt;&lt;/pre&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;time &lt;/span&gt;ruby go_lib.rb
102334155

real    0m0.883s
user    0m0.843s
sys 0m0.032s
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以看出差距也在 15 倍左右。&lt;/p&gt;
&lt;h3 id="参考资源"&gt;参考资源&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://qiita.com/achm/items/679b3f3af2cf377f0f02" rel="nofollow" target="_blank"&gt;https://qiita.com/achm/items/679b3f3af2cf377f0f02&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://c7.se/go-and-ruby-ffi/" rel="nofollow" target="_blank"&gt;https://c7.se/go-and-ruby-ffi/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/draffensperger/go-interlang" rel="nofollow" target="_blank"&gt;https://github.com/draffensperger/go-interlang&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;本文主要翻译自 1，同时参考了 2，3。&lt;/p&gt;

&lt;p&gt;勉为编译，不妥之处还请多多指教。&lt;/p&gt;</description>
      <author>gingerhot</author>
      <pubDate>Fri, 19 Jan 2018 16:28:26 +0800</pubDate>
      <link>https://ruby-china.org/topics/34921</link>
      <guid>https://ruby-china.org/topics/34921</guid>
    </item>
    <item>
      <title>如何使用 Rails 集成开发 Go API</title>
      <description>&lt;p&gt;go-on-rails 是一个 Rails 的 generator，已经发布为 &lt;a href="https://rubygems.org/gems/go-on-rails" rel="nofollow" target="_blank" title=""&gt;gem&lt;/a&gt;，用来在 Rails 项目中集成或是开发 Golang 应用。&lt;/p&gt;

&lt;p&gt;项目地址：&lt;a href="https://github.com/railstack/go-on-rails" rel="nofollow" target="_blank" title=""&gt;https://github.com/railstack/go-on-rails&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;本文不会讲述详细的使用方法，所以先把现有的几个示例教程放一下：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/railstack/example_simple" rel="nofollow" target="_blank" title=""&gt;简单示例&lt;/a&gt; 仿照 Rails guides 里那个入门的 &lt;a href="http://guides.rubyonrails.org/getting_started.html" rel="nofollow" target="_blank" title=""&gt;demo&lt;/a&gt;，演示如何使用 go-on-rails 创建和生成一个简单 blog 的 Go API。&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/railstack/example_with_admin" rel="nofollow" target="_blank" title=""&gt;高级教程&lt;/a&gt;  如何创建一个 Golang 项目，并和 rails_admin, devise, cancancan 等集成，为 Go 项目快速增加一个管理后台。同时该项目演示了如何使用 Rails 5.1 新发布的 webpacker 工具，并利用 React 制作独立的前端界面在 Rails 中调用 Go 接口。&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/railstack/example_read_rails_session" rel="nofollow" target="_blank" title=""&gt;如何从 Go API 读取 Rails session&lt;/a&gt; 讲解如何在一个 go-on-rails 生成的 Go 接口中读取 Rails 的 session 做用户验证&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="go-on-rails 做些什么"&gt;go-on-rails 做些什么&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;使用 Rails 创建 model，然后 go-on-rails 根据 model 的定义生成相应 Go 的数据结构以及一些基本的 CRUD 方法、添加 validation，同时也生成了分页等方法&lt;/li&gt;
&lt;li&gt;对以上生成的这些方法生成 godoc 文档&lt;/li&gt;
&lt;li&gt;根据 Rails 的数据库配置，生成数据库连接配置&lt;/li&gt;
&lt;li&gt;一些命令行工具帮助自动化常见任务，比如安装默认依赖、format 生成的文件、查看 godoc 文档等&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="为什么使用 go-on-rails"&gt;为什么使用 go-on-rails&lt;/h2&gt;
&lt;p&gt;这个工具的目标用户首先是 Rails 开发者，想进行 Golang 的学习或者是想在 Rails 项目中集成 Go API。也就是要对 Rails 熟悉，否则可能很多人不会为了尝试这个工具来学习 Rails 的。&lt;/p&gt;

&lt;p&gt;接下来主要说一下为什么会有这个 gem，或者说&lt;strong&gt;使用 Rails 开发 Go 项目真的有什么优势吗？&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;配置管理。比如通过在 Rails 中对数据库进行配置，生成的 Go 项目会根据 Rails 的配置生成相应环境数据库的连接配置。同样，其它的配置也可以利用 Rails 的配置来共享使用。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;利用 Rails 丰富的工具链，比如用 rails db:seed 写入测试数据，利用 rails console 对数据进行测试等，以及数据库管理部分的 rails db:* 等操作。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;方便对数据库进行各种 migrations 的管理，不用手写 schema，延续了 Rails 程序员开发过程中对数据库的操作习惯。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;model 的定义同样会方便 Rails 开发者的习惯，go-on-rails 会对 association 和 validation 中的大部分生成操作函数。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Rails 5.1 中 webpacker 的发布，更突显了 Rails 在做“Web 集成开发环境”方面的新能力。更多前后端分离系统的出现，使在 Rails 中集成 Go API 的重复工作量大大降低，只需要修改一下调用的链接可能就完成了一次系统改造。另外，使用 webpacker 可以很方便的制作前端页面来调用 Go API。关于如何使用可以看&lt;a href="https://github.com/railstack/example_with_admin#make-a-nice-page" rel="nofollow" target="_blank" title=""&gt;这里的教程&lt;/a&gt;。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;对于某些中小规模的系统，通过在 Rails 中集成 Go API 可以改善一些接口的性能，而不需要对系统架构进行重构。&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;go-on-rails 目前还在开发过程中，欢迎各种参与和 pr。&lt;/p&gt;

&lt;hr&gt;

&lt;p&gt;【UPDATE】本项目无意间获得了 matz 的转推加持：&lt;a href="https://twitter.com/yukihiro_matz/status/1031768139858501632" rel="nofollow" target="_blank"&gt;https://twitter.com/yukihiro_matz/status/1031768139858501632&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2019/458bd637-fdc0-4d20-ba32-95c797eea476.png!large" title="" alt=""&gt;&lt;/p&gt;</description>
      <author>gingerhot</author>
      <pubDate>Fri, 29 Sep 2017 11:40:27 +0800</pubDate>
      <link>https://ruby-china.org/topics/34289</link>
      <guid>https://ruby-china.org/topics/34289</guid>
    </item>
  </channel>
</rss>
