Class: Rubirai::MessageChain

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/rubirai/messages/interpolation.rb,
lib/rubirai/messages/message_chain.rb

Overview

Message chain

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#botBot (readonly)

Returns the bot object.

Returns:

  • (Bot)

    the bot object



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/rubirai/messages/message_chain.rb', line 19

class MessageChain
  include Enumerable

  attr_reader :bot, :id, :raw, :send_time, :messages

  # Makes a message chain from a list of messages
  #
  # @param messages [Array<Rubirai::Message, Rubirai::MessageChain, Hash, String, Object>] a list of messages
  # @param bot [Rubirai::Bot, nil]
  # @return [Rubirai::MessageChain] the message chain
  def self.make(*messages, bot: nil)
    chain = new(bot)
    result = []
    messages.map { |msg| Message.to_message(msg, bot) }.each do |msg|
      if !result.empty? && result[-1].is_a?(PlainMessage) && msg.is_a?(PlainMessage)
        result[-1] = PlainMessage.from(text: result[-1].text + msg.text, bot: bot)
      else
        result.append msg
      end
    end
    chain.extend(*result)
    chain
  end

  # Append messages to this message chain
  #
  # @param messages [Array<Rubirai::Message, Hash>] a list of messages
  # @return [Rubirai::MessageChain] self
  def extend(*messages)
    messages.each do |msg|
      internal_append msg
    end
    self
  end

  alias << extend
  alias append extend

  # Concats this message chain with another one
  #
  # @param msg_chain [MessageChain] another message chain
  # @return [MessageChain] self
  def concat!(msg_chain)
    msg_chain.messages.each do |msg|
      internal_append msg
    end
    self
  end

  def [](idx)
    @messages[idx]
  end

  def each(&block)
    @messages.each(&block)
  end

  def length
    @messages.length
  end

  def size
    @messages.size
  end

  def empty?
    @messages.empty?
  end

  # Don't use the constructor. Use {.make}.
  #
  # @private
  # @param bot [Rubirai::Bot, nil]
  # @param source [Array, nil]
  def initialize(bot = nil, source = nil)
    @bot = bot
    @messages = []
    @has_interpolation = false
    @interpolated_str = nil
    @ipl_objs_map = {}
    @raw = source
    return unless source
    raise(MiraiError, 'source is not array') unless source.is_a? Array
    raise(MiraiError, 'length is zero') if source.empty?

    if source[0]['type'] == 'Source'
      @id = source[0]['id']
      @send_time = source[0]['time']
      extend(*source.drop(1))
    else
      extend(*source)
    end
  end

  # Convert the message chain to an array of hashes.
  #
  # @return [Array<Hash{String => Object}>]
  def to_a
    @messages.map(&:to_h)
  end

  private

  def internal_append(msg)
    msg.must_be! [Message, MessageChain, Hash], RubiraiError, 'msg must be Message, MessageChain, or Hash'

    case msg
    when Message
      @messages.append msg
    when MessageChain
      @messages.append(*msg.messages)
    else
      @messages.append Message.build_from(msg, @bot)
    end

    self
  end
end

#has_interpolationBoolean (readonly)

Returns if this message chain has interpolation called by #interpolated_str.

Returns:



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/rubirai/messages/interpolation.rb', line 8

class MessageChain
  attr_reader :has_interpolation

  # Convert the message chain to an interpolated string.
  #
  # @return [String]
  def interpolated_str
    return @interpolated_str if @has_interpolation
    @interpolated_str = _gen_interp_str
    @has_interpolation = true
    @interpolated_str
  end

  # Get the interpolated object by given id
  #
  # @param obj_id [String] the object id
  # @return [Message, nil] the message. `nil` if `obj_id` is malformed or not found.
  def get_object(obj_id)
    _get_object(obj_id)
  end

  # Get a new chain from interpolated string generated from the original message chain.
  # The given interpolated string can be a substring of original one so that elements
  # can be extracted easily.
  #
  # @param str [String] the interpolated string
  # @return [MessageChain] the message chain constructed
  def chain_from_interpolated(str)
    _interpolate_with_objects(str)
  end

  private

  OBJ_INTERP_CHAR = '%'
  OBJ_INTERP_LEN = 6

  def _gen_interp_str
    result = +''
    @messages.each do |msg|
      result << case msg
                when PlainMessage
                  _transform_plain_txt(msg.text)
                else
                  _transform_object(msg)
                end
    end
    result
  end

  def _transform_plain_txt(str)
    str.gsub(OBJ_INTERP_CHAR, OBJ_INTERP_CHAR * 2)
  end

  def _transform_object(obj)
    obj_id = Utils.random_str(OBJ_INTERP_LEN)
    obj_id = Utils.random_str(OBJ_INTERP_LEN) while @ipl_objs_map.include?(obj_id)
    @ipl_objs_map[obj_id] = obj
    "#{OBJ_INTERP_CHAR}#{obj_id}#{OBJ_INTERP_CHAR}"
  end

  def _get_object(obj_id)
    return nil if obj_id.length != OBJ_INTERP_LEN && obj_id.length != (OBJ_INTERP_LEN + 2)
    return @ipl_objs_map[obj_id] if obj_id.length == OBJ_INTERP_LEN
    return nil if obj_id[0] != OBJ_INTERP_CHAR || obj_id[-1] != OBJ_INTERP_CHAR

    @ipl_objs_map[obj_id[1...-1]]
  end

  # @private
  # @param str [String]
  def _interpolate_with_objects(str)
    sb = +''
    result = MessageChain.new(bot)
    i = 0
    while i < str.length
      if i == str.length - 1
        sb << str[i]
        break
      end

      if str[i] != OBJ_INTERP_CHAR
        sb << str[i]
        i += 1
        next
      end

      if str[i + 1] == OBJ_INTERP_CHAR
        sb << OBJ_INTERP_CHAR
        i += 1
      else
        result.append PlainMessage.from(text: sb) unless sb.empty?
        sb = str[i...i + OBJ_INTERP_LEN + 2]
        obj = _get_object(sb)
        i += OBJ_INTERP_LEN + 1
        unless obj.nil?
          result.append obj
          sb = +''
        end
      end

      i += 1
    end

    result.append PlainMessage.from(text: sb) unless sb.nil? || sb.empty?
    result
  end
end

#idInteger? (readonly)

Returns the message id, may be nil.

Returns:

  • (Integer, nil)

    the message id, may be nil



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/rubirai/messages/message_chain.rb', line 19

class MessageChain
  include Enumerable

  attr_reader :bot, :id, :raw, :send_time, :messages

  # Makes a message chain from a list of messages
  #
  # @param messages [Array<Rubirai::Message, Rubirai::MessageChain, Hash, String, Object>] a list of messages
  # @param bot [Rubirai::Bot, nil]
  # @return [Rubirai::MessageChain] the message chain
  def self.make(*messages, bot: nil)
    chain = new(bot)
    result = []
    messages.map { |msg| Message.to_message(msg, bot) }.each do |msg|
      if !result.empty? && result[-1].is_a?(PlainMessage) && msg.is_a?(PlainMessage)
        result[-1] = PlainMessage.from(text: result[-1].text + msg.text, bot: bot)
      else
        result.append msg
      end
    end
    chain.extend(*result)
    chain
  end

  # Append messages to this message chain
  #
  # @param messages [Array<Rubirai::Message, Hash>] a list of messages
  # @return [Rubirai::MessageChain] self
  def extend(*messages)
    messages.each do |msg|
      internal_append msg
    end
    self
  end

  alias << extend
  alias append extend

  # Concats this message chain with another one
  #
  # @param msg_chain [MessageChain] another message chain
  # @return [MessageChain] self
  def concat!(msg_chain)
    msg_chain.messages.each do |msg|
      internal_append msg
    end
    self
  end

  def [](idx)
    @messages[idx]
  end

  def each(&block)
    @messages.each(&block)
  end

  def length
    @messages.length
  end

  def size
    @messages.size
  end

  def empty?
    @messages.empty?
  end

  # Don't use the constructor. Use {.make}.
  #
  # @private
  # @param bot [Rubirai::Bot, nil]
  # @param source [Array, nil]
  def initialize(bot = nil, source = nil)
    @bot = bot
    @messages = []
    @has_interpolation = false
    @interpolated_str = nil
    @ipl_objs_map = {}
    @raw = source
    return unless source
    raise(MiraiError, 'source is not array') unless source.is_a? Array
    raise(MiraiError, 'length is zero') if source.empty?

    if source[0]['type'] == 'Source'
      @id = source[0]['id']
      @send_time = source[0]['time']
      extend(*source.drop(1))
    else
      extend(*source)
    end
  end

  # Convert the message chain to an array of hashes.
  #
  # @return [Array<Hash{String => Object}>]
  def to_a
    @messages.map(&:to_h)
  end

  private

  def internal_append(msg)
    msg.must_be! [Message, MessageChain, Hash], RubiraiError, 'msg must be Message, MessageChain, or Hash'

    case msg
    when Message
      @messages.append msg
    when MessageChain
      @messages.append(*msg.messages)
    else
      @messages.append Message.build_from(msg, @bot)
    end

    self
  end
end

#messagesArray<Message> (readonly)

Returns the raw message array.

Returns:

  • (Array<Message>)

    the raw message array



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/rubirai/messages/message_chain.rb', line 19

class MessageChain
  include Enumerable

  attr_reader :bot, :id, :raw, :send_time, :messages

  # Makes a message chain from a list of messages
  #
  # @param messages [Array<Rubirai::Message, Rubirai::MessageChain, Hash, String, Object>] a list of messages
  # @param bot [Rubirai::Bot, nil]
  # @return [Rubirai::MessageChain] the message chain
  def self.make(*messages, bot: nil)
    chain = new(bot)
    result = []
    messages.map { |msg| Message.to_message(msg, bot) }.each do |msg|
      if !result.empty? && result[-1].is_a?(PlainMessage) && msg.is_a?(PlainMessage)
        result[-1] = PlainMessage.from(text: result[-1].text + msg.text, bot: bot)
      else
        result.append msg
      end
    end
    chain.extend(*result)
    chain
  end

  # Append messages to this message chain
  #
  # @param messages [Array<Rubirai::Message, Hash>] a list of messages
  # @return [Rubirai::MessageChain] self
  def extend(*messages)
    messages.each do |msg|
      internal_append msg
    end
    self
  end

  alias << extend
  alias append extend

  # Concats this message chain with another one
  #
  # @param msg_chain [MessageChain] another message chain
  # @return [MessageChain] self
  def concat!(msg_chain)
    msg_chain.messages.each do |msg|
      internal_append msg
    end
    self
  end

  def [](idx)
    @messages[idx]
  end

  def each(&block)
    @messages.each(&block)
  end

  def length
    @messages.length
  end

  def size
    @messages.size
  end

  def empty?
    @messages.empty?
  end

  # Don't use the constructor. Use {.make}.
  #
  # @private
  # @param bot [Rubirai::Bot, nil]
  # @param source [Array, nil]
  def initialize(bot = nil, source = nil)
    @bot = bot
    @messages = []
    @has_interpolation = false
    @interpolated_str = nil
    @ipl_objs_map = {}
    @raw = source
    return unless source
    raise(MiraiError, 'source is not array') unless source.is_a? Array
    raise(MiraiError, 'length is zero') if source.empty?

    if source[0]['type'] == 'Source'
      @id = source[0]['id']
      @send_time = source[0]['time']
      extend(*source.drop(1))
    else
      extend(*source)
    end
  end

  # Convert the message chain to an array of hashes.
  #
  # @return [Array<Hash{String => Object}>]
  def to_a
    @messages.map(&:to_h)
  end

  private

  def internal_append(msg)
    msg.must_be! [Message, MessageChain, Hash], RubiraiError, 'msg must be Message, MessageChain, or Hash'

    case msg
    when Message
      @messages.append msg
    when MessageChain
      @messages.append(*msg.messages)
    else
      @messages.append Message.build_from(msg, @bot)
    end

    self
  end
end

#rawHash{String => Object}? (readonly)

Returns the raw message chain, may be nil.

Returns:

  • (Hash{String => Object}, nil)

    the raw message chain, may be nil



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/rubirai/messages/message_chain.rb', line 19

class MessageChain
  include Enumerable

  attr_reader :bot, :id, :raw, :send_time, :messages

  # Makes a message chain from a list of messages
  #
  # @param messages [Array<Rubirai::Message, Rubirai::MessageChain, Hash, String, Object>] a list of messages
  # @param bot [Rubirai::Bot, nil]
  # @return [Rubirai::MessageChain] the message chain
  def self.make(*messages, bot: nil)
    chain = new(bot)
    result = []
    messages.map { |msg| Message.to_message(msg, bot) }.each do |msg|
      if !result.empty? && result[-1].is_a?(PlainMessage) && msg.is_a?(PlainMessage)
        result[-1] = PlainMessage.from(text: result[-1].text + msg.text, bot: bot)
      else
        result.append msg
      end
    end
    chain.extend(*result)
    chain
  end

  # Append messages to this message chain
  #
  # @param messages [Array<Rubirai::Message, Hash>] a list of messages
  # @return [Rubirai::MessageChain] self
  def extend(*messages)
    messages.each do |msg|
      internal_append msg
    end
    self
  end

  alias << extend
  alias append extend

  # Concats this message chain with another one
  #
  # @param msg_chain [MessageChain] another message chain
  # @return [MessageChain] self
  def concat!(msg_chain)
    msg_chain.messages.each do |msg|
      internal_append msg
    end
    self
  end

  def [](idx)
    @messages[idx]
  end

  def each(&block)
    @messages.each(&block)
  end

  def length
    @messages.length
  end

  def size
    @messages.size
  end

  def empty?
    @messages.empty?
  end

  # Don't use the constructor. Use {.make}.
  #
  # @private
  # @param bot [Rubirai::Bot, nil]
  # @param source [Array, nil]
  def initialize(bot = nil, source = nil)
    @bot = bot
    @messages = []
    @has_interpolation = false
    @interpolated_str = nil
    @ipl_objs_map = {}
    @raw = source
    return unless source
    raise(MiraiError, 'source is not array') unless source.is_a? Array
    raise(MiraiError, 'length is zero') if source.empty?

    if source[0]['type'] == 'Source'
      @id = source[0]['id']
      @send_time = source[0]['time']
      extend(*source.drop(1))
    else
      extend(*source)
    end
  end

  # Convert the message chain to an array of hashes.
  #
  # @return [Array<Hash{String => Object}>]
  def to_a
    @messages.map(&:to_h)
  end

  private

  def internal_append(msg)
    msg.must_be! [Message, MessageChain, Hash], RubiraiError, 'msg must be Message, MessageChain, or Hash'

    case msg
    when Message
      @messages.append msg
    when MessageChain
      @messages.append(*msg.messages)
    else
      @messages.append Message.build_from(msg, @bot)
    end

    self
  end
end

#send_timeInteger? (readonly)

Returns the send time of the message chain, may be nil.

Returns:

  • (Integer, nil)

    the send time of the message chain, may be nil



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/rubirai/messages/message_chain.rb', line 19

class MessageChain
  include Enumerable

  attr_reader :bot, :id, :raw, :send_time, :messages

  # Makes a message chain from a list of messages
  #
  # @param messages [Array<Rubirai::Message, Rubirai::MessageChain, Hash, String, Object>] a list of messages
  # @param bot [Rubirai::Bot, nil]
  # @return [Rubirai::MessageChain] the message chain
  def self.make(*messages, bot: nil)
    chain = new(bot)
    result = []
    messages.map { |msg| Message.to_message(msg, bot) }.each do |msg|
      if !result.empty? && result[-1].is_a?(PlainMessage) && msg.is_a?(PlainMessage)
        result[-1] = PlainMessage.from(text: result[-1].text + msg.text, bot: bot)
      else
        result.append msg
      end
    end
    chain.extend(*result)
    chain
  end

  # Append messages to this message chain
  #
  # @param messages [Array<Rubirai::Message, Hash>] a list of messages
  # @return [Rubirai::MessageChain] self
  def extend(*messages)
    messages.each do |msg|
      internal_append msg
    end
    self
  end

  alias << extend
  alias append extend

  # Concats this message chain with another one
  #
  # @param msg_chain [MessageChain] another message chain
  # @return [MessageChain] self
  def concat!(msg_chain)
    msg_chain.messages.each do |msg|
      internal_append msg
    end
    self
  end

  def [](idx)
    @messages[idx]
  end

  def each(&block)
    @messages.each(&block)
  end

  def length
    @messages.length
  end

  def size
    @messages.size
  end

  def empty?
    @messages.empty?
  end

  # Don't use the constructor. Use {.make}.
  #
  # @private
  # @param bot [Rubirai::Bot, nil]
  # @param source [Array, nil]
  def initialize(bot = nil, source = nil)
    @bot = bot
    @messages = []
    @has_interpolation = false
    @interpolated_str = nil
    @ipl_objs_map = {}
    @raw = source
    return unless source
    raise(MiraiError, 'source is not array') unless source.is_a? Array
    raise(MiraiError, 'length is zero') if source.empty?

    if source[0]['type'] == 'Source'
      @id = source[0]['id']
      @send_time = source[0]['time']
      extend(*source.drop(1))
    else
      extend(*source)
    end
  end

  # Convert the message chain to an array of hashes.
  #
  # @return [Array<Hash{String => Object}>]
  def to_a
    @messages.map(&:to_h)
  end

  private

  def internal_append(msg)
    msg.must_be! [Message, MessageChain, Hash], RubiraiError, 'msg must be Message, MessageChain, or Hash'

    case msg
    when Message
      @messages.append msg
    when MessageChain
      @messages.append(*msg.messages)
    else
      @messages.append Message.build_from(msg, @bot)
    end

    self
  end
end

Class Method Details

.make(*messages, bot: nil) ⇒ Rubirai::MessageChain

Makes a message chain from a list of messages

Parameters:

Returns:



29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/rubirai/messages/message_chain.rb', line 29

def self.make(*messages, bot: nil)
  chain = new(bot)
  result = []
  messages.map { |msg| Message.to_message(msg, bot) }.each do |msg|
    if !result.empty? && result[-1].is_a?(PlainMessage) && msg.is_a?(PlainMessage)
      result[-1] = PlainMessage.from(text: result[-1].text + msg.text, bot: bot)
    else
      result.append msg
    end
  end
  chain.extend(*result)
  chain
end

Instance Method Details

#[](idx) ⇒ Object



68
69
70
# File 'lib/rubirai/messages/message_chain.rb', line 68

def [](idx)
  @messages[idx]
end

#chain_from_interpolated(str) ⇒ MessageChain

Get a new chain from interpolated string generated from the original message chain. The given interpolated string can be a substring of original one so that elements can be extracted easily.

Parameters:

  • str (String)

    the interpolated string

Returns:



35
36
37
# File 'lib/rubirai/messages/interpolation.rb', line 35

def chain_from_interpolated(str)
  _interpolate_with_objects(str)
end

#concat!(msg_chain) ⇒ MessageChain

Concats this message chain with another one

Parameters:

Returns:



61
62
63
64
65
66
# File 'lib/rubirai/messages/message_chain.rb', line 61

def concat!(msg_chain)
  msg_chain.messages.each do |msg|
    internal_append msg
  end
  self
end

#each(&block) ⇒ Object



72
73
74
# File 'lib/rubirai/messages/message_chain.rb', line 72

def each(&block)
  @messages.each(&block)
end

#empty?Boolean

Returns:

  • (Boolean)


84
85
86
# File 'lib/rubirai/messages/message_chain.rb', line 84

def empty?
  @messages.empty?
end

#extend(*messages) ⇒ Rubirai::MessageChain Also known as: <<, append

Append messages to this message chain

Parameters:

Returns:



47
48
49
50
51
52
# File 'lib/rubirai/messages/message_chain.rb', line 47

def extend(*messages)
  messages.each do |msg|
    internal_append msg
  end
  self
end

#get_object(obj_id) ⇒ Message?

Get the interpolated object by given id

Parameters:

  • obj_id (String)

    the object id

Returns:

  • (Message, nil)

    the message. nil if obj_id is malformed or not found.



25
26
27
# File 'lib/rubirai/messages/interpolation.rb', line 25

def get_object(obj_id)
  _get_object(obj_id)
end

#interpolated_strString

Convert the message chain to an interpolated string.

Returns:

  • (String)


14
15
16
17
18
19
# File 'lib/rubirai/messages/interpolation.rb', line 14

def interpolated_str
  return @interpolated_str if @has_interpolation
  @interpolated_str = _gen_interp_str
  @has_interpolation = true
  @interpolated_str
end

#lengthObject



76
77
78
# File 'lib/rubirai/messages/message_chain.rb', line 76

def length
  @messages.length
end

#sizeObject



80
81
82
# File 'lib/rubirai/messages/message_chain.rb', line 80

def size
  @messages.size
end

#to_aArray<Hash{String => Object}>

Convert the message chain to an array of hashes.

Returns:

  • (Array<Hash{String => Object}>)


116
117
118
# File 'lib/rubirai/messages/message_chain.rb', line 116

def to_a
  @messages.map(&:to_h)
end