rack-weixin 0.0.3.1 → 0.0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +0 -1
- data/Gemfile.lock +2 -2
- data/README.md +88 -21
- data/lib/rack-weixin.rb +59 -0
- data/lib/weixin/menu.rb +60 -0
- data/lib/weixin/middleware.rb +2 -2
- data/lib/weixin/model.rb +90 -10
- data/lib/weixin/version.rb +1 -1
- data/rack-weixin.gemspec +4 -1
- metadata +36 -8
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
rack-weixin (0.0.3
|
4
|
+
rack-weixin (0.0.3)
|
5
5
|
multi_xml (>= 0.5.2)
|
6
6
|
rack
|
7
7
|
roxml
|
@@ -14,7 +14,7 @@ GEM
|
|
14
14
|
i18n (~> 0.6)
|
15
15
|
multi_json (~> 1.0)
|
16
16
|
diff-lcs (1.1.3)
|
17
|
-
i18n (0.6.
|
17
|
+
i18n (0.6.1)
|
18
18
|
multi_json (1.6.1)
|
19
19
|
multi_xml (0.5.3)
|
20
20
|
nokogiri (1.5.6)
|
data/README.md
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
-
微信公众平台 开放消息接口 Rack
|
1
|
+
微信公众平台 开放消息接口 Rack Middleware
|
2
2
|
========================================
|
3
3
|
|
4
|
+
Latest version: v0.4.0, supports subscribe/unsubscribe event
|
5
|
+
|
4
6
|
* 验证微信请求 with 'weixin/middleware'
|
5
7
|
* 解析推送消息 with 'weixin/model'
|
6
8
|
* 生成回复消息 with 'weixin/model'
|
@@ -21,8 +23,7 @@ A sinatra demo
|
|
21
23
|
```ruby
|
22
24
|
# -*- encoding : utf-8 -*-
|
23
25
|
require 'sinatra'
|
24
|
-
require 'weixin
|
25
|
-
require 'weixin/model'
|
26
|
+
require 'rack-weixin'
|
26
27
|
|
27
28
|
use Weixin::Middleware, 'your api token', '/your_app_root'
|
28
29
|
|
@@ -31,14 +32,89 @@ configure do
|
|
31
32
|
end
|
32
33
|
|
33
34
|
helpers do
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
35
|
+
def text_parse(msg)
|
36
|
+
case msg.Content
|
37
|
+
when '我想听歌'
|
38
|
+
mp3 = Weixin.music(
|
39
|
+
'身骑白马',
|
40
|
+
'徐佳莹首张专辑《LALA创作专辑》的主打歌。这首歌的是由徐佳莹及其老师苏通达共同创作,其最大的特点是改编自台湾的民间剧种歌仔戏。',
|
41
|
+
'http://nj.baidupcs.com/file/9cbb087ece3da309a31e05a7e14003c9?xcode=70d27743259294de1c42dff2d4720c05d4c19cd5e52a44f7&fid=204864837-250528-3177081425&time=1376666534&sign=FDTAXER-DCb740ccc5511e5e8fedcff06b081203-9NqxJyKhTJYx34SlHyPnK7%2B83vY%3D&to=nb&fm=B,B,T&expires=8h&rt=sh&r=756751042&logid=2171432620&sh=1&fn=%E8%BA%AB%E9%AA%91%E7%99%BD%E9%A9%AC.mp3',
|
42
|
+
'http://nj.baidupcs.com/file/9cbb087ece3da309a31e05a7e14003c9?xcode=c59d095c8566efe4d948c3846269e02ed4c19cd5e52a44f7&fid=204864837-250528-3177081425&time=1376666631&sign=FDTAXER-DCb740ccc5511e5e8fedcff06b081203-yAO3TLeuAQ867emfUs0dYKgMtSE%3D&to=nb&fm=B,B,T&expires=8h&rt=sh&r=897038653&logid=4061975287&sh=1&fn=%E8%BA%AB%E9%AA%91%E7%99%BD%E9%A9%AC.mp3'
|
43
|
+
)
|
44
|
+
Weixin.music_msg(msg.FromUserName, msg.ToUserName, mp3)
|
45
|
+
else
|
46
|
+
Weixin.text_msg(msg.FromUserName, msg.ToUserName, '这件商品暂时缺货~~')
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def image_parse(msg)
|
51
|
+
item = Weixin.item(
|
52
|
+
'发现一个基于sinatra的web框架padrino',
|
53
|
+
'gem install padrino
|
54
|
+
padrino g project myapp -d datamapper -b
|
55
|
+
cd myapp
|
56
|
+
padrino g admin
|
57
|
+
padrino rake dm:migrate seed
|
58
|
+
padrino start',
|
59
|
+
'http://www.padrinorb.com/images/screens.jpg',
|
60
|
+
'http://www.padrinorb.com/'
|
61
|
+
)
|
62
|
+
Weixin.news_msg(from, to, [item])
|
63
|
+
end
|
64
|
+
|
65
|
+
def location_parse(msg)
|
66
|
+
"http://maps.googleapis.com/maps/api/geocode/json?latlng=#{msg.Location_X},#{msg.Location_Y}"
|
67
|
+
Weixin.text_msg(msg.FromUserName, msg.ToUserName, "#{msg.Label} 周围没有妹子~")
|
68
|
+
end
|
69
|
+
|
70
|
+
def link_parse(msg)
|
71
|
+
# Mechanize.new.get(msg.Url) # 爬虫
|
72
|
+
Weixin.text_msg(msg.FromUserName, msg.ToUserName, '这件商品暂时缺货~~')
|
73
|
+
end
|
74
|
+
|
75
|
+
def event_parse(msg)
|
76
|
+
case msg.Event
|
77
|
+
when 'subscribe' # 订阅
|
78
|
+
Weixin.text_msg(msg.FromUserName, msg.ToUserName, '欢迎订阅【数字尾巴】~~')
|
79
|
+
when 'unsubscribe' # 退订
|
80
|
+
# 又少了名用户
|
81
|
+
when 'CLICK' # 点击菜单
|
82
|
+
menu_parse(msg)
|
83
|
+
else
|
84
|
+
Weixin.text_msg(msg.FromUserName, msg.ToUserName, '作为一名程序猿,表示压力山大~~')
|
41
85
|
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def menu_parse(msg)
|
89
|
+
case msg.EventKey
|
90
|
+
when 'profile'
|
91
|
+
# ???
|
92
|
+
Weixin.text_msg(msg.FromUserName, msg.ToUserName, '主人您的个人信息丢失啦~')
|
93
|
+
else
|
94
|
+
Weixin.text_msg(msg.FromUserName, msg.ToUserName, '您想来点什么?')
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def msg_router(msg)
|
99
|
+
case msg.MsgType
|
100
|
+
when 'text'
|
101
|
+
text_parse(msg)
|
102
|
+
when 'image'
|
103
|
+
image_parse(msg)
|
104
|
+
when 'location'
|
105
|
+
location_parse(msg)
|
106
|
+
when 'link'
|
107
|
+
link_parse(msg)
|
108
|
+
when 'event'
|
109
|
+
event_parse(msg)
|
110
|
+
when 'voice'
|
111
|
+
voice_parse(msg)
|
112
|
+
when 'video'
|
113
|
+
video_parse(msg)
|
114
|
+
else
|
115
|
+
Weixin.text_msg(msg.FromUserName, msg.ToUserName, '作为一名程序猿,表示压力山大~~')
|
116
|
+
end
|
117
|
+
end
|
42
118
|
end
|
43
119
|
|
44
120
|
get '/your_app_root' do
|
@@ -49,17 +125,8 @@ post '/your_app_root' do
|
|
49
125
|
content_type :xml, 'charset' => 'utf-8'
|
50
126
|
|
51
127
|
message = request.env[Weixin::Middleware::WEIXIN_MSG]
|
52
|
-
logger.info "
|
53
|
-
|
54
|
-
from = message.FromUserName
|
55
|
-
if message.class == Weixin::TextMessage
|
56
|
-
content = message.Content
|
57
|
-
if content == 'Hello2BizUser'
|
58
|
-
reply_msg_content = "感谢关注!#{reply_msg_content}"
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
create_message(settings.wx_id, from, 'text', reply_msg_content)
|
128
|
+
logger.info "原始数据: #{request.env[Weixin::Middleware::WEIXIN_MSG_RAW]}"
|
129
|
+
msg_router(message) unless message.nil?
|
63
130
|
end
|
64
131
|
```
|
65
132
|
|
data/lib/rack-weixin.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require 'weixin/version'
|
3
|
+
require 'weixin/middleware'
|
4
|
+
require 'weixin/menu'
|
5
|
+
|
6
|
+
module Weixin
|
7
|
+
|
8
|
+
autoload :Music, 'weixin/model'
|
9
|
+
autoload :Item, 'weixin/model'
|
10
|
+
|
11
|
+
autoload :TextReplyMessage, 'weixin/model'
|
12
|
+
autoload :MusicReplyMessage, 'weixin/model'
|
13
|
+
autoload :NewsReplyMessage, 'weixin/model'
|
14
|
+
|
15
|
+
extend self
|
16
|
+
|
17
|
+
def music(title, desc, music_url, hq_music_url)
|
18
|
+
item = Music.new
|
19
|
+
item.Title = title
|
20
|
+
item.Description = desc
|
21
|
+
item.MusicUrl = music_url
|
22
|
+
item.HQMusicUrl = hq_music_url
|
23
|
+
item
|
24
|
+
end
|
25
|
+
|
26
|
+
def item(title, desc, pic_url, link_url)
|
27
|
+
item = Item.new
|
28
|
+
item.Title = title
|
29
|
+
item.Description = desc
|
30
|
+
item.PicUrl = pic_url
|
31
|
+
item.Url = link_url
|
32
|
+
item
|
33
|
+
end
|
34
|
+
|
35
|
+
def text_msg(from, to, content, flag=0)
|
36
|
+
msg = TextReplyMessage.new
|
37
|
+
msg.ToUserName = to
|
38
|
+
msg.FromUserName = from
|
39
|
+
msg.Content = content
|
40
|
+
msg.to_xml
|
41
|
+
end
|
42
|
+
|
43
|
+
def music_msg(from, to, music)
|
44
|
+
msg = MusicReplyMessage.new
|
45
|
+
msg.ToUserName = to
|
46
|
+
msg.FromUserName = from
|
47
|
+
msg.Music = music
|
48
|
+
msg.to_xml
|
49
|
+
end
|
50
|
+
|
51
|
+
def news_msg(from, to, items)
|
52
|
+
msg = NewsReplyMessage.new
|
53
|
+
msg.ToUserName = to
|
54
|
+
msg.FromUserName = from
|
55
|
+
msg.Articles = items
|
56
|
+
msg.ArticleCount = items.count
|
57
|
+
msg.to_xml
|
58
|
+
end
|
59
|
+
end
|
data/lib/weixin/menu.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
require 'multi_json'
|
3
|
+
require 'nestful'
|
4
|
+
|
5
|
+
module Weixin
|
6
|
+
|
7
|
+
class Menu
|
8
|
+
def initialize(api, key)
|
9
|
+
@api = api
|
10
|
+
@key = key
|
11
|
+
|
12
|
+
@access_token = nil
|
13
|
+
@expired_at = Time.now
|
14
|
+
@endpoint = 'https://api.weixin.qq.com/cgi-bin'
|
15
|
+
end
|
16
|
+
|
17
|
+
def access_token
|
18
|
+
if Time.now >= @expired_at
|
19
|
+
authenticate
|
20
|
+
end
|
21
|
+
@access_token
|
22
|
+
end
|
23
|
+
|
24
|
+
def gw_path(method)
|
25
|
+
"/menu/#{method}?access_token=#{access_token}"
|
26
|
+
end
|
27
|
+
|
28
|
+
def gw_url(method)
|
29
|
+
"#{@endpoint}" + gw_path(method)
|
30
|
+
end
|
31
|
+
|
32
|
+
def get
|
33
|
+
request = Nestful.get gw_url('get') rescue nil
|
34
|
+
MultiJson.load(request.body) unless request.nil?
|
35
|
+
end
|
36
|
+
|
37
|
+
def add(menu)
|
38
|
+
request = Nestful::Connection.new(gw_url('create')).post(gw_path('create'), MultiJson.dump(menu)) rescue nil
|
39
|
+
unless request.nil?
|
40
|
+
errcode = MultiJson.load(request.body)['errcode']
|
41
|
+
return true if errcode == 0
|
42
|
+
end
|
43
|
+
false
|
44
|
+
end
|
45
|
+
|
46
|
+
def authenticate
|
47
|
+
url = "#{@endpoint}/token"
|
48
|
+
request = Nestful.get url, { grant_type: 'client_credential', appid: @api, secret: @key } rescue nil
|
49
|
+
unless request.nil?
|
50
|
+
auth = MultiJson.load(request.body)
|
51
|
+
unless auth.has_key?('errcode')
|
52
|
+
@access_token = auth['access_token']
|
53
|
+
@expired_at = Time.now + auth['expires_in'].to_i
|
54
|
+
end
|
55
|
+
@access_token
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
data/lib/weixin/middleware.rb
CHANGED
@@ -32,10 +32,10 @@ module Weixin
|
|
32
32
|
|
33
33
|
raw_msg = env[POST_BODY].read
|
34
34
|
begin
|
35
|
-
env.update WEIXIN_MSG => Weixin::Message.factory(raw_msg), WEIXIN_MSG_RAW =>
|
35
|
+
env.update WEIXIN_MSG => Weixin::Message.factory(raw_msg), WEIXIN_MSG_RAW => raw_msg
|
36
36
|
@app.call(env)
|
37
37
|
rescue Exception => e
|
38
|
-
return [500, { 'Content-
|
38
|
+
return [500, { 'Content-type' => 'text/html' }, ["Message parsing error: #{e.to_s}"]]
|
39
39
|
end
|
40
40
|
else
|
41
41
|
@app.call(env)
|
data/lib/weixin/model.rb
CHANGED
@@ -36,6 +36,10 @@ module Weixin
|
|
36
36
|
LinkMessage.new(hash)
|
37
37
|
when 'event'
|
38
38
|
EventMessage.new(hash)
|
39
|
+
when 'voice'
|
40
|
+
VoiceMessage.new(hash)
|
41
|
+
when 'video'
|
42
|
+
VideoMessage.new(hash)
|
39
43
|
else
|
40
44
|
raise ArgumentError, 'Unknown Message'
|
41
45
|
end
|
@@ -43,10 +47,59 @@ module Weixin
|
|
43
47
|
|
44
48
|
end
|
45
49
|
|
50
|
+
# <xml>
|
51
|
+
# <ToUserName><![CDATA[toUser]]></ToUserName>
|
52
|
+
# <FromUserName><![CDATA[fromUser]]></FromUserName>
|
53
|
+
# <CreateTime>1348831860</CreateTime>
|
54
|
+
# <MsgType><![CDATA[text]]></MsgType>
|
55
|
+
# <Content><![CDATA[this is a test]]></Content>
|
56
|
+
# <MsgId>1234567890123456</MsgId>
|
57
|
+
# </xml>
|
46
58
|
TextMessage = Class.new(Message)
|
59
|
+
|
60
|
+
# <xml>
|
61
|
+
# <ToUserName><![CDATA[toUser]]></ToUserName>
|
62
|
+
# <FromUserName><![CDATA[fromUser]]></FromUserName>
|
63
|
+
# <CreateTime>1348831860</CreateTime>
|
64
|
+
# <MsgType><![CDATA[image]]></MsgType>
|
65
|
+
# <PicUrl><![CDATA[this is a url]]></PicUrl>
|
66
|
+
# <MsgId>1234567890123456</MsgId>
|
67
|
+
# </xml>
|
47
68
|
ImageMessage = Class.new(Message)
|
69
|
+
|
70
|
+
# <xml>
|
71
|
+
# <ToUserName><![CDATA[toUser]]></ToUserName>
|
72
|
+
# <FromUserName><![CDATA[fromUser]]></FromUserName>
|
73
|
+
# <CreateTime>1351776360</CreateTime>
|
74
|
+
# <MsgType><![CDATA[link]]></MsgType>
|
75
|
+
# <Title><![CDATA[公众平台官网链接]]></Title>
|
76
|
+
# <Description><![CDATA[公众平台官网链接]]></Description>
|
77
|
+
# <Url><![CDATA[url]]></Url>
|
78
|
+
# <MsgId>1234567890123456</MsgId>
|
79
|
+
# </xml>
|
48
80
|
LinkMessage = Class.new(Message)
|
49
|
-
|
81
|
+
|
82
|
+
# <xml>
|
83
|
+
# <ToUserName><![CDATA[toUser]]></ToUserName>
|
84
|
+
# <FromUserName><![CDATA[FromUser]]></FromUserName>
|
85
|
+
# <CreateTime>123456789</CreateTime>
|
86
|
+
# <MsgType><![CDATA[event]]></MsgType>
|
87
|
+
# <Event><![CDATA[EVENT]]></Event>
|
88
|
+
# <EventKey><![CDATA[EVENTKEY]]></EventKey>
|
89
|
+
# </xml>
|
90
|
+
EventMessage = Class.new(Message)
|
91
|
+
|
92
|
+
# <xml>
|
93
|
+
# <ToUserName><![CDATA[toUser]]></ToUserName>
|
94
|
+
# <FromUserName><![CDATA[fromUser]]></FromUserName>
|
95
|
+
# <CreateTime>1351776360</CreateTime>
|
96
|
+
# <MsgType><![CDATA[location]]></MsgType>
|
97
|
+
# <Location_X>23.134521</Location_X>
|
98
|
+
# <Location_Y>113.358803</Location_Y>
|
99
|
+
# <Scale>20</Scale>
|
100
|
+
# <Label><![CDATA[位置信息]]></Label>
|
101
|
+
# <MsgId>1234567890123456</MsgId>
|
102
|
+
# </xml>
|
50
103
|
class LocationMessage < Message
|
51
104
|
|
52
105
|
def Location_X
|
@@ -62,18 +115,45 @@ module Weixin
|
|
62
115
|
end
|
63
116
|
end
|
64
117
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
118
|
+
# <xml>
|
119
|
+
# <ToUserName><![CDATA[toUser]]></ToUserName>
|
120
|
+
# <FromUserName><![CDATA[fromUser]]></FromUserName>
|
121
|
+
# <CreateTime>1376632760</CreateTime>
|
122
|
+
# <MsgType><![CDATA[voice]]></MsgType>
|
123
|
+
# <MediaId><![CDATA[Qyb0tgux6QLjhL6ipvFZJ-kUt2tcQtkn0BU365Vt3wUAtqfGam4QpZU35RXVhv6G]]></MediaId>
|
124
|
+
# <Format><![CDATA[amr]]></Format>
|
125
|
+
# <MsgId>5912592682802219078</MsgId>
|
126
|
+
# <Recognition><![CDATA[]]></Recognition>
|
127
|
+
# </xml>
|
128
|
+
class VoiceMessage < Message
|
129
|
+
|
130
|
+
def MediaId
|
131
|
+
@source.MediaId
|
132
|
+
end
|
133
|
+
|
134
|
+
def Format
|
135
|
+
@source.Format
|
69
136
|
end
|
137
|
+
end
|
138
|
+
|
139
|
+
|
140
|
+
# <xml>
|
141
|
+
# <ToUserName><![CDATA[toUser]]></ToUserName>
|
142
|
+
# <FromUserName><![CDATA[fromUser]]></FromUserName>
|
143
|
+
# <CreateTime>1376632994</CreateTime>
|
144
|
+
# <MsgType><![CDATA[video]]></MsgType>
|
145
|
+
# <MediaId><![CDATA[TAAGb6iS5LcZR1d5ICiZTWGWi6-Upic9tlWDpAKcNJA]]></MediaId>
|
146
|
+
# <ThumbMediaId><![CDATA[U-xulPW4kq6KKMWFNaBSPc65Bcgr7Qopwex0DfCeyQs]]></ThumbMediaId>
|
147
|
+
# <MsgId>5912593687824566343</MsgId>
|
148
|
+
# </xml>
|
149
|
+
class VideoMessage < Message
|
70
150
|
|
71
|
-
def
|
72
|
-
@source.
|
151
|
+
def MediaId
|
152
|
+
@source.MediaId
|
73
153
|
end
|
74
154
|
|
75
|
-
def
|
76
|
-
@source.
|
155
|
+
def ThumbMediaId
|
156
|
+
@source.ThumbMediaId
|
77
157
|
end
|
78
158
|
end
|
79
159
|
|
@@ -136,7 +216,7 @@ module Weixin
|
|
136
216
|
|
137
217
|
class NewsReplyMessage < ReplyMessage
|
138
218
|
xml_accessor :ArticleCount, :as => Integer
|
139
|
-
xml_accessor :Articles, :as => [Item], :in => 'Articles', :from => '
|
219
|
+
xml_accessor :Articles, :as => [Item], :in => 'Articles', :from => 'item'
|
140
220
|
|
141
221
|
def initialize
|
142
222
|
super
|
data/lib/weixin/version.rb
CHANGED
data/rack-weixin.gemspec
CHANGED
@@ -16,12 +16,15 @@ Gem::Specification.new do |s|
|
|
16
16
|
s.test_files = s.files.select {|path| path =~ /^spec\/.*_spec\.rb/}
|
17
17
|
|
18
18
|
s.add_dependency 'rack'
|
19
|
+
s.add_dependency 'multi_json', '>= 1.7.9'
|
19
20
|
s.add_dependency 'multi_xml', '>= 0.5.2'
|
20
21
|
s.add_dependency 'roxml'
|
22
|
+
s.add_dependency 'nestful'
|
23
|
+
|
21
24
|
s.add_development_dependency 'rake'
|
22
25
|
s.add_development_dependency 'rack-test'
|
23
26
|
s.add_development_dependency 'rspec', '>= 2.0.0'
|
24
27
|
|
25
28
|
s.homepage = 'https://github.com/wolfg1969/rack-weixin'
|
26
29
|
s.require_paths = %w[lib]
|
27
|
-
end
|
30
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-weixin
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-02
|
12
|
+
date: 2013-12-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rack
|
@@ -27,6 +27,22 @@ dependencies:
|
|
27
27
|
- - ! '>='
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: multi_json
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 1.7.9
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 1.7.9
|
30
46
|
- !ruby/object:Gem::Dependency
|
31
47
|
name: multi_xml
|
32
48
|
requirement: !ruby/object:Gem::Requirement
|
@@ -59,6 +75,22 @@ dependencies:
|
|
59
75
|
- - ! '>='
|
60
76
|
- !ruby/object:Gem::Version
|
61
77
|
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: nestful
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :runtime
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
62
94
|
- !ruby/object:Gem::Dependency
|
63
95
|
name: rake
|
64
96
|
requirement: !ruby/object:Gem::Requirement
|
@@ -118,6 +150,8 @@ files:
|
|
118
150
|
- Gemfile.lock
|
119
151
|
- README.md
|
120
152
|
- Rakefile
|
153
|
+
- lib/rack-weixin.rb
|
154
|
+
- lib/weixin/menu.rb
|
121
155
|
- lib/weixin/middleware.rb
|
122
156
|
- lib/weixin/model.rb
|
123
157
|
- lib/weixin/version.rb
|
@@ -136,18 +170,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
136
170
|
- - ! '>='
|
137
171
|
- !ruby/object:Gem::Version
|
138
172
|
version: '0'
|
139
|
-
segments:
|
140
|
-
- 0
|
141
|
-
hash: -95414285
|
142
173
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
143
174
|
none: false
|
144
175
|
requirements:
|
145
176
|
- - ! '>='
|
146
177
|
- !ruby/object:Gem::Version
|
147
178
|
version: '0'
|
148
|
-
segments:
|
149
|
-
- 0
|
150
|
-
hash: -95414285
|
151
179
|
requirements: []
|
152
180
|
rubyforge_project:
|
153
181
|
rubygems_version: 1.8.24
|