kybus-bot 0.5.1 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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