зеркало из
https://github.com/glebtv/telegram-bot.git
synced 2026-09-03 09:46:17 +03:00
Use bang-methods as actions for commands
Этот коммит содержится в:
@@ -54,6 +54,7 @@ module Telegram
|
||||
abstract!
|
||||
|
||||
%w[
|
||||
commands
|
||||
instrumentation
|
||||
log_subscriber
|
||||
reply_helpers
|
||||
@@ -79,6 +80,7 @@ module Telegram
|
||||
end
|
||||
|
||||
include AbstractController::Translation
|
||||
include Commands
|
||||
include Rescue
|
||||
include ReplyHelpers
|
||||
include Instrumentation
|
||||
@@ -96,8 +98,6 @@ module Telegram
|
||||
shipping_query
|
||||
pre_checkout_query
|
||||
].freeze
|
||||
CMD_REGEX = %r{\A/([a-z\d_]{,31})(@(\S+))?(\s|$)}i
|
||||
CONFLICT_CMD_REGEX = Regexp.new("^(#{PAYLOAD_TYPES.join('|')}|\\d)")
|
||||
|
||||
class << self
|
||||
# Initialize controller and process update.
|
||||
@@ -105,27 +105,6 @@ module Telegram
|
||||
new(*args).dispatch
|
||||
end
|
||||
|
||||
# Overrid it to filter or transform commands.
|
||||
# Default implementation is to convert to downcase and add `on_` prefix
|
||||
# for conflicting commands.
|
||||
def action_for_command(cmd)
|
||||
cmd.downcase!
|
||||
cmd.match(CONFLICT_CMD_REGEX) ? "on_#{cmd}" : cmd
|
||||
end
|
||||
|
||||
# Fetches command from text message. All subsequent words are returned
|
||||
# as arguments.
|
||||
# If command has mention (eg. `/test@SomeBot`), it returns commands only
|
||||
# for specified username. Set `username` to `true` to accept
|
||||
# any commands.
|
||||
def command_from_text(text, username = nil)
|
||||
return unless text
|
||||
match = text.match(CMD_REGEX)
|
||||
return unless match
|
||||
mention = match[3]
|
||||
[match[1], text.split.drop(1)] if username == true || !mention || mention == username
|
||||
end
|
||||
|
||||
def payload_from_update(update)
|
||||
update && PAYLOAD_TYPES.find do |type|
|
||||
item = update[type]
|
||||
@@ -134,8 +113,7 @@ module Telegram
|
||||
end
|
||||
end
|
||||
|
||||
attr_internal_reader :update, :bot, :payload, :payload_type, :is_command
|
||||
alias_method :command?, :is_command
|
||||
attr_internal_reader :update, :bot, :payload, :payload_type
|
||||
delegate :username, to: :bot, prefix: true, allow_nil: true
|
||||
|
||||
# Second argument can be either update object with hash access & string
|
||||
@@ -175,49 +153,57 @@ module Telegram
|
||||
|
||||
# Processes current update.
|
||||
def dispatch
|
||||
@_is_command, action, args = action_for_payload
|
||||
action, args = action_for_payload
|
||||
process(action, *args)
|
||||
end
|
||||
|
||||
attr_internal_reader :action_options
|
||||
|
||||
# It provides support for passing array as action, where first vaule
|
||||
# is action name and second is action metadata.
|
||||
# This metadata is stored inside action_options
|
||||
def process(action, *args)
|
||||
action, options = action if action.is_a?(Array)
|
||||
@_action_options = options || {}
|
||||
super
|
||||
end
|
||||
|
||||
# There are multiple ways how action name is calculated for update
|
||||
# (see Commands, MessageContext, etc.). This method represents the
|
||||
# way how action was calculated for current udpate.
|
||||
#
|
||||
# Some of possible values are `:payload, :command, :message_context`.
|
||||
def action_type
|
||||
action_options[:type] || :payload
|
||||
end
|
||||
|
||||
# Calculates action name and args for payload.
|
||||
# Uses `action_for_#{payload_type}` methods.
|
||||
# If this method doesn't return anything
|
||||
# it uses fallback with action same as payload type.
|
||||
# Returns array `[is_command?, action, args]`.
|
||||
# Returns array `[action, args]`.
|
||||
def action_for_payload
|
||||
if payload_type
|
||||
send("action_for_#{payload_type}") || action_for_default_payload
|
||||
else
|
||||
[false, :unsupported_payload_type, []]
|
||||
[:unsupported_payload_type, []]
|
||||
end
|
||||
end
|
||||
|
||||
def action_for_default_payload
|
||||
[false, payload_type, [payload]]
|
||||
[payload_type, [payload]]
|
||||
end
|
||||
|
||||
# If payload is a message with command, then returned action is an
|
||||
# action for this command.
|
||||
# Separate method, so it can be easily overriden (ex. MessageContext).
|
||||
#
|
||||
# This is not used for edited messages/posts. It process them as basic updates.
|
||||
def action_for_message
|
||||
cmd, args = self.class.command_from_text(payload['text'], bot_username)
|
||||
cmd &&= self.class.action_for_command(cmd)
|
||||
[true, cmd, args] if cmd
|
||||
end
|
||||
alias_method :action_for_channel_post, :action_for_message
|
||||
|
||||
def action_for_inline_query
|
||||
[false, payload_type, [payload['query'], payload['offset']]]
|
||||
[payload_type, [payload['query'], payload['offset']]]
|
||||
end
|
||||
|
||||
def action_for_chosen_inline_result
|
||||
[false, payload_type, [payload['result_id'], payload['query']]]
|
||||
[payload_type, [payload['result_id'], payload['query']]]
|
||||
end
|
||||
|
||||
def action_for_callback_query
|
||||
[false, payload_type, [payload['data']]]
|
||||
[payload_type, [payload['data']]]
|
||||
end
|
||||
|
||||
# Silently ignore unsupported messages.
|
||||
|
||||
@@ -17,8 +17,12 @@ module Telegram
|
||||
context, new_data = context_from_callback_query
|
||||
if context
|
||||
action_name = "#{context}_callback_query"
|
||||
[false, action_name, [new_data]] if action_method?(action_name)
|
||||
end || super
|
||||
if action_method?(action_name)
|
||||
action_options = {type: :callback_query_context, context: context}
|
||||
return [[action_name, action_options], [new_data]]
|
||||
end
|
||||
end
|
||||
super
|
||||
end
|
||||
|
||||
def context_from_callback_query
|
||||
|
||||
44
lib/telegram/bot/updates_controller/commands.rb
Обычный файл
44
lib/telegram/bot/updates_controller/commands.rb
Обычный файл
@@ -0,0 +1,44 @@
|
||||
module Telegram
|
||||
module Bot
|
||||
class UpdatesController
|
||||
# Support for parsing commands
|
||||
module Commands
|
||||
CMD_REGEX = %r{\A/([a-z\d_]{,31})(@(\S+))?(\s|$)}i
|
||||
|
||||
class << self
|
||||
# Fetches command from text message. All subsequent words are returned
|
||||
# as arguments.
|
||||
# If command has mention (eg. `/test@SomeBot`), it returns commands only
|
||||
# for specified username. Set `username` to `true` to accept
|
||||
# any commands.
|
||||
def command_from_text(text, username = nil)
|
||||
return unless text
|
||||
match = text.match(CMD_REGEX)
|
||||
return unless match
|
||||
mention = match[3]
|
||||
[match[1], text.split.drop(1)] if username == true || !mention || mention == username
|
||||
end
|
||||
end
|
||||
|
||||
# Override it to filter or transform commands.
|
||||
# Default implementation is to downcase and add `!` suffix.
|
||||
def action_for_command(cmd)
|
||||
"#{cmd.downcase}!"
|
||||
end
|
||||
|
||||
# If payload is a message with command, then returned action is an
|
||||
# action for this command.
|
||||
# Separate method, so it can be easily overriden (ex. MessageContext).
|
||||
#
|
||||
# This is not used for edited messages/posts. It process them as basic updates.
|
||||
def action_for_message
|
||||
cmd, args = Commands.command_from_text(payload['text'], bot_username)
|
||||
return unless cmd
|
||||
[[action_for_command(cmd), type: :command, command: cmd], args]
|
||||
end
|
||||
|
||||
alias_method :action_for_channel_post, :action_for_message
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -48,7 +48,7 @@ module Telegram
|
||||
end
|
||||
|
||||
# Action to clear context.
|
||||
def cancel
|
||||
def cancel!
|
||||
# Context is already cleared in action_for_message
|
||||
end
|
||||
|
||||
@@ -71,7 +71,10 @@ module Telegram
|
||||
@context = val && val.to_sym
|
||||
super || context && begin
|
||||
handler = handler_for_context
|
||||
[true, handler, payload['text'].try!(:split) || []] if handler
|
||||
if handler
|
||||
action_options = {type: :message_context, context: context}
|
||||
[[handler, action_options], payload['text'].try!(:split) || []]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
Ссылка в новой задаче
Block a user