<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>palytoxin</title>
    <link>https://ruby-china.org/palytoxin</link>
    <description></description>
    <language>en-us</language>
    <item>
      <title>关于用 Docker 离线部署我的做法和讨论</title>
      <description>&lt;h2 id="背景"&gt;背景&lt;/h2&gt;
&lt;p&gt;一个 rails 的项目没有互联网环境，离线部署，只能用光盘刻录数据。以往没有这种部署经验，基本是摸着石头过河。&lt;/p&gt;

&lt;p&gt;系统镜像 Centos 7.4  Ruby 2.7.3 Rails 6.1.4&lt;/p&gt;

&lt;p&gt;以往的项目都在 AWS 或者阿里云上，基本都是实体机环境直接安装依赖 cap 部署。&lt;/p&gt;

&lt;p&gt;这次因为项目依赖较多集成了一些调用 py 的 OCR，和人脸识别功能，数据库还需要对接第三方的 Oracle 数据。因为乱七八糟的环境较多，所以当时考虑用 docker 安装部署。&lt;/p&gt;
&lt;h2 id="方案"&gt;方案&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt; 打个 Docker 进去整体运行。
网上参考的资料较多较杂，流程大概和论坛里差不多（&lt;a href="https://ruby-china.org/topics/32459" rel="nofollow" target="_blank"&gt;https://ruby-china.org/topics/32459&lt;/a&gt; 类似）。这个方案测试了一下就直接放弃了，因为依赖多，打出来的包非常大，因为只能用光盘复制数据，更新代码必须整个环境打包，排除此方案。&lt;/li&gt;
&lt;li&gt;将运行环境打包进 docker。代码和 gems 单独打包，更新代码时候只更新源代码，运行时将源代码目录挂载到 docker 中运行。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="实施"&gt;实施&lt;/h2&gt;&lt;h3 id="Dockerfile"&gt;Dockerfile&lt;/h3&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;FROM ruby:2.7-slim&lt;/span&gt;
&lt;span class="s"&gt;WORKDIR /&lt;/span&gt;
&lt;span class="s"&gt;RUN sed -i 's/deb.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list &amp;amp;&amp;amp; \&lt;/span&gt;
  &lt;span class="s"&gt;sed -i 's/security.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list &amp;amp;&amp;amp; \&lt;/span&gt;
 &lt;span class="s"&gt;apt-get update &amp;amp;&amp;amp; \&lt;/span&gt;
 &lt;span class="s"&gt;apt-get install -y wget&lt;/span&gt;
&lt;span class="s"&gt;RUN wget http://test.example.com/chi_sfz.traineddata &amp;amp;&amp;amp; \&lt;/span&gt;
  &lt;span class="s"&gt;wget http://test.example.com/chi_sim.traineddata &amp;amp;&amp;amp; \&lt;/span&gt;
  &lt;span class="s"&gt;wget http://test.example.com/chi_sim_vert.traineddata&lt;/span&gt;
&lt;span class="s"&gt;RUN apt-get install -y g++ autoconf automake libtool pkg-config libpng-dev libjpeg62-turbo-dev libtiff5-dev zlib1g-dev libleptonica-dev ca-certificates git libicu-dev libpango1.0-dev libcairo-dev make &amp;amp;&amp;amp; \&lt;/span&gt;
  &lt;span class="s"&gt;git clone --depth 1 https://gitee.com/mirrors/Tesseract-OCR.git /tesseract &amp;amp;&amp;amp; \&lt;/span&gt;
  &lt;span class="s"&gt;cd /tesseract &amp;amp;&amp;amp; \&lt;/span&gt;
  &lt;span class="s"&gt;./autogen.sh &amp;amp;&amp;amp; \&lt;/span&gt;
  &lt;span class="s"&gt;./configure &amp;amp;&amp;amp; \&lt;/span&gt;
  &lt;span class="s"&gt;make&lt;/span&gt;

&lt;span class="s"&gt;FROM ruby:2.7-slim&lt;/span&gt;
&lt;span class="s"&gt;ENV APP_HOME=/app \&lt;/span&gt;
    &lt;span class="s"&gt;DEBIAN_FRONTEND=noninteractive \&lt;/span&gt;
    &lt;span class="s"&gt;RAILS_ENV=production \&lt;/span&gt;
    &lt;span class="s"&gt;EDITOR=vim \&lt;/span&gt;
    &lt;span class="s"&gt;LD_LIBRARY_PATH=/opt/oracle/instantclient \&lt;/span&gt;
    &lt;span class="s"&gt;NODE_OPTIONS="--max-old-space-size=8192" \&lt;/span&gt;
    &lt;span class="s"&gt;BUILD_PACKAGES="build-essential" \&lt;/span&gt;
    &lt;span class="s"&gt;DEV_PACKAGES="apt-utils git curl gnupg ca-certificates tzdata openssl ruby-dev imagemagick nodejs cron vim libpq-dev libxml2-dev libxslt-dev libaio1 cmake python3  python3-dev python3-pip python3-wheel python3-setuptools tesseract-ocr libtesseract-dev" \&lt;/span&gt;
    &lt;span class="s"&gt;REMOVE_PACKAGES="cmake"&lt;/span&gt;

&lt;span class="s"&gt;COPY --from=0 /tesseract /tesseract&lt;/span&gt;
&lt;span class="s"&gt;RUN mkdir $APP_HOME &amp;amp;&amp;amp; \&lt;/span&gt;
      &lt;span class="s"&gt;echo 'gem&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;--no-document' &amp;gt;&amp;gt; ~/.gemrc &amp;amp;&amp;amp; \&lt;/span&gt;
      &lt;span class="s"&gt;echo -e "registry=https://registry.npm.taobao.org\nsass_binary_site=https://npm.taobao.org/mirrors/node-sass/\nphantomjs_cdnurl=http://npm.taobao.org/mirrors/phantomjs\nELECTRON_MIRROR=http://npm.taobao.org/mirrors/electron/" &amp;gt;&amp;gt; ~/.npmrc &amp;amp;&amp;amp; \&lt;/span&gt;
      &lt;span class="s"&gt;bundle config set mirror.https://rubygems.org https://gems.ruby-china.com &amp;amp;&amp;amp; \&lt;/span&gt;
      &lt;span class="s"&gt;gem sources --add https://gems.ruby-china.com/ --remove https://rubygems.org/ &amp;amp;&amp;amp; \&lt;/span&gt;
      &lt;span class="s"&gt;bundle config set path 'vendor/bundle' &amp;amp;&amp;amp; \&lt;/span&gt;
      &lt;span class="s"&gt;bundle config set without 'development test' &amp;amp;&amp;amp; \&lt;/span&gt;
      &lt;span class="s"&gt;gem install bundler &amp;amp;&amp;amp; \&lt;/span&gt;
      &lt;span class="s"&gt;sed -i 's/deb.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list &amp;amp;&amp;amp; \&lt;/span&gt;
      &lt;span class="s"&gt;sed -i 's/security.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list &amp;amp;&amp;amp; \&lt;/span&gt;
      &lt;span class="s"&gt;apt-get update &amp;amp;&amp;amp; \&lt;/span&gt;
      &lt;span class="s"&gt;apt-get install -y $BUILD_PACKAGES $DEV_PACKAGES --no-install-recommends &amp;amp;&amp;amp; \&lt;/span&gt;
      &lt;span class="s"&gt;pip3 config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple &amp;amp;&amp;amp; \&lt;/span&gt;
      &lt;span class="s"&gt;pip3 install dlib &amp;amp;&amp;amp; \&lt;/span&gt;
      &lt;span class="s"&gt;pip3 install face_recognition &amp;amp;&amp;amp; \&lt;/span&gt;
      &lt;span class="s"&gt;apt-get remove -y $REMOVE_PACKAGES &amp;amp;&amp;amp; \&lt;/span&gt;
      &lt;span class="s"&gt;echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list &amp;amp;&amp;amp; \&lt;/span&gt;
      &lt;span class="s"&gt;curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - &amp;amp;&amp;amp; \&lt;/span&gt;
      &lt;span class="s"&gt;apt-get update &amp;amp;&amp;amp; \&lt;/span&gt;
      &lt;span class="s"&gt;apt-get install yarn &amp;amp;&amp;amp; \&lt;/span&gt;
      &lt;span class="s"&gt;rm -rf /var/lib/apt/lists/* &amp;amp;&amp;amp; \&lt;/span&gt;
      &lt;span class="s"&gt;apt-get clean autoclean &amp;amp;&amp;amp; \&lt;/span&gt;
      &lt;span class="s"&gt;apt-get autoremove --yes &amp;amp;&amp;amp; \&lt;/span&gt;
      &lt;span class="s"&gt;rm -rf /var/lib/{apt,dpkg,cache,log}/ &amp;amp;&amp;amp; \&lt;/span&gt;
      &lt;span class="s"&gt;yarn config set registry https://registry.npm.taobao.org/&lt;/span&gt;
&lt;span class="s"&gt;RUN cd /tesseract &amp;amp;&amp;amp; make install &amp;amp;&amp;amp; /sbin/ldconfig &amp;amp;&amp;amp; \&lt;/span&gt;
      &lt;span class="s"&gt;rm -rf /tesseract&lt;/span&gt;

&lt;span class="s"&gt;COPY --from=0 /*.traineddata /usr/local/share/tessdata/&lt;/span&gt;
&lt;span class="s"&gt;COPY instantclient /opt/oracle/instantclient&lt;/span&gt;
&lt;span class="s"&gt;COPY start.sh /&lt;/span&gt;

&lt;span class="s"&gt;WORKDIR $APP_HOME&lt;/span&gt;
&lt;span class="s"&gt;RUN chmod +x /start.sh&lt;/span&gt;
&lt;span class="c1"&gt;# CMD ["/start.sh"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个方案是把所有运行以及编译环境安装好，这样在本地打包的时候可以复用这个 docker 去 bundle 安装其他依赖。&lt;/p&gt;
&lt;h3 id="makefile"&gt;makefile&lt;/h3&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CURRENT_DIR = $(shell pwd)
RUBY_DOCKER_TAG = myrails:2.7-slim
NGINX_DOCKER_TAG = openresty/openresty:alpine
REDIS_DOCKER_TAG = redis:alpine
POSTGRES_DOCKER_TAG = postgres:alpine
SRC_PACKAGE = src.tar.gz
DOCKER_PACKAGE = docker.tar.gz

.PHONY: make_docker_deps package release clean docker build_src clean_tmp

build_src:
    docker run --rm -v ${CURRENT_DIR}:/app -i -t ${RUBY_DOCKER_TAG} make release
clean:
    docker run --rm -v ${CURRENT_DIR}:/app -i -t ${RUBY_DOCKER_TAG} make clean_tmp

release: make_docker_deps package

make_docker_deps:
    bundle install
    bundle exec rake assets:clobber
    yarn install
    bundle exec rake assets:precompile
    bundle exec rake webpacker:compile

package:
    @echo 'release...'
    tar \
        --exclude='./tmp' \
        --exclude='./.git' \
        --exclude='./log/' \
        --exclude='./node_modules' \
        --exclude='./yarn-error.log' \
        --exclude='./docker_conf/instantclient' \
        --exclude='*.docker' \
        --exclude='${SRC_PACKAGE}' \
        --exclude='*.tar.gz' \
        -czf ${SRC_PACKAGE} .
    @echo "release tar end."

clean_tmp:
    /bin/rm -rf ./node_modules/*
    /bin/rm -rf ./vendor/*
    /bin/rm -f ${SRC_PACKAGE} *.docker ${DOCKER_PACKAGE}

docker\:base:
    docker build ./docker_conf -t ${RUBY_DOCKER_TAG} -f docker_conf/Dockerfile

docker:
    docker save -o ruby.docker ${RUBY_DOCKER_TAG}
    docker save -o nginx.docker ${NGINX_DOCKER_TAG}
    docker save -o redis.docker ${REDIS_DOCKER_TAG}
    docker save -o postgres.docker ${POSTGRES_DOCKER_TAG}
    tar czvf ${DOCKER_PACKAGE} ruby.docker nginx.docker redis.docker postgres.docker
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里用 make 去打包生成部署的文件，运行环境&lt;/p&gt;
&lt;h3 id="docker-compose.yml"&gt;docker-compose.yml&lt;/h3&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version: '3.5'

services:
  openresty:
    image: openresty/openresty:alpine
    restart: always
    ports:
      - 80:80
      - 443:443
    environment:
      - TZ=Asia/Shanghai
    volumes:
      - $PWD/docker_conf/nginx.conf:/usr/local/openresty/nginx/conf/nginx.conf:ro
      - $PWD/docker_conf/dhparam.pem:/usr/local/openresty/nginx/conf/dhparam.pem:ro
      - $PWD/docker_conf/nginx-selfsigned.crt:/usr/local/openresty/nginx/conf/nginx-selfsigned.crt:ro
      - $PWD/docker_conf/nginx-selfsigned.key:/usr/local/openresty/nginx/conf/nginx-selfsigned.key:ro
    depends_on:
      - ruby
    networks:
      - local_network
  ruby:
    image: myrails:2.7-slim
    restart: always
    environment:
      - TZ=Asia/Shanghai
      - RAILS_ENV=production
      - PIDFILE=/tmp/server.pid
      - RAILS_SERVE_STATIC_FILES=true
      - RAILS_LOG_TO_STDOUT=true
      - DATABASE_HOST=postgres
      - DATABASE_USERNAME=username
      - DATABASE_PASSWORD=password
      - REDIS_URL=redis://redis:6379/0/cache
    volumes:
      - "$PWD:/app"
      - "$PWD/docker_conf/start.sh:/start.sh"
      - "/project/storage:/app/storage"
    depends_on:
      - postgres
      - redis
    networks:
      - local_network
    command: ["bash", "/start.sh"]
  postgres:
    image: postgres:alpine
    restart: always
    shm_size: '1gb'
    ports:
      - 5432:5432
    volumes:
      - "/project/dbdata:/var/lib/postgresql/data"
      - "$PWD/docker_conf/postgres.conf:/etc/postgresql/postgresql.conf"
    environment:
      - TZ=Asia/Shanghai
      - POSTGRES_USER=username
      - POSTGRES_PASSWORD=password
    networks:
      - local_network
  redis:
    image: redis:alpine
    restart: always
    environment:
      - TZ=Asia/Shanghai
    volumes:
      - "$PWD/docker_conf/redis.conf:/etc/redis/redis.conf"
      - "/project/redisdb:/data"
    networks:
      - local_network
networks:
  local_network:
    external: true

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里是用 docker-compose 配合 systemd 写的服务去控制项目的运行
项目存储的文件都放在/project 目录&lt;/p&gt;
&lt;h2 id="疑问"&gt;疑问&lt;/h2&gt;
&lt;p&gt;目前项目的部署和启动没有什么大的问题。但是相比实体机安装，cap 部署，这种方式无疑速度最慢，在部署过程中重启 docker-compose 冲断服务上时间更长。
另外这个项目也会对接一些 ftp 的终端，需要检测别的设备 ftp 上传的文件。目前计划在 docker-compose 中新增一个 ftp 容器，然后把 ftp 目录分别挂在到 rails 和 ftp 的容器中。&lt;/p&gt;

&lt;p&gt;目前有几个问题希望和大家讨论一下：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;请问各位有无好一些的方式来改善，新代码部署后重启 docker-compose 带来的服务中断问题？&lt;/li&gt;
&lt;li&gt;最近测试了一下 dokcer swarm 的集群模式，但是对数据库持久化，还有 ftp 存放的问题都没有很好的解决。比如只在 swarm 相关的讨论中只能找到用 nfs 去挂实体机目录，但是用户那边 nfs 一些端口安全问题也不能开&lt;/li&gt;
&lt;li&gt;当然可能也是我不太会用，请问部署这种离线的应用，正确的做法是什么？如果想引入容器集群的话，有没有最佳实践？&lt;/li&gt;
&lt;/ol&gt;</description>
      <author>palytoxin</author>
      <pubDate>Fri, 03 Sep 2021 14:13:03 +0800</pubDate>
      <link>https://ruby-china.org/topics/41650</link>
      <guid>https://ruby-china.org/topics/41650</guid>
    </item>
    <item>
      <title>Flip Flop Operator in Ruby [Ruby 中的触发器操作] (..)</title>
      <description>&lt;p&gt;翻译自&lt;a href="http://nithinbekal.com/posts/ruby-flip-flop/" rel="nofollow" target="_blank" title=""&gt;Flip Flop Operator in Ruby&lt;/a&gt;
reddit 上看到的，因为从来没看到过这种用法，一起学起~
E 文不好请多指教&lt;/p&gt;

&lt;p&gt;触发器操作符是一种很奇怪的 ruby 特性，大多数人甚至都没有意识到它的存在。这种特性是从 perl 风格中继承而来，但是几乎没有人使用。在这片文章中，我们将会看到什么是触发器操作符 [flip-flop operators]，并且学习他是如何使用的。&lt;/p&gt;
&lt;h2 id="什么是触发器操作符[flip-flop operators]？"&gt;什么是触发器操作符 [flip-flop operators]？&lt;/h2&gt;
&lt;p&gt;触发器操作符 和 range 操作符 (..) 一样，条件声明在操作符两边。类似下面这样：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;#=&amp;gt;&lt;/span&gt;
&lt;span class="mi"&gt;5&lt;/span&gt;
&lt;span class="mi"&gt;6&lt;/span&gt;
&lt;span class="mi"&gt;7&lt;/span&gt;
&lt;span class="mi"&gt;8&lt;/span&gt;
&lt;span class="mi"&gt;9&lt;/span&gt;
&lt;span class="mi"&gt;10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;直到第一个表达式为 true &lt;em&gt;之前&lt;/em&gt; 整个表达式的结果为 false。&lt;/li&gt;
&lt;li&gt;以上条件成立后，在第二个表达式为 true  &lt;em&gt;之前&lt;/em&gt;，表达式结果是 true。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;在上面那个例子中 x==5 之后 x==10 之前等式成立，所以输出了 5 到 10 这几个数字。&lt;/p&gt;
&lt;h2 id="其他的例子"&gt;其他的例子&lt;/h2&gt;
&lt;p&gt;让我们再举一个例子，看看操作符的更多行为。想象一下，当你解析一个有缩进标记和反缩进标记的文件时。每当碰到一个缩进符号就打开缩进，当碰到一个反缩进符号时就将缩进关掉。&lt;/p&gt;

&lt;p&gt;这个例子中，我们尝试处理一下文本：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;zero indentation
indent
inside block
dedent
after the block
indent
another block
dedent
end of file
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;当输出之后，它看起来应该是这样的：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;zero indentation
  indent
  inside block
  dedent
after the block
  indent
  another block
  dedent
end of file
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在这个例子中，我们需要跟踪缩进的状态。触发器操作符的处理会让我们眼前一亮。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;lines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readlines&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'somefile'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;/^indent/&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;/^dedent/&lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;" "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;line&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;现在这个操作符看起来有点用了。你可以这么理解：从包含"indent"的地方开始，到遇到"dedent"的地方，在每一行的开始都加上两个空格。&lt;/p&gt;
&lt;h2 id="这种特性将会从ruby中移除么？"&gt;这种特性将会从 ruby 中移除么？&lt;/h2&gt;
&lt;p&gt;移除这个特性的 issue 已经被提出来了。在 ruby2.0 发布之前，Matz 说如果要删除这个特性，那也应该等到 ruby3.0。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Under the current plan, I am not going to remove flip-flop from 2.0, since we are not going to made incompatible changes anytime soon. We have to wait until 3.0. (–Matz)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;我并不是这种语法的强烈依赖者，并且几乎不会在我的代码中用到。如果这种特性在将来被移除，并不会引起太多的错误。&lt;/p&gt;

&lt;p&gt;在过去几年在这个问题上并没有过多的活动，所以也不能确定在某一天这个特性会被移除。但是通过了解这种语法，我们能够在见到这种代码的时候不至于莫名奇妙。&lt;/p&gt;
&lt;h2 id="外部链接"&gt;外部链接&lt;/h2&gt;
&lt;p&gt;Feature #5400 - &lt;a href="https://bugs.ruby-lang.org/issues/5400" rel="nofollow" target="_blank" title=""&gt;Remove flip-flops in 2.0&lt;/a&gt; - the discussion on the Ruby issue tracker&lt;/p&gt;</description>
      <author>palytoxin</author>
      <pubDate>Mon, 24 Nov 2014 23:49:52 +0800</pubDate>
      <link>https://ruby-china.org/topics/22840</link>
      <guid>https://ruby-china.org/topics/22840</guid>
    </item>
    <item>
      <title>MyGitStar 管理你的 github star！</title>
      <description>&lt;p&gt;&lt;img src="//l.ruby-china.com/photo/2014/4fcac9613d4bf2f9f9878a78245cb4be.png" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;还在为 github 上那么多的 star 束手无策么&amp;gt;_&amp;lt;&lt;/p&gt;

&lt;p&gt;强迫症看见 star 项目一多就忍不住清理。现在终于找到了好工具！
偶然发现的，感谢作者 (・ω・)&lt;/p&gt;

&lt;p&gt;link: &lt;a href="http://mygitstar.herokuapp.com/" rel="nofollow" target="_blank"&gt;http://mygitstar.herokuapp.com/&lt;/a&gt;&lt;/p&gt;</description>
      <author>palytoxin</author>
      <pubDate>Thu, 15 May 2014 09:41:21 +0800</pubDate>
      <link>https://ruby-china.org/topics/19265</link>
      <guid>https://ruby-china.org/topics/19265</guid>
    </item>
    <item>
      <title>需求变更导致的数据库变动，应当如何做才能无缝迁移？</title>
      <description>&lt;p&gt;是这样的，之前的设计不能满足新的要求，一个数据库表中的数据要被拆成两部分通过某些条件。有其他的相互关联表。
这种情况下一般的思路是什么，有事例可以借鉴学习么？
现在完全没有思路
先谢过大家&lt;/p&gt;</description>
      <author>palytoxin</author>
      <pubDate>Thu, 08 May 2014 01:18:04 +0800</pubDate>
      <link>https://ruby-china.org/topics/19090</link>
      <guid>https://ruby-china.org/topics/19090</guid>
    </item>
    <item>
      <title>多表联结后，不同父对象的子对象可以从头排序么</title>
      <description>&lt;p&gt;比如我有个需求，每个人 (person) 都有单独的留言 (message 表)
person has_many message
现有 A、B 两人
给 A 留言一次 message id1 =&amp;gt; 给 a 的留言
给 B 留言一次 message id2 =&amp;gt; 给 b 的留言
给 A 留言一次 message id3 =&amp;gt; 给 a 的第二次留言&lt;/p&gt;

&lt;p&gt;有没有现成的解决方案，让给 A 留言第二次时能保存“这是第二次给 A 留言”这种信息？&lt;/p&gt;

&lt;p&gt;看过 redmine 的代码，project 中提交 issue 的情况类似，不同项目用同一个 redmine 管理，提交缺陷的时候，缺陷 id 是全局增长的，这其实不太符合逻辑？&lt;/p&gt;

&lt;p&gt;====
想了下，在 message 表中保存另外的（message id by person）字段来存放排序信息。
想法对么？
另外偶是新人，顺道求问有没有已经实现好的轮子。。。&lt;/p&gt;</description>
      <author>palytoxin</author>
      <pubDate>Tue, 12 Nov 2013 15:50:46 +0800</pubDate>
      <link>https://ruby-china.org/topics/15481</link>
      <guid>https://ruby-china.org/topics/15481</guid>
    </item>
  </channel>
</rss>
