rack-weixin 0.0.3.1 → 0.0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|