discordrb 1.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of discordrb might be problematic. Click here for more details.

@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5d928acdf371b64591d0438c7bcf45ea0f2bbba1
4
+ data.tar.gz: b5e0e4847acb2a5624598f19949c6b36e9da1d89
5
+ SHA512:
6
+ metadata.gz: 81fdfef418a981ed4318b46854b7071565dda588432353bd4b5a4fb0eb1bb01dcda575dfa4b462ee0cc3d74cb9c6454d1e1fc76c90ac39da24fac584c4c01ecd
7
+ data.tar.gz: 071a0ad1b506297193216409f3a2327e5318b4a0228f6dfe7243738b4f5e33ded817a0315760037de28eff5a5964e4b37b27d18400a0a69c5f1428090301d640
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.2
4
+ before_install: gem install bundler -v 1.10.6
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in discordrb.gemspec
4
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 meew0
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,50 @@
1
+ # discordrb
2
+
3
+ An implementation of the [Discord](https://discordapp.com/) API using Ruby.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'discordrb'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install discordrb
20
+
21
+ ## Usage
22
+
23
+ You can make a simple bot like this:
24
+
25
+ require 'discordrb'
26
+
27
+ bot = Discordrb::Bot.new "email@example.com", "hunter2"
28
+
29
+ bot.message(with_text: "Ping!") do |event|
30
+ event.respond "Pong!"
31
+ end
32
+
33
+ bot.run
34
+
35
+ This bot responds to every "Ping!" with a "Pong!".
36
+
37
+ ## Development
38
+
39
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake false` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
40
+
41
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
42
+
43
+ ## Contributing
44
+
45
+ Bug reports and pull requests are welcome on GitHub at https://github.com/meew0/discordrb.
46
+
47
+
48
+ ## License
49
+
50
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "discordrb"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'discordrb/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "discordrb"
8
+ spec.version = Discordrb::VERSION
9
+ spec.authors = ["meew0"]
10
+ spec.email = [""]
11
+
12
+ spec.summary = "Discord API for Ruby"
13
+ spec.description = "A Ruby implementation of the Discord (https://discordapp.com) API."
14
+ spec.homepage = "https://github.com/meew0/discordrb"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_dependency "faye-websocket"
23
+ spec.add_dependency "rest-client"
24
+
25
+ spec.add_development_dependency "bundler", "~> 1.10"
26
+ spec.add_development_dependency "rake", "~> 10.0"
27
+ end
@@ -0,0 +1,11 @@
1
+ # This simple bot responds to every "Ping!" message with a "Pong!"
2
+
3
+ require 'discordrb'
4
+
5
+ bot = Discordrb::Bot.new "email@example.com", "hunter2"
6
+
7
+ bot.message(with_text: "Ping!") do |event|
8
+ event.respond "Pong!"
9
+ end
10
+
11
+ bot.run
@@ -0,0 +1,6 @@
1
+ require "discordrb/version"
2
+ require "discordrb/bot"
3
+
4
+ module Discordrb
5
+ # Your code goes here...
6
+ end
@@ -0,0 +1,211 @@
1
+ require 'rest-client'
2
+ require 'faye/websocket'
3
+ require 'eventmachine'
4
+
5
+ require 'discordrb/endpoints/endpoints'
6
+
7
+ require 'discordrb/events/message'
8
+ require 'discordrb/events/typing'
9
+ require 'discordrb/events/lifetime'
10
+
11
+ require 'discordrb/exceptions'
12
+ require 'discordrb/data'
13
+
14
+ module Discordrb
15
+ class Bot
16
+ include Discordrb::Events
17
+ def initialize(email, password)
18
+ @email = email
19
+ @password = password
20
+
21
+ @token = login
22
+
23
+ @event_handlers = {}
24
+
25
+ @channels = {}
26
+ @users = {}
27
+
28
+ @debug = false
29
+ end
30
+
31
+ def run
32
+ # Handle heartbeats
33
+ @heartbeat_interval = 1
34
+ @heartbeat_active = false
35
+ @heartbeat_thread = Thread.new do
36
+ while true do
37
+ sleep @heartbeat_interval
38
+ send_heartbeat if @heartbeat_active
39
+ end
40
+ end
41
+
42
+ websocket_connect
43
+ end
44
+
45
+ def channel(id)
46
+ debug("Obtaining data for channel with id #{id}")
47
+ return @channels[id] if @channels[id]
48
+
49
+ response = RestClient.get Discordrb::Endpoints::CHANNELS + "/#{id}", {:Authorization => @token}
50
+ channel = Channel.new(JSON.parse(response), self)
51
+ @channels[id] = channel
52
+ end
53
+
54
+ def user(id)
55
+ @users[id]
56
+ end
57
+
58
+ def send_message(channel_id, content)
59
+ debug("Sending message to #{channel_id} with content '#{content}'")
60
+ data = {
61
+ 'content' => content,
62
+ 'mentions' => []
63
+ }
64
+
65
+ RestClient.post Discordrb::Endpoints::CHANNELS + "/#{channel_id}/messages", data.to_json, {:Authorization => @token, :content_type => :json}
66
+ end
67
+
68
+ def debug=(debug)
69
+ @debug = debug
70
+ end
71
+
72
+ def message(attributes = {}, &block)
73
+ @event_handlers[MessageEvent] ||= []
74
+ @event_handlers[MessageEvent] << MessageEventHandler.new(attributes, block)
75
+ end
76
+
77
+ def ready(attributes = {}, &block)
78
+ @event_handlers[ReadyEvent] ||= []
79
+ @event_handlers[ReadyEvent] << ReadyEventHandler.new(attributes, block)
80
+ end
81
+
82
+ def disconnected(attributes = {}, &block)
83
+ @event_handlers[DisconnectEvent] ||= []
84
+ @event_handlers[DisconnectEvent] << DisconnectEventHandler.new(attributes, block)
85
+ end
86
+
87
+ def typing(attributes = {}, &block)
88
+ @event_handlers[TypingEvent] ||= []
89
+ @event_handlers[TypingEvent] << TypingEvent.new(attributes, block)
90
+ end
91
+
92
+ private
93
+
94
+ def debug(message)
95
+ puts "[DEBUG] #{message}" if @debug
96
+ end
97
+
98
+ def login
99
+ debug("Logging in")
100
+ # Login
101
+ login_response = RestClient.post Discordrb::Endpoints::LOGIN, :email => @email, :password => @password
102
+ raise HTTPStatusException.new(login_response.code) if login_response.code >= 400
103
+
104
+ # Parse response
105
+ login_response_object = JSON.parse(login_response)
106
+ raise InvalidAuthenticationException unless login_response_object['token']
107
+
108
+ login_response_object['token']
109
+ end
110
+
111
+ def websocket_connect
112
+ EM.run {
113
+ @ws = Faye::WebSocket::Client.new(Discordrb::Endpoints::WEBSOCKET_HUB)
114
+
115
+ @ws.on :open do |event|; websocket_open(event); end
116
+ @ws.on :message do |event|; websocket_message(event); end
117
+
118
+ @ws.on :close do |event|
119
+ websocket_close(event)
120
+ @ws = nil
121
+ end
122
+ }
123
+ end
124
+
125
+ def websocket_message(event)
126
+ debug("Received packet #{event.data}")
127
+
128
+ # Parse packet
129
+ packet = JSON.parse(event.data)
130
+
131
+ raise "Invalid Packet" unless packet['op'] == 0 # TODO
132
+
133
+ data = packet['d']
134
+ case packet['t']
135
+ when "READY"
136
+ # Activate the heartbeats
137
+ @heartbeat_interval = data['heartbeat_interval'].to_f / 1000.0
138
+ @heartbeat_active = true
139
+ debug("Desired heartbeat_interval: #{@heartbeat_interval}")
140
+
141
+ # Initialize the bot user
142
+ @bot_user = User.new(data['user'], self)
143
+
144
+ # Initialize servers
145
+ @servers = {}
146
+ data['guilds'].each do |element|
147
+ server = Server.new(element, self)
148
+ @servers[server.id] = server
149
+
150
+ # Initialize users
151
+ server.members.each do |element|
152
+ @users[element.id] = element
153
+ end
154
+ end
155
+
156
+ # Make sure to raise the event
157
+ raise_event(ReadyEvent.new)
158
+ when "MESSAGE_CREATE"
159
+ message = Message.new(data, self)
160
+ event = MessageEvent.new(message)
161
+ raise_event(event)
162
+ when "TYPING_START"
163
+ event = TypingEvent.new(data, self)
164
+ raise_event(event)
165
+ end
166
+ end
167
+
168
+ def websocket_close(event)
169
+ raise_event(DisconnectEvent.new)
170
+ end
171
+
172
+ def websocket_open(event)
173
+ # Send the initial packet
174
+ packet = {
175
+ "op" => 2, # Packet identifier
176
+ "d" => { # Packet data
177
+ "v" => 2, # Another identifier
178
+ "token" => @token,
179
+ "properties" => { # I'm unsure what these values are for exactly, but they don't appear to impact bot functionality in any way.
180
+ "$os" => "Linux",
181
+ "$browser" => "Chrome",
182
+ "$device" => "discordrb",
183
+ "$referrer" => "",
184
+ "$referring_domain" => ""
185
+ }
186
+ }
187
+ }
188
+
189
+ @ws.send(packet.to_json)
190
+ end
191
+
192
+ def raise_event(event)
193
+ debug("Raised a #{event.class}")
194
+ handlers = @event_handlers[event.class]
195
+ (handlers || []).each do |handler|
196
+ handler.match(event)
197
+ end
198
+ end
199
+
200
+ def send_heartbeat
201
+ millis = Time.now.strftime("%s%L").to_i
202
+ debug("Sending heartbeat at #{millis}")
203
+ data = {
204
+ 'op' => 1,
205
+ 'd' => millis
206
+ }
207
+
208
+ @ws.send(data.to_json)
209
+ end
210
+ end
211
+ end
@@ -0,0 +1,80 @@
1
+ # These classes hold relevant Discord data, such as messages or channels.
2
+
3
+ module Discordrb
4
+ class User
5
+ attr_reader :username, :id, :discriminator, :avatar
6
+ alias_method :name, :username
7
+
8
+ def initialize(data, bot)
9
+ @bot = bot
10
+ @username = data['username']
11
+ @id = data['id'].to_i
12
+ @discriminator = data['discriminator']
13
+ @avatar = data['avatar']
14
+ end
15
+
16
+ # Utility function to mention users in messages
17
+ def mention
18
+ "<@#{@id}>"
19
+ end
20
+ end
21
+
22
+ class Channel
23
+ attr_reader :name, :server_id, :type, :id, :is_private
24
+
25
+ def initialize(data, bot)
26
+ @bot = bot
27
+ @name = data['name']
28
+ @server_id = data['guild_id']
29
+ @type = data['type']
30
+ @id = data['id']
31
+ @is_private = data['is_private']
32
+ end
33
+
34
+ def send_message(content)
35
+ @bot.send_message(@id, content)
36
+ end
37
+
38
+ alias_method :send, :send_message
39
+ alias_method :message, :send_message
40
+ end
41
+
42
+ class Message
43
+ attr_reader :content, :author, :channel, :timestamp, :id, :mentions
44
+ alias_method :user, :author
45
+ alias_method :text, :content
46
+
47
+ def initialize(data, bot)
48
+ @bot = bot
49
+ @content = data['content']
50
+ @author = User.new(data['author'], bot)
51
+ @channel = bot.channel(data['channel_id'].to_i)
52
+ @timestamp = Time.at(data['timestamp'].to_i)
53
+ @id = data['id'].to_i
54
+
55
+ @mentions = []
56
+
57
+ data['mentions'].each do |element|
58
+ @mentions << User.new(element, bot)
59
+ end
60
+ end
61
+ end
62
+
63
+ class Server
64
+ attr_reader :region, :name, :owner_id, :id, :members
65
+
66
+ def initialize(data, bot)
67
+ @bot = bot
68
+ @region = data['region']
69
+ @name = data['name']
70
+ @owner_id = data['owner_id'].to_i
71
+ @id = data['id'].to_i
72
+
73
+ @members = []
74
+
75
+ data['members'].each do |element|
76
+ @members << User.new(element, bot)
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,13 @@
1
+ module Discordrb::Endpoints
2
+ BASE = "https://discordapp.com/"
3
+ APIBASE = BASE + "api"
4
+
5
+ WEBSOCKET_HUB = "wss://discordapp.com/hub"
6
+
7
+ LOGIN = APIBASE + "/auth/login"
8
+ LOGOUT = APIBASE + "/auth/logout"
9
+
10
+ SERVERS = APIBASE + "/guilds"
11
+
12
+ CHANNELS = APIBASE + "/channels"
13
+ end
@@ -0,0 +1,57 @@
1
+ module Discordrb::Events
2
+ class Negated
3
+ attr_reader :object
4
+ def initialize(object); @object = object; end
5
+ end
6
+
7
+ def self.matches_all(attributes, to_check, &block)
8
+ # "Zeroth" case: attributes is nil
9
+ return true unless attributes
10
+
11
+ # First case: there's a single negated attribute
12
+ if attributes.is_a? Negated
13
+ # The contained object might also be an array, so recursively call matches_all (and negate the result)
14
+ return !matches_all(attributes.object, to_check, &block)
15
+ end
16
+
17
+ # Second case: there's a single, not-negated attribute
18
+ unless attributes.is_a? Array
19
+ return yield(attributes, to_check)
20
+ end
21
+
22
+ # Third case: it's an array of attributes
23
+ attributes.reduce(false) do |result, element|
24
+ result || yield(element, to_check)
25
+ end
26
+ end
27
+
28
+ class EventHandler
29
+ def initialize(attributes, block)
30
+ @attributes = attributes
31
+ @block = block
32
+ end
33
+
34
+ def matches?(event)
35
+ raise "Attempted to call matches?() from a generic EventHandler"
36
+ end
37
+
38
+ def match(event)
39
+ @block.call(event) if matches? event
40
+ end
41
+
42
+ def matches_all(attributes, to_check, &block)
43
+ Discordrb::Events.matches_all(attributes, to_check, &block)
44
+ end
45
+ end
46
+
47
+ # Event handler that matches all events
48
+ class TrueEventHandler < EventHandler
49
+ def matches?(event)
50
+ true
51
+ end
52
+ end
53
+ end
54
+
55
+ def not!(object)
56
+ Discordrb::Events::Negated.new(object)
57
+ end
@@ -0,0 +1,9 @@
1
+ require 'discordrb/events/generic'
2
+
3
+ module Discordrb::Events
4
+ class ReadyEvent; end
5
+ class ReadyEventHandler < TrueEventHandler; end
6
+
7
+ class DisconnectEvent; end
8
+ class DisconnectEventHandler < TrueEventHandler; end
9
+ end
@@ -0,0 +1,57 @@
1
+ require 'discordrb/events/generic'
2
+
3
+ module Discordrb::Events
4
+ class MessageEvent
5
+ attr_reader :message
6
+
7
+ def initialize(message)
8
+ @message = message
9
+ end
10
+
11
+ def author; @message.author; end
12
+ alias_method :user, :author
13
+ def channel; @message.channel; end
14
+ def content; @message.content; end
15
+ alias_method :text, :content
16
+ def timestamp; @message.timestamp; end
17
+
18
+ def send_message(content); @message.send_message(content); end
19
+ alias_method :send, :send_message
20
+ alias_method :message, :send_message
21
+ alias_method :respond, :send_message
22
+ end
23
+
24
+ class MessageEventHandler < EventHandler
25
+ def matches?(event)
26
+ # Check for the proper event type
27
+ return false unless event.is_a? MessageEvent
28
+
29
+ return [
30
+ matches_all(@attributes[:starting_with], event.content) { |a,e| e.start_with? a },
31
+ matches_all(@attributes[:ending_with], event.content) { |a,e| e.end_with? a },
32
+ matches_all(@attributes[:containing], event.content) { |a,e| e.include? a },
33
+ matches_all(@attributes[:in], event.channel) do |a,e|
34
+ if a.is_a? String
35
+ a == e.name
36
+ elsif a.is_a? Fixnum
37
+ a == e.id
38
+ else
39
+ a == e
40
+ end
41
+ end,
42
+ matches_all(@attributes[:from], event.author) do |a,e|
43
+ if a.is_a? String
44
+ a == e.name
45
+ elsif a.is_a? Fixnum
46
+ a == e.id
47
+ else
48
+ a == e
49
+ end
50
+ end,
51
+ matches_all(@attributes[:with_text], event.content) { |a,e| e == a },
52
+ matches_all(@attributes[:after], event.timestamp) { |a,e| a > e },
53
+ matches_all(@attributes[:before], event.timestamp) { |a,e| a < e }
54
+ ].reduce(true, &:&)
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,45 @@
1
+ require 'discordrb/events/generic'
2
+
3
+ module Discordrb::Events
4
+ class TypingEvent
5
+ attr_reader :channel, :user, :timestamp
6
+
7
+ def initialize(data, bot)
8
+ @user_id = data['user_id']
9
+ @user = bot.user(@user_id)
10
+ @channel_id = data['channel_id']
11
+ @channel = bot.channel(@channel_id)
12
+ @timestamp = Time.at(data['timestamp'].to_i)
13
+ end
14
+ end
15
+
16
+ class TypingEventHandler < EventHandler
17
+ def matches?(event)
18
+ # Check for the proper event type
19
+ return false unless event.is_a? TypingEvent
20
+
21
+ return [
22
+ matches_all(@attributes[:in], event.channel) do |a,e|
23
+ if a.is_a? String
24
+ a == e.name
25
+ elsif a.is_a? Fixnum
26
+ a == e.id
27
+ else
28
+ a == e
29
+ end
30
+ end,
31
+ matches_all(@attributes[:from], event.user) do |a,e|
32
+ if a.is_a? String
33
+ a == e.name
34
+ elsif a.is_a? Fixnum
35
+ a == e.id
36
+ else
37
+ a == e
38
+ end
39
+ end,
40
+ matches_all(@attributes[:after], event.timestamp) { |a,e| a > e },
41
+ matches_all(@attributes[:before], event.timestamp) { |a,e| a < e }
42
+ ].reduce(true, &:&)
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,10 @@
1
+ module Discordrb
2
+ # Raised when authentication data is invalid or incorrect.
3
+ class InvalidAuthenticationException < RuntimeError; end
4
+
5
+ # Raised when a HTTP status code indicates a failure
6
+ class HTTPStatusException < RuntimeError
7
+ attr :status
8
+ def initialize(status); @status = status; end
9
+ end
10
+ end
@@ -0,0 +1,3 @@
1
+ module Discordrb
2
+ VERSION = "1.0.0"
3
+ end
metadata ADDED
@@ -0,0 +1,120 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: discordrb
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - meew0
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2015-08-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: faye-websocket
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rest-client
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: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.10'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.10'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '10.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10.0'
69
+ description: A Ruby implementation of the Discord (https://discordapp.com) API.
70
+ email:
71
+ - ''
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - ".travis.yml"
78
+ - Gemfile
79
+ - LICENSE.txt
80
+ - README.md
81
+ - Rakefile
82
+ - bin/console
83
+ - bin/setup
84
+ - discordrb.gemspec
85
+ - examples/ping.rb
86
+ - lib/discordrb.rb
87
+ - lib/discordrb/bot.rb
88
+ - lib/discordrb/data.rb
89
+ - lib/discordrb/endpoints/endpoints.rb
90
+ - lib/discordrb/events/generic.rb
91
+ - lib/discordrb/events/lifetime.rb
92
+ - lib/discordrb/events/message.rb
93
+ - lib/discordrb/events/typing.rb
94
+ - lib/discordrb/exceptions.rb
95
+ - lib/discordrb/version.rb
96
+ homepage: https://github.com/meew0/discordrb
97
+ licenses:
98
+ - MIT
99
+ metadata: {}
100
+ post_install_message:
101
+ rdoc_options: []
102
+ require_paths:
103
+ - lib
104
+ required_ruby_version: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ required_rubygems_version: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ requirements: []
115
+ rubyforge_project:
116
+ rubygems_version: 2.4.5
117
+ signing_key:
118
+ specification_version: 4
119
+ summary: Discord API for Ruby
120
+ test_files: []