rubirai 0.0.2
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 +7 -0
- data/.github/dependabot.yml +11 -0
- data/.github/workflows/CI.yml +64 -0
- data/.github/workflows/docs.yml +32 -0
- data/.github/workflows/pull_request.yml +34 -0
- data/.gitignore +145 -0
- data/.rubocop.yml +41 -0
- data/.yardopts +7 -0
- data/Gemfile +19 -0
- data/LICENSE +661 -0
- data/README.md +24 -0
- data/Rakefile +16 -0
- data/examples/helper.rb +3 -0
- data/examples/listener_example.rb +25 -0
- data/examples/simple_example.rb +24 -0
- data/lib/rubirai.rb +66 -0
- data/lib/rubirai/auth.rb +73 -0
- data/lib/rubirai/errors.rb +26 -0
- data/lib/rubirai/event_recv.rb +83 -0
- data/lib/rubirai/event_resp.rb +129 -0
- data/lib/rubirai/events/bot_events.rb +53 -0
- data/lib/rubirai/events/event.rb +115 -0
- data/lib/rubirai/events/message_events.rb +77 -0
- data/lib/rubirai/events/request_events.rb +35 -0
- data/lib/rubirai/events/rubirai_events.rb +17 -0
- data/lib/rubirai/listener.rb +44 -0
- data/lib/rubirai/listing.rb +37 -0
- data/lib/rubirai/management.rb +200 -0
- data/lib/rubirai/message.rb +84 -0
- data/lib/rubirai/messages/message.rb +306 -0
- data/lib/rubirai/messages/message_chain.rb +119 -0
- data/lib/rubirai/multipart.rb +44 -0
- data/lib/rubirai/objects/group.rb +23 -0
- data/lib/rubirai/objects/info.rb +71 -0
- data/lib/rubirai/objects/user.rb +30 -0
- data/lib/rubirai/plugin_info.rb +19 -0
- data/lib/rubirai/retcode.rb +18 -0
- data/lib/rubirai/session.rb +26 -0
- data/lib/rubirai/utils.rb +62 -0
- data/lib/rubirai/version.rb +9 -0
- data/misc/common.css +11 -0
- data/rubirai.gemspec +24 -0
- data/spec/auth_spec.rb +118 -0
- data/spec/error_spec.rb +30 -0
- data/spec/events/event_spec.rb +78 -0
- data/spec/message_spec.rb +12 -0
- data/spec/messages/message_chain_spec.rb +32 -0
- data/spec/messages/message_spec.rb +171 -0
- data/spec/plugin_info_spec.rb +28 -0
- data/spec/rubirai_bot_spec.rb +45 -0
- data/spec/spec_helper.rb +31 -0
- data/spec/utils_spec.rb +70 -0
- metadata +121 -0
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rubirai/messages/message'
|
4
|
+
require 'rubirai/messages/message_chain'
|
5
|
+
|
6
|
+
module Rubirai
|
7
|
+
class Bot
|
8
|
+
# Send temp message
|
9
|
+
#
|
10
|
+
# @param target_qq [Integer] target qq id
|
11
|
+
# @param group_id [Integer] group id
|
12
|
+
# @param msgs [Array<Rubirai::Message, Hash, String, Object>] messages to form a chain, can be any type
|
13
|
+
# @return [Integer] message id
|
14
|
+
def send_temp_msg(target_qq, group_id, *msgs)
|
15
|
+
chain = Rubirai::MessageChain.make(*msgs, bot: self)
|
16
|
+
resp = call :post, '/sendTempMessage', json: {
|
17
|
+
sessionKey: @session,
|
18
|
+
qq: target_qq.to_i,
|
19
|
+
group: group_id.to_i,
|
20
|
+
messageChain: chain.to_a
|
21
|
+
}
|
22
|
+
resp['messageId']
|
23
|
+
end
|
24
|
+
|
25
|
+
def send_msg(type, target_id, *msgs)
|
26
|
+
self.class.ensure_type_in type, 'group', 'friend'
|
27
|
+
chain = Rubirai::MessageChain.make(*msgs, bot: self)
|
28
|
+
resp = call :post, "/send#{type.to_s.snake_to_camel}Message", json: {
|
29
|
+
sessionKey: @session,
|
30
|
+
target: target_id.to_i,
|
31
|
+
messageChain: chain.to_a
|
32
|
+
}
|
33
|
+
resp['messageId']
|
34
|
+
end
|
35
|
+
|
36
|
+
def send_friend_msg(target_qq, *msgs)
|
37
|
+
send_msg :friend, target_qq, *msgs
|
38
|
+
end
|
39
|
+
|
40
|
+
def send_group_msg(target_group_id, *msgs)
|
41
|
+
send_msg :group, target_group_id, *msgs
|
42
|
+
end
|
43
|
+
|
44
|
+
def recall(msg_id)
|
45
|
+
call :post, '/recall', json: {
|
46
|
+
sessionKey: @session,
|
47
|
+
target: msg_id
|
48
|
+
}
|
49
|
+
nil
|
50
|
+
end
|
51
|
+
|
52
|
+
# Send image messages
|
53
|
+
#
|
54
|
+
# @param urls [Array<String>] the urls of the images
|
55
|
+
# @param kwargs [Hash] keys are one of [target, qq, group].
|
56
|
+
# @return [Array<String>] the image ids
|
57
|
+
def send_image_msg(urls, **kwargs)
|
58
|
+
urls.must_be! Array
|
59
|
+
urls.each do |url|
|
60
|
+
url.must_be! String
|
61
|
+
end
|
62
|
+
valid = %w[target qq group]
|
63
|
+
res = {
|
64
|
+
sessionKey: @session,
|
65
|
+
urls: urls
|
66
|
+
}
|
67
|
+
kwargs.each do |k, v|
|
68
|
+
res[k.to_s.downcase.to_sym] = v if valid.include? k.to_s.downcase
|
69
|
+
end
|
70
|
+
call :post, '/sendImageMessage', json: res
|
71
|
+
end
|
72
|
+
|
73
|
+
def send_nudge(target_id, subject_id, kind)
|
74
|
+
kind.to_s.downcase.must_be_one_of! %w[group friend], RubiraiError, 'kind must be one of group or friend'
|
75
|
+
call :post, '/sendNudge', json: {
|
76
|
+
sessionKey: @session,
|
77
|
+
target: target_id,
|
78
|
+
subject: subject_id,
|
79
|
+
kind: kind.to_s.capitalize
|
80
|
+
}
|
81
|
+
nil
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,306 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rubirai/utils'
|
4
|
+
|
5
|
+
module Rubirai
|
6
|
+
# The message abstract class.
|
7
|
+
#
|
8
|
+
# @abstract
|
9
|
+
# @!method self.AtMessage(**kwargs)
|
10
|
+
# @param kwargs [Hash{Symbol => Object}] arguments
|
11
|
+
# @return [Rubirai::AtMessage]
|
12
|
+
# @!method self.QuoteMessage(**kwargs)
|
13
|
+
# @param kwargs [Hash{Symbol => Object}] arguments
|
14
|
+
# @return [Rubirai::QuoteMessage]
|
15
|
+
# @!method self.AtAllMessage(**kwargs)
|
16
|
+
# @param kwargs [Hash{Symbol => Object}] arguments
|
17
|
+
# @return [Rubirai::AtAllMessage]
|
18
|
+
# @!method self.FaceMessage(**kwargs)
|
19
|
+
# @param kwargs [Hash{Symbol => Object}] arguments
|
20
|
+
# @return [Rubirai::FaceMessage]
|
21
|
+
# @!method self.PlainMessage(**kwargs)
|
22
|
+
# @option text [String] the plain text
|
23
|
+
# @return [Rubirai::PlainMessage]
|
24
|
+
class Message
|
25
|
+
attr_reader :bot, :type
|
26
|
+
|
27
|
+
# Objects to {Rubirai::Message}
|
28
|
+
#
|
29
|
+
# @param msg [Rubirai::Message, Hash, Object] the object to transform to a message
|
30
|
+
# @return [Rubirai::Message] the message
|
31
|
+
def self.to_message(msg, bot = nil)
|
32
|
+
# noinspection RubyYardReturnMatch
|
33
|
+
case msg
|
34
|
+
when Message, MessageChain
|
35
|
+
msg
|
36
|
+
when Hash
|
37
|
+
Message.build_from(msg, bot)
|
38
|
+
else
|
39
|
+
PlainMessage.from(text: msg.to_s, bot: bot)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Get all message types (subclasses)
|
44
|
+
#
|
45
|
+
# @return [Array<Symbol>] all message types
|
46
|
+
def self.all_types
|
47
|
+
%i[
|
48
|
+
Source Quote At AtAll Face Plain Image
|
49
|
+
FlashImage Voice Xml Json App Poke Forward
|
50
|
+
File MusicShare
|
51
|
+
]
|
52
|
+
end
|
53
|
+
|
54
|
+
# Check if a type is in all message types
|
55
|
+
# @param type [Symbol] the type to check
|
56
|
+
# @return whether the type is in all message types
|
57
|
+
def self.check_type(type)
|
58
|
+
raise(RubiraiError, 'type not in all message types') unless Message.all_types.include? type
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.get_msg_klass(type)
|
62
|
+
Object.const_get "Rubirai::#{type}Message"
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.build_from(hash, bot = nil)
|
66
|
+
hash = hash.stringify_keys
|
67
|
+
raise(RubiraiError, 'not a valid message') unless hash.key? 'type'
|
68
|
+
|
69
|
+
type = hash['type'].to_sym
|
70
|
+
check_type type
|
71
|
+
klass = get_msg_klass type
|
72
|
+
klass.new hash, bot
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.set_message(type, *attr_keys, &initialize_block)
|
76
|
+
attr_reader(*attr_keys)
|
77
|
+
|
78
|
+
metaclass.instance_eval do
|
79
|
+
define_method(:keys) do
|
80
|
+
attr_keys
|
81
|
+
end
|
82
|
+
break if attr_keys.empty?
|
83
|
+
define_method(:from) do |bot: nil, **kwargs|
|
84
|
+
res = get_msg_klass(type).new({}, bot)
|
85
|
+
attr_keys.each do |key|
|
86
|
+
res.instance_variable_set "@#{key}", kwargs[key]
|
87
|
+
end
|
88
|
+
res
|
89
|
+
end
|
90
|
+
s = +"def from_with_param(#{attr_keys.join('= nil, ')} = nil)\n"
|
91
|
+
s << "res = Rubirai::#{type}Message.new({})\n"
|
92
|
+
attr_keys.each do |key|
|
93
|
+
s << %[res.instance_variable_set("@#{key}", #{key})\n]
|
94
|
+
end
|
95
|
+
s << "res\nend"
|
96
|
+
class_eval s
|
97
|
+
end
|
98
|
+
|
99
|
+
class_eval do
|
100
|
+
define_method(:initialize) do |hash, bot = nil|
|
101
|
+
# noinspection RubySuperCallWithoutSuperclassInspection
|
102
|
+
super type, bot
|
103
|
+
initialize_block&.call(hash)
|
104
|
+
hash = hash.stringify_keys
|
105
|
+
attr_keys.each do |k|
|
106
|
+
instance_variable_set("@#{k}", hash[k.to_s.snake_to_camel(lower: true)])
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def initialize(type, bot = nil)
|
113
|
+
Message.check_type type
|
114
|
+
@bot = bot
|
115
|
+
@type = type
|
116
|
+
end
|
117
|
+
|
118
|
+
def to_h
|
119
|
+
res = self.class.keys.to_h do |k|
|
120
|
+
v = instance_variable_get("@#{k}")
|
121
|
+
k = k.to_s.snake_to_camel(lower: true)
|
122
|
+
if v.is_a? MessageChain
|
123
|
+
[k, v.to_a]
|
124
|
+
elsif v&.respond_to?(:to_h)
|
125
|
+
[k, v.to_h]
|
126
|
+
else
|
127
|
+
[k, v]
|
128
|
+
end
|
129
|
+
end
|
130
|
+
res[:type] = @type.to_s
|
131
|
+
res.compact.stringify_keys
|
132
|
+
end
|
133
|
+
|
134
|
+
def self.metaclass
|
135
|
+
class << self
|
136
|
+
self
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def self.Message(obj, bot = nil)
|
142
|
+
Message.to_message obj, bot
|
143
|
+
end
|
144
|
+
|
145
|
+
Message.all_types.each do |type|
|
146
|
+
self.class.define_method("#{type}Message".to_sym) do |**kwargs|
|
147
|
+
Message.get_msg_klass(type).from(**kwargs)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
# The source message type
|
152
|
+
class SourceMessage < Message
|
153
|
+
# @!attribute [r] id
|
154
|
+
# @return [Integer] the message (chain) id
|
155
|
+
# @!attribute [r] time
|
156
|
+
# @return [Integer] the timestamp
|
157
|
+
set_message :Source, :id, :time
|
158
|
+
end
|
159
|
+
|
160
|
+
# The quote message type
|
161
|
+
class QuoteMessage < Message
|
162
|
+
# @!attribute [r] id
|
163
|
+
# @return [Integer] the original (quoted) message (chain) id
|
164
|
+
# @!attribute [r] group_id
|
165
|
+
# @return [Integer] the group id
|
166
|
+
# @!attribute [r] sender_id
|
167
|
+
# @return [Integer] the original sender's id
|
168
|
+
# @!attribute [r] target_id
|
169
|
+
# @return [Integer] the original receiver's (group or user) id
|
170
|
+
# @!attribute [r] origin
|
171
|
+
# @return [MessageChain] the original message chain
|
172
|
+
set_message :Quote, :id, :group_id, :sender_id, :target_id, :origin
|
173
|
+
|
174
|
+
def initialize(hash, bot = nil)
|
175
|
+
super :Quote, bot
|
176
|
+
@id = hash['id']
|
177
|
+
@group_id = hash['groupId']
|
178
|
+
@sender_id = hash['senderId']
|
179
|
+
@target_id = hash['targetId']
|
180
|
+
@origin = MessageChain.make(*hash['origin'], sender_id: @sender_id, bot: bot)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
# The At message type
|
185
|
+
class AtMessage < Message
|
186
|
+
# @!attribute [r] target
|
187
|
+
# @return [Integer] the target group user's id
|
188
|
+
# @!attribute [r] display
|
189
|
+
# @return [String] the displayed name (not used when sending)
|
190
|
+
# @!method from(**kwargs)
|
191
|
+
# @param kwargs [Hash{Symbol => Object}] not used
|
192
|
+
# @return [AtMessage] the message object
|
193
|
+
set_message :At, :target, :display
|
194
|
+
end
|
195
|
+
|
196
|
+
# The At All message type
|
197
|
+
class AtAllMessage < Message
|
198
|
+
# @!method from(**kwargs)
|
199
|
+
# @param kwargs [Hash{Symbol => Object}] the fields to set
|
200
|
+
# @return [AtAllMessage] the message object
|
201
|
+
set_message :AtAll
|
202
|
+
end
|
203
|
+
|
204
|
+
# The QQ Face Emoji message type
|
205
|
+
class FaceMessage < Message
|
206
|
+
# @!attribute [r] face_id
|
207
|
+
# @return [Integer] the face's id
|
208
|
+
# @!attribute [r] name
|
209
|
+
# @return [String, nil] the face's name
|
210
|
+
set_message :Face, :face_id, :name
|
211
|
+
end
|
212
|
+
|
213
|
+
# The plain text message type
|
214
|
+
class PlainMessage < Message
|
215
|
+
# @!attribute [r] text
|
216
|
+
# @return [String] the text
|
217
|
+
set_message :Plain, :text
|
218
|
+
end
|
219
|
+
|
220
|
+
# The image message type.
|
221
|
+
# Only one out of the three fields is needed to form the message.
|
222
|
+
class ImageMessage < Message
|
223
|
+
# @!attribute [r] image_id
|
224
|
+
# @return [Integer, nil] the image id from mirai
|
225
|
+
# @!attribute [r] url
|
226
|
+
# @return [String, nil] the url of the image
|
227
|
+
# @!attribute [r] path
|
228
|
+
# @return [String, nil] the local path of the image
|
229
|
+
set_message :Image, :image_id, :url, :path
|
230
|
+
end
|
231
|
+
|
232
|
+
# The flash image message type
|
233
|
+
class FlashImageMessage < Message
|
234
|
+
set_message :FlashImage, :image_id, :url, :path
|
235
|
+
end
|
236
|
+
|
237
|
+
# The voice message type
|
238
|
+
class VoiceMessage < Message
|
239
|
+
set_message :Voice, :voice_id, :url, :path
|
240
|
+
end
|
241
|
+
|
242
|
+
# The xml message type
|
243
|
+
class XmlMessage < Message
|
244
|
+
# @!attribute [r] xml
|
245
|
+
# @return [String] the xml content
|
246
|
+
set_message :Xml, :xml
|
247
|
+
end
|
248
|
+
|
249
|
+
# The json message type
|
250
|
+
class JsonMessage < Message
|
251
|
+
# @!attribute [r] json
|
252
|
+
# @return [String] the json content
|
253
|
+
set_message :Json, :json
|
254
|
+
end
|
255
|
+
|
256
|
+
# The app message type
|
257
|
+
class AppMessage < Message
|
258
|
+
# @!attribute [r] content
|
259
|
+
# @return [String] the app content
|
260
|
+
set_message :App, :content
|
261
|
+
end
|
262
|
+
|
263
|
+
class PokeMessage < Message
|
264
|
+
set_message :Poke, :name
|
265
|
+
end
|
266
|
+
|
267
|
+
class ForwardMessage < Message
|
268
|
+
class Node
|
269
|
+
attr_reader :sender_id, :time, :sender_name, :message_chain
|
270
|
+
|
271
|
+
def initialize(hash, bot = nil)
|
272
|
+
@sender_id = hash['senderId']
|
273
|
+
@time = hash['time']
|
274
|
+
@sender_name = hash['senderName']
|
275
|
+
@message_chain = MessageChain.make(*hash['messageChain'], sender_id: hash['senderId'], bot: bot)
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
set_message :Forward, :title, :brief, :source, :summary, :node_list
|
280
|
+
|
281
|
+
def initialize(hash, bot = nil)
|
282
|
+
super :Forward, bot
|
283
|
+
@title = hash['title']
|
284
|
+
@brief = hash['brief']
|
285
|
+
@source = hash['source']
|
286
|
+
@summary = hash['summary']
|
287
|
+
@node_list = hash['nodeList'].each do |chain|
|
288
|
+
Node.new chain, bot
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
class FileMessage < Message
|
294
|
+
set_message :File, :id, :internal_id, :name, :size
|
295
|
+
end
|
296
|
+
|
297
|
+
class MusicShareMessage < Message
|
298
|
+
def self.all_kinds
|
299
|
+
%w[NeteaseCloudMusic QQMusic MiguMusic]
|
300
|
+
end
|
301
|
+
|
302
|
+
set_message :MusicShare, :kind, :title, :summary, :jump_url, :picture_url, :music_url, :brief do |hash|
|
303
|
+
raise(RubiraiError, 'non valid music type') unless all_kinds.include? hash['kind']
|
304
|
+
end
|
305
|
+
end
|
306
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rubirai/utils'
|
4
|
+
require 'rubirai/messages/message'
|
5
|
+
|
6
|
+
module Rubirai
|
7
|
+
class MessageChain
|
8
|
+
include Enumerable
|
9
|
+
|
10
|
+
attr_reader :bot, :sender_id, :send_time, :messages, :read_only
|
11
|
+
|
12
|
+
# Makes a message chain from a list of messages
|
13
|
+
#
|
14
|
+
# @param messages [Array<Rubirai::Message, Rubirai::MessageChain, Hash, String, Object>] a list of messages
|
15
|
+
# @param sender_id [Integer, nil]
|
16
|
+
# @param bot [Rubirai::Bot, nil]
|
17
|
+
# @return [Rubirai::MessageChain] the message chain
|
18
|
+
def self.make(*messages, sender_id: nil, bot: nil)
|
19
|
+
chain = new(bot, sender_id: sender_id)
|
20
|
+
result = []
|
21
|
+
messages.map { |msg| Message.to_message(msg, bot) }.each do |msg|
|
22
|
+
if !result.empty? && result[-1].is_a?(PlainMessage) && msg.is_a?(PlainMessage)
|
23
|
+
result[-1] = PlainMessage.from(text: result[-1].text + msg.text, bot: bot)
|
24
|
+
else
|
25
|
+
result.append msg
|
26
|
+
end
|
27
|
+
end
|
28
|
+
chain.extend(*result)
|
29
|
+
chain
|
30
|
+
end
|
31
|
+
|
32
|
+
# Append messages to this message chain
|
33
|
+
#
|
34
|
+
# @param messages [Array<Rubirai::Message, Hash>] a list of messages
|
35
|
+
# @return [Rubirai::MessageChain] self
|
36
|
+
def extend(*messages)
|
37
|
+
messages.each do |msg|
|
38
|
+
internal_append msg
|
39
|
+
end
|
40
|
+
self
|
41
|
+
end
|
42
|
+
|
43
|
+
alias << extend
|
44
|
+
alias append extend
|
45
|
+
|
46
|
+
def concat(msg_chain)
|
47
|
+
msg_chain.to_a.each do |msg|
|
48
|
+
internal_append msg
|
49
|
+
end
|
50
|
+
self
|
51
|
+
end
|
52
|
+
|
53
|
+
def [](idx)
|
54
|
+
@messages[idx]
|
55
|
+
end
|
56
|
+
|
57
|
+
def each(&block)
|
58
|
+
@messages.each(&block)
|
59
|
+
end
|
60
|
+
|
61
|
+
def length
|
62
|
+
@messages.length
|
63
|
+
end
|
64
|
+
|
65
|
+
def size
|
66
|
+
@messages.size
|
67
|
+
end
|
68
|
+
|
69
|
+
def empty?
|
70
|
+
@messages.empty?
|
71
|
+
end
|
72
|
+
|
73
|
+
# @param bot [Rubirai::Bot, nil]
|
74
|
+
# @param source [Array, nil]
|
75
|
+
# @param sender_id [Integer, nil]
|
76
|
+
def initialize(bot = nil, source = nil, sender_id: nil)
|
77
|
+
@bot = bot
|
78
|
+
@sender_id = sender_id
|
79
|
+
@messages = []
|
80
|
+
return unless source
|
81
|
+
raise(MiraiError, 'source is not array') unless source.is_a? Array
|
82
|
+
raise(MiraiError, 'length is zero') if source.empty?
|
83
|
+
|
84
|
+
if source[0]['type'] == 'Source'
|
85
|
+
@sender_id = source[0]['id']
|
86
|
+
@send_time = source[0]['time']
|
87
|
+
extend(*source.drop(1))
|
88
|
+
else
|
89
|
+
extend(*source)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def to_a
|
94
|
+
@messages.map(&:to_h)
|
95
|
+
end
|
96
|
+
|
97
|
+
private
|
98
|
+
|
99
|
+
def internal_append(msg)
|
100
|
+
msg.must_be! [Message, MessageChain, Hash], RubiraiError, 'msg must be Message, MessageChain, or Hash'
|
101
|
+
|
102
|
+
case msg
|
103
|
+
when Message
|
104
|
+
@messages.append msg
|
105
|
+
when MessageChain
|
106
|
+
@messages.append(*msg.messages)
|
107
|
+
else
|
108
|
+
@messages.append Message.build_from(msg, @bot)
|
109
|
+
end
|
110
|
+
|
111
|
+
self
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# Makes a message chain. See {MessageChain#make}.
|
116
|
+
def self.MessageChain(*messages, sender_id: nil, bot: nil)
|
117
|
+
MessageChain.make(*messages, sender_id: sender_id, bot: bot)
|
118
|
+
end
|
119
|
+
end
|