kybus-bot 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 189f024f3c6411b1c2c7d918a7ccfca6afd2cffe096c53f76522932c74be1b17
4
+ data.tar.gz: 9f9b3928b68ea6b1fc1e6ae204d5e0a34223c3e909b2986bae0c477b848d73ca
5
+ SHA512:
6
+ metadata.gz: 234bf15cd1c11549de4b8d3513a7abc50f76ffaae56aeb2248a112007b540fccf0e6a42f195c67b7a2a5032d13930e20f2384fb117ab86194d564c30ebb1d423
7
+ data.tar.gz: f3c6e1743cea030340a677d6b7674932ded040e2ac4febfcc24eacfb76e7f36d39bbec85a908c52fe7e06bf782364a11abebc4f941b1d314b60e48fed7ed7766
data/lib/kybus/bot.rb ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'kybus/core'
4
+ require 'kybus/storage'
5
+
6
+ require_relative 'bot/base'
7
+ require_relative 'bot/message'
8
+ require_relative 'bot/version'
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kybus
4
+ module Bot
5
+ # Implements a factory singleton for building bot adapters
6
+ module Adapter
7
+ extend Kybus::DRY::ResourceInjector
8
+
9
+ # builds the abstract adapter
10
+ def self.from_config(configs)
11
+ require_relative configs['name']
12
+ resource(configs['name']).new(configs)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kybus
4
+ module Bot
5
+ # :nodoc: #
6
+ module Adapter
7
+ # :nodoc: #
8
+ # Wraps a debugging message inside a class.
9
+ class DebugMessage < Kybus::Bot::Message
10
+ # It receives a string with the raw text and the id of the channel
11
+ def initialize(text, channel)
12
+ @text = text
13
+ @channel = channel
14
+ end
15
+
16
+ # Returns the channel id
17
+ def channel_id
18
+ "debug_message__#{@channel}"
19
+ end
20
+
21
+ # Returns the message contents
22
+ def raw_message
23
+ @text
24
+ end
25
+ end
26
+
27
+ # This class simulates a message chat with a user.
28
+ class Channel
29
+ # It is build from
30
+ # an array of raw messages, the name of the channel and the config
31
+ # to enable debug messages
32
+ def initialize(messages, name, echo)
33
+ @state = :open
34
+ @pending_messages = messages.dup
35
+ @name = name
36
+ @echo = echo
37
+ end
38
+
39
+ # Checks if there are messages open or that has not been answered
40
+ def open?
41
+ @state == :open
42
+ end
43
+
44
+ # Checks if there are still messages in the channel
45
+ def empty?
46
+ @pending_messages.empty?
47
+ end
48
+
49
+ # returns the next message in the buffer
50
+ def read_message
51
+ @state = :closed
52
+ DebugMessage.new(@pending_messages.shift, @name)
53
+ end
54
+
55
+ def send_data(message)
56
+ return unless @echo
57
+
58
+ puts "Sending message to channel: #{@name}"
59
+ puts message
60
+ end
61
+
62
+ attr_writer :echo
63
+
64
+ # receives the answer from the bot
65
+ def answer(message)
66
+ send_data(message)
67
+ @state = :open
68
+ end
69
+ end
70
+
71
+ ##
72
+ # This adapter is intended to be used on unit tests and development.
73
+ class Debug
74
+ # Exception for stoping the loop of messages
75
+ class NoMoreMessageException < Kybus::Exceptions::AntError
76
+ def initialize
77
+ super('There are no messages left')
78
+ end
79
+ end
80
+
81
+ # It receives a hash with the configurations:
82
+ # - name: the name of the channel
83
+ # - channels a key value, where the key is a name and the value the
84
+ # list of the messages in the channel.
85
+ # - echo: a flag to enable debug messages.
86
+ def initialize(configs)
87
+ @channels = {}
88
+ configs['channels'].each do |name, messages|
89
+ @channels[name] = Channel.new(messages, name, configs['echo'])
90
+ end
91
+ end
92
+
93
+ # Interface for receiving message
94
+ def read_message
95
+ # take the first message from the first open message,
96
+ # then rotate the array
97
+ loop do
98
+ raise NoMoreMessageException if @channels.values.all?(&:empty?)
99
+
100
+ msg = @channels.values.find(&:open?)
101
+ return msg.read_message if msg
102
+
103
+ # :nocov: #
104
+ sleep(1)
105
+ # :nocov: #
106
+ end
107
+ end
108
+
109
+ # removes prefix from channel id
110
+ def channel(name)
111
+ @channels[name.gsub('debug_message__', '')]
112
+ end
113
+
114
+ # interface for sending messages
115
+ def send_message(channel_name, contents)
116
+ channel(channel_name).answer(contents)
117
+ end
118
+
119
+ # interface for sending video
120
+ def send_video(channel_name, video_url)
121
+ channel(channel_name).answer("VIDEO: #{video_url}")
122
+ end
123
+
124
+ # interface for sending uadio
125
+ def send_audio(channel_name, audio_url)
126
+ channel(channel_name).answer("AUDIO: #{audio_url}")
127
+ end
128
+
129
+ # interface for sending image
130
+ def send_image(channel_name, image_url)
131
+ channel(channel_name).answer("IMG: #{image_url}")
132
+ end
133
+
134
+ # changes echo config
135
+ def echo=(toogle)
136
+ @channels.each { |_, channel| channel.echo = toogle }
137
+ end
138
+ end
139
+
140
+ register('debug', Debug)
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,115 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'discordrb'
4
+
5
+ module Kybus
6
+ module Bot
7
+ # :nodoc: #
8
+ module Adapter
9
+ # :nodoc: #
10
+ # Wraps a debugging message inside a class.
11
+ class DiscordMessage < Kybus::Bot::Message
12
+ # It receives a string with the raw text and the id of the channel
13
+ def initialize(msg)
14
+ @message = msg
15
+ end
16
+
17
+ # Returns the channel id
18
+ def channel_id
19
+ @message.channel.id
20
+ end
21
+
22
+ # Returns the message contents
23
+ def raw_message
24
+ @message.content
25
+ end
26
+
27
+ def user
28
+ @message.author.id
29
+ end
30
+
31
+ def is_private?
32
+ @message.channel.private?
33
+ end
34
+
35
+ def reply?
36
+ @message.message.reply?
37
+ end
38
+
39
+ def replied_message
40
+ DiscordMessage.new(@message.message.referenced_message)
41
+ end
42
+ end
43
+
44
+ ##
45
+ # This adapter is intended to be used on unit tests and development.
46
+ class Discord
47
+ include ::Kybus::Logger
48
+ # It receives a hash with the configurations:
49
+ # - name: the name of the channel
50
+ # - channels a key value, where the key is a name and the value the
51
+ # list of the messages in the channel.
52
+ # - echo: a flag to enable debug messages.
53
+ def initialize(configs)
54
+ @config = configs
55
+ @client = Discordrb::Bot.new(token: @config['token'])
56
+ @pool = []
57
+ @client.message do |msg|
58
+ @pool << msg
59
+ end
60
+ @client.run(:async)
61
+ end
62
+
63
+ attr_reader :client
64
+
65
+ def mention(id)
66
+ "<@!#{id}>"
67
+ end
68
+
69
+ # Interface for receiving message
70
+ def read_message
71
+ # take the first message from the first open message,
72
+ loop do
73
+ if @pool.empty?
74
+ sleep(0.1)
75
+ else
76
+ break
77
+ end
78
+ end
79
+ DiscordMessage.new(@pool.shift)
80
+ end
81
+
82
+ # interface for sending messages
83
+ def send_message(channel_name, contents)
84
+ puts "#{channel_name} => #{contents}" if @config['debug']
85
+ channel = @client.channel(channel_name)
86
+ if channel
87
+ channel.send_message(contents)
88
+ else
89
+ @client.user(channel_name).pm(contents)
90
+ end
91
+ end
92
+
93
+ # # interface for sending video
94
+ # def send_video(channel_name, video_url)
95
+ # file = Faraday::UploadIO.new(video_url, 'video/mp4')
96
+ # @client.api.send_video(chat_id: channel_name, audio: file)
97
+ # end
98
+ #
99
+ # # interface for sending uadio
100
+ # def send_audio(channel_name, audio_url)
101
+ # file = Faraday::UploadIO.new(audio_url, 'audio/mp3')
102
+ # @client.api.send_audio(chat_id: channel_name, audio: file)
103
+ # end
104
+ #
105
+ # # interface for sending image
106
+ # def send_image(channel_name, image_url)
107
+ # file = Faraday::UploadIO.new(image_url, 'image/jpeg')
108
+ # @client.api.send_photo(chat_id: channel_name, photo: file)
109
+ # end
110
+ end
111
+
112
+ register('discord', Discord)
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'telegram/bot'
4
+
5
+ module Kybus
6
+ module Bot
7
+ # :nodoc: #
8
+ module Adapter
9
+ # :nodoc: #
10
+ # Wraps a debugging message inside a class.
11
+ class TelegramMessage < Kybus::Bot::Message
12
+ # It receives a string with the raw text and the id of the channel
13
+ def initialize(message)
14
+ @message = message
15
+ end
16
+
17
+ def reply?
18
+ !!@message.reply_to_message
19
+ end
20
+
21
+ def replied_message
22
+ TelegramMessage.new(@message.reply_to_message)
23
+ end
24
+
25
+ # Returns the channel id
26
+ def channel_id
27
+ @message.chat.id
28
+ end
29
+
30
+ # Returns the message contents
31
+ def raw_message
32
+ @message.to_s
33
+ end
34
+
35
+ def is_private?
36
+ @message.chat.type == 'private'
37
+ end
38
+
39
+ def user
40
+ @message.from.id
41
+ end
42
+ end
43
+
44
+ ##
45
+ # This adapter is intended to be used on unit tests and development.
46
+ class Telegram
47
+ include ::Kybus::Logger
48
+ # It receives a hash with the configurations:
49
+ # - name: the name of the channel
50
+ # - channels a key value, where the key is a name and the value the
51
+ # list of the messages in the channel.
52
+ # - echo: a flag to enable debug messages.
53
+ def initialize(configs)
54
+ @config = configs
55
+ @client = ::Telegram::Bot::Client.new(@config['token'])
56
+ end
57
+
58
+ # Interface for receiving message
59
+ def read_message
60
+ # take the first message from the first open message,
61
+ loop do
62
+ @client.listen do |message|
63
+ log_info('Received message', message: message.to_h,
64
+ from: message.from.to_h)
65
+ return TelegramMessage.new(message)
66
+ end
67
+ rescue Telegram::Bot::Exceptions::ResponseError => e
68
+ log_error('An error ocurred while calling to Telegram API', e)
69
+ end
70
+ end
71
+
72
+ def mention(id)
73
+ "[user](tg://user?id=#{id})"
74
+ end
75
+
76
+
77
+ # interface for sending messages
78
+ def send_message(channel_name, contents)
79
+ puts "#{channel_name} => #{contents}" if @config['debug']
80
+ @client.api.send_message(chat_id: channel_name, text: contents)
81
+ rescue Telegram::Bot::Exceptions::ResponseError => err
82
+ return if err[:error_code] == '403'
83
+ end
84
+
85
+ # interface for sending video
86
+ def send_video(channel_name, video_url)
87
+ file = Faraday::UploadIO.new(video_url, 'video/mp4')
88
+ @client.api.send_video(chat_id: channel_name, audio: file)
89
+ end
90
+
91
+ # interface for sending uadio
92
+ def send_audio(channel_name, audio_url)
93
+ file = Faraday::UploadIO.new(audio_url, 'audio/mp3')
94
+ @client.api.send_audio(chat_id: channel_name, audio: file)
95
+ end
96
+
97
+ # interface for sending image
98
+ def send_image(channel_name, image_url)
99
+ file = Faraday::UploadIO.new(image_url, 'image/jpeg')
100
+ @client.api.send_photo(chat_id: channel_name, photo: file)
101
+ end
102
+ end
103
+
104
+ register('telegram', Telegram)
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,220 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'kybus/dry/daemon'
4
+ require 'kybus/bot/adapters/base'
5
+ require 'kybus/storage'
6
+ require_relative 'command_definition'
7
+
8
+ require 'kybus/logger'
9
+
10
+ module Kybus
11
+ module Bot
12
+ # Base class for bot implementation. It wraps the threads execution, the
13
+ # provider and the state storage inside an object.
14
+ class Base
15
+ include Kybus::Storage::Datasource
16
+ include Kybus::Logger
17
+ attr_reader :provider
18
+
19
+ def send_message(content, channel = nil)
20
+ @provider.send_message(channel || current_channel, content)
21
+ end
22
+
23
+ def rescue_from(klass, &block)
24
+ @commands.register_command(klass, [], block)
25
+ end
26
+
27
+ def send_image(content, channel = nil)
28
+ @provider.send_image(channel || current_channel, content)
29
+ end
30
+
31
+ def send_audio(content, channel = nil)
32
+ @provider.send_audio(channel || current_channel, content)
33
+ end
34
+
35
+ # Configurations needed:
36
+ # - pool_size: number of threads created in execution
37
+ # - provider: a configuration for a thread provider.
38
+ # See supported adapters
39
+ # - name: The bot name
40
+ # - repository: Configurations about the state storage
41
+ def initialize(configs)
42
+ @pool_size = configs['pool_size']
43
+ @provider = Kybus::Bot::Adapter.from_config(configs['provider'])
44
+ @commands = Kybus::Bot::CommandDefinition.new
45
+
46
+ # TODO: move this to config
47
+ @repository = Kybus::Storage::Repository.from_config(
48
+ nil,
49
+ configs['state_repository']
50
+ .merge('primary_key' => 'channel_id',
51
+ 'table' => 'bot_sessions'),
52
+ {}
53
+ )
54
+ @factory = Kybus::Storage::Factory.new(EmptyModel)
55
+ @factory.register(:default, :json)
56
+ @factory.register(:json, @repository)
57
+ end
58
+
59
+ # Starts the bot execution, this is a blocking call.
60
+ def run
61
+ @pool = Array.new(@pool_size) do
62
+ # TODO: Create a subclass with the context execution
63
+ Kybus::DRY::Daemon.new(@pool_size, true) do
64
+ message = @provider.read_message
65
+ @last_message = message
66
+ process_message(message)
67
+ end
68
+ end
69
+ # TODO: Implement an interface for killing the process
70
+ @pool.each(&:run)
71
+ # :nocov: #
72
+ @pool.each(&:await)
73
+ # :nocov: #
74
+ end
75
+
76
+ # Process a single message, this method can be overwriten to enable
77
+ # more complex implementations of commands. It receives a message object.
78
+ def process_message(message)
79
+ run_simple_command!(message)
80
+ end
81
+
82
+ # Executes a command with the easiest definition. It runs a state machine:
83
+ # - If the message is a command, set the status to asking params
84
+ # - If the message is a param, stores it
85
+ # - If the command is ready to be executed, trigger it.
86
+ def run_simple_command!(message)
87
+ load_state!(message.channel_id)
88
+ log_debug('loaded state', message: message.to_h, state: @state.to_h)
89
+ if message.command?
90
+ self.command = message.raw_message
91
+ else
92
+ add_param(message.raw_message)
93
+ end
94
+ if command_ready?
95
+ run_command!
96
+ else
97
+ ask_param(next_missing_param)
98
+ end
99
+ save_state!
100
+ rescue StandardError => e
101
+ catch = @commands[e.class]
102
+ raise if catch.nil?
103
+
104
+ instance_eval(&catch.block)
105
+ clear_command
106
+ end
107
+
108
+ # DSL method for adding simple commands
109
+ def register_command(name, params = [], &block)
110
+ @commands.register_command(name, params, block)
111
+ end
112
+
113
+ # Method for triggering command
114
+ def run_command!
115
+ instance_eval(&current_command_object.block)
116
+ clear_command
117
+ end
118
+
119
+ def clear_command
120
+ @state[:cmd] = nil
121
+ end
122
+
123
+ # Checks if the command is ready to be executed
124
+ def command_ready?
125
+ cmd = current_command_object
126
+ cmd.ready?(current_params)
127
+ end
128
+
129
+ # loads parameters from state
130
+ def current_params
131
+ @state[:params] || {}
132
+ end
133
+
134
+ def params
135
+ current_params
136
+ end
137
+
138
+ def mention(name)
139
+ @provider.mention(name)
140
+ end
141
+
142
+ # Loads command from state
143
+ def current_command_object
144
+ command = @state[:cmd]
145
+ @commands[command] || @commands['default']
146
+ end
147
+
148
+ # returns the current_channel from where the message was sent
149
+ def current_channel
150
+ @state[:channel_id]
151
+ end
152
+
153
+ def current_user
154
+ @last_message.user
155
+ end
156
+
157
+ def is_private?
158
+ @last_message.is_private?
159
+ end
160
+
161
+ # stores the command into state
162
+ def command=(cmd)
163
+ log_debug('Message set as command', command: cmd)
164
+
165
+ @state[:cmd] = cmd.split(' ').first
166
+ @state[:params] = {}
167
+ end
168
+
169
+ # validates which is the following parameter required
170
+ def next_missing_param
171
+ current_command_object.next_missing_param(current_params)
172
+ end
173
+
174
+ # Sends a message to get the next parameter from the user
175
+ def ask_param(param)
176
+ log_debug('I\'m going to ask the next param', param: param)
177
+ @provider.send_message(current_channel,
178
+ "I need you to tell me #{param}")
179
+ @state[:requested_param] = param.to_s
180
+ end
181
+
182
+ # Stores a parameter into the status
183
+ def add_param(value)
184
+ return if @state[:requested_param].nil?
185
+
186
+ log_debug('Received new param',
187
+ param: @state[:requested_param].to_sym,
188
+ value: value)
189
+
190
+ @state[:params][@state[:requested_param].to_sym] = value
191
+ end
192
+
193
+ # Loads the state from storage
194
+ def load_state!(channel)
195
+ @state = load_state(channel)
196
+ end
197
+
198
+ # Private implementation for load message
199
+ def load_state(channel)
200
+ data = @factory.get(channel)
201
+ data[:params] = JSON.parse(data[:params], symbolize_names: true)
202
+ data
203
+ rescue Kybus::Storage::Exceptions::ObjectNotFound
204
+ @factory.create(channel_id: channel, params: {}.to_json)
205
+ end
206
+
207
+ # Saves the state into storage
208
+ def save_state!
209
+ json = @state[:params]
210
+ @state[:params] = json.to_json
211
+ @state.store
212
+ @state[:params] = json
213
+ end
214
+
215
+ def session
216
+ @repository
217
+ end
218
+ end
219
+ end
220
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kybus
4
+ module Bot
5
+ # Object that wraps a command, it is analogus to a route definition.
6
+ # it currently only gets a param list, but it will be extended to a more
7
+ # complex DSL.
8
+ class Command
9
+ attr_reader :block
10
+
11
+ # Receives a list of params as symbols and the lambda with the block.
12
+ def initialize(params, block)
13
+ @params = params
14
+ @block = block
15
+ end
16
+
17
+ # Checks if the params object given contains all the needed values
18
+ def ready?(current_params)
19
+ @params.all? { |key| current_params.key?(key) }
20
+ end
21
+
22
+ # Finds the first empty param from the given parameter
23
+ def next_missing_param(current_params)
24
+ @params.find { |key| !current_params.key?(key) }
25
+ end
26
+ end
27
+
28
+ # Wraps a collection of commands.
29
+ class CommandDefinition
30
+ def initialize
31
+ @commands = {}
32
+ end
33
+
34
+ # Stores an operation definition
35
+ def register_command(name, params, block)
36
+ @commands[name] = Command.new(params, block)
37
+ end
38
+
39
+ # Returns a command with the name
40
+ def [](name)
41
+ @commands[name]
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'kybus/dry/daemon'
4
+ require 'kybus/bot/adapters/base'
5
+
6
+ module Kybus
7
+ module Bot
8
+ # Base implementation for messages from distinct providers
9
+ class Message
10
+ # Converts the messages into a hash
11
+ def to_h
12
+ {
13
+ text: raw_message,
14
+ channel: channel_id
15
+ }
16
+ end
17
+
18
+ # Returns true when the received message is a command. Convention states
19
+ # that messages should start with '/' to be considered commands
20
+ def command?
21
+ raw_message&.split(' ')&.first&.start_with?('/')
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'sequel'
4
+ require 'sequel/extensions/migration'
5
+ module Kybus
6
+ module Bot
7
+ module Migrator
8
+ class << self
9
+ def run_migrations!(conn)
10
+ conn.create_table?(:bot_sessions) do
11
+ String :channel_id
12
+ String :user
13
+ String :params, text: true
14
+ String :cmd
15
+ String :requested_param
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'adapters/debug'
4
+ require_relative 'base'
5
+ module Kybus
6
+ module Bot
7
+ class NonDebugAdapterInTesting < StandardError
8
+ end
9
+
10
+ # Base class for bot implementation. It wraps the threads execution, the
11
+ # provider and the state storage inside an object.
12
+ class Base
13
+ include Kybus::Bot::Adapter
14
+ def stub_channels(messages)
15
+ raise(NonDebugAdapterInTesting) unless @provider.is_a?(Debug)
16
+
17
+ @provider = Debug.new('channels' => messages)
18
+ end
19
+
20
+ def run_test
21
+ run
22
+ rescue Debug::NoMoreMessageException
23
+ true
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kybus
4
+ module Bot
5
+ VERSION = '0.4.1'
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,250 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: kybus-bot
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.1
5
+ platform: ruby
6
+ authors:
7
+ - Gilberto Vargas
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-06-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: kybus-core
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: kybus-logger
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.1'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: kybus-storage
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.1'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.1'
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '5.11'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '5.11'
69
+ - !ruby/object:Gem::Dependency
70
+ name: mocha
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.8'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.8'
83
+ - !ruby/object:Gem::Dependency
84
+ name: pry
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.12'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.12'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rack-minitest
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rake
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '12.3'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '12.3'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rdoc
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '6.1'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '6.1'
139
+ - !ruby/object:Gem::Dependency
140
+ name: sequel
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: simplecov
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '0.16'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: '0.16'
167
+ - !ruby/object:Gem::Dependency
168
+ name: sqlite3
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
181
+ - !ruby/object:Gem::Dependency
182
+ name: telegram-bot-ruby
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - ">="
186
+ - !ruby/object:Gem::Version
187
+ version: '0'
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - ">="
193
+ - !ruby/object:Gem::Version
194
+ version: '0'
195
+ - !ruby/object:Gem::Dependency
196
+ name: webmock
197
+ requirement: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - "~>"
200
+ - !ruby/object:Gem::Version
201
+ version: '3.5'
202
+ type: :development
203
+ prerelease: false
204
+ version_requirements: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - "~>"
207
+ - !ruby/object:Gem::Version
208
+ version: '3.5'
209
+ description: Provides a framework for building bots with ruby
210
+ email:
211
+ - tachoguitar@gmail.com
212
+ executables: []
213
+ extensions: []
214
+ extra_rdoc_files: []
215
+ files:
216
+ - lib/kybus/bot.rb
217
+ - lib/kybus/bot/adapters/base.rb
218
+ - lib/kybus/bot/adapters/debug.rb
219
+ - lib/kybus/bot/adapters/discord.rb
220
+ - lib/kybus/bot/adapters/telegram.rb
221
+ - lib/kybus/bot/base.rb
222
+ - lib/kybus/bot/command_definition.rb
223
+ - lib/kybus/bot/message.rb
224
+ - lib/kybus/bot/migrator.rb
225
+ - lib/kybus/bot/testing.rb
226
+ - lib/kybus/bot/version.rb
227
+ homepage: https://github.com/tachomex/kybus
228
+ licenses:
229
+ - MIT
230
+ metadata: {}
231
+ post_install_message:
232
+ rdoc_options: []
233
+ require_paths:
234
+ - lib
235
+ required_ruby_version: !ruby/object:Gem::Requirement
236
+ requirements:
237
+ - - ">="
238
+ - !ruby/object:Gem::Version
239
+ version: '0'
240
+ required_rubygems_version: !ruby/object:Gem::Requirement
241
+ requirements:
242
+ - - ">="
243
+ - !ruby/object:Gem::Version
244
+ version: '0'
245
+ requirements: []
246
+ rubygems_version: 3.1.4
247
+ signing_key:
248
+ specification_version: 4
249
+ summary: Provides a framework for building bots with ruby
250
+ test_files: []