mini_program 0.1.0

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 04f5a8d75c16656473df0c93306b9d83833c272037d7fb60e894756eed9f4b1c
4
+ data.tar.gz: '0868870f615a9e08047465024b8293be7af4080d64fa4b1d7313ea7b56926e4a'
5
+ SHA512:
6
+ metadata.gz: ee4c68f56483b9acdbee602db221033ea503738ddd63409288b864d130ea37ca23a291fc2392a3f146ea0c5991236e8acd0f1f48a4f05ae8f817ef4f5792e100
7
+ data.tar.gz: e1ec32db171b7e4fe2168ac715668e9f6ed9e3704e276c7a61b7e6dbc30a6b30858bec73acf83c406459ef32c85382954c89e6e2efdf29ce40c86fae733d3a86
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2021 ian
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,143 @@
1
+ # MiniProgram
2
+ Short description and motivation.
3
+
4
+ ## 开始
5
+
6
+ 1. 添加`gem`
7
+ ```ruby
8
+ gem 'mini_program'
9
+ ```
10
+
11
+ 2. 执行 bundle
12
+ ```bash
13
+ $ bundle
14
+ ```
15
+
16
+ 3. 生成`initializer`文件,需要將里边的内容修改成你自己的小程序的配置
17
+ ```bash
18
+ $ rails g mini_program:install
19
+ ```
20
+
21
+ 4. 如果需要订阅消息,使用如下命令生成订阅消息的配置
22
+ ```bash
23
+ $ rails g mini_program:msg_config
24
+ ```
25
+
26
+ ## 使用
27
+
28
+ #### 授权登录(获取openid)
29
+ ```ruby
30
+ mp = MiniProgram::Client.new
31
+
32
+ # code 是在小程序端调用 wx.login 拿到的
33
+ result = mp.login(code)
34
+ if result.success?
35
+ open_id = result.data[:openid]
36
+ session_key = result.data[:session_key]
37
+ end
38
+ ```
39
+
40
+ #### 获取手机号
41
+ ```ruby
42
+ mp = MiniProgram::Client.new
43
+
44
+ # 小程序端 wx.login 拿到的 code
45
+ code = "041PuvGa1rysrB0noDJa1n7RBv2PuvGe"
46
+
47
+ # encrypted_data 和 iv 都是小程序端 getPhoneNum 获取到的参数
48
+ encrypted_data = "3G/+Fh6kCBaQszXFTxz3h3HFSbu0UuVW/4aLbz8WGzrKfmbGpvnxYHAa4QrKXJvHpB++3ogOYoU6iiG+1HW18Lkt9qEJE9GyRw5OnuXSjTnUIPSRROT3sxeAYnT1kf4ngTAfrD3f4TFtLXkRIrrc1MzSqx/LV8iXA8Lu5Y+7kZx26eulz3yVrlXDH3BOIX6zcGOeprsK5XzDx2ltmf3j5w=="
49
+ iv = "5tiyfVEHNVgHN4n8lzDrUA=="
50
+
51
+ result = mp.get_phone_num(code: code, encrypted_data: encrypted_data, iv: iv)
52
+
53
+ if result.success?
54
+ phone_num = result[:phone_num]
55
+ end
56
+
57
+ ```
58
+
59
+ #### 发送订阅消息
60
+ ```ruby
61
+
62
+ # 订阅消息配置 ,具体模板配置请参考小程序后台模板配置
63
+ #
64
+ # config/subscribe_msg.yml
65
+ #
66
+ # progress:
67
+ # template_id: YQ0cmL_ugsXwPaA2Pl75IMo_qtoc1n6CtT1orIeX4_o
68
+ # page: "/pages/index/index"
69
+ # data:
70
+ # thing2:
71
+ # value: "%{title}"
72
+ # phrase4:
73
+ # value: "%{state}"
74
+ # thing1:
75
+ # value: "%{detail}"
76
+
77
+ msg = MiniProgram::Msg.new(:progress, {
78
+ title: "测试",
79
+ state: "已完成",
80
+ detail: "测试已完成"
81
+ })
82
+
83
+ # send_to 的参数可以是 openid(字符串),或者是带有 open_id 方法的对象,返回 MiniProgram::ServiceResult
84
+ result msg.send_to("ogT7J5YddGnll-ippRvJq62Nv5W0")
85
+
86
+ # or
87
+ user = User.first
88
+ user.open_id # => ogT7J5YddGnll-ippRvJq62Nv5W0
89
+ result = msg.send_to(user)
90
+
91
+ if result.success?
92
+ puts "发送成功"
93
+ end
94
+
95
+ ```
96
+
97
+ #### 获取`access-token`
98
+ ```ruby
99
+ mp = MiniProgram::Client.new
100
+
101
+ # 缓存在 redis 中,缓存时间为 1.5 小时,微信官方`access-token`过期时间是 2小时
102
+ result = mp.get_access_token
103
+ if result.success?
104
+ access_token = result[:access_token]
105
+ end
106
+
107
+ # 传入 fresh: true 可以不使用缓存,直接调用微信api获取到 token,默认为 false
108
+ result = mp.access_token fresh:true
109
+ ```
110
+
111
+ #### MiniProgram::ServiceResult 类
112
+ ```ruby
113
+ # success 默认为 false
114
+ result = MiniProgram::ServiceResult.new(success: true, data: {data1: 1})
115
+
116
+ ## 处理结果(成功)
117
+ if result.success?
118
+ # do something...
119
+ end
120
+
121
+ # or
122
+ result.on_success do |result|
123
+ # do something...
124
+ end
125
+
126
+ ## 处理结果(失败)
127
+ if result.failure?
128
+ # do something...
129
+ end
130
+
131
+ result.on_failure do |result|
132
+ # do something...
133
+ end
134
+
135
+
136
+
137
+ ```
138
+
139
+ ## Contributing
140
+ Contribution directions go here.
141
+
142
+ ## License
143
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ require "bundler/setup"
2
+
3
+ require "bundler/gem_tasks"
4
+
5
+ require "rake/testtask"
6
+
7
+ Rake::TestTask.new(:test) do |t|
8
+ t.libs << 'test'
9
+ t.pattern = 'test/**/*_test.rb'
10
+ t.verbose = false
11
+ end
12
+
13
+ task default: :test
@@ -0,0 +1,8 @@
1
+ Description:
2
+ Explain the generator
3
+
4
+ Example:
5
+ bin/rails generate install Thing
6
+
7
+ This will create:
8
+ what/will/it/create
@@ -0,0 +1,24 @@
1
+ class MiniProgram::InstallGenerator < Rails::Generators::Base
2
+ source_root File.expand_path('templates', __dir__)
3
+ def create_initializer_file
4
+ # copy_file "initializer.rb", "config/initializers/mini_program.rb"
5
+ appid = if Object.const_defined? "WechatPayment"
6
+ WechatPayment.sub_appid || WechatPayment.appid || "your appid"
7
+ else
8
+ "your appid"
9
+ end
10
+
11
+ app_secret = if Object.const_defined? "WechatPayment"
12
+ WechatPayment.sub_app_secret || WechatPayment.app_secret || "your app secret"
13
+ else
14
+ "your app_secret"
15
+ end
16
+ create_file "config/initializers/mini_program.rb", <<~INITIALIZER
17
+
18
+ MiniProgram.setup do |config|
19
+ config.appid = "#{appid}"
20
+ config.app_secret = "#{app_secret}"
21
+ end
22
+ INITIALIZER
23
+ end
24
+ end
@@ -0,0 +1,5 @@
1
+
2
+ MiniProgram.setup do |config|
3
+ config.appid = "your appid"
4
+ config.app_secret = "your appsecret"
5
+ end
@@ -0,0 +1,8 @@
1
+ Description:
2
+ Explain the generator
3
+
4
+ Example:
5
+ bin/rails generate msg_config Thing
6
+
7
+ This will create:
8
+ what/will/it/create
@@ -0,0 +1,7 @@
1
+ class MiniProgram::MsgConfigGenerator < Rails::Generators::Base
2
+ source_root File.expand_path('templates', __dir__)
3
+
4
+ def create_subscribe_msg_config_file
5
+ copy_file "subscribe_msg.yml", "config/subscribe_msg.yml"
6
+ end
7
+ end
@@ -0,0 +1,11 @@
1
+ ---
2
+ progress:
3
+ template_id: YQ0cmL_ugsXwPaA2Pl75IMo_qtoc1n6CtT1orIeX4_o
4
+ page: "/pages/index/index"
5
+ data:
6
+ thing2:
7
+ value: "%{title}"
8
+ phrase4:
9
+ value: "%{state}"
10
+ thing1:
11
+ value: "%{detail}"
@@ -0,0 +1,16 @@
1
+ require "mini_program/version"
2
+ require "mini_program/railtie"
3
+ require "mini_program/client"
4
+ require "mini_program/msg"
5
+ require "r_logger"
6
+ require "service_result"
7
+ require "redis"
8
+
9
+ module MiniProgram
10
+ # Your code goes here...
11
+ mattr_accessor :appid, :app_secret
12
+
13
+ def self.setup
14
+ yield self if block_given?
15
+ end
16
+ end
@@ -0,0 +1,201 @@
1
+ module MiniProgram
2
+ class Client
3
+ attr_reader :appid, :app_secret
4
+
5
+ def initialize(appid: config.appid, app_secret: config.app_secret)
6
+ @appid = appid
7
+ @app_secret = app_secret
8
+
9
+ if appid == 'your appid'
10
+ warn "\e[33m" + "*" * 80 + "\e[0m"
11
+ warn "\e[33m警告: 请将 config/initializer/mini_program.rb 中的 appid 修改成你实际的appid\e[0m"
12
+ warn "\e[33m" + "*" * 80 + "\e[0m"
13
+ end
14
+
15
+ if app_secret == 'your app_secret'
16
+ warn "\e[33m" + "*" * 80 + "\e[0m"
17
+ warn "\e[33m警告: 请将 config/initializer/mini_program.rb 中的 app_secret 修改成你实际的app_secret\e[0m"
18
+ warn "\e[33m" + "*" * 80 + "\e[0m"
19
+ end
20
+ end
21
+
22
+ def get_access_token(fresh: false)
23
+ access_token = redis.get("mp-#{appid}-access-token")
24
+ if access_token.present? && !fresh
25
+ return MiniProgram::ServiceResult.new(success: true, data: {access_token: access_token})
26
+ end
27
+
28
+ result = request_access_token
29
+ if result.success?
30
+ redis.setex "mp-#{appid}-access-token", 1.5.hours.to_i, access_token
31
+ end
32
+
33
+ yield result if block_given?
34
+
35
+ result
36
+ end
37
+
38
+ # 调用微信 api 获取 access_token
39
+ #
40
+ # @return MiniProgram::ServiceResult
41
+ def request_access_token
42
+ api = "https://api.weixin.qq.com/cgi-bin/token"
43
+ params = {
44
+ appid: appid,
45
+ secret: app_secret,
46
+ grant_type: :client_credential
47
+ }
48
+
49
+ response = get(api, params)
50
+
51
+ result = JSON.parse(response)
52
+
53
+ if result["errcode"].present?
54
+ logger.error <<~ERROR
55
+ Get access token failed.
56
+ api: #{api}
57
+ error: #{result}
58
+ ERROR
59
+ return MiniProgram::ServiceResult.new(success: false, errors: result, message: result["errmsg"])
60
+ end
61
+
62
+ MiniProgram::ServiceResult.new(success: true, data: result)
63
+ end
64
+
65
+ # 调用微信授权登录 api
66
+ #
67
+ #
68
+ def login(code)
69
+ api = "https://api.weixin.qq.com/sns/jscode2session"
70
+ params = {
71
+ appid: appid,
72
+ secret: app_secret,
73
+ js_code: code,
74
+ grant_type: :authorization_code
75
+ }
76
+
77
+ response = get(api, params)
78
+
79
+ result = JSON.parse(response)
80
+
81
+ if result["errcode"]
82
+ logger.error <<~ERROR
83
+ Get session key failed.
84
+ api: #{api}
85
+ result: #{result}
86
+ ERROR
87
+ return MiniProgram::ServiceResult.new(errors: result, message: result["errmsg"])
88
+ end
89
+
90
+ MiniProgram::ServiceResult.new(success: true, data: result)
91
+ end
92
+
93
+ # 发送订阅消息
94
+ # @param [MiniProgram::Msg] msg
95
+ # @param [String] to 用户的open id
96
+ def send_msg(msg, to: )
97
+ open_id = to.try(:open_id) || to
98
+
99
+ payload = msg.as_json.merge!(touser: open_id)
100
+
101
+ # 获取 access_token
102
+ get_token_result = get_access_token
103
+ if get_token_result.failure?
104
+ return get_token_result
105
+ end
106
+
107
+ api = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=#{get_token_result["access_token"]}"
108
+ result = post(api, payload)
109
+
110
+ msg_logger.info {"{params: #{payload}, response: #{result}}"}
111
+ MiniProgram::ServiceResult.new(success: true, data: result)
112
+ end
113
+
114
+ # 获取用户手机号
115
+ def get_phone_num(code:, encrypted_data:, iv:)
116
+ login_result = login(code)
117
+ return login_result if login_result.failure?
118
+
119
+ open_id = login_result.data[:openid]
120
+ session_key = login_result.data[:session_key]
121
+
122
+ data = decrypt_phone_data(encrypted_data, iv, session_key)
123
+
124
+ phone_num = JSON.parse(data)["phoneNumber"]
125
+
126
+ MiniProgram::ServiceResult.new(
127
+ success: true,
128
+ data: {
129
+ open_id: open_id,
130
+ phone_num: phone_num
131
+ })
132
+ end
133
+
134
+ def config
135
+ appid, app_secret = if MiniProgram.appid && MiniProgram.app_secret
136
+ [MiniProgram.appid, MiniProgram.app_secret]
137
+
138
+ # 如果有挂载 WechatPayment 的 engine 时,使用里边的小程序配置
139
+ elsif Object.const_defined? "WechatPayment"
140
+ [WechatPayment.sub_appid || WechatPayment.appid, WechatPayment.sub_app_secret || WechatPayment.app_secret]
141
+ else
142
+ [nil, nil]
143
+ end
144
+
145
+ Struct.new(:appid, :app_secret).new(appid, app_secret)
146
+ end
147
+
148
+ private
149
+
150
+ def get(api, payload = {})
151
+ uri = URI(api)
152
+
153
+ if payload.present?
154
+ uri.query = URI.encode_www_form(payload)
155
+ end
156
+
157
+ Net::HTTP.get(uri)
158
+ end
159
+
160
+ def post(api, payload = {}, options = {})
161
+ uri = URI(api)
162
+
163
+ req = Net::HTTP::Post.new(uri)
164
+ req["Content-Type"] = "application/json"
165
+ options = {
166
+ use_ssl: true
167
+ }.merge(options)
168
+
169
+ res = Net::HTTP.start(uri.host, uri.port, **options) do |http|
170
+ http.request(req, payload.to_json)
171
+ end
172
+
173
+ JSON.parse(res.body)
174
+ end
175
+
176
+ def decrypt_phone_data(encrypted_data, iv, session_key)
177
+ aes = OpenSSL::Cipher::AES.new "128-CBC"
178
+ aes.decrypt
179
+ aes.key = Base64::decode64(session_key)
180
+ aes.iv = Base64.decode64(iv)
181
+ aes.update(Base64::decode64(encrypted_data)) + aes.final
182
+ end
183
+
184
+ def logger
185
+ @logger ||= MiniProgram::RLogger.make("mini_program")
186
+ end
187
+
188
+ def redis
189
+ @redis ||= Redis.current
190
+ end
191
+
192
+ def access_token_store_key
193
+ "mp-#{appid}-access-token"
194
+ end
195
+
196
+ def msg_logger
197
+ @msg_logger ||= MiniProgram::RLogger.make("wx_msg")
198
+ end
199
+
200
+ end
201
+ end
@@ -0,0 +1,30 @@
1
+
2
+ module MiniProgram
3
+ class Msg
4
+ attr_reader :msg_config, :type, :data
5
+ def initialize(type, data)
6
+ @type = type
7
+ @data = data
8
+ end
9
+
10
+ def as_json
11
+ {
12
+ template_id: config[:template_id],
13
+ data: JSON.parse(config[:data].to_json % data),
14
+ page: config[:page],
15
+ }
16
+ end
17
+
18
+ def send_to(open_id)
19
+ mini_program.send_msg(self, to: open_id)
20
+ end
21
+
22
+ def mini_program
23
+ @mini_program ||= MiniProgram::Client.new
24
+ end
25
+
26
+ def config
27
+ @config ||= YAML.load_file(Rails.root.join("config/subscribe_msg.yml")).with_indifferent_access[type]
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,4 @@
1
+ module MiniProgram
2
+ class Railtie < ::Rails::Railtie
3
+ end
4
+ end
@@ -0,0 +1,3 @@
1
+ module MiniProgram
2
+ VERSION = '0.1.0'
3
+ end
data/lib/r_logger.rb ADDED
@@ -0,0 +1,36 @@
1
+ module MiniProgram
2
+ class RLogger
3
+ def initialize
4
+ raise Exceptions::InitializeDenied.new("please use 'ILogger.make' instead of 'ILogger.new'")
5
+ end
6
+
7
+ class << self
8
+ def make(log_file)
9
+ @logger ||= {}
10
+
11
+ log_file_name = if log_file.class.in? [String, Symbol]
12
+ log_file_name = log_file.to_sym
13
+
14
+ unless log_file_name.to_s.end_with? ".log"
15
+ log_file_name = "#{log_file_name}.log"
16
+ end
17
+
18
+ "#{root_path}/#{log_file_name}"
19
+ elsif log_file.respond_to? :to_path
20
+ log_file.to_path
21
+ else
22
+ raise Exceptions::UnsupportdParamType.new("log file parameter only support 'File' or 'String' Type.")
23
+ end
24
+
25
+ # 如果已经存在日志对象,则返回已有的日志对象
26
+ @logger[log_file_name] ||= ::Logger.new(log_file_name)
27
+ end
28
+
29
+ def root_path
30
+ @root ||= "#{Rails.root}/log"
31
+ end
32
+ end
33
+
34
+
35
+ end
36
+ end
@@ -0,0 +1,49 @@
1
+ module MiniProgram
2
+ class ServiceResult
3
+ attr_accessor :success,
4
+ :errors,
5
+ :data,
6
+ :message,
7
+ :message_type
8
+
9
+ delegate :[], :[]=, to: :data
10
+
11
+ def initialize(success: false,
12
+ errors: nil,
13
+ message: nil,
14
+ message_type: nil,
15
+ data: {})
16
+ self.success = success
17
+ self.data = (data.presence || {}).with_indifferent_access
18
+ self.errors = errors.is_a?(Enumerable) ? errors : [errors]
19
+ self.message = message
20
+ self.message_type = message_type
21
+ end
22
+
23
+ alias success? :success
24
+
25
+ def failure?
26
+ !success?
27
+ end
28
+
29
+ def on_success
30
+ yield(self) if success?
31
+ self
32
+ end
33
+
34
+ def on_failure
35
+ yield(self) if failure?
36
+ self
37
+ end
38
+
39
+ def get_message_type
40
+ if message_type.present?
41
+ message_type.to_sym
42
+ elsif success?
43
+ :notice
44
+ else
45
+ :error
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :mini_program do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,105 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mini_program
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - ian
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-08-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 6.1.4
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 6.1.4
27
+ - !ruby/object:Gem::Dependency
28
+ name: redis
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: pry-rails
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: 登录授权,发送订阅消息
56
+ email:
57
+ - ianlynxk@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - MIT-LICENSE
63
+ - README.md
64
+ - Rakefile
65
+ - lib/generators/mini_program/install/USAGE
66
+ - lib/generators/mini_program/install/install_generator.rb
67
+ - lib/generators/mini_program/install/templates/initializer.rb
68
+ - lib/generators/mini_program/msg_config/USAGE
69
+ - lib/generators/mini_program/msg_config/msg_config_generator.rb
70
+ - lib/generators/mini_program/msg_config/templates/subscribe_msg.yml
71
+ - lib/mini_program.rb
72
+ - lib/mini_program/client.rb
73
+ - lib/mini_program/msg.rb
74
+ - lib/mini_program/railtie.rb
75
+ - lib/mini_program/version.rb
76
+ - lib/r_logger.rb
77
+ - lib/service_result.rb
78
+ - lib/tasks/mini_program_tasks.rake
79
+ homepage: https://github.com/otorain
80
+ licenses:
81
+ - MIT
82
+ metadata:
83
+ homepage_uri: https://github.com/otorain
84
+ source_code_uri: https://github.com/otorain/mini_program
85
+ changelog_uri: https://github.com/otorain/mini_program/CHANGELOG.md
86
+ post_install_message:
87
+ rdoc_options: []
88
+ require_paths:
89
+ - lib
90
+ required_ruby_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ requirements: []
101
+ rubygems_version: 3.2.15
102
+ signing_key:
103
+ specification_version: 4
104
+ summary: 小程序api开发工具
105
+ test_files: []