<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>skinnyworm (胡颢)</title>
    <link>https://ruby-china.org/skinnyworm</link>
    <description></description>
    <language>en-us</language>
    <item>
      <title>aliyun-mqs: 在 ruby 中使用阿里云的 MQS 队列服务</title>
      <description>&lt;p&gt;在写这个 gem 的时候发现 aliyun-mqs 的 gem 名字已经被占用，所以发了 Pull request 给原作者，希望原作者同意将这个 gem 合并回去。在这之前不能使用 gem install，只能通过 bundle 使用&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gem 'aliyun-mqs', :git =&amp;gt; 'git://github.com/skinnyworm/aliyun-mqs.git'
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;言归正转，这是一个帮助 ruby 开发者迅速使用阿里云的 MQS 服务，具体文档都写在 Github 上了，这里就简单的 copy/paste 了。github 地址是&lt;a href="https://github.com/skinnyworm/aliyun-mqs" rel="nofollow" target="_blank"&gt;https://github.com/skinnyworm/aliyun-mqs&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="aliyun-mqs"&gt;aliyun-mqs&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://travis-ci.org/skinnyworm/aliyun-mqs" rel="nofollow" target="_blank" title=""&gt;&lt;img src="https://travis-ci.org/skinnyworm/aliyun-mqs.svg" title="" alt="Build Status"&gt;&lt;/a&gt; &lt;a href="https://codeclimate.com/github/skinnyworm/aliyun-mqs" rel="nofollow" target="_blank" title=""&gt;&lt;img src="https://codeclimate.com/github/skinnyworm/aliyun-mqs.png" title="" alt="Code Climate"&gt;&lt;/a&gt; &lt;a href="https://codeclimate.com/github/skinnyworm/aliyun-mqs" rel="nofollow" target="_blank" title=""&gt;&lt;img src="https://codeclimate.com/github/skinnyworm/aliyun-mqs/coverage.png" title="" alt="Code Coverage"&gt;&lt;/a&gt; &lt;a href="http://badge.fury.io/rb/aliyun-mqs" rel="nofollow" target="_blank" title=""&gt;&lt;img src="https://badge.fury.io/rb/aliyun-mqs.svg" title="" alt="Gem Version"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Talk to the mighty Aliyun MQS with charming ruby.&lt;/p&gt;
&lt;h2 id="Installation"&gt;Installation&lt;/h2&gt;
&lt;p&gt;Add this line to your application's Gemfile:&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'aliyun-mqs'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:git&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'git://github.com/skinnyworm/aliyun-mqs.git'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then execute:&lt;/p&gt;

&lt;p&gt;$ bundle&lt;/p&gt;

&lt;p&gt;As this branch of the gem is not yet merged into the master branch, you can not install it via &lt;code&gt;gem install&lt;/code&gt; for now.&lt;/p&gt;
&lt;h2 id="Configuration"&gt;Configuration&lt;/h2&gt;&lt;h3 id="Command line configuration"&gt;Command line configuration&lt;/h3&gt;
&lt;p&gt;The gem come with a command line tool &lt;code&gt;mqs&lt;/code&gt;. It can help you easily manage the aliyun mqs within the terminal. In order to use this tool, you need to provide a configuration yaml file in your home directory which contains information about your mqs access_id and keys. &lt;/p&gt;

&lt;p&gt;The configuration file should be stored at &lt;code&gt;~/aliyun-mqs.yml&lt;/code&gt;&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
access_id:  'lUxxxxxxxx'
key:        'VWxxxxxxxxxxxxxxxxxxxxx'
region:     'cn-hangzhou'
owner_id:   'ckxxxxxxxx'

&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="Rails configuration"&gt;Rails configuration&lt;/h3&gt;
&lt;p&gt;If you are going to use this gem in a rails environment. You need to create a configuration file at &lt;code&gt;&amp;lt;RAILS_ROOT&amp;gt;/config/aliyun-mqs.yml&lt;/code&gt;. In this way, you can use different set of queues for your development or production environments.&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
development:
    access_id:  'lUxxxxxxxx'
    key:        'VWxxxxxxxxxxxxxxxxxxxxx'
    region:     'cn-hangzhou'
    owner_id:   'ckxxxxxxxx'

production:
    access_id:  'lUxxxxxxxx'
    key:        'VWxxxxxxxxxxxxxxxxxxxxx'
    region:     'cn-hangzhou'
    owner_id:   'ckxxxxxxxx'

&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="Config in an application"&gt;Config in an application&lt;/h3&gt;
&lt;p&gt;At last you can also config the gem in place, by excute the following code before invoking and queue service.&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;Aliyun&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Mqs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configure&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;config&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;access_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'access-id'&lt;/span&gt;
  &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"key"&lt;/span&gt;
  &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;region&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'region'&lt;/span&gt;
  &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;owner_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'owner-id'&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="Commandline"&gt;Commandline&lt;/h2&gt;
&lt;p&gt;This gem comes with a handy commandline tool &lt;code&gt;mqs&lt;/code&gt; to help you manage your queue. Once the queue is installed. Execute 'mqs --help' to find out what commands are supported.&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ mqs --help

Commands:
  mqs consume [queue] -wait &amp;lt;wait_seconds&amp;gt;  # 从[queue]队列接受消息并删除
  mqs create [queue]                        # 创建一个消息队列
  mqs delete [queue]                        # 删除一个消息队列
  mqs peek [queue]                          # 从[queue]队列中peek消息
  mqs queues                                # 列出所有消息队列列表
  mqs send [queue] [message]                # 往[queue]队列发送[message]消息
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Following are few examples.&lt;/p&gt;
&lt;h4 id="消息队列列表"&gt;消息队列列表&lt;/h4&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ mqs queues
消息队列列表
another
another1
another2
another3
another4
another5
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="往队列发送消息"&gt;往队列发送消息&lt;/h4&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ mqs send another "Test message"
发送消息到another队列
&amp;lt;?xml version="1.0"?&amp;gt;
&amp;lt;Message xmlns="http://mqs.aliyuncs.com/doc/v1"&amp;gt;
  &amp;lt;MessageBodyMD5&amp;gt;82DFA5549EBC9AFC168EB7931EBECE5F&amp;lt;/MessageBodyMD5&amp;gt;
  &amp;lt;MessageId&amp;gt;55D5B01D1AE93D78-1-14979D45F33-200000001&amp;lt;/MessageId&amp;gt;
&amp;lt;/Message&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="Peek队列中的消息"&gt;Peek 队列中的消息&lt;/h4&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ mqs peek another
Peek 队列another中的消息
=============================================
队列: another
ID: 55D5B01D1AE93D78-1-14979D45F33-200000001
MD5: 82DFA5549EBC9AFC168EB7931EBECE5F
Enqueue at: 2014-11-04 16:03:21 +0800
First enqueue at: 2014-11-04 16:03:21 +0800
Dequeue count: 0
Priority: 10
=============================================
Test message
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="消费队列中的消息"&gt;消费队列中的消息&lt;/h4&gt;
&lt;p&gt;Be careful, consume command will first receive the message and then delete the message within a time period specfied by the queue.&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ mqs consume another
Consume 队列another中的消息
=============================================
队列: another
ID: 55D5B01D1AE93D78-1-14979D45F33-200000001
MD5: 82DFA5549EBC9AFC168EB7931EBECE5F
Receipt handle: 1-ODU4OTkzNDU5My0xNDE1MDg4MzU2LTEtMTA=
Enqueue at: 2014-11-04 16:03:21 +0800
First enqueue at: 2014-11-04 16:05:26 +0800
Next visible at: 2014-11-04 16:05:56 +0800
Dequeue count: 1
Priority: 10
=============================================
Test message
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="Usage"&gt;Usage&lt;/h2&gt;
&lt;p&gt;Following are some example useage of the gem. You can read the specs to understand the full features of this gem&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;#get a list of queue object&lt;/span&gt;
&lt;span class="n"&gt;queues&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Aliyun&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Mqs&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;queues&lt;/span&gt;

&lt;span class="c1"&gt;#get all queues start with name 'query'&lt;/span&gt;
&lt;span class="n"&gt;queues&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="no"&gt;Aliyun&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Mqs&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;queues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;query: &lt;/span&gt;&lt;span class="s2"&gt;"query"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 

&lt;span class="c1"&gt;#get all queues start with name 'query'&lt;/span&gt;
&lt;span class="n"&gt;queues&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Aliyun&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Mqs&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;queues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;size: &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;#Obtain a queue object with name "aQueue"&lt;/span&gt;
&lt;span class="n"&gt;queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Aliyun&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Mqs&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"aQueue"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; 

&lt;span class="c1"&gt;#Create a new queue&lt;/span&gt;
&lt;span class="no"&gt;Aliyun&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Mqs&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"aQueue"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;

&lt;span class="c1"&gt;#Create a new queue with polling wait 30 seconds&lt;/span&gt;
&lt;span class="no"&gt;Aliyun&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Mqs&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"aQueue"&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="ss"&gt;:PollingWaitSeconds&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;#Delete an existing queue&lt;/span&gt;
&lt;span class="no"&gt;Aliyun&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Mqs&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"aQueue"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;delete&lt;/span&gt;

&lt;span class="c1"&gt;#Send a text message&lt;/span&gt;
&lt;span class="no"&gt;Aliyun&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Mqs&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"aQueue"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;send_message&lt;/span&gt; &lt;span class="s2"&gt;"text message"&lt;/span&gt;

&lt;span class="c1"&gt;#Send a text message with priority option&lt;/span&gt;
&lt;span class="no"&gt;Aliyun&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Mqs&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"aQueue"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;send_message&lt;/span&gt; &lt;span class="s2"&gt;"text message"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:Priority&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;

&lt;span class="c1"&gt;#Receive a message&lt;/span&gt;
&lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Aliyun&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Mqs&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"aQueue"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;receive_message&lt;/span&gt;

&lt;span class="c1"&gt;#Sample rspec for a message&lt;/span&gt;
&lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;not_to&lt;/span&gt; &lt;span class="n"&gt;be_nil&lt;/span&gt;
&lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"5fea7756-0ea4-451a-a703-a558b933e274"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;body&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"This is a test message"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;body_md5&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"fafb00f5732ab283681e124bf8747ed1"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;receipt_handle&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"MbZj6wDWli+QEauMZc8ZRv37sIW2iJKq3M9Mx/KSbkJ0"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enqueue_at&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;at&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1250700979248000&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mf"&gt;1000.0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;first_enqueue_at&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;at&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1250700779318000&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mf"&gt;1000.0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next_visible_at&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;at&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1250700799348000&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mf"&gt;1000.0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dequeue_count&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;eq&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="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;#Receive a message with option to override the default poll wait time of the queue.&lt;/span&gt;
&lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Aliyun&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Mqs&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"aQueue"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;receive_message&lt;/span&gt; &lt;span class="ss"&gt;wait_seconds: &lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;

&lt;span class="c1"&gt;#Peek message in the queue&lt;/span&gt;
&lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Aliyun&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Mqs&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"aQueue"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;peek_message&lt;/span&gt;

&lt;span class="c1"&gt;#Delete received message&lt;/span&gt;
&lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Aliyun&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Mqs&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"aQueue"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;receive_message&lt;/span&gt;
&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delete&lt;/span&gt;

&lt;span class="c1"&gt;#Change message visibility&lt;/span&gt;
&lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Aliyun&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Mqs&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"aQueue"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;receive_message&lt;/span&gt;
&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;change_visibility&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;</description>
      <author>skinnyworm</author>
      <pubDate>Tue, 04 Nov 2014 16:52:34 +0800</pubDate>
      <link>https://ruby-china.org/topics/22471</link>
      <guid>https://ruby-china.org/topics/22471</guid>
    </item>
    <item>
      <title>万万没想到竟然排到了 Github Ruby Trends 今天的第一名，国内 ruby 开发社区真是强悍</title>
      <description>&lt;p&gt;刚刚经同事提醒，才发现&lt;a href="https://github.com/skinnyworm/wechat-rails" rel="nofollow" target="_blank" title=""&gt;wechat-rails&lt;/a&gt;竟然排到了 Github Ruby Trends 今天的第一名，受惊了，其实这个小项目刚刚起步，还有很多问题，希望和大家一起能把它越搞越好&lt;/p&gt;

&lt;p&gt;&lt;img src="//l.ruby-china.com/photo/2014/d8640b8189f03cc43f7c18ef787b7e44.jpg" title="" alt=""&gt;&lt;/p&gt;</description>
      <author>skinnyworm</author>
      <pubDate>Thu, 03 Apr 2014 11:02:39 +0800</pubDate>
      <link>https://ruby-china.org/topics/18359</link>
      <guid>https://ruby-china.org/topics/18359</guid>
    </item>
    <item>
      <title>wechat-rails 微信 DSL for ruby</title>
      <description>&lt;h2 id="Wechat Rails"&gt;Wechat Rails&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://travis-ci.org/skinnyworm/wechat-rails" rel="nofollow" target="_blank" title=""&gt;&lt;img src="https://travis-ci.org/skinnyworm/omniauth-wechat-oauth2.svg" title="" alt="Build Status"&gt;&lt;/a&gt; &lt;a href="https://codeclimate.com/github/skinnyworm/wechat-rails" rel="nofollow" target="_blank" title=""&gt;&lt;img src="https://codeclimate.com/github/skinnyworm/wechat-rails.png" title="" alt="Code Climate"&gt;&lt;/a&gt; &lt;a href="https://codeclimate.com/github/skinnyworm/wechat-rails" rel="nofollow" target="_blank" title=""&gt;&lt;img src="https://codeclimate.com/github/skinnyworm/wechat-rails/coverage.png" title="" alt="Code Coverage"&gt;&lt;/a&gt; &lt;a href="http://badge.fury.io/rb/wechat-rails" rel="nofollow" target="_blank" title=""&gt;&lt;img src="https://badge.fury.io/rb/wechat-rails.png" title="" alt="Gem Version"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;看了 Github 上几个 ruby 的微信的 Gems, 感觉大多有以下几个问题&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; 实现不够完整，&lt;/li&gt;
&lt;li&gt; 代码质量有待提高&lt;/li&gt;
&lt;li&gt; 设计上没有从开发者的 Use case 去考虑，大多数以实现微信的 API 为目标，但实际使用的话不顺手，很多使用场景需要写很多代码&lt;/li&gt;
&lt;li&gt;不是很 Ruby way&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;由于找不到好的方案，决定自己动手写一个。我的目的比较明确，这个 Gem 是帮助开发者方便地在已有的 Rails app 中集成微信的消息机制，同时提供命令行程序帮助日常的维护，比如更新菜单等。目前还没有在正式的生产环境中使用过，欢迎大家吐槽，参与，让这个项目可以成为每个希望集成微信公众平台的开发者的好工具。&lt;/p&gt;
&lt;h5 id="以下是项目文档，正在完善中 :P"&gt;以下是项目文档，正在完善中 :P&lt;/h5&gt;
&lt;p&gt;Wechat-rails 可以帮助开发者方便地在 Rails 环境中集成微信公众平台提供的所有服务，目前微信公众平台提供了以下几种类型的服务。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;微信公众平台基本 API, 无需 Web 环境。&lt;/li&gt;
&lt;li&gt;消息处理机制，需运行在 Web 环境中。&lt;/li&gt;
&lt;li&gt;OAuth 2.0 认证机制&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Wechat-rails gem 包含了一个命令行程序可以调用各种无需 web 环境的 API。同时它也提供了 Rails Controller 的 responder DSL, 可以帮助开发者方便地在 Rails 应用中集成微信的消息处理机制。如果你的 App 还需要集成微信 OAuth2.0, 你可以考虑&lt;a href="https://github.com/skinnyworm/omniauth-wechat-oauth2" rel="nofollow" target="_blank" title=""&gt;omniauth-wechat-oauth2&lt;/a&gt;, 这个 gem 可以方便地和 devise 集成提供完整的用户认证。&lt;/p&gt;

&lt;p&gt;在使用这个 Gem 前，你需要获得微信 API 的 appid, secret, token。具体情况可以参见&lt;a href="http://mp.weixin.qq.com" rel="nofollow" target="_blank"&gt;http://mp.weixin.qq.com&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="安装"&gt;安装&lt;/h2&gt;
&lt;p&gt;Using &lt;code&gt;gem install&lt;/code&gt; or add to your app's &lt;code&gt;Gemfile&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gem install "wechat-rails"
&lt;/code&gt;&lt;/pre&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gem "wechat-rails", git:"https://github.com/skinnyworm/wechat-rails"
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="配置"&gt;配置&lt;/h2&gt;&lt;h4 id="命令行程序的配置"&gt;命令行程序的配置&lt;/h4&gt;
&lt;p&gt;要使用命令行程序，你需要在你的 home 目录中创建一个&lt;code&gt;~/.wechat.yml&lt;/code&gt;，包含以下内容。其中&lt;code&gt;access_token&lt;/code&gt;是存放 access_token 的文件位置。&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;appid: "my_appid"
secret: "my_secret"
access_token: "/var/tmp/wechat_access_token"
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="Rails 全局配置"&gt;Rails 全局配置&lt;/h4&gt;
&lt;p&gt;Rails 环境中，你可以在 config 中创建 wechat.yml, 为每个 rails environment 创建不同的配置。&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;default: &amp;amp;default
  appid: "app_id"
  secret: "app_secret"
  token:  "app_token"
  access_token: "/var/tmp/wechat_access_token"

production: 
  appid: &amp;lt;%= ENV['WECHAT_APPID'] %&amp;gt;
  secret: &amp;lt;%= ENV['WECHAT_APP_SECRET'] %&amp;gt;
  token:   &amp;lt;%= ENV['WECHAT_TOKEN'] %&amp;gt;
  access_token:  &amp;lt;%= ENV['WECHAT_ACCESS_TOKEN'] %&amp;gt;

staging: 
  &amp;lt;&amp;lt;: *default

development: 
  &amp;lt;&amp;lt;: *default

test: 
  &amp;lt;&amp;lt;: *default
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="Rails 为每个Responder配置不同的appid和secret"&gt;Rails 为每个 Responder 配置不同的 appid 和 secret&lt;/h4&gt;
&lt;p&gt;在个别情况下，你的 app 可能需要处理来自多个公众账号的消息，这时你可以配置多个 responder controller。&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;WechatFirstController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
   &lt;span class="n"&gt;wechat_responder&lt;/span&gt; &lt;span class="ss"&gt;appid: &lt;/span&gt;&lt;span class="s2"&gt;"app1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;secret: &lt;/span&gt;&lt;span class="s2"&gt;"secret1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;token: &lt;/span&gt;&lt;span class="s2"&gt;"token1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;access_token: &lt;/span&gt;&lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;root&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="s2"&gt;"tmp/access_token1"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

   &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="ss"&gt;:text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt;&lt;span class="ss"&gt;:"help"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;respond: &lt;/span&gt;&lt;span class="s2"&gt;"help content"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="使用命令行"&gt;使用命令行&lt;/h2&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ wechat
Wechat commands:
  wechat custom_image [OPENID, IMAGE_PATH]                 # 发送图片客服消息
  wechat custom_music [OPENID, THUMBNAIL_PATH, MUSIC_URL]  # 发送音乐客服消息
  wechat custom_news [OPENID, NEWS_YAML_FILE]              # 发送图文客服消息
  wechat custom_text [OPENID, TEXT_MESSAGE]                # 发送文字客服消息
  wechat custom_video [OPENID, VIDEO_PATH]                 # 发送视频客服消息
  wechat custom_voice [OPENID, VOICE_PATH]                 # 发送语音客服消息
  wechat help [COMMAND]                                    # Describe available commands or one specific command
  wechat media [MEDIA_ID, PATH]                            # 媒体下载
  wechat media_create [MEDIA_TYPE, PATH]                     # 媒体上传
  wechat menu                                              # 当前菜单
  wechat menu_create [MENU_YAML]                           # 创建菜单
  wechat menu_delete                                       # 删除菜单
  wechat user [OPEN_ID]                                    # 查找关注者
  wechat users                                             # 关注者列表

&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="使用场景"&gt;使用场景&lt;/h3&gt;
&lt;p&gt;以下是几种典型场景的使用方法&lt;/p&gt;

&lt;p&gt;#####获取所有用户的 OPENID&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ wechat users

{"total"=&amp;gt;4, "count"=&amp;gt;4, "data"=&amp;gt;{"openid"=&amp;gt;["oCfEht9***********", "oCfEhtwqa***********", "oCfEht9oMCqGo***********", "oCfEht_81H5o2***********"]}, "next_openid"=&amp;gt;"oCfEht_81H5o2***********"}

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;#####获取用户的信息&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ wechat user "oCfEht9***********"

{"subscribe"=&amp;gt;1, "openid"=&amp;gt;"oCfEht9***********", "nickname"=&amp;gt;"Nickname", "sex"=&amp;gt;1, "language"=&amp;gt;"zh_CN", "city"=&amp;gt;"徐汇", "province"=&amp;gt;"上海", "country"=&amp;gt;"中国", "headimgurl"=&amp;gt;"http://wx.qlogo.cn/mmopen/ajNVdqHZLLBd0SG8NjV3UpXZuiaGGPDcaKHebTKiaTyof*********/0", "subscribe_time"=&amp;gt;1395715239}
&lt;/code&gt;&lt;/pre&gt;&lt;h5 id="获取当前菜单"&gt;获取当前菜单&lt;/h5&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ wechat menu

{"menu"=&amp;gt;{"button"=&amp;gt;[{"type"=&amp;gt;"view", "name"=&amp;gt;"保护的", "url"=&amp;gt;"http://***/protected", "sub_button"=&amp;gt;[]}, {"type"=&amp;gt;"view", "name"=&amp;gt;"公开的", "url"=&amp;gt;"http://***", "sub_button"=&amp;gt;[]}]}}

&lt;/code&gt;&lt;/pre&gt;&lt;h5 id="创建菜单"&gt;创建菜单&lt;/h5&gt;
&lt;p&gt;创建菜单需要一个定义菜单内容的 yaml 文件，比如
menu.yaml&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;button:
  -
    type: "view"
    name: "保护的"
    url: "http://***/protected"
  -
    type: "view"
    name: "公开的"
    url: "http://***"

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后执行命令行&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ wechat menu_create menu.yaml

&lt;/code&gt;&lt;/pre&gt;&lt;h5 id="发送客服图文消息"&gt;发送客服图文消息&lt;/h5&gt;
&lt;p&gt;需定义一个图文消息内容的 yaml 文件，比如
articles.yaml&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;articles:
 -
  title: "习近平在布鲁日欧洲学院演讲"
  description: "新华网比利时布鲁日4月1日电 国家主席习近平1日在比利时布鲁日欧洲学院发表重要演讲"
  url: "http://news.sina.com.cn/c/2014-04-01/232629843387.shtml"
  pic_url: "http://i3.sinaimg.cn/dy/c/2014-04-01/1396366518_bYays1.jpg"
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后执行命令行&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ wechat custom_news oCfEht9oM*********** articles.yml 

&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="Rails Responder Controller DSL"&gt;Rails Responder Controller DSL&lt;/h2&gt;
&lt;p&gt;为了在 Rails app 中响应用户的消息，开发者需要创建一个 wechat responder controller. 首先在 router 中定义&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;resource&lt;/span&gt; &lt;span class="ss"&gt;:wechat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;only&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="ss"&gt;:show&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:create&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后创建 Controller class, 例如&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;WechatsController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
  &lt;span class="n"&gt;wechat_responder&lt;/span&gt;

  &lt;span class="c1"&gt;# 默认的文字信息responder&lt;/span&gt;
  &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="ss"&gt;:text&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;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt; &lt;span class="s2"&gt;"echo: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="c1"&gt;#Just echo&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="c1"&gt;# 当请求的文字信息内容为'help'时, 使用这个responder处理&lt;/span&gt;
  &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="ss"&gt;:text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt;&lt;span class="ss"&gt;:"help"&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;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt; &lt;span class="s2"&gt;"help content"&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;# 当请求的文字信息内容为'&amp;lt;n&amp;gt;条新闻'时, 使用这个responder处理, 并将n作为第二个参数&lt;/span&gt;
  &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="ss"&gt;:text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;with: &lt;/span&gt;&lt;span class="sr"&gt;/^(\d+)条新闻$/&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;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;articles_range&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;news&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;articles_range&lt;/span&gt;&lt;span class="p"&gt;)&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;article&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="c1"&gt;#回复"articles"&lt;/span&gt;
      &lt;span class="n"&gt;article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;item&lt;/span&gt; &lt;span class="ss"&gt;title: &lt;/span&gt;&lt;span class="s2"&gt;"标题&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="ss"&gt;:"内容描述&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="ss"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;pic_url: &lt;/span&gt;&lt;span class="s2"&gt;"http://www.baidu.com/img/bdlogo.gif"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="ss"&gt;:"http://www.baidu.com/"&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="c1"&gt;# 处理图片信息&lt;/span&gt;
  &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="ss"&gt;:image&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;request&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:MediaId&lt;/span&gt;&lt;span class="p"&gt;])&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;# 处理语音信息&lt;/span&gt;
  &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="ss"&gt;:voice&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;request&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;voice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:MediaId&lt;/span&gt;&lt;span class="p"&gt;])&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;# 处理视频信息&lt;/span&gt;
  &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="ss"&gt;:video&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;request&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;video&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:MediaId&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="ss"&gt;title: &lt;/span&gt;&lt;span class="s2"&gt;"回声"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;description: &lt;/span&gt;&lt;span class="s2"&gt;"发来的视频请求"&lt;/span&gt;&lt;span class="p"&gt;)&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;# 处理地理位置信息&lt;/span&gt;
  &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="ss"&gt;:location&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;request&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;nickname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;wechat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:FromUserName&lt;/span&gt;&lt;span class="p"&gt;])[&lt;/span&gt;&lt;span class="s2"&gt;"nickname"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;#呼叫 api 获得发送者的nickname&lt;/span&gt;
    &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;nickname&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;在 &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:Location_X&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:Location_Y&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&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;# 当无任何responder处理用户信息时,使用这个responder处理&lt;/span&gt;
  &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="ss"&gt;:fallback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;respond: &lt;/span&gt;&lt;span class="s2"&gt;"fallback message"&lt;/span&gt;  
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在 controller 中使用&lt;code&gt;wechat_responder&lt;/code&gt;引入 Responder DSL, 之后可以用&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;on &amp;lt;message_type&amp;gt; do |message|
 message.reply.text "some text"
end

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;来响应用户信息。&lt;/p&gt;

&lt;p&gt;目前支持的 message_type 有如下几种&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;:text 响应文字消息，可以用&lt;code&gt;:with&lt;/code&gt;参数来匹配文本内容 &lt;code&gt;on(:text, with:'help'){|message, content| ...}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;:image 响应图片消息&lt;/li&gt;
&lt;li&gt;:voice 响应语音消息&lt;/li&gt;
&lt;li&gt;:video 响应视频消息&lt;/li&gt;
&lt;li&gt;:location 响应地理位置消息&lt;/li&gt;
&lt;li&gt;:link 响应链接消息&lt;/li&gt;
&lt;li&gt;:event 响应事件消息，可以用&lt;code&gt;:with&lt;/code&gt;参数来匹配事件类型&lt;/li&gt;
&lt;li&gt;:fallback 默认响应，当收到的消息无法被其他 responder 响应时，会使用这个 responder.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="Message DSL"&gt;Message DSL&lt;/h2&gt;
&lt;p&gt;Wechat-rails 的核心是一个 Message DSL，帮助开发者构建各种类型的消息，包括主动推送的和被动响应的。
....&lt;/p&gt;</description>
      <author>skinnyworm</author>
      <pubDate>Wed, 02 Apr 2014 13:02:41 +0800</pubDate>
      <link>https://ruby-china.org/topics/18337</link>
      <guid>https://ruby-china.org/topics/18337</guid>
    </item>
  </channel>
</rss>
