kybus-bot 0.5.1 → 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,131 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+ require_relative 'command/command'
5
+ require_relative 'command/command_definition'
6
+ require_relative 'command/execution_context'
7
+
8
+ module Kybus
9
+ module Bot
10
+ class CommandExecutor
11
+ extend Forwardable
12
+
13
+ include Kybus::Logger
14
+ attr_reader :dsl, :bot, :execution_context
15
+
16
+ def_delegator :execution_context, :save!, :save_execution_context!
17
+
18
+ def state
19
+ execution_context&.state
20
+ end
21
+
22
+ def initialize(bot, channel_factory, inline_args)
23
+ @bot = bot
24
+ @channel_factory = channel_factory
25
+ @dsl = DSLMethods.new(bot.provider, state, bot)
26
+ @inline_args = inline_args
27
+ @precommand_hook = proc {}
28
+ end
29
+
30
+ # Process a single message, this method can be overwriten to enable
31
+ # more complex implementations of commands. It receives a message object.
32
+ def process_message(message)
33
+ @execution_context = ExecutionContest.new(message.channel_id, @channel_factory)
34
+ save_token!(message)
35
+ msg = run_command_or_prepare!
36
+ save_execution_context!
37
+ msg
38
+ end
39
+
40
+ def save_param!(message)
41
+ execution_context.add_param(message.raw_message)
42
+ return unless message.has_attachment?
43
+
44
+ file = bot.provider.file_builder(message.attachment)
45
+ execution_context.add_file(file)
46
+ end
47
+
48
+ def search_command_with_inline_arg(message)
49
+ command, values = @channel_factory.command_with_inline_arg(message.raw_message)
50
+ if command
51
+ execution_context.command = command
52
+ values.each do |value|
53
+ execution_context.next_param = execution_context.next_missing_param
54
+ execution_context.add_param(value)
55
+ end
56
+ else
57
+ execution_context.command = @channel_factory.default_command
58
+ end
59
+ end
60
+
61
+ def save_token!(message)
62
+ if execution_context.expecting_command?
63
+ command = @channel_factory.command(message.command)
64
+ if @inline_args && !command
65
+ search_command_with_inline_arg(message)
66
+ elsif !@inline_args && !command
67
+ execution_context.command = @channel_factory.default_command
68
+ else
69
+ execution_context.command = command
70
+ end
71
+ else
72
+ save_param!(message)
73
+ end
74
+ end
75
+
76
+ def run_command_or_prepare!
77
+ if execution_context.ready?
78
+ @dsl.state = execution_context.state
79
+ @dsl.instance_eval(&@precommand_hook)
80
+ msg = run_command!
81
+ execution_context.clear_command
82
+ msg
83
+ else
84
+ param = execution_context.next_missing_param
85
+ ask_param(param, execution_context.state.command.params_ask_label(param))
86
+ end
87
+ end
88
+
89
+ def precommand_hook(&block)
90
+ @precommand_hook = proc(&block)
91
+ end
92
+
93
+ def fallback(error)
94
+ catch = @channel_factory.command(error)
95
+ log_error('Unexpected error', error)
96
+ execution_context.command = catch if catch
97
+ end
98
+
99
+ # Method for triggering command
100
+ def run_command!
101
+ execution_context.call!(@dsl)
102
+ rescue StandardError => e
103
+ raise unless fallback(e)
104
+
105
+ execution_context.state.store_param(:_last_exception, e)
106
+ retry
107
+ end
108
+
109
+ def invoke(command_name, args)
110
+ command = @channel_factory.command(command_name)
111
+ if command.nil? || command.params_size != args.size
112
+ raise "Wrong redirect #{command_name}, #{bot.registered_commands}"
113
+ end
114
+
115
+ state.command = command
116
+ command.params.zip(args).each do |param, value|
117
+ state.store_param(param, value)
118
+ end
119
+ run_command_or_prepare!
120
+ end
121
+
122
+ # Sends a message to get the next parameter from the user
123
+ def ask_param(param, label = nil)
124
+ provider = bot.provider
125
+ msg = label || "I need you to tell me #{param}"
126
+ bot.send_message(provider.last_message.channel_id, msg)
127
+ execution_context.next_param = param
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kybus
4
+ module Bot
5
+ class DSLMethods
6
+ attr_accessor :state
7
+ attr_reader :provider
8
+
9
+ def initialize(provider, state, bot)
10
+ @provider = provider
11
+ @state = state
12
+ @bot = bot
13
+ end
14
+
15
+ def send_message(content, channel = nil)
16
+ raise(Base::EmptyMessageError) unless content
17
+
18
+ provider.send_message(channel || current_channel, content)
19
+ end
20
+
21
+ def send_image(content, channel = nil, caption: nil)
22
+ provider.send_image(channel || current_channel, content, caption)
23
+ end
24
+
25
+ def send_video(content, channel = nil, caption: nil)
26
+ provider.send_video(channel || current_channel, content, caption)
27
+ end
28
+
29
+ def send_audio(content, channel = nil)
30
+ provider.send_audio(channel || current_channel, content)
31
+ end
32
+
33
+ def send_document(content, channel = nil)
34
+ provider.send_document(channel || current_channel, content)
35
+ end
36
+
37
+ def params
38
+ state.params
39
+ end
40
+
41
+ def files
42
+ state.files
43
+ end
44
+
45
+ def file(name)
46
+ (file = files[name]) && provider.file_builder(file)
47
+ end
48
+
49
+ def mention(name)
50
+ provider.mention(name)
51
+ end
52
+
53
+ def current_user
54
+ provider.last_message.user
55
+ end
56
+
57
+ def is_private?
58
+ provider.last_message.is_private?
59
+ end
60
+
61
+ def last_message
62
+ provider.last_message
63
+ end
64
+
65
+ # returns the current_channel from where the message was sent
66
+ def current_channel
67
+ state.channel_id
68
+ end
69
+
70
+ def command_name
71
+ state&.command&.name
72
+ end
73
+
74
+ def method_missing(method, *args, &block)
75
+ @bot.send(method, *args, &block)
76
+ end
77
+ end
78
+ end
79
+ end
@@ -8,17 +8,14 @@ module Kybus
8
8
  # Base implementation for messages from distinct providers
9
9
  class Message
10
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
11
  # Returns true when the received message is a command. Convention states
19
12
  # that messages should start with '/' to be considered commands
20
13
  def command?
21
- raw_message&.split(' ')&.first&.start_with?('/')
14
+ command&.start_with?('/')
15
+ end
16
+
17
+ def command
18
+ raw_message&.split(' ')&.first
22
19
  end
23
20
  end
24
21
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'base'
2
4
  require_relative 'adapters/debug'
3
5
 
@@ -13,19 +15,29 @@ module Kybus
13
15
  'pool_size' => 1,
14
16
  'provider' => {
15
17
  'name' => 'debug',
16
- 'echo' => true,
18
+ 'echo' => false,
17
19
  'channels' => { 'testing' => [] }
18
20
  }
19
21
  }.freeze
20
22
 
21
- def self.make_test_bot
22
- new(CONFIG)
23
+ def self.make_test_bot(extra_configs = {})
24
+ conf = CONFIG.merge(extra_configs)
25
+ conf['provider']['channels'] = { conf['channel_id'] => [] } if conf['channel_id']
26
+ bot = new(conf)
27
+ bot.instance_variable_set(:@default_channel_id, conf['provider']['channels'].keys.first)
28
+ bot
23
29
  end
24
30
 
25
31
  def receives(msg, attachments = nil)
26
- msg = ::Kybus::Bot::Adapter::DebugMessage.new(msg, 'testing', attachments)
27
- @last_message = msg
28
- process_message(msg)
32
+ attachments = Adapter::DebugMessage::DebugFile.new(attachments) if attachments
33
+ msg = Adapter::DebugMessage.new(msg, @default_channel_id, attachments)
34
+ log_info('Received message', channel: @default_channel_id, msg:)
35
+ provider.last_message = msg
36
+ executor.process_message(msg)
37
+ end
38
+
39
+ def expects(method)
40
+ executor.dsl.expects(method)
29
41
  end
30
42
  end
31
43
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Kybus
4
4
  module Bot
5
- VERSION = '0.5.1'
5
+ VERSION = '0.8.1'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kybus-bot
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gilberto Vargas
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-02-16 00:00:00.000000000 Z
11
+ date: 2023-05-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: kybus-core
@@ -218,8 +218,16 @@ files:
218
218
  - lib/kybus/bot/adapters/debug.rb
219
219
  - lib/kybus/bot/adapters/discord.rb
220
220
  - lib/kybus/bot/adapters/telegram.rb
221
+ - lib/kybus/bot/adapters/telegram_file.rb
222
+ - lib/kybus/bot/adapters/telegram_message.rb
221
223
  - lib/kybus/bot/base.rb
222
- - lib/kybus/bot/command_definition.rb
224
+ - lib/kybus/bot/command/command.rb
225
+ - lib/kybus/bot/command/command_definition.rb
226
+ - lib/kybus/bot/command/command_state.rb
227
+ - lib/kybus/bot/command/command_state_factory.rb
228
+ - lib/kybus/bot/command/execution_context.rb
229
+ - lib/kybus/bot/command_executor.rb
230
+ - lib/kybus/bot/dsl_methods.rb
223
231
  - lib/kybus/bot/message.rb
224
232
  - lib/kybus/bot/migrator.rb
225
233
  - lib/kybus/bot/test.rb
@@ -228,7 +236,8 @@ files:
228
236
  homepage: https://github.com/tachomex/kybus
229
237
  licenses:
230
238
  - MIT
231
- metadata: {}
239
+ metadata:
240
+ rubygems_mfa_required: 'true'
232
241
  post_install_message:
233
242
  rdoc_options: []
234
243
  require_paths:
@@ -244,7 +253,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
244
253
  - !ruby/object:Gem::Version
245
254
  version: '0'
246
255
  requirements: []
247
- rubygems_version: 3.2.32
256
+ rubygems_version: 3.4.10
248
257
  signing_key:
249
258
  specification_version: 4
250
259
  summary: Provides a framework for building bots with ruby