rubirai 0.0.2 → 0.0.3.pre.a1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c1e4f114e6246e5449ef45b0ffe65436287a13fb213675a831df0139e710f931
4
- data.tar.gz: f65b3a647129a20ca95ac94536a9ac25c750f26afe0ccf1fbf690da0255b0c81
3
+ metadata.gz: 9af7ce359d2d64f6e7f1228870a74558fc3004b6b5f23257b951c13893ca4599
4
+ data.tar.gz: 421a1ecaa61dd1049501873197b01b22fe78bbdc7ef8c38766f20582ee598125
5
5
  SHA512:
6
- metadata.gz: 98fee9c38a3ff90729799a97bd095dbe78f15fd96113528e151d23ef3ee1b6803c4225fd47104863b89d7a8b49d82c6a79af7720fc6ae2a9cb0dc15b2b24a3e3
7
- data.tar.gz: ecca01ed496c19207979bb056aec2b3dc5f70e775156fb11108025c58adf560cdffec58a5075b53ec546c891bdd609f763e5c7e0f48a9bfb7c68a39f6f764f49
6
+ metadata.gz: ae1ada8f42c7d9c8df3422262782b2c2a5ee16a8611d104ccd53d78c156430d8e88e9d8bff1283b05bca3c7faf530ab8af71e3ea1cdf81dbfab9b296838bbbc5
7
+ data.tar.gz: 9621c881cd3812da59a2c1371c5ed56d87bd8971c6c472c056ce05b1159a37333f1d3701a0b3fe287278fe9e33b5de357baa7f8df4c7bbea554ab93a4c035224
@@ -32,33 +32,3 @@ jobs:
32
32
  CI: "true"
33
33
  CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
34
34
  run: bundle exec rake
35
- publish:
36
- runs-on: ubuntu-latest
37
- steps:
38
- - uses: actions/checkout@v2
39
- - name: Set up Ruby 2.6
40
- uses: actions/setup-ruby@v1
41
- with:
42
- ruby-version: 2.6.x
43
- - name: Publish to GPR
44
- run: |
45
- mkdir -p $HOME/.gem
46
- touch $HOME/.gem/credentials
47
- chmod 0600 $HOME/.gem/credentials
48
- printf -- "---\n:github: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
49
- gem build *.gemspec
50
- gem push --KEY github --host https://rubygems.pkg.github.com/${OWNER} *.gem
51
- env:
52
- GEM_HOST_API_KEY: "Bearer ${{secrets.GITHUB_TOKEN}}"
53
- OWNER: ${{ github.repository_owner }}
54
-
55
- - name: Publish to RubyGems
56
- run: |
57
- mkdir -p $HOME/.gem
58
- touch $HOME/.gem/credentials
59
- chmod 0600 $HOME/.gem/credentials
60
- printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
61
- gem build *.gemspec
62
- gem push *.gem
63
- env:
64
- GEM_HOST_API_KEY: "${{secrets.RUBYGEMS_AUTH_TOKEN}}"
@@ -0,0 +1,39 @@
1
+ name: Package
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v*'
7
+
8
+ jobs:
9
+ publish:
10
+ if: github.event.base_ref == 'refs/heads/master'
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v2
14
+ - name: Set up Ruby 2.6
15
+ uses: actions/setup-ruby@v1
16
+ with:
17
+ ruby-version: 2.6.x
18
+ - name: Publish to GPR
19
+ run: |
20
+ mkdir -p $HOME/.gem
21
+ touch $HOME/.gem/credentials
22
+ chmod 0600 $HOME/.gem/credentials
23
+ printf -- "---\n:github: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
24
+ gem build *.gemspec
25
+ gem push --KEY github --host https://rubygems.pkg.github.com/${OWNER} *.gem
26
+ env:
27
+ GEM_HOST_API_KEY: "Bearer ${{secrets.GITHUB_TOKEN}}"
28
+ OWNER: ${{ github.repository_owner }}
29
+
30
+ - name: Publish to RubyGems
31
+ run: |
32
+ mkdir -p $HOME/.gem
33
+ touch $HOME/.gem/credentials
34
+ chmod 0600 $HOME/.gem/credentials
35
+ printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
36
+ gem build *.gemspec
37
+ gem push *.gem
38
+ env:
39
+ GEM_HOST_API_KEY: "${{secrets.RUBYGEMS_AUTH_TOKEN}}"
data/.rubocop.yml CHANGED
@@ -39,3 +39,6 @@ Metrics/PerceivedComplexity:
39
39
 
40
40
  Naming/AccessorMethodName:
41
41
  Enabled: false
42
+
43
+ Style/AsciiComments:
44
+ Enabled: false
data/README.md CHANGED
@@ -1,15 +1,26 @@
1
1
  # Rubirai
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/rubirai.svg)](https://rubygems.org/gems/rubirai)
2
4
  [![CI](https://github.com/Shimogawa/rubirai/actions/workflows/CI.yml/badge.svg?branch=master)](https://github.com/Shimogawa/rubirai/actions/workflows/CI.yml)
3
5
  [![codecov](https://codecov.io/gh/Shimogawa/rubirai/branch/master/graph/badge.svg?token=OVUVEWFPKY)](https://codecov.io/gh/Shimogawa/rubirai)
4
6
  [![Maintainability](https://api.codeclimate.com/v1/badges/9a9d8c887e5deb601e1e/maintainability)](https://codeclimate.com/github/Shimogawa/rubirai/maintainability)
5
7
  [![Inline docs](http://inch-ci.org/github/shimogawa/rubirai.svg?branch=master)](http://inch-ci.org/github/shimogawa/rubirai)
6
8
  [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2FShimogawa%2Frubirai.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2FShimogawa%2Frubirai?ref=badge_shield)
7
9
 
8
-
9
10
  A light-weight Mirai QQ bot http interface lib for Ruby.
10
11
 
12
+ [中文][wiki] | [Rubydocs][rubydocs]
13
+
11
14
  ## Usage
12
15
 
16
+ First, download the package using `gem`. In your `Gemfile`, add
17
+
18
+ ```ruby
19
+ gem 'rubirai'
20
+ ```
21
+
22
+ Then, start to write code (no matter if it's a rails application or something else):
23
+
13
24
  ```ruby
14
25
  require 'rubirai'
15
26
  # assuming your mirai http api address and port
@@ -17,8 +28,35 @@ require 'rubirai'
17
28
  bot = Rubirai::Bot.new('127.0.0.1', '8080')
18
29
  # qq and auth key
19
30
  bot.login 1145141919, 'ikisugi_key'
31
+
32
+ # Add a listener function
33
+ bot.add_listener do |event|
34
+ puts event.inspect
35
+ if event.is_a?(Rubirai::MessageEvent)
36
+ event.respond("Hello, world!")
37
+ end
38
+ end
39
+
40
+ # Listen to message every 0.5 seconds
41
+ # And blocks the current thread
42
+ bot.start_listen 0.5, is_blocking: true
43
+ ```
44
+
45
+ > If you want to install globally with `gem`, use
46
+
47
+ ```bash
48
+ gem install rubirai
20
49
  ```
21
50
 
51
+ ## Wiki and Documentation
52
+
53
+ - [中文 Wiki][wiki]
54
+ - [Docs][rubydocs]
55
+
22
56
 
23
57
  ## License
24
- [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2FShimogawa%2Frubirai.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2FShimogawa%2Frubirai?ref=badge_large)
58
+ [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2FShimogawa%2Frubirai.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2FShimogawa%2Frubirai?ref=badge_large)
59
+
60
+
61
+ [wiki]: https://github.com/Shimogawa/rubirai/wiki
62
+ [rubydocs]: https://www.rebuild.moe/rubirai/
data/lib/rubirai.rb CHANGED
@@ -17,6 +17,8 @@ module Rubirai
17
17
  # @return [String, Integer] the qq of the bot
18
18
  attr_reader :base_uri, :session, :qq
19
19
 
20
+ alias id qq
21
+
20
22
  # Initializes the bot
21
23
  #
22
24
  # @param host [String] the host (IP or domain)
@@ -19,17 +19,29 @@ module Rubirai
19
19
  # Operations for responding to group join requests.
20
20
  # Only use the values defined in this module to respond to group join requests.
21
21
  module JoinGroupRequestOperation
22
+ # Approve the request
22
23
  APPROVE = 0
24
+
25
+ # Deny the request
23
26
  DENY = 1
27
+
28
+ # Ignore the request
24
29
  IGNORE = 2
30
+
31
+ # Deny and blacklist the sender of the request
25
32
  DENY_AND_BLACKLIST = 3
33
+
34
+ # Ignore and blacklist the sender of the request
26
35
  IGNORE_AND_BLACKLIST = 4
27
36
  end
28
37
 
29
38
  # Operations for responding to group invite requests.
30
39
  # Only use the values defined in this module to respond to group invite requests.
31
40
  module GroupInviteRequestOperation
41
+ # Approve the request
32
42
  APPROVE = 0
43
+
44
+ # Deny the request
33
45
  DENY = 1
34
46
  end
35
47
 
@@ -74,6 +86,14 @@ module Rubirai
74
86
  nil
75
87
  end
76
88
 
89
+ # Respond to group invitations (raw)
90
+ #
91
+ # @param event_id [Integer] the event id
92
+ # @param from_id [Integer] id of the sender
93
+ # @param group_id [Integer] the group id
94
+ # @param operation [Integer] see {GroupInviteRequestOperation}
95
+ # @param message [String] the message to reply
96
+ # @return [void]
77
97
  def respond_to_group_invite(event_id, from_id, group_id, operation, message = '')
78
98
  call :post, '/resp/botInvitedJoinGroupRequestEvent', json: {
79
99
  sessionKey: @session,
@@ -3,7 +3,11 @@
3
3
  require 'rubirai/events/event'
4
4
 
5
5
  module Rubirai
6
+ # Bot event
7
+ # @abstract
6
8
  class BotEvent < Event
9
+ # @!attribute [r] qq
10
+ # @return [Integer] qq id of the event's bot
7
11
  set_event nil, :qq
8
12
  end
9
13
 
@@ -102,6 +102,7 @@ module Rubirai
102
102
  # @return [Hash]
103
103
  attr_reader :bot, :raw
104
104
 
105
+ # @private
105
106
  def initialize(hash, bot = nil)
106
107
  @raw = hash
107
108
  @bot = bot
@@ -8,6 +8,8 @@ module Rubirai
8
8
  class MessageEvent < Event
9
9
  # @!attribute [r] message_chain
10
10
  # @return [MessageChain] the message chain
11
+ # @!attribute [r] sender
12
+ # @return [User] the sender
11
13
  set_event nil, :message_chain, :sender
12
14
  end
13
15
 
@@ -3,6 +3,8 @@
3
3
  require 'rubirai/events/event'
4
4
 
5
5
  module Rubirai
6
+ # Request events
7
+ # @abstract
6
8
  class RequestEvent < Event
7
9
  # @!attribute [r] event_id
8
10
  # @return [Integer] the event id
@@ -17,16 +19,19 @@ module Rubirai
17
19
  set_event nil, :event_id, :from_id, :group_id, :nick, :message
18
20
  end
19
21
 
22
+ # New friend request event
20
23
  class NewFriendRequestEvent < RequestEvent
21
24
  set_event :NewFriendRequestEvent
22
25
  end
23
26
 
27
+ # Join group request event
24
28
  class JoinGroupRequestEvent < RequestEvent
25
29
  # @!attribute [r] group_name
26
30
  # @return [String] the group name
27
31
  set_event :MemberJoinRequestEvent, :group_name
28
32
  end
29
33
 
34
+ # Event that the bot is invited to a group
30
35
  class BotInvitedToGroupEvent < RequestEvent
31
36
  # @!attribute [r] group_name
32
37
  # @return [String] the group name
@@ -3,7 +3,10 @@
3
3
  require 'rubirai/events/event'
4
4
 
5
5
  module Rubirai
6
+ # Error events thrown when errors happened in event listeners
6
7
  class RubiraiErrorEvent < Event
8
+ # @!attribute [r] err
9
+ # @return [RuntimeError] the error
7
10
  attr_reader :err
8
11
 
9
12
  # An error event just for internal use
@@ -5,6 +5,12 @@ require 'rubirai/events/rubirai_events'
5
5
 
6
6
  module Rubirai
7
7
  class Bot
8
+ # Start to listen for events
9
+ #
10
+ # @param interval [Numeric] the interval to fetch events in seconds.
11
+ # @param is_blocking [Boolean] if the listen thread should block the current thread
12
+ # @param ignore_error [Boolean] if errors should generate error events (see {RubiraiErrorEvent})
13
+ # @return [void]
8
14
  def start_listen(interval, is_blocking: false, ignore_error: false)
9
15
  raise RubiraiError, 'listener is already running' if @listener&.running?
10
16
  @listener_stop_event = Concurrent::Event.new if is_blocking
@@ -27,14 +33,24 @@ module Rubirai
27
33
  @listener_stop_event.wait if is_blocking
28
34
  end
29
35
 
36
+ # Add a listener
37
+ #
38
+ # @return [void]
30
39
  def add_listener(&listener_block)
31
40
  @listener_funcs << listener_block
32
41
  end
33
42
 
43
+ # Clear all listeners
44
+ #
45
+ # @return [void]
34
46
  def clear_listener
35
47
  @listener_funcs.clear
36
48
  end
37
49
 
50
+ # Stop listening to events. Will unblock the thread if
51
+ # `is_blocking` is `true` when calling {#start_listen}
52
+ #
53
+ # @return [void]
38
54
  def stop_listen
39
55
  @listener.shutdown
40
56
  @listener_stop_event&.set
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rubirai/objects/info'
3
+ require 'rubirai/objects/group_info'
4
4
 
5
5
  module Rubirai
6
6
  class Bot
@@ -62,7 +62,7 @@ module Rubirai
62
62
  nil
63
63
  end
64
64
 
65
- # Mute all group
65
+ # Mute all in a group
66
66
  #
67
67
  # @param group_id [Integer] group id
68
68
  # @return [void]
@@ -74,6 +74,10 @@ module Rubirai
74
74
  nil
75
75
  end
76
76
 
77
+ # Unmute all in a group
78
+ #
79
+ # @param group_id [Integer] group id
80
+ # @return [void]
77
81
  def unmute_all(group_id)
78
82
  call :post, '/unmuteAll', json: {
79
83
  sessionKey: @session,
@@ -82,6 +86,10 @@ module Rubirai
82
86
  nil
83
87
  end
84
88
 
89
+ # Get group config
90
+ #
91
+ # @param group_id [Integer] group id
92
+ # @return [GroupConfig] the config
85
93
  def get_group_config(group_id)
86
94
  resp = call :get, '/groupConfig', params: {
87
95
  sessionKey: @session,
@@ -93,7 +101,9 @@ module Rubirai
93
101
  # Set group config
94
102
  #
95
103
  # @param group_id [Integer] group id
96
- # @param config [GroupConfig, Hash{String => Object}] the configuration
104
+ # @param config [GroupConfig, Hash{String, Symbol => Object}] the configuration. If given as
105
+ # a hash, then it should be exactly named the same as given in `mirai-api-http`
106
+ # docs.
97
107
  # @return [void]
98
108
  def set_group_config(group_id, config)
99
109
  config.must_be! [GroupConfig, Hash], RubiraiError, 'must be GroupConfig or Hash'
@@ -107,6 +117,11 @@ module Rubirai
107
117
  nil
108
118
  end
109
119
 
120
+ # Get member info
121
+ #
122
+ # @param group_id [Integer] group id
123
+ # @param member_id [Integer] the member's qq id
124
+ # @return [MemberInfo] the member's info
110
125
  def get_member_info(group_id, member_id)
111
126
  resp = call :get, '/memberInfo', params: {
112
127
  sessionKey: @session,
@@ -116,6 +131,14 @@ module Rubirai
116
131
  MemberInfo.new resp, self
117
132
  end
118
133
 
134
+ # Set member info
135
+ #
136
+ # @param group_id [Integer] group id
137
+ # @param member_id [Integer] the member's qq id
138
+ # @param info [MemberInfo, Hash{String,Symbol => Object}] the info to set. If given as
139
+ # a hash, then it should be exactly named the same as given in `mirai-api-http`
140
+ # docs.
141
+ # @return [void]
119
142
  def set_member_info(group_id, member_id, info)
120
143
  info.must_be! [MemberInfo, Hash], RubiraiError, 'must be MemberInfo or Hash'
121
144
  info.stringify_keys! if info.is_a? Hash
@@ -129,6 +152,11 @@ module Rubirai
129
152
  nil
130
153
  end
131
154
 
155
+ # Get the group files as a list
156
+ #
157
+ # @param group_id [Integer] the group id
158
+ # @param dir [String, nil] the directory to get. If `nil`, then the root directory is asserted.
159
+ # @return [Array<GroupFileSimple>] the list of files
132
160
  def get_group_file_list(group_id, dir = nil)
133
161
  resp = call :get, '/groupFileList', params: {
134
162
  sessionKey: @session,
@@ -141,12 +169,18 @@ module Rubirai
141
169
 
142
170
  # Get the info about a group file
143
171
  # @param group_id [Integer] the group id
144
- # @param file_id [String] the file id, e.g. `/xxx-xxx-xxx-xxx`
145
- def get_group_file_info(group_id, file_id)
172
+ # @param file_or_id [GroupFileSimple, String] the file id, e.g. `/xxx-xxx-xxx-xxx`
173
+ #
174
+ # @return [GroupFile] the info about the file
175
+ def get_group_file_info(group_id, file_or_id)
176
+ file_or_id.must_be! [GroupFileSimple, String], RubiraiError, 'must be GroupFileSimple or String'
177
+ raise RubiraiError, "#{file_or_id} is not a file" if file_or_id.is_a?(GroupFileSimple) && !file_or_id.is_file?
178
+ id = file_or_id.is_a? String ? file_or_id : file_or_id.id
179
+
146
180
  resp = call :get, '/groupFileInfo', params: {
147
181
  sessionKey: @session,
148
182
  target: group_id,
149
- id: file_id
183
+ id: id
150
184
  }
151
185
  GroupFile.new resp, self
152
186
  end
@@ -22,6 +22,12 @@ module Rubirai
22
22
  resp['messageId']
23
23
  end
24
24
 
25
+ # Send friend or group message
26
+ #
27
+ # @param type [Symbol, String] options: [group, friend]
28
+ # @param target_id [Integer] target qq/group id
29
+ # @param msgs [Array<Rubirai::Message, Hash, String, Object>] messages to form a chain, can be any type
30
+ # @return [Integer] message id
25
31
  def send_msg(type, target_id, *msgs)
26
32
  self.class.ensure_type_in type, 'group', 'friend'
27
33
  chain = Rubirai::MessageChain.make(*msgs, bot: self)
@@ -33,14 +39,28 @@ module Rubirai
33
39
  resp['messageId']
34
40
  end
35
41
 
42
+ # Send friend message
43
+ #
44
+ # @param target_qq [Integer] target qq id
45
+ # @param msgs [Array<Rubirai::Message, Hash, String, Object>] messages to form a chain, can be any type
46
+ # @return [Integer] message id
36
47
  def send_friend_msg(target_qq, *msgs)
37
48
  send_msg :friend, target_qq, *msgs
38
49
  end
39
50
 
51
+ # Send group message
52
+ #
53
+ # @param target_group_id [Integer] group id
54
+ # @param msgs [Array<Rubirai::Message, Hash, String, Object>] messages to form a chain, can be any type
55
+ # @return [Integer] message id
40
56
  def send_group_msg(target_group_id, *msgs)
41
57
  send_msg :group, target_group_id, *msgs
42
58
  end
43
59
 
60
+ # Recall a message
61
+ #
62
+ # @param msg_id [Integer] message id
63
+ # @return [void]
44
64
  def recall(msg_id)
45
65
  call :post, '/recall', json: {
46
66
  sessionKey: @session,
@@ -70,6 +90,13 @@ module Rubirai
70
90
  call :post, '/sendImageMessage', json: res
71
91
  end
72
92
 
93
+ # Send nudge
94
+ #
95
+ # @param target_id [Integer] target id
96
+ # @param subject_id [Integer] the id of the place where the nudge will be seen.
97
+ # Should be a group id or a friend's id
98
+ # @param kind [String, Symbol] options: `[Group, Friend]`
99
+ # @return [void]
73
100
  def send_nudge(target_id, subject_id, kind)
74
101
  kind.to_s.downcase.must_be_one_of! %w[group friend], RubiraiError, 'kind must be one of group or friend'
75
102
  call :post, '/sendNudge', json: {
@@ -81,4 +108,46 @@ module Rubirai
81
108
  nil
82
109
  end
83
110
  end
111
+
112
+ class MessageEvent
113
+ # Respond to a message event
114
+ #
115
+ # @param msgs [Array<Rubirai::Message, Hash, String, Object>] messages to form a chain
116
+ # @param quote [Boolean] if to quote the original message
117
+ # @return [void]
118
+ def respond(*msgs, quote: false)
119
+ check_bot
120
+ msgs.prepend(gen_quote) if quote
121
+ case self
122
+ when FriendMessageEvent
123
+ @bot.send_friend_msg(@sender.id, *msgs)
124
+ when GroupMessageEvent
125
+ @bot.send_group_msg(@sender.group.id, *msgs)
126
+ when TempMessageEvent
127
+ @bot.send_temp_msg(@sender.id, @sender.group.id, *msgs)
128
+ else
129
+ raise 'undefined error'
130
+ end
131
+ nil
132
+ end
133
+
134
+ # Generates a quote message from this event
135
+ #
136
+ # @return [QuoteMessage] the quote message
137
+ def gen_quote
138
+ QuoteMessage.from(
139
+ id: @message_chain.id,
140
+ group_id: @sender.is_a?(GroupUser) ? @sender.group.id : 0,
141
+ sender_id: @sender.id,
142
+ target_id: @sender.is_a?(GroupUser) ? @sender.group.id : @bot.qq,
143
+ origin: @message_chain
144
+ )
145
+ end
146
+
147
+ private
148
+
149
+ def check_bot
150
+ raise RubiraiError, 'no bot found in event' unless @bot
151
+ end
152
+ end
84
153
  end
@@ -22,6 +22,10 @@ module Rubirai
22
22
  # @option text [String] the plain text
23
23
  # @return [Rubirai::PlainMessage]
24
24
  class Message
25
+ # @!attribute [r] bot
26
+ # @return [Bot] the bot
27
+ # @!attribute [r] type
28
+ # @return [Symbol] the type
25
29
  attr_reader :bot, :type
26
30
 
27
31
  # Objects to {Rubirai::Message}
@@ -58,10 +62,12 @@ module Rubirai
58
62
  raise(RubiraiError, 'type not in all message types') unless Message.all_types.include? type
59
63
  end
60
64
 
65
+ # @private
61
66
  def self.get_msg_klass(type)
62
67
  Object.const_get "Rubirai::#{type}Message"
63
68
  end
64
69
 
70
+ # @private
65
71
  def self.build_from(hash, bot = nil)
66
72
  hash = hash.stringify_keys
67
73
  raise(RubiraiError, 'not a valid message') unless hash.key? 'type'
@@ -72,6 +78,7 @@ module Rubirai
72
78
  klass.new hash, bot
73
79
  end
74
80
 
81
+ # @private
75
82
  def self.set_message(type, *attr_keys, &initialize_block)
76
83
  attr_reader(*attr_keys)
77
84
 
@@ -109,12 +116,16 @@ module Rubirai
109
116
  end
110
117
  end
111
118
 
119
+ # @private
112
120
  def initialize(type, bot = nil)
113
121
  Message.check_type type
114
122
  @bot = bot
115
123
  @type = type
116
124
  end
117
125
 
126
+ # Convert the message to a hash
127
+ #
128
+ # @return [Hash{String => Object}]
118
129
  def to_h
119
130
  res = self.class.keys.to_h do |k|
120
131
  v = instance_variable_get("@#{k}")
@@ -131,6 +142,7 @@ module Rubirai
131
142
  res.compact.stringify_keys
132
143
  end
133
144
 
145
+ # @private
134
146
  def self.metaclass
135
147
  class << self
136
148
  self
@@ -154,15 +166,19 @@ module Rubirai
154
166
  # @return [Integer] the message (chain) id
155
167
  # @!attribute [r] time
156
168
  # @return [Integer] the timestamp
169
+ # @!method from(**kwargs)
170
+ # @option kwargs [Integer] :id the id
171
+ # @option kwargs [Integer] :time the timestamp
172
+ # @!scope class
157
173
  set_message :Source, :id, :time
158
174
  end
159
175
 
160
176
  # The quote message type
161
177
  class QuoteMessage < Message
162
178
  # @!attribute [r] id
163
- # @return [Integer] the original (quoted) message (chain) id
179
+ # @return [Integer] the original (quoted) message chain id
164
180
  # @!attribute [r] group_id
165
- # @return [Integer] the group id
181
+ # @return [Integer] the group id. `0` if from friend.
166
182
  # @!attribute [r] sender_id
167
183
  # @return [Integer] the original sender's id
168
184
  # @!attribute [r] target_id
@@ -171,13 +187,14 @@ module Rubirai
171
187
  # @return [MessageChain] the original message chain
172
188
  set_message :Quote, :id, :group_id, :sender_id, :target_id, :origin
173
189
 
190
+ # @private
174
191
  def initialize(hash, bot = nil)
175
192
  super :Quote, bot
176
193
  @id = hash['id']
177
194
  @group_id = hash['groupId']
178
195
  @sender_id = hash['senderId']
179
196
  @target_id = hash['targetId']
180
- @origin = MessageChain.make(*hash['origin'], sender_id: @sender_id, bot: bot)
197
+ @origin = MessageChain.make(*hash['origin'], bot: bot)
181
198
  end
182
199
  end
183
200
 
@@ -272,7 +289,7 @@ module Rubirai
272
289
  @sender_id = hash['senderId']
273
290
  @time = hash['time']
274
291
  @sender_name = hash['senderName']
275
- @message_chain = MessageChain.make(*hash['messageChain'], sender_id: hash['senderId'], bot: bot)
292
+ @message_chain = MessageChain.make(*hash['messageChain'], bot: bot)
276
293
  end
277
294
  end
278
295
 
@@ -4,19 +4,27 @@ require 'rubirai/utils'
4
4
  require 'rubirai/messages/message'
5
5
 
6
6
  module Rubirai
7
+ # Message chain
7
8
  class MessageChain
8
9
  include Enumerable
9
10
 
10
- attr_reader :bot, :sender_id, :send_time, :messages, :read_only
11
+ # @!attribute [r] bot
12
+ # @return [Bot] the bot object
13
+ # @!attribute [r] id
14
+ # @return [Integer, nil] the message id, may be `nil`
15
+ # @!attribute [r] send_time
16
+ # @return [Integer, nil] the send time of the message chain, may be `nil`
17
+ # @!attribute [r] messages
18
+ # @return [Array<Message>] the raw message array
19
+ attr_reader :bot, :id, :send_time, :messages
11
20
 
12
21
  # Makes a message chain from a list of messages
13
22
  #
14
23
  # @param messages [Array<Rubirai::Message, Rubirai::MessageChain, Hash, String, Object>] a list of messages
15
- # @param sender_id [Integer, nil]
16
24
  # @param bot [Rubirai::Bot, nil]
17
25
  # @return [Rubirai::MessageChain] the message chain
18
- def self.make(*messages, sender_id: nil, bot: nil)
19
- chain = new(bot, sender_id: sender_id)
26
+ def self.make(*messages, bot: nil)
27
+ chain = new(bot)
20
28
  result = []
21
29
  messages.map { |msg| Message.to_message(msg, bot) }.each do |msg|
22
30
  if !result.empty? && result[-1].is_a?(PlainMessage) && msg.is_a?(PlainMessage)
@@ -43,8 +51,12 @@ module Rubirai
43
51
  alias << extend
44
52
  alias append extend
45
53
 
46
- def concat(msg_chain)
47
- msg_chain.to_a.each do |msg|
54
+ # Concats this message chain with another one
55
+ #
56
+ # @param msg_chain [MessageChain] another message chain
57
+ # @return [MessageChain] self
58
+ def concat!(msg_chain)
59
+ msg_chain.messages.each do |msg|
48
60
  internal_append msg
49
61
  end
50
62
  self
@@ -70,19 +82,21 @@ module Rubirai
70
82
  @messages.empty?
71
83
  end
72
84
 
85
+ # Don't use the constructor. Use {.make}.
86
+ #
87
+ # @private
73
88
  # @param bot [Rubirai::Bot, nil]
74
89
  # @param source [Array, nil]
75
- # @param sender_id [Integer, nil]
76
- def initialize(bot = nil, source = nil, sender_id: nil)
90
+ # @param id [Integer, nil]
91
+ def initialize(bot = nil, source = nil)
77
92
  @bot = bot
78
- @sender_id = sender_id
79
93
  @messages = []
80
94
  return unless source
81
95
  raise(MiraiError, 'source is not array') unless source.is_a? Array
82
96
  raise(MiraiError, 'length is zero') if source.empty?
83
97
 
84
98
  if source[0]['type'] == 'Source'
85
- @sender_id = source[0]['id']
99
+ @id = source[0]['id']
86
100
  @send_time = source[0]['time']
87
101
  extend(*source.drop(1))
88
102
  else
@@ -90,6 +104,9 @@ module Rubirai
90
104
  end
91
105
  end
92
106
 
107
+ # Convert the message chain to an array of hashes.
108
+ #
109
+ # @return [Array<Hash{String => Object}>]
93
110
  def to_a
94
111
  @messages.map(&:to_h)
95
112
  end
@@ -113,7 +130,7 @@ module Rubirai
113
130
  end
114
131
 
115
132
  # 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)
133
+ def self.MessageChain(*messages, bot: nil)
134
+ MessageChain.make(*messages, bot: bot)
118
135
  end
119
136
  end
@@ -1,6 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rubirai
4
+ # The group
5
+ #
6
+ # @!attribute [r] bot
7
+ # @return [Bot] the bot
8
+ # @!attribute [r] id
9
+ # @return [Integer] group id
10
+ # @!attribute [r] name
11
+ # @return [String] group name
12
+ # @!attribute [r] permission
13
+ # @return [String] the group permission of the bot. See {Permission}
4
14
  class Group
5
15
  attr_reader :bot, :id, :name, :permission
6
16
 
@@ -14,9 +24,15 @@ module Rubirai
14
24
  @permission = hash['permission']
15
25
  end
16
26
 
27
+ # Group permissions
17
28
  class Permission
29
+ # Owner
18
30
  OWNER = 'OWNER'
31
+
32
+ # Administrator
19
33
  ADMINISTRATOR = 'ADMINISTRATOR'
34
+
35
+ # Member
20
36
  MEMBER = 'MEMBER'
21
37
  end
22
38
  end
@@ -0,0 +1,139 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rubirai/utils'
4
+
5
+ module Rubirai
6
+ # The abstract class for group information
7
+ # @abstract
8
+ class GroupInfo
9
+ # @private
10
+ def self.set_fields(*fields, **default_values)
11
+ attr_reader(*fields)
12
+
13
+ class_eval do
14
+ define_method(:initialize) do |hash, bot = nil|
15
+ # noinspection RubySuperCallWithoutSuperclassInspection
16
+ super hash, bot
17
+ fields.each do |field|
18
+ value = hash[field.to_s.snake_to_camel(lower: true)] || default_values[field]
19
+ instance_variable_set("@#{field}", value)
20
+ end
21
+ end
22
+
23
+ define_method(:to_h) do
24
+ fields.to_h do |field|
25
+ [field.to_s.snake_to_camel(lower: true), instance_variable_get(field)]
26
+ end.compact
27
+ end
28
+ end
29
+ end
30
+
31
+ # @private
32
+ def self.set_modifiable_fields(*fields)
33
+ set_fields(*fields)
34
+ attr_writer(*fields)
35
+ end
36
+
37
+ # @!attribute [r] raw
38
+ # @return [Hash{String => Object}] the raw hash
39
+ # @!attribute [r] bot
40
+ # @return [Bot] the bot
41
+ attr_reader :raw, :bot
42
+
43
+ # @private
44
+ def initialize(hash, bot = nil)
45
+ @raw = hash
46
+ @bot = bot
47
+ end
48
+ end
49
+
50
+ # Group config
51
+ class GroupConfig < GroupInfo
52
+ # @!method initialize(hash, bot = nil)
53
+ # @param hash [Hash{String => Object}]
54
+ # @param bot [Rubirai::Bot, nil]
55
+ # @!method to_h
56
+ # @return [Hash{String => Object}]
57
+ # @!attribute [rw] name
58
+ # @return [String]
59
+ # @!attribute [rw] announcement
60
+ # @return [String]
61
+ # @!attribute [rw] confess_talk
62
+ # @return [Boolean] is confess talk enabled
63
+ # @!attribute [rw] allow_member_invite
64
+ # @return [Boolean]
65
+ # @!attribute [rw] auto_approve
66
+ # @return [Boolean]
67
+ # @!attribute [rw] anonymous_chat
68
+ # @return [Boolean] is anonymous chat enabled
69
+ set_modifiable_fields :name, :announcement, :confess_talk, :allow_member_invite, :auto_approve, :anonymous_chat
70
+ end
71
+
72
+ # Member info
73
+ class MemberInfo < GroupInfo
74
+ # @!method initialize(hash, bot = nil)
75
+ # @param hash [Hash{String => Object}]
76
+ # @param bot [Rubirai::Bot, nil]
77
+ # @!method to_h
78
+ # @return [Hash{String => Object}]
79
+ # @!attribute [rw] name
80
+ # @return [String] member's name in the group
81
+ # @!attribute [r] nick
82
+ # @return [String] member's personal nickname
83
+ # @!attribute [rw] special_title
84
+ # @return [String] member's special title in the group
85
+ set_fields :name, :nick, :special_title
86
+ attr_writer :name, :special_title
87
+ end
88
+
89
+ # Group file with less information
90
+ class GroupFileSimple < GroupInfo
91
+ # @!method initialize(hash, bot = nil)
92
+ # @param hash [Hash{String => Object}]
93
+ # @param bot [Rubirai::Bot, nil]
94
+ # @!method to_h
95
+ # @return [Hash{String => Object}]
96
+ # @!attribute [r] name
97
+ # @return [String]
98
+ # @!attribute [r] id
99
+ # @return [Integer]
100
+ # @!attribute [r] is_file
101
+ # @return [Boolean]
102
+ set_fields :name, :id, :path, :is_file, is_file: true
103
+
104
+ alias is_file? is_file
105
+ end
106
+
107
+ # Group file with detailed information
108
+ class GroupFile < GroupFileSimple
109
+ # @!method initialize(hash, bot = nil)
110
+ # @param hash [Hash{String => Object}]
111
+ # @param bot [Rubirai::Bot, nil]
112
+ # @!method to_h
113
+ # @return [Hash{String => Object}]
114
+ # @!attribute [r] length
115
+ # @return [Integer]
116
+ # @!attribute [r] download_times
117
+ # @return [Integer]
118
+ # @!attribute [r] uploader_id
119
+ # @return [Integer]
120
+ # @!attribute [r] upload_time
121
+ # @return [Integer]
122
+ # @!attribute [r] last_modify_time
123
+ # @return [Integer]
124
+ # @!attribute [r] download_url
125
+ # @return [String]
126
+ # @!attribute [r] sha1
127
+ # @return [String]
128
+ # @!attribute [r] md5
129
+ # @return [String]
130
+ set_fields :length,
131
+ :download_times,
132
+ :uploader_id,
133
+ :upload_time,
134
+ :last_modify_time,
135
+ :download_url,
136
+ :sha1,
137
+ :md5
138
+ end
139
+ end
@@ -2,8 +2,9 @@
2
2
 
3
3
  module Rubirai
4
4
  class Bot
5
- # Get Mirai API plugin information such as
5
+ # Get Mirai API plugin information.
6
6
  #
7
+ # The information is like
7
8
  # ```ruby
8
9
  # {
9
10
  # 'version' => '1.0.0'
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Rubirai
4
4
  # Rubirai version
5
- VERSION = '0.0.2'
5
+ VERSION = '0.0.3-a1'
6
6
 
7
7
  # mirai-api-http version
8
8
  MIRAI_API_VERSION = '1.10.0'
data/misc/common.css CHANGED
@@ -7,5 +7,5 @@ h1, h2, h3, h4, h5, h6, h3.signature .aliases {
7
7
 
8
8
  pre, code, tt, dt code, table tr td dt code, ul.summary, h3.signature .aliases .names,
9
9
  p.signature, h3.signature, .tags ul .name, p.inherited a {
10
- font-family: 'Menlo', 'Roboto Mono', monospace !important;
10
+ font-family: 'Roboto Mono', monospace !important;
11
11
  }
data/rubirai.gemspec CHANGED
@@ -10,7 +10,6 @@ Gem::Specification.new do |s|
10
10
  s.description = 'A Mirai QQ bot http interface lib for Ruby.'
11
11
  s.authors = ['Rebuild']
12
12
  s.email = 'admin@rebuild.moe'
13
- s.licenses = ['AGPLv3']
14
13
  s.files = `git ls-files`.split("\n")
15
14
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
15
  s.require_paths = ['lib']
@@ -20,5 +19,5 @@ Gem::Specification.new do |s|
20
19
  s.add_dependency 'concurrent-ruby', '~> 1.1.8'
21
20
  s.add_dependency 'http', '~> 5.0'
22
21
  s.homepage = 'https://github.com/Shimogawa/rubirai'
23
- s.license = 'AGPLv3'
22
+ s.license = 'AGPL-3.0'
24
23
  end
data/spec/auth_spec.rb CHANGED
@@ -79,23 +79,7 @@ describe 'auth api' do
79
79
 
80
80
  it 'should be able to login and logout' do
81
81
  mirai_bot = Rubirai::Bot.new 'test'
82
- stub_request(:post, @mirai_bot.gen_uri('/auth'))
83
- .with(body: {
84
- "authKey": @auth_key
85
- })
86
- .to_return(status: 200, body: %({
87
- "code": 0,
88
- "session": "#{@session_key}"
89
- }))
90
- stub_request(:post, @mirai_bot.gen_uri('/verify'))
91
- .with(body: {
92
- "sessionKey": @session_key,
93
- "qq": @qq
94
- })
95
- .to_return(status: 200, body: %({
96
- "code": 0,
97
- "session": "success"
98
- }))
82
+ stub_login
99
83
  stub_request(:post, @mirai_bot.gen_uri('/release'))
100
84
  .with(body: {
101
85
  "sessionKey": @session_key,
@@ -73,6 +73,9 @@ describe Rubirai::Event do
73
73
  }
74
74
  e = Rubirai::Event.parse hash
75
75
  expect(e).to be_a(Rubirai::BotGroupPermissionChangedEvent)
76
- expect(e.class.type)
76
+ expect(e.class.type).to eq(:BotGroupPermissionChangeEvent)
77
+ expect(e.origin).to eq(Rubirai::Group::Permission::MEMBER)
78
+ expect(e.new).to eq(Rubirai::Group::Permission::ADMINISTRATOR)
79
+ expect(e.group.id).to eq(123456789)
77
80
  end
78
81
  end
data/spec/message_spec.rb CHANGED
@@ -5,8 +5,83 @@ require 'spec_helper'
5
5
  describe 'message api' do
6
6
  before :all do
7
7
  @mirai_bot = new_bot
8
+ stub_login
9
+ @mirai_bot.login @qq, @auth_key
8
10
  end
9
11
 
10
12
  after do
11
13
  end
14
+
15
+ it 'should be able to send friend message' do
16
+ stub_request(:post, @mirai_bot.gen_uri('/sendFriendMessage'))
17
+ .with(body: {
18
+ "sessionKey": @session_key,
19
+ "target": 987654321,
20
+ "messageChain": [
21
+ { "type": 'Plain', "text": "hello\nworld" },
22
+ { "type": 'Image', "url": 'a' }
23
+ ]
24
+ })
25
+ .to_return(status: 200, body: %({
26
+ "code": 0,
27
+ "msg": "success",
28
+ "messageId": 1234567890
29
+ }))
30
+ res = @mirai_bot.send_friend_msg 987654321, "hello\nworld", Rubirai::ImageMessage(url: 'a')
31
+ expect(res).to eq(1234567890)
32
+ end
33
+
34
+ it 'should be able to send temp message' do
35
+ stub_request(:post, @mirai_bot.gen_uri('/sendTempMessage'))
36
+ .with(body: {
37
+ "sessionKey": @session_key,
38
+ "qq": 123,
39
+ "group": 456,
40
+ "messageChain": [
41
+ { "type": 'Plain', "text": "hello\nworld" },
42
+ { "type": 'Image', "url": 'a' }
43
+ ]
44
+ })
45
+ .to_return(status: 200, body: %({
46
+ "code": 0,
47
+ "msg": "success",
48
+ "messageId": 1234567890
49
+ }))
50
+ res = @mirai_bot.send_temp_msg 123, 456, "hello\nworld", Rubirai::ImageMessage(url: 'a')
51
+ expect(res).to eq(1234567890)
52
+ end
53
+
54
+ it 'should be able to send group message' do
55
+ stub_request(:post, @mirai_bot.gen_uri('/sendGroupMessage'))
56
+ .with(body: {
57
+ "sessionKey": @session_key,
58
+ "target": 456,
59
+ "messageChain": [
60
+ { "type": 'Plain', "text": "hello\nworld" },
61
+ { "type": 'Image', "url": 'a' }
62
+ ]
63
+ })
64
+ .to_return(status: 200, body: %({
65
+ "code": 0,
66
+ "msg": "success",
67
+ "messageId": 1234567890
68
+ }))
69
+ res = @mirai_bot.send_group_msg 456, "hello\nworld", Rubirai::ImageMessage(url: 'a')
70
+ expect(res).to eq(1234567890)
71
+ end
72
+
73
+ it 'should be able to recall a message' do
74
+ stub_request(:post, @mirai_bot.gen_uri('/recall'))
75
+ .with(body: {
76
+ "sessionKey": @session_key,
77
+ "target": 123
78
+ })
79
+ .to_return(status: 200, body: %({
80
+ "code": 0,
81
+ "msg": "success"
82
+ }))
83
+ expect do
84
+ expect(@mirai_bot.recall(123)).to be_nil
85
+ end.not_to raise_error
86
+ end
12
87
  end
@@ -37,7 +37,7 @@ describe Rubirai::Message do
37
37
  qm = Rubirai::QuoteMessage.new hash
38
38
  expect(qm.id).to eq(123456)
39
39
  expect(qm.origin).to be_a(Rubirai::MessageChain)
40
- expect(qm.origin.sender_id).to eq(987654321)
40
+ expect(qm.origin.id).to be_nil
41
41
  expect(qm.origin.messages).to be_a(Array)
42
42
  expect(qm.origin.messages.length).to eq(1)
43
43
  expect(qm.origin.messages[0]).to be_a(Rubirai::Message)
data/spec/spec_helper.rb CHANGED
@@ -29,3 +29,23 @@ RSpec.configure do |config|
29
29
  @qq = 1145141919
30
30
  end
31
31
  end
32
+
33
+ def stub_login
34
+ stub_request(:post, @mirai_bot.gen_uri('/auth'))
35
+ .with(body: {
36
+ "authKey": @auth_key
37
+ })
38
+ .to_return(status: 200, body: %({
39
+ "code": 0,
40
+ "session": "#{@session_key}"
41
+ }))
42
+ stub_request(:post, @mirai_bot.gen_uri('/verify'))
43
+ .with(body: {
44
+ "sessionKey": @session_key,
45
+ "qq": @qq
46
+ })
47
+ .to_return(status: 200, body: %({
48
+ "code": 0,
49
+ "session": "success"
50
+ }))
51
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubirai
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3.pre.a1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rebuild
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-05-28 00:00:00.000000000 Z
11
+ date: 2021-05-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -47,6 +47,7 @@ files:
47
47
  - ".github/dependabot.yml"
48
48
  - ".github/workflows/CI.yml"
49
49
  - ".github/workflows/docs.yml"
50
+ - ".github/workflows/package.yml"
50
51
  - ".github/workflows/pull_request.yml"
51
52
  - ".gitignore"
52
53
  - ".rubocop.yml"
@@ -76,7 +77,7 @@ files:
76
77
  - lib/rubirai/messages/message_chain.rb
77
78
  - lib/rubirai/multipart.rb
78
79
  - lib/rubirai/objects/group.rb
79
- - lib/rubirai/objects/info.rb
80
+ - lib/rubirai/objects/group_info.rb
80
81
  - lib/rubirai/objects/user.rb
81
82
  - lib/rubirai/plugin_info.rb
82
83
  - lib/rubirai/retcode.rb
@@ -97,7 +98,7 @@ files:
97
98
  - spec/utils_spec.rb
98
99
  homepage: https://github.com/Shimogawa/rubirai
99
100
  licenses:
100
- - AGPLv3
101
+ - AGPL-3.0
101
102
  metadata: {}
102
103
  post_install_message:
103
104
  rdoc_options: []
@@ -110,9 +111,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
110
111
  version: '2.6'
111
112
  required_rubygems_version: !ruby/object:Gem::Requirement
112
113
  requirements:
113
- - - ">="
114
+ - - ">"
114
115
  - !ruby/object:Gem::Version
115
- version: '0'
116
+ version: 1.3.1
116
117
  requirements: []
117
118
  rubygems_version: 3.0.3.1
118
119
  signing_key:
@@ -1,71 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'rubirai/utils'
4
-
5
- module Rubirai
6
- # @abstract
7
- class Info
8
- # @!method initialize(hash, bot = nil)
9
- # @param hash [Hash{String => Object}]
10
- # @param bot [Rubirai::Bot, nil]
11
- # @!method to_h
12
- # @return [Hash{String => Object}]
13
- def self.set_fields(*fields, **default_values)
14
- attr_reader(*fields)
15
-
16
- class_eval do
17
- define_method(:initialize) do |hash, bot = nil|
18
- # noinspection RubySuperCallWithoutSuperclassInspection
19
- super hash, bot
20
- fields.each do |field|
21
- value = hash[field.to_s.snake_to_camel(lower: true)] || default_values[field]
22
- instance_variable_set("@#{field}", value)
23
- end
24
- end
25
-
26
- define_method(:to_h) do
27
- fields.to_h do |field|
28
- [field.to_s.snake_to_camel(lower: true), instance_variable_get(field)]
29
- end.compact
30
- end
31
- end
32
- end
33
-
34
- def self.set_modifiable_fields(*fields)
35
- set_fields(*fields)
36
- attr_writer(*fields)
37
- end
38
-
39
- attr_reader :raw, :bot
40
-
41
- def initialize(hash, bot = nil)
42
- @raw = hash
43
- @bot = bot
44
- end
45
- end
46
-
47
- class GroupConfig < Info
48
- set_modifiable_fields :name, :announcement, :confess_talk, :allow_member_invite, :auto_approve, :anonymous_chat
49
- end
50
-
51
- class MemberInfo < Info
52
- set_fields :name, :nick, :special_title
53
- attr_writer :name, :special_title
54
- end
55
-
56
- class GroupFileSimple < Info
57
- set_fields :name, :id, :path, :is_file, is_file: true
58
- end
59
-
60
- class GroupFile < GroupFileSimple
61
- set_fields :length,
62
- :download_times,
63
- :uploader_id,
64
- :upload_time,
65
- :last_modify_time,
66
- :download_url,
67
- :sha1,
68
- :md5,
69
- call_super: true
70
- end
71
- end